fix: stripPrefix and stripPrefixRegex.
This commit is contained in:
parent
770b3739e0
commit
f843f260ee
6 changed files with 55 additions and 52 deletions
|
@ -3,20 +3,16 @@
|
|||
Removing Prefixes From the Path Before Forwarding the Request (Using a Regex)
|
||||
{: .subtitle }
|
||||
|
||||
`TODO: add schema`
|
||||
|
||||
Remove the matching prefixes from the URL path.
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
```yaml tab="Docker"
|
||||
# Replace the path by /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=^/foo/(.*)",
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/",
|
||||
```
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
# Replace the path by /foo
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
|
@ -24,36 +20,33 @@ metadata:
|
|||
spec:
|
||||
stripPrefixRegex:
|
||||
regex:
|
||||
- "^/foo/(.*)"
|
||||
- "/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
```json tab="Marathon"
|
||||
"labels": {
|
||||
"traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex": "^/foo/(.*)"
|
||||
"traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex": "/foo/[a-z0-9]+/[0-9]+/"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml tab="Rancher"
|
||||
# Replace the path by /foo
|
||||
labels:
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=^/foo/(.*)",
|
||||
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/",
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
# Replace the path by /foo
|
||||
[http.middlewares]
|
||||
[http.middlewares.test-stripprefixregex.stripPrefixRegex]
|
||||
regex = ["^/foo/(.*)"]
|
||||
regex = ["/foo/[a-z0-9]+/[0-9]+/"]
|
||||
```
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
# Replace the path by /foo
|
||||
http:
|
||||
middlewares:
|
||||
test-stripprefixregex:
|
||||
stripPrefixRegex:
|
||||
regex:
|
||||
- "^/foo/(.*)"
|
||||
- "/foo/[a-z0-9]+/[0-9]+/"
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
|
|
@ -150,9 +150,9 @@
|
|||
[http.middlewares.foo-slash-add-prefix.addPrefix]
|
||||
prefix = "/foo/"
|
||||
[http.middlewares.id-strip-regex-prefix.stripPrefixRegex]
|
||||
regex = ["/{id:[a-z]+}"]
|
||||
regex = ["/[a-z]+"]
|
||||
[http.middlewares.id-slash-strip-regex-prefix.stripPrefixRegex]
|
||||
regex = ["/{id:[a-z]+}/"]
|
||||
regex = ["/[a-z]+/"]
|
||||
[http.middlewares.api-regex-replace.replacePathRegex]
|
||||
regex = "/api"
|
||||
replacement = "/"
|
||||
|
|
|
@ -49,7 +49,7 @@ func (s *stripPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
}
|
||||
http.NotFound(rw, req)
|
||||
s.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
func (s *stripPrefix) serveRequest(rw http.ResponseWriter, req *http.Request, prefix string) {
|
||||
|
|
|
@ -28,7 +28,8 @@ func TestStripPrefix(t *testing.T) {
|
|||
Prefixes: []string{},
|
||||
},
|
||||
path: "/noprefixes",
|
||||
expectedStatusCode: http.StatusNotFound,
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedPath: "/noprefixes",
|
||||
},
|
||||
{
|
||||
desc: "wildcard (.*) requests",
|
||||
|
@ -76,7 +77,8 @@ func TestStripPrefix(t *testing.T) {
|
|||
Prefixes: []string{"/stat/"},
|
||||
},
|
||||
path: "/status",
|
||||
expectedStatusCode: http.StatusNotFound,
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedPath: "/status",
|
||||
},
|
||||
{
|
||||
desc: "general prefix on matching path",
|
||||
|
@ -149,6 +151,8 @@ func TestStripPrefix(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost"+test.path, nil)
|
||||
req.RequestURI = req.URL.RequestURI()
|
||||
|
||||
resp := &httptest.ResponseRecorder{Code: http.StatusOK}
|
||||
|
||||
handler.ServeHTTP(resp, req)
|
||||
|
|
|
@ -3,13 +3,13 @@ package stripprefixregex
|
|||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/containous/traefik/v2/pkg/middlewares"
|
||||
"github.com/containous/traefik/v2/pkg/middlewares/stripprefix"
|
||||
"github.com/containous/traefik/v2/pkg/tracing"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
)
|
||||
|
||||
|
@ -19,9 +19,9 @@ const (
|
|||
|
||||
// StripPrefixRegex is a middleware used to strip prefix from an URL request.
|
||||
type stripPrefixRegex struct {
|
||||
next http.Handler
|
||||
router *mux.Router
|
||||
name string
|
||||
next http.Handler
|
||||
expressions []*regexp.Regexp
|
||||
name string
|
||||
}
|
||||
|
||||
// New builds a new StripPrefixRegex middleware.
|
||||
|
@ -29,13 +29,16 @@ func New(ctx context.Context, next http.Handler, config dynamic.StripPrefixRegex
|
|||
middlewares.GetLogger(ctx, name, typeName).Debug("Creating middleware")
|
||||
|
||||
stripPrefix := stripPrefixRegex{
|
||||
next: next,
|
||||
router: mux.NewRouter(),
|
||||
name: name,
|
||||
next: next,
|
||||
name: name,
|
||||
}
|
||||
|
||||
for _, prefix := range config.Regex {
|
||||
stripPrefix.router.PathPrefix(prefix)
|
||||
for _, exp := range config.Regex {
|
||||
reg, err := regexp.Compile(strings.TrimSpace(exp))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stripPrefix.expressions = append(stripPrefix.expressions, reg)
|
||||
}
|
||||
|
||||
return &stripPrefix, nil
|
||||
|
@ -46,32 +49,28 @@ func (s *stripPrefixRegex) GetTracingInformation() (string, ext.SpanKindEnum) {
|
|||
}
|
||||
|
||||
func (s *stripPrefixRegex) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
var match mux.RouteMatch
|
||||
if s.router.Match(req, &match) {
|
||||
params := make([]string, 0, len(match.Vars)*2)
|
||||
for key, val := range match.Vars {
|
||||
params = append(params, key)
|
||||
params = append(params, val)
|
||||
}
|
||||
for _, exp := range s.expressions {
|
||||
parts := exp.FindStringSubmatch(req.URL.Path)
|
||||
if len(parts) > 0 && len(parts[0]) > 0 {
|
||||
prefix := parts[0]
|
||||
if !strings.HasPrefix(req.URL.Path, prefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
prefix, err := match.Route.URL(params...)
|
||||
if err != nil || len(prefix.Path) > len(req.URL.Path) {
|
||||
logger := middlewares.GetLogger(req.Context(), s.name, typeName)
|
||||
logger.Error("Error in stripPrefix middleware", err)
|
||||
req.Header.Add(stripprefix.ForwardedPrefixHeader, prefix)
|
||||
|
||||
req.URL.Path = strings.Replace(req.URL.Path, prefix, "", 1)
|
||||
if req.URL.RawPath != "" {
|
||||
req.URL.RawPath = req.URL.RawPath[len(prefix):]
|
||||
}
|
||||
|
||||
req.RequestURI = ensureLeadingSlash(req.URL.RequestURI())
|
||||
s.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
req.URL.Path = req.URL.Path[len(prefix.Path):]
|
||||
if req.URL.RawPath != "" {
|
||||
req.URL.RawPath = req.URL.RawPath[len(prefix.Path):]
|
||||
}
|
||||
req.Header.Add(stripprefix.ForwardedPrefixHeader, prefix.Path)
|
||||
req.RequestURI = ensureLeadingSlash(req.URL.RequestURI())
|
||||
|
||||
s.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
http.NotFound(rw, req)
|
||||
|
||||
s.next.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
func ensureLeadingSlash(str string) string {
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
func TestStripPrefixRegex(t *testing.T) {
|
||||
testPrefixRegex := dynamic.StripPrefixRegex{
|
||||
Regex: []string{"/a/api/", "/b/{regex}/", "/c/{category}/{id:[0-9]+}/"},
|
||||
Regex: []string{"/a/api/", "/b/([a-z0-9]+)/", "/c/[a-z0-9]+/[0-9]+/"},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
|
@ -27,7 +27,13 @@ func TestStripPrefixRegex(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
path: "/a/test",
|
||||
expectedStatusCode: http.StatusNotFound,
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedPath: "/a/test",
|
||||
},
|
||||
{
|
||||
path: "/a/test",
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedPath: "/a/test",
|
||||
},
|
||||
{
|
||||
path: "/a/api/test",
|
||||
|
@ -65,7 +71,8 @@ func TestStripPrefixRegex(t *testing.T) {
|
|||
},
|
||||
{
|
||||
path: "/c/api/abc/test4",
|
||||
expectedStatusCode: http.StatusNotFound,
|
||||
expectedStatusCode: http.StatusOK,
|
||||
expectedPath: "/c/api/abc/test4",
|
||||
},
|
||||
{
|
||||
path: "/a/api/a%2Fb",
|
||||
|
|
Loading…
Reference in a new issue