Skip to content

Commit

Permalink
Merge pull request #1374 from ssttevee/path-replace-rule
Browse files Browse the repository at this point in the history
Add Path Replacement Rule
  • Loading branch information
ldez committed Apr 27, 2017
2 parents 5a8215a + aa8375e commit 521e295
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

- `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

Expand Down
20 changes: 20 additions & 0 deletions middlewares/replace_path.go
Original file line number Diff line number Diff line change
@@ -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 changes: 44 additions & 0 deletions middlewares/replace_path_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}
8 changes: 8 additions & 0 deletions server/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ func (r *Rules) pathStrip(paths ...string) *mux.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 {
for _, path := range paths {
r.route.addPrefix = path
Expand Down Expand Up @@ -116,6 +123,7 @@ func (r *Rules) parseRules(expression string, onRule func(functionName string, f
"Headers": r.headers,
"HeadersRegexp": r.headersRegexp,
"AddPrefix": r.addPrefix,
"ReplacePath": r.replacePath,
}

if len(expression) == 0 {
Expand Down
9 changes: 9 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type serverRoute struct {
route *mux.Route
stripPrefixes []string
addPrefix string
replacePath string
}

// NewServer returns an initialized Server.
Expand Down Expand Up @@ -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)
}

Expand Down

0 comments on commit 521e295

Please sign in to comment.