Skip to content

Commit

Permalink
Add $host pseudo variable (#544)
Browse files Browse the repository at this point in the history
This adds support for $host, which behaves similarly to $path.  The idea with this is to be able to create a global redirect of anything received on, say, http to the https equivalent of what you were trying to hit.  Fixes #533
  • Loading branch information
holtwilkins authored and aaronhurt committed Sep 12, 2018
1 parent c730093 commit dc67d5a
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 3 deletions.
41 changes: 40 additions & 1 deletion proxy/http_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,46 @@ func TestProxyHost(t *testing.T) {
})
}

func TestRedirect(t *testing.T) {
func TestHostRedirect(t *testing.T) {
routes := "route add https-redir *:80 https://$host$path opts \"redirect=301\"\n"

tbl, _ := route.NewTable(routes)

proxy := httptest.NewServer(&HTTPProxy{
Transport: http.DefaultTransport,
Lookup: func(r *http.Request) *route.Target {
r.Host = "c.com"
return tbl.Lookup(r, "", route.Picker["rr"], route.Matcher["prefix"])
},
})
defer proxy.Close()

tests := []struct {
req string
wantCode int
wantLoc string
}{
{req: "/baz", wantCode: 301, wantLoc: "https://c.com/baz"},
}

http.DefaultClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
// do not follow redirects
return http.ErrUseLastResponse
}

for _, tt := range tests {
resp, _ := mustGet(proxy.URL + tt.req)
if resp.StatusCode != tt.wantCode {
t.Errorf("got status code %d, want %d", resp.StatusCode, tt.wantCode)
}
gotLoc, _ := resp.Location()
if gotLoc.String() != tt.wantLoc {
t.Errorf("got location %s, want %s", gotLoc, tt.wantLoc)
}
}
}

func TestPathRedirect(t *testing.T) {
routes := "route add mock / http://a.com/$path opts \"redirect=301\"\n"
routes += "route add mock /foo http://a.com/abc opts \"redirect=301\"\n"
routes += "route add mock /bar http://b.com/$path opts \"redirect=302 strip=/bar\"\n"
Expand Down
1 change: 1 addition & 0 deletions route/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ func (t Table) Lookup(req *http.Request, trace string, pick picker, match matche
for _, h := range hosts {
if target = t.lookup(h, req.URL.Path, trace, pick, match); target != nil {
if target.RedirectCode != 0 {
req.URL.Host = req.Host
target.BuildRedirectURL(req.URL) // build redirect url and cache in target
if target.RedirectURL.Scheme == req.Header.Get("X-Forwarded-Proto") &&
target.RedirectURL.Host == req.Host &&
Expand Down
3 changes: 3 additions & 0 deletions route/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,7 @@ func (t *Target) BuildRedirectURL(requestURL *url.URL) {
if t.RedirectURL.Path == "" {
t.RedirectURL.Path = "/"
}
if strings.Contains(t.RedirectURL.Host, "$host") {
t.RedirectURL.Host = strings.Replace(t.RedirectURL.Host, "$host", requestURL.Host, 1)
}
}
54 changes: 52 additions & 2 deletions route/target_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ func TestTarget_BuildRedirectURL(t *testing.T) {
{req: "/?aaa=1", want: "http://bar.com/a/b/c?foo=bar"},
},
},
{ // simple http -> https redirect with static path
route: "route add redirect *:80/ https://$host/",
tests: []routeTest{
{req: "/", want: "https://foo.com/"},
{req: "/abc", want: "https://foo.com/"},
{req: "/a/b/c", want: "https://foo.com/"},
{req: "/?aaa=1", want: "https://foo.com/"},
{req: "/abc/?aaa=1", want: "https://foo.com/"},
},
},
{ // simple redirect to corresponding path
route: "route add svc / http://bar.com/$path",
tests: []routeTest{
Expand All @@ -42,7 +52,17 @@ func TestTarget_BuildRedirectURL(t *testing.T) {
{req: "/abc/?aaa=1", want: "http://bar.com/abc/?aaa=1"},
},
},
{ // same as above but without / before $path
{ // simple http -> https redirect to corresponding host & path
route: "route add redirect *:80/ https://$host/$path",
tests: []routeTest{
{req: "/", want: "https://foo.com/"},
{req: "/abc", want: "https://foo.com/abc"},
{req: "/a/b/c", want: "https://foo.com/a/b/c"},
{req: "/?aaa=1", want: "https://foo.com/?aaa=1"},
{req: "/abc/?aaa=1", want: "https://foo.com/abc/?aaa=1"},
},
},
{ // simple redirect to corresponding path without / before $path
route: "route add svc / http://bar.com$path",
tests: []routeTest{
{req: "/", want: "http://bar.com/"},
Expand All @@ -52,6 +72,16 @@ func TestTarget_BuildRedirectURL(t *testing.T) {
{req: "/abc/?aaa=1", want: "http://bar.com/abc/?aaa=1"},
},
},
{ // simple http -> https redirect to corresponding host & path without / before $path
route: "route add redirect *:80/ https://$host$path",
tests: []routeTest{
{req: "/", want: "https://foo.com/"},
{req: "/abc", want: "https://foo.com/abc"},
{req: "/a/b/c", want: "https://foo.com/a/b/c"},
{req: "/?aaa=1", want: "https://foo.com/?aaa=1"},
{req: "/abc/?aaa=1", want: "https://foo.com/abc/?aaa=1"},
},
},
{ // arbitrary subdir on target with $path at end
route: "route add svc / http://bar.com/bbb/$path",
tests: []routeTest{
Expand All @@ -62,7 +92,17 @@ func TestTarget_BuildRedirectURL(t *testing.T) {
{req: "/abc/?aaa=1", want: "http://bar.com/bbb/abc/?aaa=1"},
},
},
{ // same as above but without / before $path
{ // http -> https redir to corresonding host w/ arbitrary subdir on target with $path at end
route: "route add redirect *:80/ https://$host/bbb/$path",
tests: []routeTest{
{req: "/", want: "https://foo.com/bbb/"},
{req: "/abc", want: "https://foo.com/bbb/abc"},
{req: "/a/b/c", want: "https://foo.com/bbb/a/b/c"},
{req: "/?aaa=1", want: "https://foo.com/bbb/?aaa=1"},
{req: "/abc/?aaa=1", want: "https://foo.com/bbb/abc/?aaa=1"},
},
},
{ // arbitrary subdir on target with $path at end but without / before $path
route: "route add svc / http://bar.com/bbb$path",
tests: []routeTest{
{req: "/", want: "http://bar.com/bbb/"},
Expand All @@ -72,6 +112,16 @@ func TestTarget_BuildRedirectURL(t *testing.T) {
{req: "/abc/?aaa=1", want: "http://bar.com/bbb/abc/?aaa=1"},
},
},
{ // http -> https redir to corresonding host w/ arbitrary subdir on target with $path at end but without / before $path
route: "route add redirect *:80/ https://$host/bbb$path",
tests: []routeTest{
{req: "/", want: "https://foo.com/bbb/"},
{req: "/abc", want: "https://foo.com/bbb/abc"},
{req: "/a/b/c", want: "https://foo.com/bbb/a/b/c"},
{req: "/?aaa=1", want: "https://foo.com/bbb/?aaa=1"},
{req: "/abc/?aaa=1", want: "https://foo.com/bbb/abc/?aaa=1"},
},
},
{ // strip prefix
route: "route add svc /stripme http://bar.com/$path opts \"strip=/stripme\"",
tests: []routeTest{
Expand Down

0 comments on commit dc67d5a

Please sign in to comment.