git » gofer » commit 8221b0a

http: Implement domain-based routing

author Alberto Bertogli
2017-08-11 01:44:59 UTC
committer Alberto Bertogli
2017-08-11 01:44:59 UTC
parent 3434104aa03a82e994f9fe56dd7080f6ccda62af

http: Implement domain-based routing

This patch completes the implementation of domain-based routing, so we
can have HTTP routes such as:

  example.com/x/ -> http://backend.com
  example.net/y/ -> http://backend.net

That is, the route will apply only for the given domain, as documented
in https://golang.org/pkg/net/http/#ServeMux.

proxy/http.go +15 -3
proxy/proxy_test.go +9 -1

diff --git a/proxy/http.go b/proxy/http.go
index 540ce7d..4dddd73 100644
--- a/proxy/http.go
+++ b/proxy/http.go
@@ -28,7 +28,7 @@ func httpServer(conf config.HTTP) *http.Server {
 				from, to, err)
 		}
 		util.Log.Printf("%s route %q -> %q", srv.Addr, from, toURL)
-		mux.Handle(from, makeProxy(from, toURL))
+		mux.Handle(from, makeProxy(from, *toURL))
 	}
 
 	return srv
@@ -55,15 +55,27 @@ func HTTPS(conf config.HTTPS) {
 	util.Log.Fatalf("HTTPS proxy exited: %v", err)
 }
 
-func makeProxy(from string, to *url.URL) http.Handler {
+func makeProxy(from string, to url.URL) http.Handler {
 	proxy := &httputil.ReverseProxy{}
 	proxy.ErrorLog = util.Log
 	proxy.Transport = transport
 
 	// Director that strips "from" from the request path, so that if we have
 	// this config:
+	//
 	//   /a/ -> http://dst/b
-	// then a request for /a/x goes to http://dst/b/x, not http://dst/b/a/x.
+	//   www.example.com/p/ -> http://dst/q
+	//
+	// then:
+	//   /a/x  goes to  http://dst/b/x (not http://dst/b/a/x)
+	//   www.example.com/p/x  goes to  http://dst/q/x
+
+	// Strip the domain from `from`, if any. That is useful for the http
+	// router, but to us is irrelevant.
+	if idx := strings.Index(from, "/"); idx > 0 {
+		from = from[idx:]
+	}
+
 	proxy.Director = func(req *http.Request) {
 		req.URL.Scheme = to.Scheme
 		req.URL.Host = to.Host
diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go
index 772b1fc..a5eb438 100644
--- a/proxy/proxy_test.go
+++ b/proxy/proxy_test.go
@@ -34,7 +34,10 @@ to = "$BACKEND_ADDR"
 
 [[http]]
 addr = "$HTTP_ADDR"
-routes = { "/be/" = "$BACKEND_URL" }
+
+[http.routes]
+"/be/" = "$BACKEND_URL"
+"localhost/xy/" = "$BACKEND_URL"
 `
 	configStr := strings.NewReplacer(
 		"$RAW_ADDR", rawAddr,
@@ -66,7 +69,12 @@ routes = { "/be/" = "$BACKEND_URL" }
 	testGet(t, "http://"+httpAddr+"/be/2", 200)
 	testGet(t, "http://"+httpAddr+"/be/3", 200)
 	testGet(t, "http://"+httpAddr+"/x", 404)
+	testGet(t, "http://"+httpAddr+"/xy/1", 404)
 
+	// Test the domain-based routing.
+	_, httpPort, _ := net.SplitHostPort(httpAddr)
+	testGet(t, "http://localhost:"+httpPort+"/be/", 200)
+	testGet(t, "http://localhost:"+httpPort+"/xy/1", 200)
 }
 
 func testGet(t *testing.T, url string, expectedStatus int) {