From: Tom Bergan Date: Fri, 13 Oct 2017 22:56:37 +0000 (-0700) Subject: net/http: preserve Host header following a relative redirect X-Git-Tag: go1.10beta1~700 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=47f4e7a9768a613371ccd4a94a6b325fd603727e;p=gostls13.git net/http: preserve Host header following a relative redirect If the client sends a request with a custom Host header and receives a relative redirect in response, the second request should use the same Host header as the first request. However, if the response is an abolute redirect, the Host header should not be preserved. See further discussion on the issue tracker. Fixes #22233 Change-Id: I8796e2fbc1c89b3445e651f739d5d0c82e727c14 Reviewed-on: https://go-review.googlesource.com/70792 Reviewed-by: Joe Tsai Run-TryBot: Joe Tsai TryBot-Result: Gobot Gobot --- diff --git a/src/net/http/client.go b/src/net/http/client.go index 25cd5739fe..3ed666e815 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -536,12 +536,22 @@ func (c *Client) Do(req *Request) (*Response, error) { resp.closeBody() return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err)) } + host := "" + if req.Host != "" && req.Host != req.URL.Host { + // If the caller specified a custom Host header and the + // redirect location is relative, preserve the Host header + // through the redirect. See issue #22233. + if u, _ := url.Parse(loc); u != nil && !u.IsAbs() { + host = req.Host + } + } ireq := reqs[0] req = &Request{ Method: redirectMethod, Response: resp, URL: u, Header: make(Header), + Host: host, Cancel: ireq.Cancel, ctx: ireq.ctx, } diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 7db74dd4cb..eea3b16fb3 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -1426,7 +1426,7 @@ func TestClientRedirectResponseWithoutRequest(t *testing.T) { c.Get("http://dummy.tld") } -// Issue 4800: copy (some) headers when Client follows a redirect +// Issue 4800: copy (some) headers when Client follows a redirect. func TestClientCopyHeadersOnRedirect(t *testing.T) { const ( ua = "some-agent/1.2" @@ -1487,6 +1487,76 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) { } } +// Issue 22233: copy host when Client follows a relative redirect. +func TestClientCopyHostOnRedirect(t *testing.T) { + // Virtual hostname: should not receive any request. + virtual := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + t.Errorf("Virtual host received request %v", r.URL) + w.WriteHeader(403) + io.WriteString(w, "should not see this response") + })) + defer virtual.Close() + virtualHost := strings.TrimPrefix(virtual.URL, "http://") + t.Logf("Virtual host is %v", virtualHost) + + // Actual hostname: should not receive any request. + const wantBody = "response body" + var tsURL string + var tsHost string + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + switch r.URL.Path { + case "/": + // Relative redirect. + if r.Host != virtualHost { + t.Errorf("Serving /: Request.Host = %#v; want %#v", r.Host, virtualHost) + w.WriteHeader(404) + return + } + w.Header().Set("Location", "/hop") + w.WriteHeader(302) + case "/hop": + // Absolute redirect. + if r.Host != virtualHost { + t.Errorf("Serving /hop: Request.Host = %#v; want %#v", r.Host, virtualHost) + w.WriteHeader(404) + return + } + w.Header().Set("Location", tsURL+"/final") + w.WriteHeader(302) + case "/final": + if r.Host != tsHost { + t.Errorf("Serving /final: Request.Host = %#v; want %#v", r.Host, tsHost) + w.WriteHeader(404) + return + } + w.WriteHeader(200) + io.WriteString(w, wantBody) + default: + t.Errorf("Serving unexpected path %q", r.URL.Path) + w.WriteHeader(404) + } + })) + defer ts.Close() + tsURL = ts.URL + tsHost = strings.TrimPrefix(ts.URL, "http://") + t.Logf("Server host is %v", tsHost) + + c := ts.Client() + req, _ := NewRequest("GET", ts.URL, nil) + req.Host = virtualHost + resp, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + t.Fatal(resp.Status) + } + if got, err := ioutil.ReadAll(resp.Body); err != nil || string(got) != wantBody { + t.Errorf("body = %q; want %q", got, wantBody) + } +} + // Issue 17494: cookies should be altered when Client follows redirects. func TestClientAltersCookiesOnRedirect(t *testing.T) { cookieMap := func(cs []*Cookie) map[string][]string {