Skip to content

Commit

Permalink
Add connection-proxy-header annotation (#1999)
Browse files Browse the repository at this point in the history
This is the override the default connection header
  • Loading branch information
qiujian16 authored and aledbf committed Jan 30, 2018
1 parent b020686 commit 951a704
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 5 deletions.
3 changes: 3 additions & 0 deletions internal/ingress/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
"k8s.io/ingress-nginx/internal/ingress/annotations/clientbodybuffersize"
"k8s.io/ingress-nginx/internal/ingress/annotations/connection"
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
"k8s.io/ingress-nginx/internal/ingress/annotations/defaultbackend"
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
Expand Down Expand Up @@ -63,6 +64,7 @@ type Ingress struct {
CertificateAuth authtls.Config
ClientBodyBufferSize string
ConfigurationSnippet string
Connection connection.Config
CorsConfig cors.Config
DefaultBackend string
Denied error
Expand Down Expand Up @@ -99,6 +101,7 @@ func NewAnnotationExtractor(cfg resolver.Resolver) Extractor {
"CertificateAuth": authtls.NewParser(cfg),
"ClientBodyBufferSize": clientbodybuffersize.NewParser(cfg),
"ConfigurationSnippet": snippet.NewParser(cfg),
"Connection": connection.NewParser(cfg),
"CorsConfig": cors.NewParser(cfg),
"DefaultBackend": defaultbackend.NewParser(cfg),
"ExternalAuth": authreq.NewParser(cfg),
Expand Down
72 changes: 72 additions & 0 deletions internal/ingress/annotations/connection/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package connection

import (
extensions "k8s.io/api/extensions/v1beta1"

"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)

// Config returns the connection header configuration for an Ingress rule
type Config struct {
Header string `json:"header"`
Enabled bool `json:"enabled"`
}

type connection struct {
r resolver.Resolver
}

// NewParser creates a new port in redirect annotation parser
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
return connection{r}
}

// Parse parses the annotations contained in the ingress
// rule used to indicate if the connection header should be overridden.
func (a connection) Parse(ing *extensions.Ingress) (interface{}, error) {
cp, err := parser.GetStringAnnotation("connection-proxy-header", ing)
if err != nil {
return &Config{
Enabled: false,
}, err
}
return &Config{
Enabled: true,
Header: cp,
}, nil
}

// Equal tests for equality between two Connection types
func (r1 *Config) Equal(r2 *Config) bool {
if r1 == r2 {
return true
}
if r1 == nil || r2 == nil {
return false
}
if r1.Enabled != r2.Enabled {
return false
}
if r1.Header != r2.Header {
return false
}

return true
}
64 changes: 64 additions & 0 deletions internal/ingress/annotations/connection/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package connection

import (
"testing"

api "k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/resolver"
)

func TestParse(t *testing.T) {
annotation := parser.GetAnnotationWithPrefix("connection-proxy-header")

ap := NewParser(&resolver.Mock{})
if ap == nil {
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
}

testCases := []struct {
annotations map[string]string
expected *Config
}{
{map[string]string{annotation: ""}, &Config{Enabled: true, Header: ""}},
{map[string]string{annotation: "keep-alive"}, &Config{Enabled: true, Header: "keep-alive"}},
{map[string]string{}, &Config{Enabled: false}},
{nil, &Config{Enabled: false}},
}

ing := &extensions.Ingress{
ObjectMeta: meta_v1.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
},
Spec: extensions.IngressSpec{},
}

for _, testCase := range testCases {
ing.SetAnnotations(testCase.annotations)
i, _ := ap.Parse(ing)
p, _ := i.(*Config)

if !p.Equal(testCase.expected) {
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, p, testCase.annotations)
}
}
}
2 changes: 2 additions & 0 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
loc.Denied = anns.Denied
loc.XForwardedPrefix = anns.XForwardedPrefix
loc.UsePortInRedirects = anns.UsePortInRedirects
loc.Connection = anns.Connection

if loc.Redirect.FromToWWW {
server.RedirectFromToWWW = true
Expand Down Expand Up @@ -458,6 +459,7 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
Denied: anns.Denied,
XForwardedPrefix: anns.XForwardedPrefix,
UsePortInRedirects: anns.UsePortInRedirects,
Connection: anns.Connection,
}

if loc.Redirect.FromToWWW {
Expand Down
5 changes: 5 additions & 0 deletions internal/ingress/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/annotations/auth"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
"k8s.io/ingress-nginx/internal/ingress/annotations/connection"
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
Expand Down Expand Up @@ -240,6 +241,10 @@ type Location struct {
// ConfigurationSnippet contains additional configuration for the backend
// to be considered in the configuration of the location
ConfigurationSnippet string `json:"configurationSnippet"`
// Connection contains connection header to orverride the default Connection header
// to the request.
// +optional
Connection connection.Config `json:"connection"`
// ClientBodyBufferSize allows for the configuration of the client body
// buffer size for a specific location.
// +optional
Expand Down
3 changes: 3 additions & 0 deletions internal/ingress/types_equals.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ func (l1 *Location) Equal(l2 *Location) bool {
if l1.XForwardedPrefix != l2.XForwardedPrefix {
return false
}
if !(&l1.Connection).Equal(&l2.Connection) {
return false
}

return true
}
Expand Down
14 changes: 9 additions & 5 deletions rootfs/etc/nginx/template/nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ http {

include /etc/nginx/mime.types;
default_type text/html;

{{ if $cfg.EnableBrotli }}
brotli on;
brotli_comp_level {{ $cfg.BrotliLevel }};
Expand Down Expand Up @@ -242,7 +242,7 @@ http {
port_in_redirect off;

rewrite_log on;

ssl_protocols {{ $cfg.SSLProtocols }};

# turn on session caching to drastically improve performance
Expand Down Expand Up @@ -294,7 +294,7 @@ http {

{{ range $header := $cfg.HideHeaders }}proxy_hide_header {{ $header }};
{{ end }}

{{ if not (empty $cfg.HTTPSnippet) }}
# Custom code snippet configured in the configuration configmap
{{ $cfg.HTTPSnippet }}
Expand Down Expand Up @@ -700,10 +700,10 @@ stream {
{{/* redirect to HTTPS can be achieved forcing the redirect or having a SSL Certificate configured for the server */}}
{{ if (or $location.Rewrite.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Rewrite.SSLRedirect)) }}
# enforce ssl on server side
if ($redirect_to_https) {
if ($redirect_to_https) {
{{ if $location.UsePortInRedirects }}
# using custom ports require a different rewrite directive
{{ $redirect_port := (printf ":%v" $all.ListenPorts.HTTPS) }}
{{ $redirect_port := (printf ":%v" $all.ListenPorts.HTTPS) }}
error_page 497 ={{ $all.Cfg.HTTPRedirectCode }} https://$host{{ $redirect_port }}$request_uri;

return 497;
Expand Down Expand Up @@ -798,7 +798,11 @@ stream {

# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
{{ if $location.Connection.Enabled}}
proxy_set_header Connection {{ $location.Connection.Header }};
{{ else }}
proxy_set_header Connection $connection_upgrade;
{{ end }}

proxy_set_header X-Real-IP $the_real_ip;
{{ if $all.Cfg.ComputeFullForwardedFor }}
Expand Down

0 comments on commit 951a704

Please sign in to comment.