Redirect request if it would match with an appended trailing slash
This commit is contained in:
parent
6c62b25bf1
commit
8a06779d41
|
|
@ -1,6 +1,7 @@
|
||||||
package upstream
|
package upstream
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
@ -50,6 +51,8 @@ func NewProxy(upstreams options.Upstreams, sigData *options.SignatureData, write
|
||||||
return nil, fmt.Errorf("unknown scheme for upstream %q: %q", upstream.ID, u.Scheme)
|
return nil, fmt.Errorf("unknown scheme for upstream %q: %q", upstream.ID, u.Scheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerTrailingSlashHandler(m.serveMux)
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,3 +123,25 @@ func (m *multiUpstreamProxy) registerRewriteHandler(upstream options.Upstream, h
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// registerTrailingSlashHandler creates a new matcher that will check if the
|
||||||
|
// requested path would match if it had a trailing slash appended.
|
||||||
|
// If the path matches with a trailing slash, we send back a redirect.
|
||||||
|
// This allows us to be consistent with the built in go servemux implementation.
|
||||||
|
func registerTrailingSlashHandler(serveMux *mux.Router) {
|
||||||
|
serveMux.MatcherFunc(func(req *http.Request, _ *mux.RouteMatch) bool {
|
||||||
|
if strings.HasSuffix(req.URL.Path, "/") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a separate RouteMatch so that we can redirect to the path + /.
|
||||||
|
// If we pass through the match then the matched backed will be served
|
||||||
|
// instead of the redirect handler.
|
||||||
|
m := &mux.RouteMatch{}
|
||||||
|
slashReq := req.Clone(context.Background())
|
||||||
|
slashReq.URL.Path += "/"
|
||||||
|
return serveMux.Match(slashReq, m)
|
||||||
|
}).Handler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
http.Redirect(rw, req, req.URL.String()+"/", http.StatusMovedPermanently)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ var _ = Describe("Proxy Suite", func() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := http.StatusOK
|
ok := http.StatusOK
|
||||||
|
accepted := http.StatusAccepted
|
||||||
|
|
||||||
upstreams := options.Upstreams{
|
upstreams := options.Upstreams{
|
||||||
{
|
{
|
||||||
|
|
@ -47,6 +48,12 @@ var _ = Describe("Proxy Suite", func() {
|
||||||
Static: true,
|
Static: true,
|
||||||
StaticCode: &ok,
|
StaticCode: &ok,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: "static-backend-no-trailing-slash",
|
||||||
|
Path: "/static",
|
||||||
|
Static: true,
|
||||||
|
StaticCode: &accepted,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ID: "bad-http-backend",
|
ID: "bad-http-backend",
|
||||||
Path: "/bad-http/",
|
Path: "/bad-http/",
|
||||||
|
|
@ -235,5 +242,25 @@ var _ = Describe("Proxy Suite", func() {
|
||||||
},
|
},
|
||||||
upstream: "backend-with-rewrite-prefix",
|
upstream: "backend-with-rewrite-prefix",
|
||||||
}),
|
}),
|
||||||
|
Entry("with a request to a path, missing the trailing slash", &proxyTableInput{
|
||||||
|
target: "http://example.localhost/http",
|
||||||
|
response: testHTTPResponse{
|
||||||
|
code: 301,
|
||||||
|
header: map[string][]string{
|
||||||
|
contentType: {textHTMLUTF8},
|
||||||
|
"Location": {"http://example.localhost/http/"},
|
||||||
|
},
|
||||||
|
raw: "<a href=\"http://example.localhost/http/\">Moved Permanently</a>.\n\n",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Entry("with a request to a path, missing the trailing slash, but registered separately", &proxyTableInput{
|
||||||
|
target: "http://example.localhost/static",
|
||||||
|
response: testHTTPResponse{
|
||||||
|
code: 202,
|
||||||
|
header: map[string][]string{},
|
||||||
|
raw: "Authenticated",
|
||||||
|
},
|
||||||
|
upstream: "static-backend-no-trailing-slash",
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ const (
|
||||||
acceptEncoding = "Accept-Encoding"
|
acceptEncoding = "Accept-Encoding"
|
||||||
applicationJSON = "application/json"
|
applicationJSON = "application/json"
|
||||||
textPlainUTF8 = "text/plain; charset=utf-8"
|
textPlainUTF8 = "text/plain; charset=utf-8"
|
||||||
|
textHTMLUTF8 = "text/html; charset=utf-8"
|
||||||
gapAuth = "Gap-Auth"
|
gapAuth = "Gap-Auth"
|
||||||
gapSignature = "Gap-Signature"
|
gapSignature = "Gap-Signature"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue