]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: add Cookie.Valid method
authorJohn Kelly <jkelly@squarespace.com>
Thu, 29 Jul 2021 19:47:23 +0000 (15:47 -0400)
committerIan Lance Taylor <iant@golang.org>
Wed, 6 Oct 2021 23:26:57 +0000 (23:26 +0000)
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>
api/next.txt
src/net/http/cookie.go
src/net/http/cookie_test.go

index b1b9c1d7b16d0d44b996a181f03d5515119edcc3..1192fc9069614a9d9ef84b9327e550d85fc01b2c 100644 (file)
@@ -142,3 +142,4 @@ pkg testing, type FuzzResult struct, T time.Duration
 pkg testing, type InternalFuzzTarget struct
 pkg testing, type InternalFuzzTarget struct, Fn func(*F)
 pkg testing, type InternalFuzzTarget struct, Name string
+pkg net/http, method (*Cookie) Valid() error
index 02b40315deb9fac197bdafd2144f5a4247a74bdb..cb37f2351f58890b0c73008946dded3456be1e28 100644 (file)
@@ -5,6 +5,8 @@
 package http
 
 import (
+       "errors"
+       "fmt"
        "log"
        "net"
        "net/http/internal/ascii"
@@ -236,6 +238,37 @@ func (c *Cookie) String() string {
        return b.String()
 }
 
+// Valid reports whether the cookie is valid.
+func (c *Cookie) Valid() error {
+       if c == nil {
+               return errors.New("http: nil Cookie")
+       }
+       if !isCookieNameValid(c.Name) {
+               return errors.New("http: invalid Cookie.Name")
+       }
+       if !validCookieExpires(c.Expires) {
+               return errors.New("http: invalid Cookie.Expires")
+       }
+       for i := 0; i < len(c.Value); i++ {
+               if !validCookieValueByte(c.Value[i]) {
+                       return fmt.Errorf("http: invalid byte %q in Cookie.Value", c.Value[i])
+               }
+       }
+       if len(c.Path) > 0 {
+               for i := 0; i < len(c.Path); i++ {
+                       if !validCookiePathByte(c.Path[i]) {
+                               return fmt.Errorf("http: invalid byte %q in Cookie.Path", c.Path[i])
+                       }
+               }
+       }
+       if len(c.Domain) > 0 {
+               if !validCookieDomain(c.Domain) {
+                       return errors.New("http: invalid Cookie.Domain")
+               }
+       }
+       return nil
+}
+
 // readCookies parses all "Cookie" values from the header h and
 // returns the successfully parsed Cookies.
 //
index 959713a0dcf0a092e9cde35824517f89cecbb303..257dc57420b0d2cc6ca726b2eb997bb094aa76bc 100644 (file)
@@ -529,6 +529,31 @@ func TestCookieSanitizePath(t *testing.T) {
        }
 }
 
+func TestCookieValid(t *testing.T) {
+       tests := []struct {
+               cookie *Cookie
+               valid  bool
+       }{
+               {nil, false},
+               {&Cookie{Name: ""}, false},
+               {&Cookie{Name: "invalid-expires"}, false},
+               {&Cookie{Name: "invalid-value", Value: "foo\"bar"}, false},
+               {&Cookie{Name: "invalid-path", Path: "/foo;bar/"}, false},
+               {&Cookie{Name: "invalid-domain", Domain: "example.com:80"}, false},
+               {&Cookie{Name: "valid", Value: "foo", Path: "/bar", Domain: "example.com", Expires: time.Unix(0, 0)}, true},
+       }
+
+       for _, tt := range tests {
+               err := tt.cookie.Valid()
+               if err != nil && tt.valid {
+                       t.Errorf("%#v.Valid() returned error %v; want nil", tt.cookie, err)
+               }
+               if err == nil && !tt.valid {
+                       t.Errorf("%#v.Valid() returned nil; want error", tt.cookie)
+               }
+       }
+}
+
 func BenchmarkCookieString(b *testing.B) {
        const wantCookieString = `cookie-9=i3e01nf61b6t23bvfmplnanol3; Path=/restricted/; Domain=example.com; Expires=Tue, 10 Nov 2009 23:00:00 GMT; Max-Age=3600`
        c := &Cookie{