Repository: go
Issue: net/http/cookie: readSetCookies does not strip whitespace for key/value pair received
Labels: NeedsInvestigation

<!--
Please answer these questions before submitting your issue. Thanks!
For questions please use one of our forums: https://github.com/golang/go/wiki/Questions
-->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.14.6 windows/amd64
</pre>

### Does this issue reproduce with the latest release?

Yes. I'm using the latest go release for Windows.

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
set GO111MODULE=on
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\-snip-\AppData\Local\go-build
set GOENV=C:\Users\-snip-\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\-snip-\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=-snip-
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\-snip-\AppData\Local\Temp\go-build817710326=/tmp/go-build -gno-record-gcc-switches
</pre></details>

### What did you do?

<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
-->

Use `http.Client` with cookie jar to access site with valid `Set-Cookie` header, but the cookie did not persist.

The first two requests:

```http
GET http://192.168.2.1/html/footer.html HTTP/1.1
Host: 192.168.2.1
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip

HTTP/1.1 200 OK
Date: Thu, 01 Jan 1970 00:00:00 GMT
Server: webserver
Connection: keep-alive
Keep-Alive: timeout=10, max=100
X-Download-Options: noopen
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubdomains
Content-Length: 185
Content-Type: text/html
Expires: 0
Cache-Control: no-cache
Set-Cookie: SessionID=some_value;path =/;HttpOnly;

GET http://192.168.2.1/api/user/state-login HTTP/1.1
Host: 192.168.2.1
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
```

In the second request, the cookie did not persist. When looking at the cookie jar after the first request, the cookie has been stored under the path `/html` instead of expected `/`, which applies to the whole domain.

When I further examine the response header from the initial request, there's a white-space after the `path` key. This extra whitespace has caused `readSetCookies` to not recognise the key-pair, and the cookie has been stored relative to the document path (i.e. `/html`).

A quick read in [RFC6265#5.2, step 4](https://tools.ietf.org/html/rfc6265#section-5.2) states that the user-agent should strip leading or trailing whitespaces for the key/value string.

An attempt to fix this behaviour:

```patch
--- cookie.go   2020-07-16 22:30:44.000000000 +0100
+++ cookie_2.go 2020-07-26 11:33:31.710704300 +0100
@@ -92,8 +92,8 @@
                        if j := strings.Index(attr, "="); j >= 0 {
                                attr, val = attr[:j], attr[j+1:]
                        }
-                       lowerAttr := strings.ToLower(attr)
-                       val, ok = parseCookieValue(val, false)
+                       lowerAttr := strings.TrimSpace(strings.ToLower(attr))
+                       val, ok = parseCookieValue(strings.TrimSpace(val), false)
                        if !ok {
                                c.Unparsed = append(c.Unparsed, parts[i])
                                continue
```

### What did you expect to see?

The cookie is carried with subsequent requests.

### What did you see instead?

The cookie was not set in subsequent requests, due to path mismatch.