From: Christian Himpel Date: Wed, 11 May 2011 20:33:27 +0000 (-0700) Subject: http: write cookies according to RFC 6265 X-Git-Tag: weekly.2011-05-22~109 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=158970ea66bf062010878f8bc4aa4867bb9349b8;p=gostls13.git 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 --- diff --git a/src/pkg/http/cookie.go b/src/pkg/http/cookie.go index cc51316438..8e8ff89aca 100644 --- a/src/pkg/http/cookie.go +++ b/src/pkg/http/cookie.go @@ -218,22 +218,26 @@ func readCookies(h Header) []*Cookie { return cookies } -// writeCookies writes the wire representation of the cookies -// to w. Each cookie is written on a separate "Cookie: " line. -// This choice is made because HTTP parsers tend to have a limit on -// line-length, so it seems safer to place cookies on separate lines. +// writeCookies writes the wire representation of the cookies to +// w. According to RFC 6265 section 5.4, writeCookies does not +// attach more than one Cookie header field. That means all +// cookies, if any, are written into the same line, separated by +// semicolon. func writeCookies(w io.Writer, kk []*Cookie) os.Error { - lines := make([]string, 0, len(kk)) - for _, c := range kk { - lines = append(lines, fmt.Sprintf("Cookie: %s=%s\r\n", sanitizeName(c.Name), sanitizeValue(c.Value))) + if len(kk) == 0 { + return nil } - sort.SortStrings(lines) - for _, l := range lines { - if _, err := io.WriteString(w, l); err != nil { - return err + var buf bytes.Buffer + fmt.Fprintf(&buf, "Cookie: ") + for i, c := range kk { + 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 { diff --git a/src/pkg/http/cookie_test.go b/src/pkg/http/cookie_test.go index a3ae85cd6c..e8b3df2ccf 100644 --- a/src/pkg/http/cookie_test.go +++ b/src/pkg/http/cookie_test.go @@ -47,10 +47,22 @@ var writeCookiesTests = []struct { Cookies []*Cookie Raw string }{ + { + []*Cookie{}, + "", + }, { []*Cookie{&Cookie{Name: "cookie-1", Value: "v$1"}}, "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) {