Skip to content

Commit c8dd89e

Browse files
John Kellyianlancetaylor
John Kelly
authored andcommitted
net/http: add Cookie.Valid method
The (*http.Cookie).String method used by SetCookie will silently discard or sanitize any fields it deems invalid, making it difficult to tell whether a cookie will be sent as expected. This change introduces a new (*http.Cookie).Valid method which may be used to check if any cookie fields will be discarded or sanitized prior to calling (*http.Cookie).String. Fixes #46370 Change-Id: I2db80078de190d267a9c675a9717c8be8acc8704 Reviewed-on: https://go-review.googlesource.com/c/go/+/338590 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Cherry Mui <cherryyz@google.com> Trust: Damien Neil <dneil@google.com> Reviewed-by: Damien Neil <dneil@google.com>
1 parent f375844 commit c8dd89e

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

api/next.txt

+1
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,4 @@ pkg testing, type FuzzResult struct, T time.Duration
142142
pkg testing, type InternalFuzzTarget struct
143143
pkg testing, type InternalFuzzTarget struct, Fn func(*F)
144144
pkg testing, type InternalFuzzTarget struct, Name string
145+
pkg net/http, method (*Cookie) Valid() error

src/net/http/cookie.go

+33
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package http
66

77
import (
8+
"errors"
9+
"fmt"
810
"log"
911
"net"
1012
"net/http/internal/ascii"
@@ -236,6 +238,37 @@ func (c *Cookie) String() string {
236238
return b.String()
237239
}
238240

241+
// Valid reports whether the cookie is valid.
242+
func (c *Cookie) Valid() error {
243+
if c == nil {
244+
return errors.New("http: nil Cookie")
245+
}
246+
if !isCookieNameValid(c.Name) {
247+
return errors.New("http: invalid Cookie.Name")
248+
}
249+
if !validCookieExpires(c.Expires) {
250+
return errors.New("http: invalid Cookie.Expires")
251+
}
252+
for i := 0; i < len(c.Value); i++ {
253+
if !validCookieValueByte(c.Value[i]) {
254+
return fmt.Errorf("http: invalid byte %q in Cookie.Value", c.Value[i])
255+
}
256+
}
257+
if len(c.Path) > 0 {
258+
for i := 0; i < len(c.Path); i++ {
259+
if !validCookiePathByte(c.Path[i]) {
260+
return fmt.Errorf("http: invalid byte %q in Cookie.Path", c.Path[i])
261+
}
262+
}
263+
}
264+
if len(c.Domain) > 0 {
265+
if !validCookieDomain(c.Domain) {
266+
return errors.New("http: invalid Cookie.Domain")
267+
}
268+
}
269+
return nil
270+
}
271+
239272
// readCookies parses all "Cookie" values from the header h and
240273
// returns the successfully parsed Cookies.
241274
//

src/net/http/cookie_test.go

+25
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,31 @@ func TestCookieSanitizePath(t *testing.T) {
529529
}
530530
}
531531

532+
func TestCookieValid(t *testing.T) {
533+
tests := []struct {
534+
cookie *Cookie
535+
valid bool
536+
}{
537+
{nil, false},
538+
{&Cookie{Name: ""}, false},
539+
{&Cookie{Name: "invalid-expires"}, false},
540+
{&Cookie{Name: "invalid-value", Value: "foo\"bar"}, false},
541+
{&Cookie{Name: "invalid-path", Path: "/foo;bar/"}, false},
542+
{&Cookie{Name: "invalid-domain", Domain: "example.com:80"}, false},
543+
{&Cookie{Name: "valid", Value: "foo", Path: "/bar", Domain: "example.com", Expires: time.Unix(0, 0)}, true},
544+
}
545+
546+
for _, tt := range tests {
547+
err := tt.cookie.Valid()
548+
if err != nil && tt.valid {
549+
t.Errorf("%#v.Valid() returned error %v; want nil", tt.cookie, err)
550+
}
551+
if err == nil && !tt.valid {
552+
t.Errorf("%#v.Valid() returned nil; want error", tt.cookie)
553+
}
554+
}
555+
}
556+
532557
func BenchmarkCookieString(b *testing.B) {
533558
const wantCookieString = `cookie-9=i3e01nf61b6t23bvfmplnanol3; Path=/restricted/; Domain=example.com; Expires=Tue, 10 Nov 2009 23:00:00 GMT; Max-Age=3600`
534559
c := &Cookie{

0 commit comments

Comments
 (0)