SchemeRedirect Middleware
Co-authored-by: jbdoumenjou <jb.doumenjou@gmail.com>
This commit is contained in:
parent
04958c6951
commit
a433e469cc
11 changed files with 407 additions and 66 deletions
|
@ -20,11 +20,6 @@ func Test_doOnJSON(t *testing.T) {
|
|||
"Network": "",
|
||||
"Address": ":80",
|
||||
"TLS": null,
|
||||
"Redirect": {
|
||||
"EntryPoint": "https",
|
||||
"Regex": "",
|
||||
"Replacement": ""
|
||||
},
|
||||
"Auth": null,
|
||||
"Compress": false
|
||||
},
|
||||
|
@ -36,7 +31,6 @@ func Test_doOnJSON(t *testing.T) {
|
|||
"Certificates": null,
|
||||
"ClientCAFiles": null
|
||||
},
|
||||
"Redirect": null,
|
||||
"Auth": null,
|
||||
"Compress": false
|
||||
}
|
||||
|
@ -109,11 +103,6 @@ func Test_doOnJSON(t *testing.T) {
|
|||
"Network": "",
|
||||
"Address": ":80",
|
||||
"TLS": null,
|
||||
"Redirect": {
|
||||
"EntryPoint": "https",
|
||||
"Regex": "",
|
||||
"Replacement": ""
|
||||
},
|
||||
"Auth": null,
|
||||
"Compress": false
|
||||
},
|
||||
|
@ -125,7 +114,6 @@ func Test_doOnJSON(t *testing.T) {
|
|||
"Certificates": null,
|
||||
"ClientCAFiles": null
|
||||
},
|
||||
"Redirect": null,
|
||||
"Auth": null,
|
||||
"Compress": false
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ type Middleware struct {
|
|||
Headers *Headers `json:"headers,omitempty"`
|
||||
Errors *ErrorPage `json:"errors,omitempty"`
|
||||
RateLimit *RateLimit `json:"rateLimit,omitempty"`
|
||||
Redirect *Redirect `json:"redirect,omitempty"`
|
||||
RedirectRegex *RedirectRegex `json:"redirectregex,omitempty"`
|
||||
RedirectScheme *RedirectScheme `json:"redirectscheme,omitempty"`
|
||||
BasicAuth *BasicAuth `json:"basicAuth,omitempty"`
|
||||
DigestAuth *DigestAuth `json:"digestAuth,omitempty"`
|
||||
ForwardAuth *ForwardAuth `json:"forwardAuth,omitempty"`
|
||||
|
@ -229,13 +230,20 @@ func (r *RateLimit) SetDefaults() {
|
|||
r.ExtractorFunc = "request.host"
|
||||
}
|
||||
|
||||
// Redirect holds the redirection configuration of an entry point to another, or to an URL.
|
||||
type Redirect struct {
|
||||
// RedirectRegex holds the redirection configuration.
|
||||
type RedirectRegex struct {
|
||||
Regex string `json:"regex,omitempty"`
|
||||
Replacement string `json:"replacement,omitempty"`
|
||||
Permanent bool `json:"permanent,omitempty"`
|
||||
}
|
||||
|
||||
// RedirectScheme holds the scheme redirection configuration.
|
||||
type RedirectScheme struct {
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
Port string `json:"port,omitempty"`
|
||||
Permanent bool `json:"permanent,omitempty"`
|
||||
}
|
||||
|
||||
// ReplacePath holds the ReplacePath configuration.
|
||||
type ReplacePath struct {
|
||||
Path string `json:"path,omitempty"`
|
||||
|
@ -247,7 +255,7 @@ type ReplacePathRegex struct {
|
|||
Replacement string `json:"replacement,omitempty"`
|
||||
}
|
||||
|
||||
// Retry contains request retry config
|
||||
// Retry holds the retry configuration.
|
||||
type Retry struct {
|
||||
Attempts int `description:"Number of attempts" export:"true"`
|
||||
}
|
||||
|
|
|
@ -6,9 +6,6 @@ logLevel = "DEBUG"
|
|||
[entryPoints.http]
|
||||
address = ":8888"
|
||||
|
||||
[entryPoints.http.redirect]
|
||||
entryPoint = "https"
|
||||
|
||||
[entryPoints.https]
|
||||
address = ":8443"
|
||||
[entryPoints.https.tls]
|
||||
|
@ -92,9 +89,9 @@ logLevel = "DEBUG"
|
|||
path = "/api"
|
||||
[Middlewares.api-slash-replace-path.ReplacePath]
|
||||
path = "/api/"
|
||||
[Middlewares.redirect-https.redirect]
|
||||
regex = "^(?:https?://)?([\\w\\._-]+)(?::\\d+)?(.*)$"
|
||||
replacement = "https://${1}:8443${2}"
|
||||
[Middlewares.redirect-https.redirectScheme]
|
||||
scheme = "https"
|
||||
port = "8443"
|
||||
|
||||
[Services]
|
||||
[Services.service1]
|
||||
|
|
|
@ -53,8 +53,8 @@ frontendRedirect:
|
|||
- traefik.routers.rt-frontendRedirect.entryPoints=frontendRedirect
|
||||
- traefik.routers.rt-frontendRedirect.rule=Path:/test
|
||||
- traefik.routers.rt-frontendRedirect.middlewares=redirecthttp
|
||||
- traefik.middlewares.redirecthttp.redirect.regex=^(?:https?://)?([\w\._-]+)(?::\d+)?(.*)$$
|
||||
- traefik.middlewares.redirecthttp.redirect.replacement=http://$${1}:8000$${2}
|
||||
- traefik.middlewares.redirecthttp.redirectScheme.scheme=http
|
||||
- traefik.middlewares.redirecthttp.redirectScheme.port=8000
|
||||
- traefik.services.service3.loadbalancer.server.port=80
|
||||
rateLimit:
|
||||
image: containous/whoami
|
||||
|
|
|
@ -10,17 +10,11 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/containous/traefik/middlewares"
|
||||
"github.com/containous/traefik/tracing"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"github.com/vulcand/oxy/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
typeName = "Redirect"
|
||||
)
|
||||
|
||||
type redirect struct {
|
||||
next http.Handler
|
||||
regex *regexp.Regexp
|
||||
|
@ -30,21 +24,17 @@ type redirect struct {
|
|||
name string
|
||||
}
|
||||
|
||||
// New creates a redirect middleware.
|
||||
func New(ctx context.Context, next http.Handler, config config.Redirect, name string) (http.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeName)
|
||||
logger.Debug("Creating middleware")
|
||||
logger.Debugf("Setting up redirect %s -> %s", config.Regex, config.Replacement)
|
||||
|
||||
re, err := regexp.Compile(config.Regex)
|
||||
// New creates a Redirect middleware.
|
||||
func newRedirect(ctx context.Context, next http.Handler, regex string, replacement string, permanent bool, name string) (http.Handler, error) {
|
||||
re, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &redirect{
|
||||
regex: re,
|
||||
replacement: config.Replacement,
|
||||
permanent: config.Permanent,
|
||||
replacement: replacement,
|
||||
permanent: permanent,
|
||||
errHandler: utils.DefaultHandler,
|
||||
next: next,
|
||||
name: name,
|
||||
|
@ -122,11 +112,32 @@ func (m *moveHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
|
||||
func rawURL(req *http.Request) string {
|
||||
scheme := "http"
|
||||
host := req.Host
|
||||
port := ""
|
||||
uri := req.RequestURI
|
||||
|
||||
schemeRegex := `^(https?):\/\/([\w\._-]+)(:\d+)?(.*)$`
|
||||
re, _ := regexp.Compile(schemeRegex)
|
||||
if re.Match([]byte(req.RequestURI)) {
|
||||
match := re.FindStringSubmatch(req.RequestURI)
|
||||
scheme = match[1]
|
||||
|
||||
if len(match[2]) > 0 {
|
||||
host = match[2]
|
||||
}
|
||||
|
||||
if len(match[3]) > 0 {
|
||||
port = match[3]
|
||||
}
|
||||
|
||||
uri = match[4]
|
||||
}
|
||||
|
||||
if req.TLS != nil || isXForwardedHTTPS(req) {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
return strings.Join([]string{scheme, "://", req.Host, req.RequestURI}, "")
|
||||
return strings.Join([]string{scheme, "://", host, port, uri}, "")
|
||||
}
|
||||
|
||||
func isXForwardedHTTPS(request *http.Request) bool {
|
||||
|
|
22
middlewares/redirect/redirect_regex.go
Normal file
22
middlewares/redirect/redirect_regex.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/containous/traefik/middlewares"
|
||||
)
|
||||
|
||||
const (
|
||||
typeRegexName = "RedirectRegex"
|
||||
)
|
||||
|
||||
// NewRedirectRegex creates a redirect middleware.
|
||||
func NewRedirectRegex(ctx context.Context, next http.Handler, conf config.RedirectRegex, name string) (http.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeRegexName)
|
||||
logger.Debug("Creating middleware")
|
||||
logger.Debugf("Setting up redirection from %s to %s", conf.Regex, conf.Replacement)
|
||||
|
||||
return newRedirect(ctx, next, conf.Regex, conf.Replacement, conf.Permanent, name)
|
||||
}
|
|
@ -13,10 +13,10 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewRegexHandler(t *testing.T) {
|
||||
func TestRedirectRegexHandler(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
config config.Redirect
|
||||
config config.RedirectRegex
|
||||
method string
|
||||
url string
|
||||
secured bool
|
||||
|
@ -26,7 +26,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
desc: "simple redirection",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^(?:http?:\/\/)(foo)(\.com)(:\d+)(.*)$`,
|
||||
Replacement: "https://${1}bar$2:443$4",
|
||||
},
|
||||
|
@ -36,7 +36,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "use request header",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^(?:http?:\/\/)(foo)(\.com)(:\d+)(.*)$`,
|
||||
Replacement: `https://${1}{{ .Request.Header.Get "X-Foo" }}$2:443$4`,
|
||||
},
|
||||
|
@ -46,7 +46,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "URL doesn't match regex",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^(?:http?:\/\/)(foo)(\.com)(:\d+)(.*)$`,
|
||||
Replacement: "https://${1}bar$2:443$4",
|
||||
},
|
||||
|
@ -55,7 +55,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "invalid rewritten URL",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^(.*)$`,
|
||||
Replacement: "http://192.168.0.%31/",
|
||||
},
|
||||
|
@ -64,7 +64,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "invalid regex",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^(.*`,
|
||||
Replacement: "$1",
|
||||
},
|
||||
|
@ -73,7 +73,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "HTTP to HTTPS permanent",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^http://`,
|
||||
Replacement: "https://$1",
|
||||
Permanent: true,
|
||||
|
@ -84,7 +84,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "HTTPS to HTTP permanent",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `https://foo`,
|
||||
Replacement: "http://foo",
|
||||
Permanent: true,
|
||||
|
@ -96,7 +96,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "HTTP to HTTPS",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `http://foo:80`,
|
||||
Replacement: "https://foo:443",
|
||||
},
|
||||
|
@ -106,7 +106,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "HTTPS to HTTP",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `https://foo:443`,
|
||||
Replacement: "http://foo:80",
|
||||
},
|
||||
|
@ -117,7 +117,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "HTTP to HTTP",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `http://foo:80`,
|
||||
Replacement: "http://foo:88",
|
||||
},
|
||||
|
@ -127,7 +127,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "HTTP to HTTP POST",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^http://`,
|
||||
Replacement: "https://$1",
|
||||
},
|
||||
|
@ -138,7 +138,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
},
|
||||
{
|
||||
desc: "HTTP to HTTP POST permanent",
|
||||
config: config.Redirect{
|
||||
config: config.RedirectRegex{
|
||||
Regex: `^http://`,
|
||||
Replacement: "https://$1",
|
||||
Permanent: true,
|
||||
|
@ -156,7 +156,7 @@ func TestNewRegexHandler(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
handler, err := New(context.Background(), next, test.config, "traefikTest")
|
||||
handler, err := NewRedirectRegex(context.Background(), next, test.config, "traefikTest")
|
||||
|
||||
if test.errorExpected {
|
||||
require.Error(t, err)
|
34
middlewares/redirect/redirect_scheme.go
Normal file
34
middlewares/redirect/redirect_scheme.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/containous/traefik/middlewares"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/containous/traefik/config"
|
||||
)
|
||||
|
||||
const (
|
||||
typeSchemeName = "RedirectScheme"
|
||||
schemeRedirectRegex = `^(https?:\/\/)?([\w\._-]+)(:\d+)?(.*)$`
|
||||
)
|
||||
|
||||
// NewRedirectScheme creates a new RedirectScheme middleware.
|
||||
func NewRedirectScheme(ctx context.Context, next http.Handler, conf config.RedirectScheme, name string) (http.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeSchemeName)
|
||||
logger.Debug("Creating middleware")
|
||||
logger.Debugf("Setting up redirection to %s %s", conf.Scheme, conf.Port)
|
||||
|
||||
if len(conf.Scheme) == 0 {
|
||||
return nil, errors.New("you must provide a target scheme")
|
||||
}
|
||||
|
||||
port := ""
|
||||
if len(conf.Port) > 0 && !(conf.Scheme == "http" && conf.Port == "80" || conf.Scheme == "https" && conf.Port == "443") {
|
||||
port = ":" + conf.Port
|
||||
}
|
||||
|
||||
return newRedirect(ctx, next, schemeRedirectRegex, conf.Scheme+"://${2}"+port+"${4}", conf.Permanent, name)
|
||||
}
|
250
middlewares/redirect/redirect_scheme_test.go
Normal file
250
middlewares/redirect/redirect_scheme_test.go
Normal file
|
@ -0,0 +1,250 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRedirectSchemeHandler(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
config config.RedirectScheme
|
||||
method string
|
||||
url string
|
||||
secured bool
|
||||
expectedURL string
|
||||
expectedStatus int
|
||||
errorExpected bool
|
||||
}{
|
||||
{
|
||||
desc: "Without scheme",
|
||||
config: config.RedirectScheme{},
|
||||
url: "http://foo",
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
desc: "HTTP to HTTPS",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "http://foo",
|
||||
expectedURL: "https://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP with port to HTTPS without port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "http://foo:8080",
|
||||
expectedURL: "https://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP without port to HTTPS with port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "8443",
|
||||
},
|
||||
url: "http://foo",
|
||||
expectedURL: "https://foo:8443",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP with port to HTTPS with port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "8443",
|
||||
},
|
||||
url: "http://foo:8000",
|
||||
expectedURL: "https://foo:8443",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTPS with port to HTTPS with port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "8443",
|
||||
},
|
||||
url: "https://foo:8000",
|
||||
expectedURL: "https://foo:8443",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTPS with port to HTTPS without port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "https://foo:8000",
|
||||
expectedURL: "https://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "redirection to HTTPS without port from an URL already in https",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "https://foo:8000/theother",
|
||||
expectedURL: "https://foo/theother",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP to HTTPS permanent",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "8443",
|
||||
Permanent: true,
|
||||
},
|
||||
url: "http://foo",
|
||||
expectedURL: "https://foo:8443",
|
||||
expectedStatus: http.StatusMovedPermanently,
|
||||
},
|
||||
{
|
||||
desc: "to HTTP 80",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "http",
|
||||
Port: "80",
|
||||
},
|
||||
url: "http://foo:80",
|
||||
expectedURL: "http://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP to wss",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "wss",
|
||||
Port: "9443",
|
||||
},
|
||||
url: "http://foo",
|
||||
expectedURL: "wss://foo:9443",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP to wss without port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "wss",
|
||||
},
|
||||
url: "http://foo",
|
||||
expectedURL: "wss://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP with port to wss without port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "wss",
|
||||
},
|
||||
url: "http://foo:5678",
|
||||
expectedURL: "wss://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP to HTTPS without port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "http://foo:443",
|
||||
expectedURL: "https://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTP port redirection",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "http",
|
||||
Port: "8181",
|
||||
},
|
||||
url: "http://foo:8080",
|
||||
expectedURL: "http://foo:8181",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
desc: "HTTPS with port 80 to HTTPS without port",
|
||||
config: config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
},
|
||||
url: "https://foo:80",
|
||||
expectedURL: "https://foo",
|
||||
expectedStatus: http.StatusFound,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
handler, err := NewRedirectScheme(context.Background(), next, test.config, "traefikTest")
|
||||
|
||||
if test.errorExpected {
|
||||
require.Error(t, err)
|
||||
require.Nil(t, handler)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, handler)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
method := http.MethodGet
|
||||
if test.method != "" {
|
||||
method = test.method
|
||||
}
|
||||
r := httptest.NewRequest(method, test.url, nil)
|
||||
|
||||
if test.secured {
|
||||
r.TLS = &tls.ConnectionState{}
|
||||
}
|
||||
r.Header.Set("X-Foo", "bar")
|
||||
handler.ServeHTTP(recorder, r)
|
||||
|
||||
assert.Equal(t, test.expectedStatus, recorder.Code)
|
||||
if test.expectedStatus == http.StatusMovedPermanently ||
|
||||
test.expectedStatus == http.StatusFound ||
|
||||
test.expectedStatus == http.StatusTemporaryRedirect ||
|
||||
test.expectedStatus == http.StatusPermanentRedirect {
|
||||
|
||||
location, err := recorder.Result().Location()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, test.expectedURL, location.String())
|
||||
} else {
|
||||
location, err := recorder.Result().Location()
|
||||
require.Errorf(t, err, "Location %v", location)
|
||||
}
|
||||
|
||||
schemeRegex := `^(https?):\/\/([\w\._-]+)(:\d+)?(.*)$`
|
||||
re, _ := regexp.Compile(schemeRegex)
|
||||
|
||||
if re.Match([]byte(test.url)) {
|
||||
match := re.FindStringSubmatch(test.url)
|
||||
r.RequestURI = match[4]
|
||||
|
||||
handler.ServeHTTP(recorder, r)
|
||||
|
||||
assert.Equal(t, test.expectedStatus, recorder.Code)
|
||||
if test.expectedStatus == http.StatusMovedPermanently ||
|
||||
test.expectedStatus == http.StatusFound ||
|
||||
test.expectedStatus == http.StatusTemporaryRedirect ||
|
||||
test.expectedStatus == http.StatusPermanentRedirect {
|
||||
|
||||
location, err := recorder.Result().Location()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, test.expectedURL, location.String())
|
||||
} else {
|
||||
location, err := recorder.Result().Location()
|
||||
require.Errorf(t, err, "Location %v", location)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -90,9 +90,12 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
"traefik.middlewares.Middleware12.ratelimit.rateset.Rate1.average": "42",
|
||||
"traefik.middlewares.Middleware12.ratelimit.rateset.Rate1.burst": "42",
|
||||
"traefik.middlewares.Middleware12.ratelimit.rateset.Rate1.period": "42",
|
||||
"traefik.middlewares.Middleware13.redirect.permanent": "true",
|
||||
"traefik.middlewares.Middleware13.redirect.regex": "foobar",
|
||||
"traefik.middlewares.Middleware13.redirect.replacement": "foobar",
|
||||
"traefik.middlewares.Middleware13.redirectregex.permanent": "true",
|
||||
"traefik.middlewares.Middleware13.redirectregex.regex": "foobar",
|
||||
"traefik.middlewares.Middleware13.redirectregex.replacement": "foobar",
|
||||
"traefik.middlewares.Middleware13b.redirectscheme.scheme": "https",
|
||||
"traefik.middlewares.Middleware13b.redirectscheme.port": "80",
|
||||
"traefik.middlewares.Middleware13b.redirectscheme.permanent": "true",
|
||||
"traefik.middlewares.Middleware14.replacepath.path": "foobar",
|
||||
"traefik.middlewares.Middleware15.replacepathregex.regex": "foobar",
|
||||
"traefik.middlewares.Middleware15.replacepathregex.replacement": "foobar",
|
||||
|
@ -237,12 +240,19 @@ func TestDecodeConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Middleware13": {
|
||||
Redirect: &config.Redirect{
|
||||
RedirectRegex: &config.RedirectRegex{
|
||||
Regex: "foobar",
|
||||
Replacement: "foobar",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
"Middleware13b": {
|
||||
RedirectScheme: &config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "80",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
"Middleware14": {
|
||||
ReplacePath: &config.ReplacePath{
|
||||
Path: "foobar",
|
||||
|
@ -553,12 +563,19 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"Middleware13": {
|
||||
Redirect: &config.Redirect{
|
||||
RedirectRegex: &config.RedirectRegex{
|
||||
Regex: "foobar",
|
||||
Replacement: "foobar",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
"Middleware13b": {
|
||||
RedirectScheme: &config.RedirectScheme{
|
||||
Scheme: "https",
|
||||
Port: "80",
|
||||
Permanent: true,
|
||||
},
|
||||
},
|
||||
"Middleware14": {
|
||||
ReplacePath: &config.ReplacePath{
|
||||
Path: "foobar",
|
||||
|
@ -856,9 +873,12 @@ func TestEncodeConfiguration(t *testing.T) {
|
|||
"traefik.Middlewares.Middleware12.RateLimit.RateSet.Rate1.Average": "42",
|
||||
"traefik.Middlewares.Middleware12.RateLimit.RateSet.Rate1.Burst": "42",
|
||||
"traefik.Middlewares.Middleware12.RateLimit.RateSet.Rate1.Period": "42",
|
||||
"traefik.Middlewares.Middleware13.Redirect.Permanent": "true",
|
||||
"traefik.Middlewares.Middleware13.Redirect.Regex": "foobar",
|
||||
"traefik.Middlewares.Middleware13.Redirect.Replacement": "foobar",
|
||||
"traefik.Middlewares.Middleware13.RedirectRegex.Regex": "foobar",
|
||||
"traefik.Middlewares.Middleware13.RedirectRegex.Replacement": "foobar",
|
||||
"traefik.Middlewares.Middleware13.RedirectRegex.Permanent": "true",
|
||||
"traefik.Middlewares.Middleware13b.RedirectScheme.Scheme": "https",
|
||||
"traefik.Middlewares.Middleware13b.RedirectScheme.Port": "80",
|
||||
"traefik.Middlewares.Middleware13b.RedirectScheme.Permanent": "true",
|
||||
"traefik.Middlewares.Middleware14.ReplacePath.Path": "foobar",
|
||||
"traefik.Middlewares.Middleware15.ReplacePathRegex.Regex": "foobar",
|
||||
"traefik.Middlewares.Middleware15.ReplacePathRegex.Replacement": "foobar",
|
||||
|
|
|
@ -248,11 +248,22 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string, c
|
|||
}
|
||||
}
|
||||
|
||||
// Redirect
|
||||
if config.Redirect != nil {
|
||||
// RedirectRegex
|
||||
if config.RedirectRegex != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return redirect.New(ctx, next, *config.Redirect, middlewareName)
|
||||
return redirect.NewRedirectRegex(ctx, next, *config.RedirectRegex, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// RedirectScheme
|
||||
if config.RedirectScheme != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return redirect.NewRedirectScheme(ctx, next, *config.RedirectScheme, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
|
|
Loading…
Reference in a new issue