Merge pull request #1374 from ssttevee/path-replace-rule
Add Path Replacement Rule
This commit is contained in:
commit
521e295349
5 changed files with 82 additions and 0 deletions
|
@ -84,6 +84,7 @@ Modifier rules only modify the request. They do not have any impact on routing d
|
||||||
Following is the list of existing modifier rules:
|
Following is the list of existing modifier rules:
|
||||||
|
|
||||||
- `AddPrefix: /products`: Add path prefix to the existing request path prior to forwarding the request to the backend.
|
- `AddPrefix: /products`: Add path prefix to the existing request path prior to forwarding the request to the backend.
|
||||||
|
- `ReplacePath: /serverless-path`: Replaces the path and adds the old path to the `X-Replaced-Path` header. Useful for mapping to AWS Lambda or Google Cloud Functions.
|
||||||
|
|
||||||
### Matchers
|
### Matchers
|
||||||
|
|
||||||
|
|
20
middlewares/replace_path.go
Normal file
20
middlewares/replace_path.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReplacePath is a middleware used to replace the path of a URL request
|
||||||
|
type ReplacePath struct {
|
||||||
|
Handler http.Handler
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplacedPathHeader is the default header to set the old path to
|
||||||
|
const ReplacedPathHeader = "X-Replaced-Path"
|
||||||
|
|
||||||
|
func (s *ReplacePath) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.Header.Add(ReplacedPathHeader, r.URL.Path)
|
||||||
|
r.URL.Path = s.Path
|
||||||
|
s.Handler.ServeHTTP(w, r)
|
||||||
|
}
|
44
middlewares/replace_path_test.go
Normal file
44
middlewares/replace_path_test.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package middlewares_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/middlewares"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReplacePath(t *testing.T) {
|
||||||
|
const replacementPath = "/replacement-path"
|
||||||
|
|
||||||
|
paths := []string{
|
||||||
|
"/example",
|
||||||
|
"/some/really/long/path",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
t.Run(path, func(t *testing.T) {
|
||||||
|
var newPath, oldPath string
|
||||||
|
handler := &middlewares.ReplacePath{
|
||||||
|
Path: replacementPath,
|
||||||
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
newPath = r.URL.Path
|
||||||
|
oldPath = r.Header.Get("X-Replaced-Path")
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://localhost"+path, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.ServeHTTP(nil, req)
|
||||||
|
if newPath != replacementPath {
|
||||||
|
t.Fatalf("new path should be '%s'", replacementPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldPath != path {
|
||||||
|
t.Fatalf("old path should be '%s'", path)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,6 +75,13 @@ func (r *Rules) pathStrip(paths ...string) *mux.Route {
|
||||||
return r.route.route
|
return r.route.route
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Rules) replacePath(paths ...string) *mux.Route {
|
||||||
|
for _, path := range paths {
|
||||||
|
r.route.replacePath = path
|
||||||
|
}
|
||||||
|
return r.route.route
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Rules) addPrefix(paths ...string) *mux.Route {
|
func (r *Rules) addPrefix(paths ...string) *mux.Route {
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
r.route.addPrefix = path
|
r.route.addPrefix = path
|
||||||
|
@ -116,6 +123,7 @@ func (r *Rules) parseRules(expression string, onRule func(functionName string, f
|
||||||
"Headers": r.headers,
|
"Headers": r.headers,
|
||||||
"HeadersRegexp": r.headersRegexp,
|
"HeadersRegexp": r.headersRegexp,
|
||||||
"AddPrefix": r.addPrefix,
|
"AddPrefix": r.addPrefix,
|
||||||
|
"ReplacePath": r.replacePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(expression) == 0 {
|
if len(expression) == 0 {
|
||||||
|
|
|
@ -65,6 +65,7 @@ type serverRoute struct {
|
||||||
route *mux.Route
|
route *mux.Route
|
||||||
stripPrefixes []string
|
stripPrefixes []string
|
||||||
addPrefix string
|
addPrefix string
|
||||||
|
replacePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer returns an initialized Server.
|
// NewServer returns an initialized Server.
|
||||||
|
@ -806,6 +807,14 @@ func (server *Server) wireFrontendBackend(serverRoute *serverRoute, handler http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// path replace
|
||||||
|
if len(serverRoute.replacePath) > 0 {
|
||||||
|
handler = &middlewares.ReplacePath{
|
||||||
|
Path: serverRoute.replacePath,
|
||||||
|
Handler: handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serverRoute.route.Handler(handler)
|
serverRoute.route.Handler(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue