]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: set cookie host to Request.Host when available
authorSean Liao <sean@liao.dev>
Wed, 8 Oct 2025 21:33:24 +0000 (22:33 +0100)
committerGopher Robot <gobot@golang.org>
Fri, 10 Oct 2025 21:38:20 +0000 (14:38 -0700)
When both Request.URL and Request.Host are set, the host in URL
is used for connecting at the transport level, while Host is used
for the request host line. Cookies should be set for the request,
not the underlying connection destination.

Fixes #38988

Change-Id: I09053b87ccac67081f6038d205837d9763701526
Reviewed-on: https://go-review.googlesource.com/c/go/+/710335
Reviewed-by: Damien Neil <dneil@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/net/http/client.go
src/net/http/client_test.go

index ba095ea1e34e5cdf9450cdf6e6a3282616f09768..8faab2b17af01a2169669dfce371e401f8c34486 100644 (file)
@@ -172,8 +172,13 @@ func refererForURL(lastReq, newReq *url.URL, explicitRef string) string {
 
 // didTimeout is non-nil only if err != nil.
 func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
+       cookieURL := req.URL
+       if req.Host != "" {
+               cookieURL = cloneURL(cookieURL)
+               cookieURL.Host = req.Host
+       }
        if c.Jar != nil {
-               for _, cookie := range c.Jar.Cookies(req.URL) {
+               for _, cookie := range c.Jar.Cookies(cookieURL) {
                        req.AddCookie(cookie)
                }
        }
@@ -183,7 +188,7 @@ func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTime
        }
        if c.Jar != nil {
                if rc := resp.Cookies(); len(rc) > 0 {
-                       c.Jar.SetCookies(req.URL, rc)
+                       c.Jar.SetCookies(cookieURL, rc)
                }
        }
        return resp, nil, nil
index 94fddb508e0e386da144c326915d8a2bbcda19b8..2a3ee385f3c81071cac64dfb4f32f25e07c6d36e 100644 (file)
@@ -585,6 +585,36 @@ var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request)
        }
 })
 
+func TestHostMismatchCookies(t *testing.T) { run(t, testHostMismatchCookies) }
+func testHostMismatchCookies(t *testing.T, mode testMode) {
+       ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+               for _, c := range r.Cookies() {
+                       c.Value = "SetOnServer"
+                       SetCookie(w, c)
+               }
+       })).ts
+
+       reqURL, _ := url.Parse(ts.URL)
+       hostURL := *reqURL
+       hostURL.Host = "cookies.example.com"
+
+       c := ts.Client()
+       c.Jar = new(TestJar)
+       c.Jar.SetCookies(reqURL, []*Cookie{{Name: "First", Value: "SetOnClient"}})
+       c.Jar.SetCookies(&hostURL, []*Cookie{{Name: "Second", Value: "SetOnClient"}})
+
+       req, _ := NewRequest("GET", ts.URL, NoBody)
+       req.Host = hostURL.Host
+       resp, err := c.Do(req)
+       if err != nil {
+               t.Fatalf("Get: %v", err)
+       }
+       resp.Body.Close()
+
+       matchReturnedCookies(t, []*Cookie{{Name: "First", Value: "SetOnClient"}}, c.Jar.Cookies(reqURL))
+       matchReturnedCookies(t, []*Cookie{{Name: "Second", Value: "SetOnServer"}}, c.Jar.Cookies(&hostURL))
+}
+
 func TestClientSendsCookieFromJar(t *testing.T) {
        defer afterTest(t)
        tr := &recordingTransport{}