1
0
mirror of https://github.com/golang/go synced 2024-11-24 22:57:57 -07:00

net/http/httputil: preserve query params in reverse proxy

Fixes #2853

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5642056
This commit is contained in:
Brad Fitzpatrick 2012-02-07 18:00:30 -08:00
parent 92f55949f9
commit 518ee115b7
2 changed files with 44 additions and 1 deletions

View File

@ -55,11 +55,16 @@ func singleJoiningSlash(a, b string) string {
// target's path is "/base" and the incoming request was for "/dir", // target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir. // the target request will be for /base/dir.
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy { func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
targetQuery := target.RawQuery
director := func(req *http.Request) { director := func(req *http.Request) {
req.URL.Scheme = target.Scheme req.URL.Scheme = target.Scheme
req.URL.Host = target.Host req.URL.Host = target.Host
req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path) 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} return &ReverseProxy{Director: director}
} }

View File

@ -69,3 +69,41 @@ func TestReverseProxy(t *testing.T) {
t.Errorf("got body %q; expected %q", g, e) 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()
}
}