Redirection: permanent move option.
This commit is contained in:
parent
c944d203fb
commit
58d6681824
83 changed files with 622 additions and 8611 deletions
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/containous/traefik/middlewares"
|
||||
"github.com/containous/traefik/middlewares/accesslog"
|
||||
mauth "github.com/containous/traefik/middlewares/auth"
|
||||
"github.com/containous/traefik/middlewares/redirect"
|
||||
"github.com/containous/traefik/middlewares/tracing"
|
||||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/safe"
|
||||
|
@ -51,10 +52,6 @@ import (
|
|||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultRedirectRegex = `^(?:https?:\/\/)?([\w\._-]+)(?::\d+)?(.*)$`
|
||||
)
|
||||
|
||||
var (
|
||||
httpServerLogger = stdlog.New(log.WriterLevel(logrus.DebugLevel), "", 0)
|
||||
)
|
||||
|
@ -1117,9 +1114,10 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
rewrite, err := s.buildRedirectHandler(entryPointName, frontend.Redirect)
|
||||
if err != nil {
|
||||
log.Errorf("Error creating Frontend Redirect: %v", err)
|
||||
} else {
|
||||
n.Use(s.wrapNegroniHandlerWithAccessLog(rewrite, fmt.Sprintf("frontend redirect for %s", frontendName)))
|
||||
log.Debugf("Frontend %s redirect created", frontendName)
|
||||
}
|
||||
n.Use(s.wrapNegroniHandlerWithAccessLog(rewrite, fmt.Sprintf("frontend redirect for %s", frontendName)))
|
||||
log.Debugf("Frontend %s redirect created", frontendName)
|
||||
}
|
||||
|
||||
if len(frontend.BasicAuth) > 0 {
|
||||
|
@ -1282,57 +1280,25 @@ func (s *Server) wireFrontendBackend(serverRoute *serverRoute, handler http.Hand
|
|||
serverRoute.route.Handler(handler)
|
||||
}
|
||||
|
||||
func (s *Server) buildRedirectHandler(srcEntryPointName string, redirect *types.Redirect) (*middlewares.Rewrite, error) {
|
||||
func (s *Server) buildRedirectHandler(srcEntryPointName string, opt *types.Redirect) (negroni.Handler, error) {
|
||||
// entry point redirect
|
||||
if len(redirect.EntryPoint) > 0 {
|
||||
return s.buildEntryPointRedirect(srcEntryPointName, redirect.EntryPoint)
|
||||
if len(opt.EntryPoint) > 0 {
|
||||
entryPoint := s.globalConfiguration.EntryPoints[opt.EntryPoint]
|
||||
if entryPoint == nil {
|
||||
return nil, fmt.Errorf("unknown target entrypoint %q", srcEntryPointName)
|
||||
}
|
||||
log.Debugf("Creating entry point redirect %s -> %s", srcEntryPointName, opt.EntryPoint)
|
||||
return redirect.NewEntryPointHandler(entryPoint, opt.Permanent)
|
||||
}
|
||||
|
||||
// regex redirect
|
||||
rewrite, err := middlewares.NewRewrite(redirect.Regex, redirect.Replacement, true)
|
||||
redirection, err := redirect.NewRegexHandler(opt.Regex, opt.Replacement, opt.Permanent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("Creating entryPoint redirect %s -> %s -> %s", srcEntryPointName, redirect.Regex, redirect.Replacement)
|
||||
log.Debugf("Creating regex redirect %s -> %s -> %s", srcEntryPointName, opt.Regex, opt.Replacement)
|
||||
|
||||
return rewrite, nil
|
||||
}
|
||||
|
||||
func (s *Server) buildEntryPointRedirect(srcEntryPointName string, redirectEntryPoint string) (*middlewares.Rewrite, error) {
|
||||
regex, replacement, err := s.buildRedirect(redirectEntryPoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rewrite, err := middlewares.NewRewrite(regex, replacement, true)
|
||||
if err != nil {
|
||||
// Impossible case because error is always nil
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("Creating entryPoint redirect %s -> %s : %s -> %s", srcEntryPointName, redirectEntryPoint, regex, replacement)
|
||||
|
||||
return rewrite, nil
|
||||
}
|
||||
|
||||
func (s *Server) buildRedirect(entryPointName string) (string, string, error) {
|
||||
entryPoint := s.globalConfiguration.EntryPoints[entryPointName]
|
||||
if entryPoint == nil {
|
||||
return "", "", fmt.Errorf("unknown target entrypoint %q", entryPointName)
|
||||
}
|
||||
|
||||
exp := regexp.MustCompile(`(:\d+)`)
|
||||
match := exp.FindStringSubmatch(entryPoint.Address)
|
||||
if len(match) == 0 {
|
||||
return "", "", fmt.Errorf("bad Address format %q", entryPoint.Address)
|
||||
}
|
||||
|
||||
var protocol = "http"
|
||||
if s.globalConfiguration.EntryPoints[entryPointName].TLS != nil {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
replacement := protocol + "://$1" + match[0] + "$2"
|
||||
return defaultRedirectRegex, replacement, nil
|
||||
return redirection, nil
|
||||
}
|
||||
|
||||
func (s *Server) buildDefaultHTTPRouter() *mux.Router {
|
||||
|
@ -1440,7 +1406,7 @@ func registerMetricClients(metricsConfig *types.Metrics) metrics.Registry {
|
|||
return metrics.NewVoidRegistry()
|
||||
}
|
||||
|
||||
registries := []metrics.Registry{}
|
||||
var registries []metrics.Registry
|
||||
if metricsConfig.Prometheus != nil {
|
||||
registries = append(registries, metrics.RegisterPrometheus(metricsConfig.Prometheus))
|
||||
log.Debug("Configured Prometheus metrics")
|
||||
|
|
|
@ -923,7 +923,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBuildEntryPointRedirect(t *testing.T) {
|
||||
func TestBuildRedirectHandler(t *testing.T) {
|
||||
srv := Server{
|
||||
globalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
|
@ -1016,133 +1016,6 @@ func TestBuildEntryPointRedirect(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServerBuildEntryPointRedirect(t *testing.T) {
|
||||
srv := Server{
|
||||
globalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
"http": &configuration.EntryPoint{Address: ":80"},
|
||||
"https": &configuration.EntryPoint{Address: ":443", TLS: &tls.TLS{}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
srcEntryPointName string
|
||||
redirectEntryPoint string
|
||||
url string
|
||||
expectedURL string
|
||||
errorExpected bool
|
||||
}{
|
||||
{
|
||||
desc: "existing redirect entry point",
|
||||
srcEntryPointName: "http",
|
||||
redirectEntryPoint: "https",
|
||||
url: "http://foo:80",
|
||||
expectedURL: "https://foo:443",
|
||||
},
|
||||
{
|
||||
desc: "non-existing redirect entry point",
|
||||
srcEntryPointName: "http",
|
||||
redirectEntryPoint: "foo",
|
||||
url: "http://foo:80",
|
||||
errorExpected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rewrite, err := srv.buildEntryPointRedirect(test.srcEntryPointName, test.redirectEntryPoint)
|
||||
if test.errorExpected {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
r := testhelpers.MustNewRequest(http.MethodGet, test.url, nil)
|
||||
rewrite.ServeHTTP(recorder, r, nil)
|
||||
|
||||
location, err := recorder.Result().Location()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, test.expectedURL, location.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerBuildRedirect(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
globalConfiguration configuration.GlobalConfiguration
|
||||
redirectEntryPointName string
|
||||
expectedReplacement string
|
||||
errorExpected bool
|
||||
}{
|
||||
{
|
||||
desc: "Redirect endpoint http to https with HTTPS protocol",
|
||||
redirectEntryPointName: "https",
|
||||
globalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
"http": &configuration.EntryPoint{Address: ":80"},
|
||||
"https": &configuration.EntryPoint{Address: ":443", TLS: &tls.TLS{}},
|
||||
},
|
||||
},
|
||||
expectedReplacement: "https://$1:443$2",
|
||||
},
|
||||
{
|
||||
desc: "Redirect endpoint http to http02 with HTTP protocol",
|
||||
redirectEntryPointName: "http02",
|
||||
globalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
"http": &configuration.EntryPoint{Address: ":80"},
|
||||
"http02": &configuration.EntryPoint{Address: ":88"},
|
||||
},
|
||||
},
|
||||
expectedReplacement: "http://$1:88$2",
|
||||
},
|
||||
{
|
||||
desc: "Redirect endpoint to non-existent entry point",
|
||||
redirectEntryPointName: "foobar",
|
||||
globalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
"http": &configuration.EntryPoint{Address: ":80"},
|
||||
"http02": &configuration.EntryPoint{Address: ":88"},
|
||||
},
|
||||
},
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
desc: "Redirect endpoint to an entry point with a malformed address",
|
||||
redirectEntryPointName: "http02",
|
||||
globalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
"http": &configuration.EntryPoint{Address: ":80"},
|
||||
"http02": &configuration.EntryPoint{Address: "88"},
|
||||
},
|
||||
},
|
||||
errorExpected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
srv := Server{globalConfiguration: test.globalConfiguration}
|
||||
|
||||
_, replacement, err := srv.buildRedirect(test.redirectEntryPointName)
|
||||
|
||||
require.Equal(t, test.errorExpected, err != nil, "Expected an error but don't have error, or Expected no error but have an error: %v", err)
|
||||
assert.Equal(t, test.expectedReplacement, replacement, "build redirect does not return the right replacement pattern")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func buildDynamicConfig(dynamicConfigBuilders ...func(*types.Configuration)) *types.Configuration {
|
||||
config := &types.Configuration{
|
||||
Frontends: make(map[string]*types.Frontend),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue