From db941817803a209f895212ed0bc3a4bf46b1bddf Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Wed, 11 Mar 2020 12:02:19 +0300 Subject: [PATCH 01/11] Add singleHost flag --- app_config.go | 1 + main.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app_config.go b/app_config.go index 245a9e0d5..3c6a8d31d 100644 --- a/app_config.go +++ b/app_config.go @@ -4,6 +4,7 @@ import "time" type appConfig struct { Domain string + SingleHost bool ArtifactsServer string ArtifactsServerTimeout int RootCertificate []byte diff --git a/main.go b/main.go index 9a316c5e5..d306ede1f 100644 --- a/main.go +++ b/main.go @@ -73,6 +73,7 @@ var ( tlsMaxVersion = flag.String("tls-max-version", "", tlsconfig.FlagUsage("max")) disableCrossOriginRequests = flag.Bool("disable-cross-origin-requests", false, "Disable cross-origin requests") + singleHost = flag.Bool("singleHost", false, "EXPERIMENTAL: can be removed without notice") // See init() listenHTTP MultiStringFlag @@ -147,6 +148,7 @@ func configFromFlags() appConfig { var config appConfig config.Domain = strings.ToLower(*pagesDomain) + config.SingleHost = *singleHost config.RedirectHTTP = *redirectHTTP config.HTTP2 = *useHTTP2 config.DisableCrossOriginRequests = *disableCrossOriginRequests -- GitLab From 26d0463d6fc5f61a89265d3925f1afd753b0d718 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Wed, 11 Mar 2020 12:41:13 +0300 Subject: [PATCH 02/11] Add singlehost package --- app.go | 5 +++++ internal/singlehost/middleware.go | 36 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 internal/singlehost/middleware.go diff --git a/app.go b/app.go index 22264eb8e..2329a537e 100644 --- a/app.go +++ b/app.go @@ -24,6 +24,7 @@ import ( "gitlab.com/gitlab-org/gitlab-pages/internal/logging" "gitlab.com/gitlab-org/gitlab-pages/internal/netutil" "gitlab.com/gitlab-org/gitlab-pages/internal/request" + "gitlab.com/gitlab-org/gitlab-pages/internal/singlehost" "gitlab.com/gitlab-org/gitlab-pages/internal/source" ) @@ -336,6 +337,10 @@ func (a *theApp) buildHandlerPipeline() (http.Handler, error) { handler = a.routingMiddleware(handler) + if a.appConfig.SingleHost { + handler = singlehost.NewMiddleware(handler) + } + // Health Check handler, err = a.healthCheckMiddleware(handler) if err != nil { diff --git a/internal/singlehost/middleware.go b/internal/singlehost/middleware.go new file mode 100644 index 000000000..a23f05784 --- /dev/null +++ b/internal/singlehost/middleware.go @@ -0,0 +1,36 @@ +package singlehost + +import ( + "net/http" + "strings" +) + +type middleware struct { + next http.Handler + pagesDomain string +} + +// NewMiddleware returns new single host middleware +// which substitutes first path segment for host +func NewMiddleware(next http.Handler, pagesDomain string) http.Handler { + return middleware{next: next, pagesDomain: pagesDomain} +} + +func (m middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { + m.extractHostFromPath(r) + + m.next.ServeHTTP(w, r) +} + +func (m middleware) extractHostFromPath(r *http.Request) { + // custom domain + if r.Host != m.pagesDomain { + return + } + + segments := strings.SplitN(r.URL.Path, "/", 2) + namespace, newPath := segments[0], segments[1] + + r.Host = namespace + "." + m.pagesDomain + r.URL.Path = newPath +} -- GitLab From 9418d3407c2168b00115ce60edc537bb528ad738 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Wed, 11 Mar 2020 14:55:35 +0300 Subject: [PATCH 03/11] Add singlehost middleware tests --- internal/singlehost/middleware_test.go | 54 ++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 internal/singlehost/middleware_test.go diff --git a/internal/singlehost/middleware_test.go b/internal/singlehost/middleware_test.go new file mode 100644 index 000000000..d962d921f --- /dev/null +++ b/internal/singlehost/middleware_test.go @@ -0,0 +1,54 @@ +package singlehost + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" +) + +var writeURLhandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, r.Host+"/"+r.URL.Path) +}) + +func testServeHTTP(t *testing.T) { + handler := NewMiddleware(writeURLhandler, "pages.example.com") + + tests := []struct { + name string + URL string + expectedURL string + }{ + { + name: "custom domain", + URL: "mydomain.example.com", + expectedURL: "mydomain.example.com", + }, + { + name: "namespace root", + URL: "pages.example.com/group", + expectedURL: "group.pages.example.com", + }, + { + name: "namespace with path", + URL: "pages.example.com/group/path/to/file", + expectedURL: "group.pages.example.com/path/to/file", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := httptest.NewRequest("GET", tt.URL, nil) + recorder := httptest.NewRecorder() + + handler.ServeHTTP(recorder, req) + + body, err := ioutil.ReadAll(recorder.Body) + require.NoError(t, err) + + require.Equal(t, tt.expectedURL, string(body)) + }) + } +} -- GitLab From 78e7ce0a3d5a4fc0963eb0568ded882fa9709600 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Wed, 11 Mar 2020 15:16:08 +0300 Subject: [PATCH 04/11] Rename flag to single-host --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index d306ede1f..55573bec7 100644 --- a/main.go +++ b/main.go @@ -73,7 +73,7 @@ var ( tlsMaxVersion = flag.String("tls-max-version", "", tlsconfig.FlagUsage("max")) disableCrossOriginRequests = flag.Bool("disable-cross-origin-requests", false, "Disable cross-origin requests") - singleHost = flag.Bool("singleHost", false, "EXPERIMENTAL: can be removed without notice") + singleHost = flag.Bool("single-host", false, "EXPERIMENTAL: can be removed without notice") // See init() listenHTTP MultiStringFlag -- GitLab From 801ab4886bc25737c859ee9840355f626e490fe2 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Wed, 11 Mar 2020 15:16:32 +0300 Subject: [PATCH 05/11] Fix build: add pages domain to singlehost middleware --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index 2329a537e..c7a494463 100644 --- a/app.go +++ b/app.go @@ -338,7 +338,7 @@ func (a *theApp) buildHandlerPipeline() (http.Handler, error) { handler = a.routingMiddleware(handler) if a.appConfig.SingleHost { - handler = singlehost.NewMiddleware(handler) + handler = singlehost.NewMiddleware(handler, a.appConfig.Domain) } // Health Check -- GitLab From 909733bc6594c0d7b3e93127b3737f125a010552 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Wed, 11 Mar 2020 15:17:08 +0300 Subject: [PATCH 06/11] Fix singlehost middleware --- internal/singlehost/middleware.go | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/internal/singlehost/middleware.go b/internal/singlehost/middleware.go index a23f05784..25c3b26c8 100644 --- a/internal/singlehost/middleware.go +++ b/internal/singlehost/middleware.go @@ -1,8 +1,11 @@ package singlehost import ( + "net" "net/http" "strings" + + log "github.com/sirupsen/logrus" ) type middleware struct { @@ -23,14 +26,31 @@ func (m middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func (m middleware) extractHostFromPath(r *http.Request) { - // custom domain - if r.Host != m.pagesDomain { + host, port, err := net.SplitHostPort(r.Host) + if err != nil { + return + } + + if host != m.pagesDomain { return } - segments := strings.SplitN(r.URL.Path, "/", 2) - namespace, newPath := segments[0], segments[1] + segments := strings.SplitN(r.URL.Path, "/", 3) + namespace, newPath := segments[1], "/"+segments[2] + + newHost := namespace + "." + m.pagesDomain + + if port != "" { + newHost += ":" + port + } + + log.WithFields(log.Fields{ + "old_host": r.Host, + "new_host": newHost, + "old_path": r.URL.Path, + "new_path": newPath, + }).Debug("Rewrite namespace host") - r.Host = namespace + "." + m.pagesDomain + r.Host = newHost r.URL.Path = newPath } -- GitLab From 2f95a419edb89e4a4705b478d2e60b37459609e3 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Thu, 12 Mar 2020 17:26:38 +0300 Subject: [PATCH 07/11] Add examples for singlehost middleware --- internal/singlehost/middleware.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/singlehost/middleware.go b/internal/singlehost/middleware.go index 25c3b26c8..419781b04 100644 --- a/internal/singlehost/middleware.go +++ b/internal/singlehost/middleware.go @@ -14,7 +14,9 @@ type middleware struct { } // NewMiddleware returns new single host middleware -// which substitutes first path segment for host +// which substitutes first path segment for host, e.g.: +// pages.example.com/group becames group.pages.example.com +// pages.example.com/group/subgroup/path/index.html becames group.pages.example.com/subgroup/path/index.html func NewMiddleware(next http.Handler, pagesDomain string) http.Handler { return middleware{next: next, pagesDomain: pagesDomain} } -- GitLab From b8179eb346d4f6e360da93d67e4cb4974b2f75f0 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Thu, 12 Mar 2020 18:55:53 +0300 Subject: [PATCH 08/11] Fix singlehost middleware and tests --- internal/singlehost/middleware.go | 40 ++++++++++++++++++-------- internal/singlehost/middleware_test.go | 25 ++++++++++++---- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/internal/singlehost/middleware.go b/internal/singlehost/middleware.go index 419781b04..5d3982ab3 100644 --- a/internal/singlehost/middleware.go +++ b/internal/singlehost/middleware.go @@ -3,6 +3,7 @@ package singlehost import ( "net" "net/http" + "path" "strings" log "github.com/sirupsen/logrus" @@ -28,27 +29,34 @@ func (m middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func (m middleware) extractHostFromPath(r *http.Request) { - host, port, err := net.SplitHostPort(r.Host) - if err != nil { + logger := log.WithFields(log.Fields{ + "orig_host": r.Host, + "orig_path": r.URL.Path, + "pages_domain": m.pagesDomain, + }) + + if !m.isTopPagesDomain(r.Host) { + logger.Debug("Incoming request does not match pages domain") return } - if host != m.pagesDomain { + path := strings.TrimPrefix(path.Clean(r.URL.Path), "/") + segments := strings.SplitN(path, "/", 2) + if len(segments) == 0 { + logger.Debug("can't extract group from path because first segment is empty") return } - segments := strings.SplitN(r.URL.Path, "/", 3) - namespace, newPath := segments[1], "/"+segments[2] + namespace := segments[0] + newPath := "" - newHost := namespace + "." + m.pagesDomain - - if port != "" { - newHost += ":" + port + if len(segments) > 1 { + newPath = "/" + segments[1] } - log.WithFields(log.Fields{ - "old_host": r.Host, - "new_host": newHost, + newHost := namespace + "." + r.Host + + logger.WithFields(log.Fields{ "old_path": r.URL.Path, "new_path": newPath, }).Debug("Rewrite namespace host") @@ -56,3 +64,11 @@ func (m middleware) extractHostFromPath(r *http.Request) { r.Host = newHost r.URL.Path = newPath } + +func (m middleware) isTopPagesDomain(host string) bool { + hostWithoutPort, _, err := net.SplitHostPort(host) + if err != nil { + hostWithoutPort = host + } + return hostWithoutPort == m.pagesDomain +} diff --git a/internal/singlehost/middleware_test.go b/internal/singlehost/middleware_test.go index d962d921f..9e5a37158 100644 --- a/internal/singlehost/middleware_test.go +++ b/internal/singlehost/middleware_test.go @@ -11,10 +11,10 @@ import ( ) var writeURLhandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, r.Host+"/"+r.URL.Path) + fmt.Fprintf(w, r.Host+r.URL.Path) }) -func testServeHTTP(t *testing.T) { +func TestServeHTTP(t *testing.T) { handler := NewMiddleware(writeURLhandler, "pages.example.com") tests := []struct { @@ -24,19 +24,34 @@ func testServeHTTP(t *testing.T) { }{ { name: "custom domain", - URL: "mydomain.example.com", + URL: "http://mydomain.example.com", expectedURL: "mydomain.example.com", }, { name: "namespace root", - URL: "pages.example.com/group", + URL: "http://pages.example.com/group", + expectedURL: "group.pages.example.com", + }, + { + name: "namespace root with port", + URL: "http://pages.example.com:8080/group", + expectedURL: "group.pages.example.com:8080", + }, + { + name: "namespace root with trailing slash", + URL: "http://pages.example.com/group/", expectedURL: "group.pages.example.com", }, { name: "namespace with path", - URL: "pages.example.com/group/path/to/file", + URL: "http://pages.example.com/group/path/to/file", expectedURL: "group.pages.example.com/path/to/file", }, + { + name: "namespace with path and port", + URL: "http://pages.example.com:8080/group/path/to/file", + expectedURL: "group.pages.example.com:8080/path/to/file", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { -- GitLab From 217d6dc316aa14e4fbbd00de4c1bac532d0d1838 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Fri, 13 Mar 2020 12:54:27 +0300 Subject: [PATCH 09/11] Fix trailing slash removal --- internal/singlehost/middleware.go | 7 +++---- internal/singlehost/middleware_test.go | 11 ++++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/internal/singlehost/middleware.go b/internal/singlehost/middleware.go index 5d3982ab3..9ef014082 100644 --- a/internal/singlehost/middleware.go +++ b/internal/singlehost/middleware.go @@ -3,7 +3,6 @@ package singlehost import ( "net" "net/http" - "path" "strings" log "github.com/sirupsen/logrus" @@ -40,7 +39,7 @@ func (m middleware) extractHostFromPath(r *http.Request) { return } - path := strings.TrimPrefix(path.Clean(r.URL.Path), "/") + path := strings.TrimLeft(r.URL.Path, "/") segments := strings.SplitN(path, "/", 2) if len(segments) == 0 { logger.Debug("can't extract group from path because first segment is empty") @@ -48,10 +47,10 @@ func (m middleware) extractHostFromPath(r *http.Request) { } namespace := segments[0] - newPath := "" + newPath := "/" if len(segments) > 1 { - newPath = "/" + segments[1] + newPath += segments[1] } newHost := namespace + "." + r.Host diff --git a/internal/singlehost/middleware_test.go b/internal/singlehost/middleware_test.go index 9e5a37158..72c979ef5 100644 --- a/internal/singlehost/middleware_test.go +++ b/internal/singlehost/middleware_test.go @@ -30,23 +30,28 @@ func TestServeHTTP(t *testing.T) { { name: "namespace root", URL: "http://pages.example.com/group", - expectedURL: "group.pages.example.com", + expectedURL: "group.pages.example.com/", }, { name: "namespace root with port", URL: "http://pages.example.com:8080/group", - expectedURL: "group.pages.example.com:8080", + expectedURL: "group.pages.example.com:8080/", }, { name: "namespace root with trailing slash", URL: "http://pages.example.com/group/", - expectedURL: "group.pages.example.com", + expectedURL: "group.pages.example.com/", }, { name: "namespace with path", URL: "http://pages.example.com/group/path/to/file", expectedURL: "group.pages.example.com/path/to/file", }, + { + name: "namespace with path does not remove trailing slash", + URL: "http://pages.example.com/group/path/to/file/", + expectedURL: "group.pages.example.com/path/to/file/", + }, { name: "namespace with path and port", URL: "http://pages.example.com:8080/group/path/to/file", -- GitLab From 247ccda06527cda7763beedc9050f372a0683a8e Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Fri, 13 Mar 2020 14:24:06 +0300 Subject: [PATCH 10/11] Add redirect transformation --- internal/singlehost/middleware.go | 4 +- internal/singlehost/middleware_test.go | 29 ++++++++++++ internal/singlehost/responsewriter.go | 64 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 internal/singlehost/responsewriter.go diff --git a/internal/singlehost/middleware.go b/internal/singlehost/middleware.go index 9ef014082..dff21ff18 100644 --- a/internal/singlehost/middleware.go +++ b/internal/singlehost/middleware.go @@ -24,7 +24,9 @@ func NewMiddleware(next http.Handler, pagesDomain string) http.Handler { func (m middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { m.extractHostFromPath(r) - m.next.ServeHTTP(w, r) + ww := newResponseWriter(w, m.pagesDomain) + + m.next.ServeHTTP(ww, r) } func (m middleware) extractHostFromPath(r *http.Request) { diff --git a/internal/singlehost/middleware_test.go b/internal/singlehost/middleware_test.go index 72c979ef5..d4be6e7d6 100644 --- a/internal/singlehost/middleware_test.go +++ b/internal/singlehost/middleware_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitlab-pages/internal/testhelpers" ) var writeURLhandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -72,3 +73,31 @@ func TestServeHTTP(t *testing.T) { }) } } + +func TestServeHTTPWithRedirect(t *testing.T) { + tests := []struct { + name string + redirectURL string + expectedRedirectURL string + }{ + { + name: "redirecting to non-group domain", + redirectURL: "//example.com:8080/test", + expectedRedirectURL: "//example.com:8080/test", + }, + { + name: "redirecting to group domain", + redirectURL: "//group.pages.example.com:8080/test", + expectedRedirectURL: "//pages.example.com:8080/group/test", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + redirectHandler := http.RedirectHandler(tt.redirectURL, 302) + handler := NewMiddleware(redirectHandler, "pages.example.com") + + testhelpers.AssertRedirectTo(t, handler.ServeHTTP, "GET", "/", nil, tt.expectedRedirectURL) + }) + } +} diff --git a/internal/singlehost/responsewriter.go b/internal/singlehost/responsewriter.go new file mode 100644 index 000000000..a4bb7ea72 --- /dev/null +++ b/internal/singlehost/responsewriter.go @@ -0,0 +1,64 @@ +package singlehost + +import ( + "net/http" + "net/url" + "strings" + + log "github.com/sirupsen/logrus" +) + +type responseWriter struct { + http.ResponseWriter + pagesDomain string +} + +func newResponseWriter(original http.ResponseWriter, pagesDomain string) http.ResponseWriter { + return responseWriter{ResponseWriter: original, pagesDomain: pagesDomain} +} + +func (w responseWriter) WriteHeader(statusCode int) { + if statusCode == http.StatusMovedPermanently || statusCode == http.StatusFound { + header := w.ResponseWriter.Header() + header.Set("Location", w.transformLocation(header.Get("Location"))) + } + w.ResponseWriter.WriteHeader(statusCode) +} + +func (w responseWriter) transformLocation(location string) string { + URL, err := url.Parse(location) + if err != nil { + log.WithField("location", location).WithError(err).Error("Can't parse redirected location") + + return location + } + + if !strings.HasSuffix(URL.Hostname(), "."+w.pagesDomain) { + log.WithFields(log.Fields{ + "hostname": URL.Hostname(), + "pages_domain": w.pagesDomain, + }).Debug("Redirected URL doesn't match pages domain") + + return location + } + + namespace := strings.TrimSuffix(URL.Hostname(), "."+w.pagesDomain) + + host := w.pagesDomain + + if URL.Port() != "" { + host += ":" + URL.Port() + } + + URL.Host = host + URL.Path = "/" + namespace + URL.Path + + newLocation := URL.String() + + log.WithFields(log.Fields{ + "orig_location": location, + "new_location": newLocation, + }).Debug("Changing redirected location") + + return newLocation +} -- GitLab From 1a17e6b9fde6fba6f399aa9a9361a7de5904c6c0 Mon Sep 17 00:00:00 2001 From: Vladimir Shushlin Date: Fri, 13 Mar 2020 14:31:49 +0300 Subject: [PATCH 11/11] Return error if next middleware is nil --- app.go | 5 ++++- internal/singlehost/middleware.go | 8 ++++++-- internal/singlehost/middleware_test.go | 7 +++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app.go b/app.go index c7a494463..8a87f1052 100644 --- a/app.go +++ b/app.go @@ -338,7 +338,10 @@ func (a *theApp) buildHandlerPipeline() (http.Handler, error) { handler = a.routingMiddleware(handler) if a.appConfig.SingleHost { - handler = singlehost.NewMiddleware(handler, a.appConfig.Domain) + handler, err = singlehost.NewMiddleware(handler, a.appConfig.Domain) + if err != nil { + return nil, err + } } // Health Check diff --git a/internal/singlehost/middleware.go b/internal/singlehost/middleware.go index dff21ff18..820626c82 100644 --- a/internal/singlehost/middleware.go +++ b/internal/singlehost/middleware.go @@ -1,6 +1,7 @@ package singlehost import ( + "errors" "net" "net/http" "strings" @@ -17,8 +18,11 @@ type middleware struct { // which substitutes first path segment for host, e.g.: // pages.example.com/group becames group.pages.example.com // pages.example.com/group/subgroup/path/index.html becames group.pages.example.com/subgroup/path/index.html -func NewMiddleware(next http.Handler, pagesDomain string) http.Handler { - return middleware{next: next, pagesDomain: pagesDomain} +func NewMiddleware(next http.Handler, pagesDomain string) (http.Handler, error) { + if next == nil { + return nil, errors.New("Can't build singlehost middleware: next middleware is empty") + } + return middleware{next: next, pagesDomain: pagesDomain}, nil } func (m middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { diff --git a/internal/singlehost/middleware_test.go b/internal/singlehost/middleware_test.go index d4be6e7d6..ee5269ce3 100644 --- a/internal/singlehost/middleware_test.go +++ b/internal/singlehost/middleware_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitlab-pages/internal/testhelpers" ) @@ -16,7 +17,8 @@ var writeURLhandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Reque }) func TestServeHTTP(t *testing.T) { - handler := NewMiddleware(writeURLhandler, "pages.example.com") + handler, err := NewMiddleware(writeURLhandler, "pages.example.com") + require.NoError(t, err) tests := []struct { name string @@ -95,7 +97,8 @@ func TestServeHTTPWithRedirect(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { redirectHandler := http.RedirectHandler(tt.redirectURL, 302) - handler := NewMiddleware(redirectHandler, "pages.example.com") + handler, err := NewMiddleware(redirectHandler, "pages.example.com") + require.NoError(t, err) testhelpers.AssertRedirectTo(t, handler.ServeHTTP, "GET", "/", nil, tt.expectedRedirectURL) }) -- GitLab