Commit 9ea0bd39 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

http: add http.SetCookie(ResponseWriter, *Cookie)

R=golang-dev, gary.burd, rsc
CC=golang-dev
https://golang.org/cl/4526062
parent 83fd82b3
...@@ -130,39 +130,50 @@ func readSetCookies(h Header) []*Cookie { ...@@ -130,39 +130,50 @@ func readSetCookies(h Header) []*Cookie {
return cookies return cookies
} }
// writeSetCookies writes the wire representation of the set-cookies // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
// to w. Each cookie is written on a separate "Set-Cookie: " line. func SetCookie(w ResponseWriter, cookie *Cookie) {
// 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 var b bytes.Buffer
for _, c := range kk { writeSetCookieToBuffer(&b, cookie)
b.Reset() w.Header().Add("Set-Cookie", b.String())
fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value)) }
func writeSetCookieToBuffer(buf *bytes.Buffer, c *Cookie) {
fmt.Fprintf(buf, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
if len(c.Path) > 0 { if len(c.Path) > 0 {
fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path)) fmt.Fprintf(buf, "; Path=%s", sanitizeValue(c.Path))
} }
if len(c.Domain) > 0 { if len(c.Domain) > 0 {
fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain)) fmt.Fprintf(buf, "; Domain=%s", sanitizeValue(c.Domain))
} }
if len(c.Expires.Zone) > 0 { if len(c.Expires.Zone) > 0 {
fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123)) fmt.Fprintf(buf, "; Expires=%s", c.Expires.Format(time.RFC1123))
} }
if c.MaxAge > 0 { if c.MaxAge > 0 {
fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge) fmt.Fprintf(buf, "; Max-Age=%d", c.MaxAge)
} else if c.MaxAge < 0 { } else if c.MaxAge < 0 {
fmt.Fprintf(&b, "; Max-Age=0") fmt.Fprintf(buf, "; Max-Age=0")
} }
if c.HttpOnly { if c.HttpOnly {
fmt.Fprintf(&b, "; HttpOnly") fmt.Fprintf(buf, "; HttpOnly")
} }
if c.Secure { if c.Secure {
fmt.Fprintf(&b, "; Secure") fmt.Fprintf(buf, "; Secure")
} }
}
// 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") lines = append(lines, "Set-Cookie: "+b.String()+"\r\n")
} }
sort.SortStrings(lines) sort.SortStrings(lines)
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"json" "json"
"os"
"reflect" "reflect"
"testing" "testing"
) )
...@@ -43,6 +44,35 @@ func TestWriteSetCookies(t *testing.T) { ...@@ -43,6 +44,35 @@ func TestWriteSetCookies(t *testing.T) {
} }
} }
type headerOnlyResponseWriter Header
func (ho headerOnlyResponseWriter) Header() Header {
return Header(ho)
}
func (ho headerOnlyResponseWriter) Write([]byte) (int, os.Error) {
panic("NOIMPL")
}
func (ho headerOnlyResponseWriter) WriteHeader(int) {
panic("NOIMPL")
}
func TestSetCookie(t *testing.T) {
m := make(Header)
SetCookie(headerOnlyResponseWriter(m), &Cookie{Name: "cookie-1", Value: "one", Path: "/restricted/"})
SetCookie(headerOnlyResponseWriter(m), &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600})
if l := len(m["Set-Cookie"]); l != 2 {
t.Fatalf("expected %d cookies, got %d", 2, l)
}
if g, e := m["Set-Cookie"][0], "cookie-1=one; Path=/restricted/"; g != e {
t.Errorf("cookie #1: want %q, got %q", e, g)
}
if g, e := m["Set-Cookie"][1], "cookie-2=two; Max-Age=3600"; g != e {
t.Errorf("cookie #2: want %q, got %q", e, g)
}
}
var writeCookiesTests = []struct { var writeCookiesTests = []struct {
Cookies []*Cookie Cookies []*Cookie
Raw string Raw string
......
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