From 9462bcedc612eb8b735ad7f3417c88be37f387b4 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 29 Jun 2015 18:10:43 -0700 Subject: [PATCH] net/http: harden, document func SetCookie and type Cookie Fixes #9758 Change-Id: I3089ec06cddd74b547d8b10834d7478a04b02069 Reviewed-on: https://go-review.googlesource.com/11701 Reviewed-by: Russ Cox Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/cookie.go | 32 +++++++++++++++++++++----------- src/net/http/cookie_test.go | 12 ++++++++++++ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go index 635a265706..cf7a3dbe5b 100644 --- a/src/net/http/cookie.go +++ b/src/net/http/cookie.go @@ -14,19 +14,18 @@ import ( "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 // HTTP response or the Cookie header of an HTTP request. +// +// See http://tools.ietf.org/html/rfc6265 for details. type Cookie struct { - Name string - Value string - Path string - Domain string - Expires time.Time - RawExpires string + Name string + Value string + + Path string // optional + Domain string // optional + Expires time.Time // optional + RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' @@ -126,14 +125,22 @@ func readSetCookies(h Header) []*Cookie { } // 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) { - 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 // header (if only Name and Value are set) or a Set-Cookie response // 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 { + if c == nil || !isCookieNameValid(c.Name) { + return "" + } var b bytes.Buffer fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value)) if len(c.Path) > 0 { @@ -359,5 +366,8 @@ func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) { } func isCookieNameValid(raw string) bool { + if raw == "" { + return false + } return strings.IndexFunc(raw, isNotToken) < 0 } diff --git a/src/net/http/cookie_test.go b/src/net/http/cookie_test.go index bcad88c012..d474f31347 100644 --- a/src/net/http/cookie_test.go +++ b/src/net/http/cookie_test.go @@ -94,6 +94,18 @@ var writeSetCookiesTests = []struct { &Cookie{Name: "empty-value", Value: ""}, `empty-value=`, }, + { + nil, + ``, + }, + { + &Cookie{Name: ""}, + ``, + }, + { + &Cookie{Name: "\t"}, + ``, + }, } func TestWriteSetCookies(t *testing.T) { -- 2.50.0