]> Cypherpunks repositories - gostls13.git/commitdiff
http: write cookies according to RFC 6265
authorChristian Himpel <chressie@googlemail.com>
Wed, 11 May 2011 20:33:27 +0000 (13:33 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 11 May 2011 20:33:27 +0000 (13:33 -0700)
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

src/pkg/http/cookie.go
src/pkg/http/cookie_test.go

index cc51316438aa8377630e002731b7e1c192e221ac..8e8ff89aca9f7fea27ed6a64cff768135e618900 100644 (file)
@@ -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 {
index a3ae85cd6c956644131d722ad7a13417770e3b28..e8b3df2ccf9ee297acb654531f28a6bfbc7f239b 100644 (file)
@@ -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) {