diff --git a/proxy/proxy.go b/proxy/proxy.go index 994a84ea4..d6f774506 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -2,6 +2,7 @@ package proxy import ( "errors" + "fmt" "net" "net/http" "net/http/httputil" @@ -13,6 +14,7 @@ import ( router_http "github.com/cloudfoundry/gorouter/common/http" "github.com/cloudfoundry/gorouter/route" steno "github.com/cloudfoundry/gosteno" + "github.com/onsi/gomega/format" ) const ( @@ -99,6 +101,20 @@ func hostWithoutPort(req *http.Request) string { return host } +func ChopUpPath(str string) []string { + // Remove : + ln := len(str) + if str[ln-1:ln] == "/" { + str = str[0 : ln-1] + } + ret := strings.Split(str, "/") + + for i := 1; i < len(ret); i++ { + ret[i] = ret[i-1] + "/" + ret[i] + } + return ret +} + func (p *proxy) getStickySession(request *http.Request) string { // Try choosing a backend using sticky session if _, err := request.Cookie(StickyCookieKey); err == nil { @@ -110,9 +126,17 @@ func (p *proxy) getStickySession(request *http.Request) string { } func (p *proxy) lookup(request *http.Request) *route.Pool { - uri := route.Uri(hostWithoutPort(request)) - // Choose backend using host alone - return p.registry.Lookup(uri) + chopt := ChopUpPath(request.RequestURI) + fmt.Println(format.Object(request, 1)) + // fmt.Println(format.Object(chopt, 1)) + for i := len(chopt) - 1; i >= 0; i-- { + uri := route.Uri(hostWithoutPort(request) + chopt[i]) + ret := p.registry.Lookup(uri) + if ret != nil && !ret.IsEmpty() { + return ret + } + } + return nil } func (p *proxy) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) { diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index 27ea73b0d..8f6613944 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -15,6 +15,7 @@ import ( "github.com/cloudfoundry/dropsonde/emitter/fake" "github.com/cloudfoundry/dropsonde/events" router_http "github.com/cloudfoundry/gorouter/common/http" + "github.com/cloudfoundry/gorouter/proxy" "github.com/cloudfoundry/gorouter/registry" "github.com/cloudfoundry/gorouter/route" "github.com/cloudfoundry/gorouter/stats" @@ -39,6 +40,55 @@ func (_ nullVarz) CaptureRoutingResponse(b *route.Endpoint, res *http.Response, } var _ = Describe("Proxy", func() { + Describe("helper functions", func() { + It("chops up paths", func() { + Expect(proxy.ChopUpPath("/path/foo/")).To(Equal([]string{"", "/path", "/path/foo"})) + Expect(proxy.ChopUpPath("/")).To(Equal([]string{""})) + Expect(proxy.ChopUpPath("/path/")).To(Equal([]string{"", "/path"})) + }) + }) + It("responds to http/1.0 with path", func() { + ln := registerHandler(r, "test/my_path", func(x *test_util.HttpConn) { + x.CheckLine("GET /my_path HTTP/1.1") + + x.WriteLines([]string{ + "HTTP/1.1 200 OK", + "Content-Length: 0", + }) + }) + defer ln.Close() + + x := dialProxy(proxyServer) + + x.WriteLines([]string{ + "GET /my_path HTTP/1.0", + "Host: test", + }) + + x.CheckLine("HTTP/1.0 200 OK") + }) + + FIt("responds to http/1.0 with path/path", func() { + ln := registerHandler(r, "test/my%20path/your_path", func(x *test_util.HttpConn) { + x.CheckLine("GET /my%20path/your_path HTTP/1.1") + + x.WriteLines([]string{ + "HTTP/1.1 200 OK", + "Content-Length: 0", + }) + }) + defer ln.Close() + + x := dialProxy(proxyServer) + + x.WriteLines([]string{ + "GET /my%20path/your_path HTTP/1.0", + "Host: test", + }) + + x.CheckLine("HTTP/1.0 200 OK") + }) + It("responds to http/1.0", func() { ln := registerHandler(r, "test", func(x *test_util.HttpConn) { x.CheckLine("GET / HTTP/1.1")