diff options
Diffstat (limited to 'src/pkg/http/cookie.go')
-rw-r--r-- | src/pkg/http/cookie.go | 116 |
1 files changed, 32 insertions, 84 deletions
diff --git a/src/pkg/http/cookie.go b/src/pkg/http/cookie.go index eb61a7001..fe70431bb 100644 --- a/src/pkg/http/cookie.go +++ b/src/pkg/http/cookie.go @@ -7,9 +7,6 @@ package http import ( "bytes" "fmt" - "io" - "os" - "sort" "strconv" "strings" "time" @@ -40,30 +37,25 @@ type Cookie struct { } // readSetCookies parses all "Set-Cookie" values from -// the header h, removes the successfully parsed values from the -// "Set-Cookie" key in h and returns the parsed Cookies. +// the header h and returns the successfully parsed Cookies. func readSetCookies(h Header) []*Cookie { cookies := []*Cookie{} - var unparsedLines []string for _, line := range h["Set-Cookie"] { - parts := strings.Split(strings.TrimSpace(line), ";", -1) + parts := strings.Split(strings.TrimSpace(line), ";") if len(parts) == 1 && parts[0] == "" { continue } parts[0] = strings.TrimSpace(parts[0]) j := strings.Index(parts[0], "=") if j < 0 { - unparsedLines = append(unparsedLines, line) continue } name, value := parts[0][:j], parts[0][j+1:] if !isCookieNameValid(name) { - unparsedLines = append(unparsedLines, line) continue } value, success := parseCookieValue(value) if !success { - unparsedLines = append(unparsedLines, line) continue } c := &Cookie{ @@ -134,77 +126,56 @@ func readSetCookies(h Header) []*Cookie { } cookies = append(cookies, c) } - h["Set-Cookie"] = unparsedLines, unparsedLines != nil return cookies } // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers. func SetCookie(w ResponseWriter, cookie *Cookie) { - var b bytes.Buffer - writeSetCookieToBuffer(&b, cookie) - w.Header().Add("Set-Cookie", b.String()) + w.Header().Add("Set-Cookie", cookie.String()) } -func writeSetCookieToBuffer(buf *bytes.Buffer, c *Cookie) { - fmt.Fprintf(buf, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value)) +// String returns the serialization of the cookie for use in a Cookie +// header (if only Name and Value are set) or a Set-Cookie response +// header (if other fields are set). +func (c *Cookie) String() string { + var b bytes.Buffer + fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value)) if len(c.Path) > 0 { - fmt.Fprintf(buf, "; Path=%s", sanitizeValue(c.Path)) + fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path)) } if len(c.Domain) > 0 { - fmt.Fprintf(buf, "; Domain=%s", sanitizeValue(c.Domain)) + fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain)) } if len(c.Expires.Zone) > 0 { - fmt.Fprintf(buf, "; Expires=%s", c.Expires.Format(time.RFC1123)) + fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123)) } if c.MaxAge > 0 { - fmt.Fprintf(buf, "; Max-Age=%d", c.MaxAge) + fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge) } else if c.MaxAge < 0 { - fmt.Fprintf(buf, "; Max-Age=0") + fmt.Fprintf(&b, "; Max-Age=0") } if c.HttpOnly { - fmt.Fprintf(buf, "; HttpOnly") + fmt.Fprintf(&b, "; HttpOnly") } if c.Secure { - fmt.Fprintf(buf, "; Secure") + fmt.Fprintf(&b, "; Secure") } + return b.String() } -// writeSetCookies writes the wire representation of the set-cookies -// to w. Each cookie is written on a separate "Set-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. -func writeSetCookies(w io.Writer, kk []*Cookie) os.Error { - if kk == nil { - return nil - } - lines := make([]string, 0, len(kk)) - var b bytes.Buffer - for _, c := range kk { - b.Reset() - writeSetCookieToBuffer(&b, c) - lines = append(lines, "Set-Cookie: "+b.String()+"\r\n") - } - sort.SortStrings(lines) - for _, l := range lines { - if _, err := io.WriteString(w, l); err != nil { - return err - } - } - return nil -} - -// readCookies parses all "Cookie" values from -// the header h, removes the successfully parsed values from the -// "Cookie" key in h and returns the parsed Cookies. -func readCookies(h Header) []*Cookie { +// readCookies parses all "Cookie" values from the header h and +// returns the successfully parsed Cookies. +// +// if filter isn't empty, only cookies of that name are returned +func readCookies(h Header, filter string) []*Cookie { cookies := []*Cookie{} lines, ok := h["Cookie"] if !ok { return cookies } - unparsedLines := []string{} + for _, line := range lines { - parts := strings.Split(strings.TrimSpace(line), ";", -1) + parts := strings.Split(strings.TrimSpace(line), ";") if len(parts) == 1 && parts[0] == "" { continue } @@ -215,50 +186,27 @@ func readCookies(h Header) []*Cookie { if len(parts[i]) == 0 { continue } - attr, val := parts[i], "" - if j := strings.Index(attr, "="); j >= 0 { - attr, val = attr[:j], attr[j+1:] + name, val := parts[i], "" + if j := strings.Index(name, "="); j >= 0 { + name, val = name[:j], name[j+1:] } - if !isCookieNameValid(attr) { + if !isCookieNameValid(name) { + continue + } + if filter != "" && filter != name { continue } val, success := parseCookieValue(val) if !success { continue } - cookies = append(cookies, &Cookie{Name: attr, Value: val}) + cookies = append(cookies, &Cookie{Name: name, Value: val}) parsedPairs++ } - if parsedPairs == 0 { - unparsedLines = append(unparsedLines, line) - } } - h["Cookie"] = unparsedLines, len(unparsedLines) > 0 return cookies } -// 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 { - if len(kk) == 0 { - return nil - } - 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)) - } - fmt.Fprintf(&buf, "\r\n") - _, err := w.Write(buf.Bytes()) - return err -} - func sanitizeName(n string) string { n = strings.Replace(n, "\n", "-", -1) n = strings.Replace(n, "\r", "-", -1) |