Fix SSL redirect middleware to match NGINX behavior
This commit is contained in:
parent
7314f7ddc9
commit
d6b127ba91
10 changed files with 70 additions and 33 deletions
|
|
@ -2041,8 +2041,9 @@ spec:
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/redirectscheme/
|
More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/redirectscheme/
|
||||||
properties:
|
properties:
|
||||||
permanent:
|
permanent:
|
||||||
description: Permanent defines whether the redirection is permanent
|
description: |-
|
||||||
(308).
|
Permanent defines whether the redirection is permanent.
|
||||||
|
For HTTP GET requests a 301 is returned, otherwise a 308 is returned.
|
||||||
type: boolean
|
type: boolean
|
||||||
port:
|
port:
|
||||||
description: Port defines the port of the new URL.
|
description: Port defines the port of the new URL.
|
||||||
|
|
|
||||||
|
|
@ -1211,8 +1211,9 @@ spec:
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/redirectscheme/
|
More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/redirectscheme/
|
||||||
properties:
|
properties:
|
||||||
permanent:
|
permanent:
|
||||||
description: Permanent defines whether the redirection is permanent
|
description: |-
|
||||||
(308).
|
Permanent defines whether the redirection is permanent.
|
||||||
|
For HTTP GET requests a 301 is returned, otherwise a 308 is returned.
|
||||||
type: boolean
|
type: boolean
|
||||||
port:
|
port:
|
||||||
description: Port defines the port of the new URL.
|
description: Port defines the port of the new URL.
|
||||||
|
|
|
||||||
|
|
@ -2041,8 +2041,9 @@ spec:
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/redirectscheme/
|
More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/redirectscheme/
|
||||||
properties:
|
properties:
|
||||||
permanent:
|
permanent:
|
||||||
description: Permanent defines whether the redirection is permanent
|
description: |-
|
||||||
(308).
|
Permanent defines whether the redirection is permanent.
|
||||||
|
For HTTP GET requests a 301 is returned, otherwise a 308 is returned.
|
||||||
type: boolean
|
type: boolean
|
||||||
port:
|
port:
|
||||||
description: Port defines the port of the new URL.
|
description: Port defines the port of the new URL.
|
||||||
|
|
|
||||||
|
|
@ -655,8 +655,13 @@ type RedirectScheme struct {
|
||||||
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
|
Scheme string `json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty" export:"true"`
|
||||||
// Port defines the port of the new URL.
|
// Port defines the port of the new URL.
|
||||||
Port string `json:"port,omitempty" toml:"port,omitempty" yaml:"port,omitempty" export:"true"`
|
Port string `json:"port,omitempty" toml:"port,omitempty" yaml:"port,omitempty" export:"true"`
|
||||||
// Permanent defines whether the redirection is permanent (308).
|
// Permanent defines whether the redirection is permanent.
|
||||||
|
// For HTTP GET requests a 301 is returned, otherwise a 308 is returned.
|
||||||
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
|
Permanent bool `json:"permanent,omitempty" toml:"permanent,omitempty" yaml:"permanent,omitempty" export:"true"`
|
||||||
|
// ForcePermanentRedirect is an internal field (not exposed in configuration).
|
||||||
|
// When set to true, this forces the use of permanent redirects 308, regardless of the request method.
|
||||||
|
// Used by the provider ingress-ngin.
|
||||||
|
ForcePermanentRedirect bool `json:"-" toml:"-" yaml:"-" label:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,14 @@ type redirect struct {
|
||||||
regex *regexp.Regexp
|
regex *regexp.Regexp
|
||||||
replacement string
|
replacement string
|
||||||
permanent bool
|
permanent bool
|
||||||
|
forcePermanentRedirect bool
|
||||||
errHandler utils.ErrorHandler
|
errHandler utils.ErrorHandler
|
||||||
name string
|
name string
|
||||||
rawURL func(*http.Request) string
|
rawURL func(*http.Request) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Redirect middleware.
|
// New creates a Redirect middleware.
|
||||||
func newRedirect(next http.Handler, regex, replacement string, permanent bool, rawURL func(*http.Request) string, name string) (http.Handler, error) {
|
func newRedirect(next http.Handler, regex, replacement string, permanent bool, forcePermanentRedirect bool, rawURL func(*http.Request) string, name string) (http.Handler, error) {
|
||||||
re, err := regexp.Compile(regex)
|
re, err := regexp.Compile(regex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -38,6 +39,7 @@ func newRedirect(next http.Handler, regex, replacement string, permanent bool, r
|
||||||
regex: re,
|
regex: re,
|
||||||
replacement: replacement,
|
replacement: replacement,
|
||||||
permanent: permanent,
|
permanent: permanent,
|
||||||
|
forcePermanentRedirect: forcePermanentRedirect,
|
||||||
errHandler: utils.DefaultHandler,
|
errHandler: utils.DefaultHandler,
|
||||||
next: next,
|
next: next,
|
||||||
name: name,
|
name: name,
|
||||||
|
|
@ -69,7 +71,7 @@ func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if newURL != oldURL {
|
if newURL != oldURL {
|
||||||
handler := &moveHandler{location: parsedURL, permanent: r.permanent}
|
handler := &moveHandler{location: parsedURL, permanent: r.permanent, forcePermanentRedirect: r.forcePermanentRedirect}
|
||||||
handler.ServeHTTP(rw, req)
|
handler.ServeHTTP(rw, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +86,7 @@ func (r *redirect) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
type moveHandler struct {
|
type moveHandler struct {
|
||||||
location *url.URL
|
location *url.URL
|
||||||
permanent bool
|
permanent bool
|
||||||
|
forcePermanentRedirect bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
@ -100,6 +103,11 @@ func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
status = http.StatusPermanentRedirect
|
status = http.StatusPermanentRedirect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.forcePermanentRedirect {
|
||||||
|
status = http.StatusPermanentRedirect
|
||||||
|
}
|
||||||
|
|
||||||
rw.WriteHeader(status)
|
rw.WriteHeader(status)
|
||||||
_, err := rw.Write([]byte(http.StatusText(status)))
|
_, err := rw.Write([]byte(http.StatusText(status)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ func NewRedirectRegex(ctx context.Context, next http.Handler, conf dynamic.Redir
|
||||||
logger.Debug().Msg("Creating middleware")
|
logger.Debug().Msg("Creating middleware")
|
||||||
logger.Debug().Msgf("Setting up redirection from %s to %s", conf.Regex, conf.Replacement)
|
logger.Debug().Msgf("Setting up redirection from %s to %s", conf.Regex, conf.Replacement)
|
||||||
|
|
||||||
return newRedirect(next, conf.Regex, conf.Replacement, conf.Permanent, rawURL, name)
|
return newRedirect(next, conf.Regex, conf.Replacement, conf.Permanent, false, rawURL, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rawURL(req *http.Request) string {
|
func rawURL(req *http.Request) string {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func NewRedirectScheme(ctx context.Context, next http.Handler, conf dynamic.Redi
|
||||||
|
|
||||||
rs := &redirectScheme{name: name}
|
rs := &redirectScheme{name: name}
|
||||||
|
|
||||||
handler, err := newRedirect(next, uriPattern, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, rs.clientRequestURL, name)
|
handler, err := newRedirect(next, uriPattern, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, conf.ForcePermanentRedirect, rs.clientRequestURL, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,27 @@ func TestRedirectSchemeHandler(t *testing.T) {
|
||||||
expectedURL: "https://foo:8443",
|
expectedURL: "https://foo:8443",
|
||||||
expectedStatus: http.StatusMovedPermanently,
|
expectedStatus: http.StatusMovedPermanently,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP to HTTPS with explicit 308 status code",
|
||||||
|
config: dynamic.RedirectScheme{
|
||||||
|
Scheme: "https",
|
||||||
|
ForcePermanentRedirect: true,
|
||||||
|
},
|
||||||
|
url: "http://foo",
|
||||||
|
expectedURL: "https://foo",
|
||||||
|
expectedStatus: http.StatusPermanentRedirect,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "HTTP to HTTPS with explicit 308 status code for GET request",
|
||||||
|
method: http.MethodGet,
|
||||||
|
config: dynamic.RedirectScheme{
|
||||||
|
Scheme: "https",
|
||||||
|
ForcePermanentRedirect: true,
|
||||||
|
},
|
||||||
|
url: "http://foo",
|
||||||
|
expectedURL: "https://foo",
|
||||||
|
expectedStatus: http.StatusPermanentRedirect,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "to HTTP 80",
|
desc: "to HTTP 80",
|
||||||
config: dynamic.RedirectScheme{
|
config: dynamic.RedirectScheme{
|
||||||
|
|
|
||||||
|
|
@ -969,7 +969,7 @@ func applySSLRedirectConfiguration(routerName string, ingressConfig ingressConfi
|
||||||
conf.HTTP.Middlewares[redirectMiddlewareName] = &dynamic.Middleware{
|
conf.HTTP.Middlewares[redirectMiddlewareName] = &dynamic.Middleware{
|
||||||
RedirectScheme: &dynamic.RedirectScheme{
|
RedirectScheme: &dynamic.RedirectScheme{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Permanent: true,
|
ForcePermanentRedirect: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
redirectRouter.Middlewares = append(redirectRouter.Middlewares, redirectMiddlewareName)
|
redirectRouter.Middlewares = append(redirectRouter.Middlewares, redirectMiddlewareName)
|
||||||
|
|
|
||||||
|
|
@ -208,13 +208,13 @@ func TestLoadIngresses(t *testing.T) {
|
||||||
"default-ingress-with-ssl-redirect-rule-0-path-0-redirect-scheme": {
|
"default-ingress-with-ssl-redirect-rule-0-path-0-redirect-scheme": {
|
||||||
RedirectScheme: &dynamic.RedirectScheme{
|
RedirectScheme: &dynamic.RedirectScheme{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Permanent: true,
|
ForcePermanentRedirect: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"default-ingress-with-force-ssl-redirect-rule-0-path-0-redirect-scheme": {
|
"default-ingress-with-force-ssl-redirect-rule-0-path-0-redirect-scheme": {
|
||||||
RedirectScheme: &dynamic.RedirectScheme{
|
RedirectScheme: &dynamic.RedirectScheme{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Permanent: true,
|
ForcePermanentRedirect: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue