diff --git a/docs/configuration/backends/docker.md b/docs/configuration/backends/docker.md index 9c491c88e..2dfd9fdd7 100644 --- a/docs/configuration/backends/docker.md +++ b/docs/configuration/backends/docker.md @@ -178,13 +178,13 @@ Labels can be used on containers to override default behaviour. | Label | Description | |----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `traefik.frontend.headers.allowedHosts=EXPR` | Provides a list of allowed hosts that requests will be processed. Format: `Host1,Host2` | -| `traefik.frontend.headers.customrequestheaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: `HEADER:value,HEADER2:value2` | -| `traefik.frontend.headers.customresponseheaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: `HEADER:value,HEADER2:value2` | +| `traefik.frontend.headers.customRequestHeaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: HEADER:value||HEADER2:value2 | +| `traefik.frontend.headers.customResponseHeaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: HEADER:value||HEADER2:value2 | | `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` | | `traefik.frontend.headers.SSLRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. | | `traefik.frontend.headers.SSLTemporaryRedirect=true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. | | `traefik.frontend.headers.SSLHost=HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. | -| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`). Format: `HEADER:value,HEADER2:value2` | +| `traefik.frontend.headers.SSLProxyHeaders=EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`). Format: HEADER:value||HEADER2:value2 | | `traefik.frontend.headers.STSSeconds=315360000` | Sets the max-age of the STS header. | | `traefik.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. | | `traefik.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. | diff --git a/docs/configuration/backends/kubernetes.md b/docs/configuration/backends/kubernetes.md index b2d6d27dd..069054602 100644 --- a/docs/configuration/backends/kubernetes.md +++ b/docs/configuration/backends/kubernetes.md @@ -139,13 +139,13 @@ The following security annotations can be applied to the ingress object to add s | Annotation | Description | |----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `ingress.kubernetes.io/allowed-hosts:EXPR` | Provides a list of allowed hosts that requests will be processed. Format: `Host1,Host2` | -| `ingress.kubernetes.io/custom-request-headers:EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: `HEADER:value,HEADER2:value2` | -| `ingress.kubernetes.io/custom-response-headers:EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: `HEADER:value,HEADER2:value2` | +| `ingress.kubernetes.io/custom-request-headers:EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container. Format: HEADER:value||HEADER2:value2 | +| `ingress.kubernetes.io/custom-response-headers:EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client. Format: HEADER:value||HEADER2:value2 | | `ingress.kubernetes.io/proxy-headers:EXPR ` | Provides a list of headers that the proxied hostname may be stored. Format: `HEADER1,HEADER2` | | `ingress.kubernetes.io/ssl-redirect:true` | Forces the frontend to redirect to SSL if a non-SSL request is sent. | | `ingress.kubernetes.io/ssl-temporary-redirect:true` | Forces the frontend to redirect to SSL if a non-SSL request is sent, but by sending a 302 instead of a 301. | | `ingress.kubernetes.io/ssl-host:HOST` | This setting configures the hostname that redirects will be based on. Default is "", which is the same host as the request. | -| `ingress.kubernetes.io/ssl-proxy-headers:EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`). Format: `HEADER:value,HEADER2:value2` | +| `ingress.kubernetes.io/ssl-proxy-headers:EXPR` | Header combinations that would signify a proper SSL Request (Such as `X-Forwarded-For:https`). Format: HEADER:value||HEADER2:value2 | | `ingress.kubernetes.io/hsts-max-age:315360000` | Sets the max-age of the HSTS header. | | `ngress.kubernetes.io/hsts-include-subdomains:true` | Adds the IncludeSubdomains section of the STS header. | | `ingress.kubernetes.io/hsts-preload:true` | Adds the preload flag to the HSTS header. | diff --git a/provider/docker/docker.go b/provider/docker/docker.go index e13c79412..721953425 100644 --- a/provider/docker/docker.go +++ b/provider/docker/docker.go @@ -86,7 +86,7 @@ type networkData struct { ID string } -func (p Provider) createClient() (client.APIClient, error) { +func (p *Provider) createClient() (client.APIClient, error) { var httpClient *http.Client if p.TLS != nil { @@ -292,10 +292,10 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con "getServiceRedirect": getFuncServiceStringLabel(types.SuffixFrontendRedirect, defaultFrontendRedirect), "getWhitelistSourceRange": getFuncSliceStringLabel(types.LabelTraefikFrontendWhitelistSourceRange), - "hasRequestHeaders": hasLabel(types.LabelFrontendRequestHeader), - "getRequestHeaders": getFuncMapLabel(types.LabelFrontendRequestHeader), - "hasResponseHeaders": hasLabel(types.LabelFrontendResponseHeader), - "getResponseHeaders": getFuncMapLabel(types.LabelFrontendResponseHeader), + "hasRequestHeaders": hasLabel(types.LabelFrontendRequestHeaders), + "getRequestHeaders": getFuncMapLabel(types.LabelFrontendRequestHeaders), + "hasResponseHeaders": hasLabel(types.LabelFrontendResponseHeaders), + "getResponseHeaders": getFuncMapLabel(types.LabelFrontendResponseHeaders), "hasAllowedHostsHeaders": hasLabel(types.LabelFrontendAllowedHosts), "getAllowedHostsHeaders": getFuncSliceStringLabel(types.LabelFrontendAllowedHosts), "hasHostsProxyHeaders": hasLabel(types.LabelFrontendHostsProxyHeaders), diff --git a/provider/docker/labels.go b/provider/docker/labels.go index 41f494cc1..ad12a271b 100644 --- a/provider/docker/labels.go +++ b/provider/docker/labels.go @@ -2,6 +2,7 @@ package docker import ( "fmt" + "net/http" "strconv" "strings" @@ -42,21 +43,30 @@ func getFuncMapLabel(labelName string) func(container dockerData) map[string]str } func parseMapLabel(container dockerData, labelName string) map[string]string { - customHeaders := make(map[string]string) - if label, err := getLabel(container, labelName); err == nil { - for _, headers := range strings.Split(label, ",") { - pair := strings.Split(headers, ":") + if parts, err := getLabel(container, labelName); err == nil { + if len(parts) == 0 { + log.Errorf("Could not load %q", labelName) + return nil + } + + values := make(map[string]string) + for _, headers := range strings.Split(parts, "||") { + pair := strings.SplitN(headers, ":", 2) if len(pair) != 2 { - log.Warnf("Could not load header %q: %v, skipping...", labelName, pair) + log.Warnf("Could not load %q: %v, skipping...", labelName, pair) } else { - customHeaders[pair[0]] = pair[1] + values[http.CanonicalHeaderKey(strings.TrimSpace(pair[0]))] = strings.TrimSpace(pair[1]) } } + + if len(values) == 0 { + log.Errorf("Could not load %q", labelName) + return nil + } + return values } - if len(customHeaders) == 0 { - log.Errorf("Could not load %q", labelName) - } - return customHeaders + + return nil } func getFuncStringLabel(label string, defaultValue string) func(container dockerData) string { diff --git a/provider/kubernetes/annotations_parser.go b/provider/kubernetes/annotations_parser.go index ba2538325..813146e6f 100644 --- a/provider/kubernetes/annotations_parser.go +++ b/provider/kubernetes/annotations_parser.go @@ -1,6 +1,7 @@ package kubernetes import ( + "net/http" "strings" "github.com/containous/traefik/log" @@ -50,12 +51,12 @@ func getMapAnnotation(meta *v1beta1.Ingress, annotName string) map[string]string } mapValue := make(map[string]string) - for _, parts := range strings.Split(values, ",") { - pair := strings.Split(parts, ":") + for _, parts := range strings.Split(values, "||") { + pair := strings.SplitN(parts, ":", 2) if len(pair) != 2 { log.Warnf("Could not load %q: %v, skipping...", annotName, pair) } else { - mapValue[pair[0]] = pair[1] + mapValue[http.CanonicalHeaderKey(strings.TrimSpace(pair[0]))] = strings.TrimSpace(pair[1]) } } diff --git a/provider/kubernetes/kubernetes.go b/provider/kubernetes/kubernetes.go index 5284a2220..804510d73 100644 --- a/provider/kubernetes/kubernetes.go +++ b/provider/kubernetes/kubernetes.go @@ -73,7 +73,7 @@ type Provider struct { lastConfiguration safe.Safe } -func (p Provider) newK8sClient() (Client, error) { +func (p *Provider) newK8sClient() (Client, error) { withEndpoint := "" if p.Endpoint != "" { withEndpoint = fmt.Sprintf(" with endpoint %v", p.Endpoint) @@ -356,7 +356,7 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) return &templateObjects, nil } -func (p Provider) loadConfig(templateObjects types.Configuration) *types.Configuration { +func (p *Provider) loadConfig(templateObjects types.Configuration) *types.Configuration { var FuncMap = template.FuncMap{} configuration, err := p.GetConfiguration("templates/kubernetes.tmpl", FuncMap, templateObjects) if err != nil { diff --git a/types/common_label.go b/types/common_label.go index 5b2e19351..af543b573 100644 --- a/types/common_label.go +++ b/types/common_label.go @@ -32,8 +32,8 @@ const ( LabelFrontendRedirect = LabelPrefix + SuffixFrontendRedirect LabelTraefikFrontendValue = LabelPrefix + "frontend.value" LabelTraefikFrontendWhitelistSourceRange = LabelPrefix + "frontend.whitelistSourceRange" - LabelFrontendRequestHeader = LabelPrefix + "frontend.headers.customrequestheaders" - LabelFrontendResponseHeader = LabelPrefix + "frontend.headers.customresponseheaders" + LabelFrontendRequestHeaders = LabelPrefix + "frontend.headers.customRequestHeaders" + LabelFrontendResponseHeaders = LabelPrefix + "frontend.headers.customResponseHeaders" LabelFrontendAllowedHosts = LabelPrefix + "frontend.headers.allowedHosts" LabelFrontendHostsProxyHeaders = LabelPrefix + "frontend.headers.hostsProxyHeaders" LabelFrontendSSLRedirect = LabelPrefix + "frontend.headers.SSLRedirect"