Commit 158970ea authored by Christian Himpel's avatar Christian Himpel Committed by Brad Fitzpatrick

http: write cookies according to RFC 6265

RFC 6265 requires that user agents MUST NOT send more than
one Cookie header in a request.

Note, this change also fixes an issue when sending requests
with more than one cookie header line to a php script served
by an apache web server.  Apache concatenates the cookies
with ", ", but php tries to split them only at ";".  E.g.
two cookies: "a=b, c=d" are seen by php as one cookie "a"
with the value "b, c=d".

Fixes #1801

R=bradfitz
CC=golang-dev
https://golang.org/cl/4535048
parent ca83cd2c
...@@ -218,22 +218,26 @@ func readCookies(h Header) []*Cookie { ...@@ -218,22 +218,26 @@ func readCookies(h Header) []*Cookie {
return cookies return cookies
} }
// writeCookies writes the wire representation of the cookies // writeCookies writes the wire representation of the cookies to
// to w. Each cookie is written on a separate "Cookie: " line. // w. According to RFC 6265 section 5.4, writeCookies does not
// This choice is made because HTTP parsers tend to have a limit on // attach more than one Cookie header field. That means all
// line-length, so it seems safer to place cookies on separate lines. // cookies, if any, are written into the same line, separated by
// semicolon.
func writeCookies(w io.Writer, kk []*Cookie) os.Error { func writeCookies(w io.Writer, kk []*Cookie) os.Error {
lines := make([]string, 0, len(kk)) if len(kk) == 0 {
for _, c := range kk { return nil
lines = append(lines, fmt.Sprintf("Cookie: %s=%s\r\n", sanitizeName(c.Name), sanitizeValue(c.Value)))
} }
sort.SortStrings(lines) var buf bytes.Buffer
for _, l := range lines { fmt.Fprintf(&buf, "Cookie: ")
if _, err := io.WriteString(w, l); err != nil { for i, c := range kk {
return err if i > 0 {
fmt.Fprintf(&buf, "; ")
} }
fmt.Fprintf(&buf, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
} }
return nil fmt.Fprintf(&buf, "\r\n")
_, err := w.Write(buf.Bytes())
return err
} }
func sanitizeName(n string) string { func sanitizeName(n string) string {
......
...@@ -47,10 +47,22 @@ var writeCookiesTests = []struct { ...@@ -47,10 +47,22 @@ var writeCookiesTests = []struct {
Cookies []*Cookie Cookies []*Cookie
Raw string Raw string
}{ }{
{
[]*Cookie{},
"",
},
{ {
[]*Cookie{&Cookie{Name: "cookie-1", Value: "v$1"}}, []*Cookie{&Cookie{Name: "cookie-1", Value: "v$1"}},
"Cookie: cookie-1=v$1\r\n", "Cookie: cookie-1=v$1\r\n",
}, },
{
[]*Cookie{
&Cookie{Name: "cookie-1", Value: "v$1"},
&Cookie{Name: "cookie-2", Value: "v$2"},
&Cookie{Name: "cookie-3", Value: "v$3"},
},
"Cookie: cookie-1=v$1; cookie-2=v$2; cookie-3=v$3\r\n",
},
} }
func TestWriteCookies(t *testing.T) { func TestWriteCookies(t *testing.T) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment