Commit 9462bced authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: harden, document func SetCookie and type Cookie

Fixes #9758

Change-Id: I3089ec06cddd74b547d8b10834d7478a04b02069
Reviewed-on: https://go-review.googlesource.com/11701Reviewed-by: default avatarRuss Cox <rsc@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 8e6dc76e
...@@ -14,19 +14,18 @@ import ( ...@@ -14,19 +14,18 @@ import (
"time" "time"
) )
// This implementation is done according to RFC 6265:
//
// http://tools.ietf.org/html/rfc6265
// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an // A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
// HTTP response or the Cookie header of an HTTP request. // HTTP response or the Cookie header of an HTTP request.
//
// See http://tools.ietf.org/html/rfc6265 for details.
type Cookie struct { type Cookie struct {
Name string Name string
Value string Value string
Path string
Domain string Path string // optional
Expires time.Time Domain string // optional
RawExpires string Expires time.Time // optional
RawExpires string // for reading cookies only
// MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
...@@ -126,14 +125,22 @@ func readSetCookies(h Header) []*Cookie { ...@@ -126,14 +125,22 @@ func readSetCookies(h Header) []*Cookie {
} }
// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers. // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
// The provided cookie must have a valid Name. Invalid cookies may be
// silently dropped.
func SetCookie(w ResponseWriter, cookie *Cookie) { func SetCookie(w ResponseWriter, cookie *Cookie) {
w.Header().Add("Set-Cookie", cookie.String()) if v := cookie.String(); v != "" {
w.Header().Add("Set-Cookie", v)
}
} }
// String returns the serialization of the cookie for use in a Cookie // 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 only Name and Value are set) or a Set-Cookie response
// header (if other fields are set). // header (if other fields are set).
// If c is nil or c.Name is invalid, the empty string is returned.
func (c *Cookie) String() string { func (c *Cookie) String() string {
if c == nil || !isCookieNameValid(c.Name) {
return ""
}
var b bytes.Buffer var b bytes.Buffer
fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value)) fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value))
if len(c.Path) > 0 { if len(c.Path) > 0 {
...@@ -359,5 +366,8 @@ func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) { ...@@ -359,5 +366,8 @@ func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
} }
func isCookieNameValid(raw string) bool { func isCookieNameValid(raw string) bool {
if raw == "" {
return false
}
return strings.IndexFunc(raw, isNotToken) < 0 return strings.IndexFunc(raw, isNotToken) < 0
} }
...@@ -94,6 +94,18 @@ var writeSetCookiesTests = []struct { ...@@ -94,6 +94,18 @@ var writeSetCookiesTests = []struct {
&Cookie{Name: "empty-value", Value: ""}, &Cookie{Name: "empty-value", Value: ""},
`empty-value=`, `empty-value=`,
}, },
{
nil,
``,
},
{
&Cookie{Name: ""},
``,
},
{
&Cookie{Name: "\t"},
``,
},
} }
func TestWriteSetCookies(t *testing.T) { func TestWriteSetCookies(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