aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2012-02-07 18:00:30 -0800
committerBrad Fitzpatrick <bradfitz@golang.org>2012-02-07 18:00:30 -0800
commit518ee115b75c72c68364e1f376d9d9d3f808ffda (patch)
treec8b0f4755a34c25eb26da362c376630245a17e3d
parent92f55949f9e747477937e66df3cb486b1912e97f (diff)
downloadgo-518ee115b75c72c68364e1f376d9d9d3f808ffda.tar.gz
go-518ee115b75c72c68364e1f376d9d9d3f808ffda.zip
net/http/httputil: preserve query params in reverse proxy
Fixes #2853 R=golang-dev, r CC=golang-dev https://golang.org/cl/5642056
-rw-r--r--src/pkg/net/http/httputil/reverseproxy.go7
-rw-r--r--src/pkg/net/http/httputil/reverseproxy_test.go38
2 files changed, 44 insertions, 1 deletions
diff --git a/src/pkg/net/http/httputil/reverseproxy.go b/src/pkg/net/http/httputil/reverseproxy.go
index 1072e2e342..9c4bd6e09a 100644
--- a/src/pkg/net/http/httputil/reverseproxy.go
+++ b/src/pkg/net/http/httputil/reverseproxy.go
@@ -55,11 +55,16 @@ func singleJoiningSlash(a, b string) string {
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
+ targetQuery := target.RawQuery
director := func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
- req.URL.RawQuery = target.RawQuery
+ if targetQuery == "" || req.URL.RawQuery == "" {
+ req.URL.RawQuery = targetQuery + req.URL.RawQuery
+ } else {
+ req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
+ }
}
return &ReverseProxy{Director: director}
}
diff --git a/src/pkg/net/http/httputil/reverseproxy_test.go b/src/pkg/net/http/httputil/reverseproxy_test.go
index 655784b30d..28e9c90ad3 100644
--- a/src/pkg/net/http/httputil/reverseproxy_test.go
+++ b/src/pkg/net/http/httputil/reverseproxy_test.go
@@ -69,3 +69,41 @@ func TestReverseProxy(t *testing.T) {
t.Errorf("got body %q; expected %q", g, e)
}
}
+
+var proxyQueryTests = []struct {
+ baseSuffix string // suffix to add to backend URL
+ reqSuffix string // suffix to add to frontend's request URL
+ want string // what backend should see for final request URL (without ?)
+}{
+ {"", "", ""},
+ {"?sta=tic", "?us=er", "sta=tic&us=er"},
+ {"", "?us=er", "us=er"},
+ {"?sta=tic", "", "sta=tic"},
+}
+
+func TestReverseProxyQuery(t *testing.T) {
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("X-Got-Query", r.URL.RawQuery)
+ w.Write([]byte("hi"))
+ }))
+ defer backend.Close()
+
+ for i, tt := range proxyQueryTests {
+ backendURL, err := url.Parse(backend.URL + tt.baseSuffix)
+ if err != nil {
+ t.Fatal(err)
+ }
+ frontend := httptest.NewServer(NewSingleHostReverseProxy(backendURL))
+ req, _ := http.NewRequest("GET", frontend.URL+tt.reqSuffix, nil)
+ req.Close = true
+ res, err := http.DefaultClient.Do(req)
+ if err != nil {
+ t.Fatalf("%d. Get: %v", i, err)
+ }
+ if g, e := res.Header.Get("X-Got-Query"), tt.want; g != e {
+ t.Errorf("%d. got query %q; expected %q", i, g, e)
+ }
+ res.Body.Close()
+ frontend.Close()
+ }
+}