diff --git a/route/table.go b/route/table.go index 35b92038e..c2744242e 100644 --- a/route/table.go +++ b/route/table.go @@ -222,6 +222,19 @@ func (t Table) route(host, path string) *Route { return routes.find(path) } +// normalizeHost returns the hostname from the request +// and removes the default port if present. +func normalizeHost(req *http.Request) string { + host := strings.ToLower(req.Host) + if req.TLS == nil && strings.HasSuffix(host, ":80") { + return host[:len(host)-3] + } + if req.TLS != nil && strings.HasSuffix(host, ":443") { + return host[:len(host)-4] + } + return host +} + // Lookup finds a target url based on the current matcher and picker // or nil if there is none. It first checks the routes for the host // and if none matches then it falls back to generic routes without @@ -234,7 +247,7 @@ func (t Table) Lookup(req *http.Request, trace string) *Target { log.Printf("[TRACE] %s Tracing %s%s", trace, req.Host, req.RequestURI) } - target := t.doLookup(strings.ToLower(req.Host), req.RequestURI, trace) + target := t.doLookup(normalizeHost(req), req.RequestURI, trace) if target == nil { target = t.doLookup("", req.RequestURI, trace) } diff --git a/route/table_lookup_test.go b/route/table_lookup_test.go index a70869dd1..da6071735 100644 --- a/route/table_lookup_test.go +++ b/route/table_lookup_test.go @@ -1,10 +1,31 @@ package route import ( + "crypto/tls" "net/http" "testing" ) +func TestNormalizeHost(t *testing.T) { + tests := []struct { + req *http.Request + host string + }{ + {&http.Request{Host: "foo.com"}, "foo.com"}, + {&http.Request{Host: "foo.com:80"}, "foo.com"}, + {&http.Request{Host: "foo.com:81"}, "foo.com:81"}, + {&http.Request{Host: "foo.com", TLS: &tls.ConnectionState{}}, "foo.com"}, + {&http.Request{Host: "foo.com:443", TLS: &tls.ConnectionState{}}, "foo.com"}, + {&http.Request{Host: "foo.com:444", TLS: &tls.ConnectionState{}}, "foo.com:444"}, + } + + for i, tt := range tests { + if got, want := normalizeHost(tt.req), tt.host; got != want { + t.Errorf("%d: got %v want %v", i, got, want) + } + } +} + func TestTableLookup(t *testing.T) { s := ` route add svc / http://foo.com:800 @@ -25,6 +46,7 @@ func TestTableLookup(t *testing.T) { req *http.Request dst string }{ + // match on host and path with and without trailing slash {&http.Request{Host: "abc.com", RequestURI: "/"}, "http://foo.com:1000"}, {&http.Request{Host: "abc.com", RequestURI: "/bar"}, "http://foo.com:1000"}, {&http.Request{Host: "abc.com", RequestURI: "/foo"}, "http://foo.com:1500"}, @@ -32,11 +54,18 @@ func TestTableLookup(t *testing.T) { {&http.Request{Host: "abc.com", RequestURI: "/foo/bar"}, "http://foo.com:2500"}, {&http.Request{Host: "abc.com", RequestURI: "/foo/bar/"}, "http://foo.com:3000"}, + // do not match on host but maybe on path {&http.Request{Host: "def.com", RequestURI: "/"}, "http://foo.com:800"}, {&http.Request{Host: "def.com", RequestURI: "/bar"}, "http://foo.com:800"}, - {&http.Request{Host: "def.com", RequestURI: "/baz"}, "http://foo.com:800"}, - {&http.Request{Host: "def.com", RequestURI: "/foo"}, "http://foo.com:900"}, + + // strip default port + {&http.Request{Host: "abc.com:80", RequestURI: "/"}, "http://foo.com:1000"}, + {&http.Request{Host: "abc.com:443", RequestURI: "/", TLS: &tls.ConnectionState{}}, "http://foo.com:1000"}, + + // not using default port + {&http.Request{Host: "abc.com:443", RequestURI: "/"}, "http://foo.com:800"}, + {&http.Request{Host: "abc.com:80", RequestURI: "/", TLS: &tls.ConnectionState{}}, "http://foo.com:800"}, } for i, tt := range tests {