2017-02-07 21:33:23 +00:00
package forward
import (
"net"
"net/http"
"strings"
"github.com/vulcand/oxy/utils"
)
2018-08-20 08:38:03 +00:00
// HeaderRewriter is responsible for removing hop-by-hop headers and setting forwarding headers
2017-02-07 21:33:23 +00:00
type HeaderRewriter struct {
TrustForwardHeader bool
Hostname string
}
2017-11-22 17:20:03 +00:00
// clean up IP in case if it is ipv6 address and it has {zone} information in it, like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3 Ethernet Adapter - Virtual Switch)]:64692"
func ipv6fix ( clientIP string ) string {
return strings . Split ( clientIP , "%" ) [ 0 ]
}
2018-08-20 08:38:03 +00:00
// Rewrite rewrite request headers
2017-02-07 21:33:23 +00:00
func ( rw * HeaderRewriter ) Rewrite ( req * http . Request ) {
2017-10-23 14:12:03 +00:00
if ! rw . TrustForwardHeader {
utils . RemoveHeaders ( req . Header , XHeaders ... )
}
2017-02-07 21:33:23 +00:00
if clientIP , _ , err := net . SplitHostPort ( req . RemoteAddr ) ; err == nil {
2017-11-22 17:20:03 +00:00
clientIP = ipv6fix ( clientIP )
// If not websocket, done in http.ReverseProxy
if IsWebsocketRequest ( req ) {
if prior , ok := req . Header [ XForwardedFor ] ; ok {
req . Header . Set ( XForwardedFor , strings . Join ( prior , ", " ) + ", " + clientIP )
} else {
req . Header . Set ( XForwardedFor , clientIP )
}
2017-10-23 14:12:03 +00:00
}
if req . Header . Get ( XRealIp ) == "" {
req . Header . Set ( XRealIp , clientIP )
2017-02-07 21:33:23 +00:00
}
}
2017-10-23 14:12:03 +00:00
xfProto := req . Header . Get ( XForwardedProto )
if xfProto == "" {
if req . TLS != nil {
req . Header . Set ( XForwardedProto , "https" )
} else {
req . Header . Set ( XForwardedProto , "http" )
}
2017-02-07 21:33:23 +00:00
}
2017-11-22 17:20:03 +00:00
if IsWebsocketRequest ( req ) {
if req . Header . Get ( XForwardedProto ) == "https" {
req . Header . Set ( XForwardedProto , "wss" )
} else {
req . Header . Set ( XForwardedProto , "ws" )
}
}
if xfPort := req . Header . Get ( XForwardedPort ) ; xfPort == "" {
2017-10-23 14:12:03 +00:00
req . Header . Set ( XForwardedPort , forwardedPort ( req ) )
2017-08-20 17:02:02 +00:00
}
2017-10-23 14:12:03 +00:00
if xfHost := req . Header . Get ( XForwardedHost ) ; xfHost == "" && req . Host != "" {
2017-02-07 21:33:23 +00:00
req . Header . Set ( XForwardedHost , req . Host )
}
if rw . Hostname != "" {
req . Header . Set ( XForwardedServer , rw . Hostname )
}
2017-11-22 17:20:03 +00:00
if ! IsWebsocketRequest ( req ) {
// Remove hop-by-hop headers to the backend. Especially important is "Connection" because we want a persistent
// connection, regardless of what the client sent to us.
utils . RemoveHeaders ( req . Header , HopHeaders ... )
}
2017-02-07 21:33:23 +00:00
}
2017-10-23 14:12:03 +00:00
func forwardedPort ( req * http . Request ) string {
if req == nil {
return ""
}
if _ , port , err := net . SplitHostPort ( req . Host ) ; err == nil && port != "" {
return port
}
2018-08-20 08:38:03 +00:00
if req . Header . Get ( XForwardedProto ) == "https" || req . Header . Get ( XForwardedProto ) == "wss" {
return "443"
}
2017-10-23 14:12:03 +00:00
if req . TLS != nil {
return "443"
}
return "80"
}