From 67e3bc6380a680eac0a9663f55c0cdb05bc875ac Mon Sep 17 00:00:00 2001 From: Romain Date: Tue, 20 Sep 2022 12:22:08 +0200 Subject: [PATCH 1/4] Add documentation for ECS constraints option --- docs/content/providers/ecs.md | 64 ++++++++++++++++++++++++++++++ docs/content/providers/overview.md | 2 + 2 files changed, 66 insertions(+) diff --git a/docs/content/providers/ecs.md b/docs/content/providers/ecs.md index 282da12aa..629a7a394 100644 --- a/docs/content/providers/ecs.md +++ b/docs/content/providers/ecs.md @@ -137,6 +137,70 @@ providers: # ... ``` +### `constraints` + +_Optional, Default=""_ + +The `constraints` option can be set to an expression that Traefik matches against the container labels (task), +to determine whether to create any route for that container. +If none of the container labels match the expression, no route for that container is created. +If the expression is empty, all detected containers are included. + +The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions, +as well as the usual boolean logic, as shown in examples below. + +??? example "Constraints Expression Examples" + + ```toml + # Includes only containers having a label with key `a.label.name` and value `foo` + constraints = "Label(`a.label.name`, `foo`)" + ``` + + ```toml + # Excludes containers having any label with key `a.label.name` and value `foo` + constraints = "!Label(`a.label.name`, `value`)" + ``` + + ```toml + # With logical AND. + constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)" + ``` + + ```toml + # With logical OR. + constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)" + ``` + + ```toml + # With logical AND and OR, with precedence set by parentheses. + constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))" + ``` + + ```toml + # Includes only containers having a label with key `a.label.name` and a value matching the `a.+` regular expression. + constraints = "LabelRegex(`a.label.name`, `a.+`)" + ``` + +For additional information, refer to [Restrict the Scope of Service Discovery](./overview.md#restrict-the-scope-of-service-discovery). + +```yaml tab="File (YAML)" +providers: + ecs: + constraints: "Label(`a.label.name`,`foo`)" + # ... +``` + +```toml tab="File (TOML)" +[providers.ecs] + constraints = "Label(`a.label.name`,`foo`)" + # ... +``` + +```bash tab="CLI" +--providers.ecs.constraints=Label(`a.label.name`,`foo`) +# ... +``` + ### `defaultRule` _Optional, Default=```Host(`{{ normalize .Name }}`)```_ diff --git a/docs/content/providers/overview.md b/docs/content/providers/overview.md index 8366d1155..de0af45fe 100644 --- a/docs/content/providers/overview.md +++ b/docs/content/providers/overview.md @@ -213,6 +213,7 @@ you can do so in two different ways: List of providers that support these features: - [Docker](./docker.md#exposedbydefault) +- [ECS](./ecs.md#exposedbydefault) - [Consul Catalog](./consul-catalog.md#exposedbydefault) - [Nomad](./nomad.md#exposedbydefault) - [Rancher](./rancher.md#exposedbydefault) @@ -223,6 +224,7 @@ List of providers that support these features: List of providers that support constraints: - [Docker](./docker.md#constraints) +- [ECS](./ecs.md#constraints) - [Consul Catalog](./consul-catalog.md#constraints) - [Nomad](./nomad.md#constraints) - [Rancher](./rancher.md#constraints) From 83ae1021f696d841ac2e0a0518b8fc200d1b14e3 Mon Sep 17 00:00:00 2001 From: t3hchipmunk <11212165+t3hchipmunk@users.noreply.github.com> Date: Wed, 21 Sep 2022 08:30:09 -0400 Subject: [PATCH 2/4] fix: UDP loadbalancer tags not being used with Consul Catalog --- pkg/provider/consulcatalog/config.go | 59 +++++++++++------------ pkg/provider/consulcatalog/config_test.go | 55 ++++++++++++++++++++- 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/pkg/provider/consulcatalog/config.go b/pkg/provider/consulcatalog/config.go index 9a81a9c63..15da47679 100644 --- a/pkg/provider/consulcatalog/config.go +++ b/pkg/provider/consulcatalog/config.go @@ -198,29 +198,27 @@ func (p *Provider) addServerTCP(item itemData, loadBalancer *dynamic.TCPServersL return errors.New("load-balancer is not defined") } - var port string - if len(loadBalancer.Servers) > 0 { - port = loadBalancer.Servers[0].Port - } - if len(loadBalancer.Servers) == 0 { loadBalancer.Servers = []dynamic.TCPServer{{}} } - if item.Port != "" && port == "" { - port = item.Port - } - loadBalancer.Servers[0].Port = "" - - if port == "" { - return errors.New("port is missing") - } - if item.Address == "" { return errors.New("address is missing") } + port := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + + if port == "" { + port = item.Port + } + + if port == "" { + return errors.New("port is missing") + } + loadBalancer.Servers[0].Address = net.JoinHostPort(item.Address, port) + return nil } @@ -233,21 +231,23 @@ func (p *Provider) addServerUDP(item itemData, loadBalancer *dynamic.UDPServersL loadBalancer.Servers = []dynamic.UDPServer{{}} } - var port string - if item.Port != "" { + if item.Address == "" { + return errors.New("address is missing") + } + + port := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + + if port == "" { port = item.Port - loadBalancer.Servers[0].Port = "" } if port == "" { return errors.New("port is missing") } - if item.Address == "" { - return errors.New("address is missing") - } - loadBalancer.Servers[0].Address = net.JoinHostPort(item.Address, port) + return nil } @@ -256,11 +256,6 @@ func (p *Provider) addServer(item itemData, loadBalancer *dynamic.ServersLoadBal return errors.New("load-balancer is not defined") } - var port string - if len(loadBalancer.Servers) > 0 { - port = loadBalancer.Servers[0].Port - } - if len(loadBalancer.Servers) == 0 { server := dynamic.Server{} server.SetDefaults() @@ -268,17 +263,19 @@ func (p *Provider) addServer(item itemData, loadBalancer *dynamic.ServersLoadBal loadBalancer.Servers = []dynamic.Server{server} } - if item.Port != "" && port == "" { - port = item.Port + if item.Address == "" { + return errors.New("address is missing") } + + port := loadBalancer.Servers[0].Port loadBalancer.Servers[0].Port = "" if port == "" { - return errors.New("port is missing") + port = item.Port } - if item.Address == "" { - return errors.New("address is missing") + if port == "" { + return errors.New("port is missing") } scheme := loadBalancer.Servers[0].Scheme diff --git a/pkg/provider/consulcatalog/config_test.go b/pkg/provider/consulcatalog/config_test.go index a63d916d0..4e5b0a4e5 100644 --- a/pkg/provider/consulcatalog/config_test.go +++ b/pkg/provider/consulcatalog/config_test.go @@ -2220,7 +2220,7 @@ func Test_buildConfiguration(t *testing.T) { Labels: map[string]string{ "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", "traefik.tcp.routers.foo.tls.options": "foo", - "traefik.tcp.services.foo.loadbalancer.server.port": "80", + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", }, Address: "127.0.0.1", Port: "80", @@ -2244,7 +2244,7 @@ func Test_buildConfiguration(t *testing.T) { LoadBalancer: &dynamic.TCPServersLoadBalancer{ Servers: []dynamic.TCPServer{ { - Address: "127.0.0.1:80", + Address: "127.0.0.1:8080", }, }, TerminationDelay: Int(100), @@ -2611,6 +2611,57 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, + { + desc: "UDP service with labels only", + ConnectAware: true, + items: []itemData{ + { + ID: "1", + Node: "Node1", + Datacenter: "dc1", + Name: "Test", + Namespace: "ns", + Labels: map[string]string{ + "traefik.udp.routers.test-udp-label.service": "test-udp-label-service", + "traefik.udp.routers.test-udp-label.entryPoints": "udp", + "traefik.udp.services.test-udp-label-service.loadBalancer.server.port": "21116", + }, + Address: "127.0.0.1", + Port: "80", + Status: api.HealthPassing, + }, + }, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{}, + Middlewares: map[string]*dynamic.TCPMiddleware{}, + Services: map[string]*dynamic.TCPService{}, + }, + UDP: &dynamic.UDPConfiguration{ + Routers: map[string]*dynamic.UDPRouter{ + "test-udp-label": { + EntryPoints: []string{"udp"}, + Service: "test-udp-label-service", + }, + }, + Services: map[string]*dynamic.UDPService{ + "test-udp-label-service": { + LoadBalancer: &dynamic.UDPServersLoadBalancer{ + Servers: []dynamic.UDPServer{ + {Address: "127.0.0.1:21116"}, + }, + }, + }, + }, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{}, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{}, + ServersTransports: map[string]*dynamic.ServersTransport{}, + }, + }, + }, } for _, test := range testCases { From 7ac687a0a96e942847636a3b7d30abd18ce1185c Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Wed, 21 Sep 2022 14:54:08 +0200 Subject: [PATCH 3/4] providers: simplify AddServer algorithms --- pkg/provider/docker/config.go | 51 ++++++++++-------------- pkg/provider/ecs/config.go | 53 ++++++++++--------------- pkg/provider/nomad/config.go | 71 +++++++++++++++------------------- pkg/provider/rancher/config.go | 65 ++++++++++++++----------------- 4 files changed, 101 insertions(+), 139 deletions(-) diff --git a/pkg/provider/docker/config.go b/pkg/provider/docker/config.go index fe1e6c655..25e0133c1 100644 --- a/pkg/provider/docker/config.go +++ b/pkg/provider/docker/config.go @@ -187,28 +187,24 @@ func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadB return errors.New("load-balancer is not defined") } - var serverPort string - if len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port - loadBalancer.Servers[0].Port = "" + if len(loadBalancer.Servers) == 0 { + loadBalancer.Servers = []dynamic.TCPServer{{}} } + serverPort := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + ip, port, err := p.getIPPort(ctx, container, serverPort) if err != nil { return err } - if len(loadBalancer.Servers) == 0 { - server := dynamic.TCPServer{} - - loadBalancer.Servers = []dynamic.TCPServer{server} - } - if port == "" { return errors.New("port is missing") } loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port) + return nil } @@ -217,28 +213,24 @@ func (p *Provider) addServerUDP(ctx context.Context, container dockerData, loadB return errors.New("load-balancer is not defined") } - var serverPort string - if len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port - loadBalancer.Servers[0].Port = "" + if len(loadBalancer.Servers) == 0 { + loadBalancer.Servers = []dynamic.UDPServer{{}} } + serverPort := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + ip, port, err := p.getIPPort(ctx, container, serverPort) if err != nil { return err } - if len(loadBalancer.Servers) == 0 { - server := dynamic.UDPServer{} - - loadBalancer.Servers = []dynamic.UDPServer{server} - } - if port == "" { return errors.New("port is missing") } loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port) + return nil } @@ -247,17 +239,6 @@ func (p *Provider) addServer(ctx context.Context, container dockerData, loadBala return errors.New("load-balancer is not defined") } - var serverPort string - if len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port - loadBalancer.Servers[0].Port = "" - } - - ip, port, err := p.getIPPort(ctx, container, serverPort) - if err != nil { - return err - } - if len(loadBalancer.Servers) == 0 { server := dynamic.Server{} server.SetDefaults() @@ -265,6 +246,14 @@ func (p *Provider) addServer(ctx context.Context, container dockerData, loadBala loadBalancer.Servers = []dynamic.Server{server} } + serverPort := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + + ip, port, err := p.getIPPort(ctx, container, serverPort) + if err != nil { + return err + } + if port == "" { return errors.New("port is missing") } diff --git a/pkg/provider/ecs/config.go b/pkg/provider/ecs/config.go index 02684a07f..7d38d8ac3 100644 --- a/pkg/provider/ecs/config.go +++ b/pkg/provider/ecs/config.go @@ -185,7 +185,7 @@ func (p *Provider) filterInstance(ctx context.Context, instance ecsInstance) boo matches, err := constraints.MatchLabels(instance.Labels, p.Constraints) if err != nil { - logger.Errorf("Error matching constraints expression: %v", err) + logger.Errorf("Error matching constraint expression: %v", err) return false } if !matches { @@ -201,28 +201,24 @@ func (p *Provider) addServerTCP(instance ecsInstance, loadBalancer *dynamic.TCPS return errors.New("load-balancer is not defined") } - var serverPort string - if len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port - loadBalancer.Servers[0].Port = "" + if len(loadBalancer.Servers) == 0 { + loadBalancer.Servers = []dynamic.TCPServer{{}} } + serverPort := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + ip, port, err := p.getIPPort(instance, serverPort) if err != nil { return err } - if len(loadBalancer.Servers) == 0 { - server := dynamic.TCPServer{} - - loadBalancer.Servers = []dynamic.TCPServer{server} - } - if port == "" { return errors.New("port is missing") } loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port) + return nil } @@ -231,28 +227,24 @@ func (p *Provider) addServerUDP(instance ecsInstance, loadBalancer *dynamic.UDPS return errors.New("load-balancer is not defined") } - var serverPort string - if len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port - loadBalancer.Servers[0].Port = "" + if len(loadBalancer.Servers) == 0 { + loadBalancer.Servers = []dynamic.UDPServer{{}} } + serverPort := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + ip, port, err := p.getIPPort(instance, serverPort) if err != nil { return err } - if len(loadBalancer.Servers) == 0 { - server := dynamic.UDPServer{} - - loadBalancer.Servers = []dynamic.UDPServer{server} - } - if port == "" { return errors.New("port is missing") } loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port) + return nil } @@ -261,17 +253,6 @@ func (p *Provider) addServer(instance ecsInstance, loadBalancer *dynamic.Servers return errors.New("load-balancer is not defined") } - var serverPort string - if len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port - loadBalancer.Servers[0].Port = "" - } - - ip, port, err := p.getIPPort(instance, serverPort) - if err != nil { - return err - } - if len(loadBalancer.Servers) == 0 { server := dynamic.Server{} server.SetDefaults() @@ -279,6 +260,14 @@ func (p *Provider) addServer(instance ecsInstance, loadBalancer *dynamic.Servers loadBalancer.Servers = []dynamic.Server{server} } + serverPort := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + + ip, port, err := p.getIPPort(instance, serverPort) + if err != nil { + return err + } + if port == "" { return errors.New("port is missing") } diff --git a/pkg/provider/nomad/config.go b/pkg/provider/nomad/config.go index 6ae3ebdfb..713438cb8 100644 --- a/pkg/provider/nomad/config.go +++ b/pkg/provider/nomad/config.go @@ -172,29 +172,27 @@ func (p *Provider) addServerTCP(i item, lb *dynamic.TCPServersLoadBalancer) erro return errors.New("load-balancer is missing") } - var port string - if len(lb.Servers) > 0 { - port = lb.Servers[0].Port - } - if len(lb.Servers) == 0 { lb.Servers = []dynamic.TCPServer{{}} } - if i.Port != 0 && port == "" { - port = strconv.Itoa(i.Port) - } - lb.Servers[0].Port = "" - - if port == "" { - return errors.New("port is missing") - } - if i.Address == "" { return errors.New("address is missing") } + port := lb.Servers[0].Port + lb.Servers[0].Port = "" + + if port == "" && i.Port > 0 { + port = strconv.Itoa(i.Port) + } + + if port == "" { + return errors.New("port is missing") + } + lb.Servers[0].Address = net.JoinHostPort(i.Address, port) + return nil } @@ -203,29 +201,27 @@ func (p *Provider) addServerUDP(i item, lb *dynamic.UDPServersLoadBalancer) erro return errors.New("load-balancer is missing") } - var port string - if len(lb.Servers) > 0 { - port = lb.Servers[0].Port - } - if len(lb.Servers) == 0 { lb.Servers = []dynamic.UDPServer{{}} } - if i.Port != 0 && port == "" { - port = strconv.Itoa(i.Port) - } - lb.Servers[0].Port = "" - - if port == "" { - return errors.New("port is missing") - } - if i.Address == "" { return errors.New("address is missing") } + port := lb.Servers[0].Port + lb.Servers[0].Port = "" + + if port == "" && i.Port > 0 { + port = strconv.Itoa(i.Port) + } + + if port == "" { + return errors.New("port is missing") + } + lb.Servers[0].Address = net.JoinHostPort(i.Address, port) + return nil } @@ -234,11 +230,6 @@ func (p *Provider) addServer(i item, lb *dynamic.ServersLoadBalancer) error { return errors.New("load-balancer is missing") } - var port string - if len(lb.Servers) > 0 { - port = lb.Servers[0].Port - } - if len(lb.Servers) == 0 { server := dynamic.Server{} server.SetDefaults() @@ -246,19 +237,21 @@ func (p *Provider) addServer(i item, lb *dynamic.ServersLoadBalancer) error { lb.Servers = []dynamic.Server{server} } - if i.Port != 0 && port == "" { + if i.Address == "" { + return errors.New("address is missing") + } + + port := lb.Servers[0].Port + lb.Servers[0].Port = "" + + if port == "" && i.Port > 0 { port = strconv.Itoa(i.Port) } - lb.Servers[0].Port = "" if port == "" { return errors.New("port is missing") } - if i.Address == "" { - return errors.New("address is missing") - } - scheme := lb.Servers[0].Scheme lb.Servers[0].Scheme = "" lb.Servers[0].URL = fmt.Sprintf("%s://%s", scheme, net.JoinHostPort(i.Address, port)) diff --git a/pkg/provider/rancher/config.go b/pkg/provider/rancher/config.go index 711ed5bb1..1f16e5e6f 100644 --- a/pkg/provider/rancher/config.go +++ b/pkg/provider/rancher/config.go @@ -160,7 +160,7 @@ func (p *Provider) keepService(ctx context.Context, service rancherData) bool { matches, err := constraints.MatchLabels(service.Labels, p.Constraints) if err != nil { - logger.Errorf("Error matching constraints expression: %v", err) + logger.Errorf("Error matching constraint expression: %v", err) return false } if !matches { @@ -185,23 +185,19 @@ func (p *Provider) keepService(ctx context.Context, service rancherData) bool { func (p *Provider) addServerTCP(ctx context.Context, service rancherData, loadBalancer *dynamic.TCPServersLoadBalancer) error { log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name) - serverPort := "" - - if loadBalancer != nil && len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port + if loadBalancer == nil { + return errors.New("load-balancer is not defined") } - port := getServicePort(service) - if len(loadBalancer.Servers) == 0 { - server := dynamic.TCPServer{} - - loadBalancer.Servers = []dynamic.TCPServer{server} + loadBalancer.Servers = []dynamic.TCPServer{{}} } - if serverPort != "" { - port = serverPort - loadBalancer.Servers[0].Port = "" + port := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + + if port == "" { + port = getServicePort(service) } if port == "" { @@ -216,29 +212,26 @@ func (p *Provider) addServerTCP(ctx context.Context, service rancherData, loadBa } loadBalancer.Servers = servers + return nil } func (p *Provider) addServerUDP(ctx context.Context, service rancherData, loadBalancer *dynamic.UDPServersLoadBalancer) error { log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name) - serverPort := "" - - if loadBalancer != nil && len(loadBalancer.Servers) > 0 { - serverPort = loadBalancer.Servers[0].Port + if loadBalancer == nil { + return errors.New("load-balancer is not defined") } - port := getServicePort(service) - if len(loadBalancer.Servers) == 0 { - server := dynamic.UDPServer{} - - loadBalancer.Servers = []dynamic.UDPServer{server} + loadBalancer.Servers = []dynamic.UDPServer{{}} } - if serverPort != "" { - port = serverPort - loadBalancer.Servers[0].Port = "" + port := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + + if port == "" { + port = getServicePort(service) } if port == "" { @@ -253,14 +246,16 @@ func (p *Provider) addServerUDP(ctx context.Context, service rancherData, loadBa } loadBalancer.Servers = servers + return nil } func (p *Provider) addServers(ctx context.Context, service rancherData, loadBalancer *dynamic.ServersLoadBalancer) error { log.FromContext(ctx).Debugf("Trying to add servers for service %s \n", service.Name) - serverPort := getLBServerPort(loadBalancer) - port := getServicePort(service) + if loadBalancer == nil { + return errors.New("load-balancer is not defined") + } if len(loadBalancer.Servers) == 0 { server := dynamic.Server{} @@ -269,9 +264,11 @@ func (p *Provider) addServers(ctx context.Context, service rancherData, loadBala loadBalancer.Servers = []dynamic.Server{server} } - if serverPort != "" { - port = serverPort - loadBalancer.Servers[0].Port = "" + port := loadBalancer.Servers[0].Port + loadBalancer.Servers[0].Port = "" + + if port == "" { + port = getServicePort(service) } if port == "" { @@ -286,14 +283,8 @@ func (p *Provider) addServers(ctx context.Context, service rancherData, loadBala } loadBalancer.Servers = servers - return nil -} -func getLBServerPort(loadBalancer *dynamic.ServersLoadBalancer) string { - if loadBalancer != nil && len(loadBalancer.Servers) > 0 { - return loadBalancer.Servers[0].Port - } - return "" + return nil } func getServicePort(data rancherData) string { From 9cd54baca4d608564ad49e4bf260d3c070c7f20b Mon Sep 17 00:00:00 2001 From: Julien Salleyron Date: Thu, 22 Sep 2022 10:00:09 +0200 Subject: [PATCH 4/4] Optimize websocket headers handling Co-authored-by: Kevin Pollet --- pkg/server/service/proxy.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pkg/server/service/proxy.go b/pkg/server/service/proxy.go index 93cd1c033..12ce95ce7 100644 --- a/pkg/server/service/proxy.go +++ b/pkg/server/service/proxy.go @@ -15,6 +15,7 @@ import ( ptypes "github.com/traefik/paerser/types" "github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/log" + "golang.org/x/net/http/httpguts" ) // StatusClientClosedRequest non-standard HTTP status code for client disconnection. @@ -67,16 +68,18 @@ func buildProxy(passHostHeader *bool, responseForwarding *dynamic.ResponseForwar // some servers need Sec-WebSocket-Key, Sec-WebSocket-Extensions, Sec-WebSocket-Accept, // Sec-WebSocket-Protocol and Sec-WebSocket-Version to be case-sensitive. // https://tools.ietf.org/html/rfc6455#page-20 - outReq.Header["Sec-WebSocket-Key"] = outReq.Header["Sec-Websocket-Key"] - outReq.Header["Sec-WebSocket-Extensions"] = outReq.Header["Sec-Websocket-Extensions"] - outReq.Header["Sec-WebSocket-Accept"] = outReq.Header["Sec-Websocket-Accept"] - outReq.Header["Sec-WebSocket-Protocol"] = outReq.Header["Sec-Websocket-Protocol"] - outReq.Header["Sec-WebSocket-Version"] = outReq.Header["Sec-Websocket-Version"] - delete(outReq.Header, "Sec-Websocket-Key") - delete(outReq.Header, "Sec-Websocket-Extensions") - delete(outReq.Header, "Sec-Websocket-Accept") - delete(outReq.Header, "Sec-Websocket-Protocol") - delete(outReq.Header, "Sec-Websocket-Version") + if isWebSocketUpgrade(outReq) { + outReq.Header["Sec-WebSocket-Key"] = outReq.Header["Sec-Websocket-Key"] + outReq.Header["Sec-WebSocket-Extensions"] = outReq.Header["Sec-Websocket-Extensions"] + outReq.Header["Sec-WebSocket-Accept"] = outReq.Header["Sec-Websocket-Accept"] + outReq.Header["Sec-WebSocket-Protocol"] = outReq.Header["Sec-Websocket-Protocol"] + outReq.Header["Sec-WebSocket-Version"] = outReq.Header["Sec-Websocket-Version"] + delete(outReq.Header, "Sec-Websocket-Key") + delete(outReq.Header, "Sec-Websocket-Extensions") + delete(outReq.Header, "Sec-Websocket-Accept") + delete(outReq.Header, "Sec-Websocket-Protocol") + delete(outReq.Header, "Sec-Websocket-Version") + } }, Transport: roundTripper, FlushInterval: time.Duration(flushInterval), @@ -112,6 +115,14 @@ func buildProxy(passHostHeader *bool, responseForwarding *dynamic.ResponseForwar return proxy, nil } +func isWebSocketUpgrade(req *http.Request) bool { + if !httpguts.HeaderValuesContainsToken(req.Header["Connection"], "Upgrade") { + return false + } + + return strings.EqualFold(req.Header.Get("Upgrade"), "websocket") +} + func statusText(statusCode int) string { if statusCode == StatusClientClosedRequest { return StatusClientClosedRequestText