Home | History | Annotate | Download | only in cookiejar
      1 // Copyright 2013 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package cookiejar
      6 
      7 import (
      8 	"fmt"
      9 	"net/http"
     10 	"net/url"
     11 	"sort"
     12 	"strings"
     13 	"testing"
     14 	"time"
     15 )
     16 
     17 // tNow is the synthetic current time used as now during testing.
     18 var tNow = time.Date(2013, 1, 1, 12, 0, 0, 0, time.UTC)
     19 
     20 // testPSL implements PublicSuffixList with just two rules: "co.uk"
     21 // and the default rule "*".
     22 type testPSL struct{}
     23 
     24 func (testPSL) String() string {
     25 	return "testPSL"
     26 }
     27 func (testPSL) PublicSuffix(d string) string {
     28 	if d == "co.uk" || strings.HasSuffix(d, ".co.uk") {
     29 		return "co.uk"
     30 	}
     31 	return d[strings.LastIndex(d, ".")+1:]
     32 }
     33 
     34 // newTestJar creates an empty Jar with testPSL as the public suffix list.
     35 func newTestJar() *Jar {
     36 	jar, err := New(&Options{PublicSuffixList: testPSL{}})
     37 	if err != nil {
     38 		panic(err)
     39 	}
     40 	return jar
     41 }
     42 
     43 var hasDotSuffixTests = [...]struct {
     44 	s, suffix string
     45 }{
     46 	{"", ""},
     47 	{"", "."},
     48 	{"", "x"},
     49 	{".", ""},
     50 	{".", "."},
     51 	{".", ".."},
     52 	{".", "x"},
     53 	{".", "x."},
     54 	{".", ".x"},
     55 	{".", ".x."},
     56 	{"x", ""},
     57 	{"x", "."},
     58 	{"x", ".."},
     59 	{"x", "x"},
     60 	{"x", "x."},
     61 	{"x", ".x"},
     62 	{"x", ".x."},
     63 	{".x", ""},
     64 	{".x", "."},
     65 	{".x", ".."},
     66 	{".x", "x"},
     67 	{".x", "x."},
     68 	{".x", ".x"},
     69 	{".x", ".x."},
     70 	{"x.", ""},
     71 	{"x.", "."},
     72 	{"x.", ".."},
     73 	{"x.", "x"},
     74 	{"x.", "x."},
     75 	{"x.", ".x"},
     76 	{"x.", ".x."},
     77 	{"com", ""},
     78 	{"com", "m"},
     79 	{"com", "om"},
     80 	{"com", "com"},
     81 	{"com", ".com"},
     82 	{"com", "x.com"},
     83 	{"com", "xcom"},
     84 	{"com", "xorg"},
     85 	{"com", "org"},
     86 	{"com", "rg"},
     87 	{"foo.com", ""},
     88 	{"foo.com", "m"},
     89 	{"foo.com", "om"},
     90 	{"foo.com", "com"},
     91 	{"foo.com", ".com"},
     92 	{"foo.com", "o.com"},
     93 	{"foo.com", "oo.com"},
     94 	{"foo.com", "foo.com"},
     95 	{"foo.com", ".foo.com"},
     96 	{"foo.com", "x.foo.com"},
     97 	{"foo.com", "xfoo.com"},
     98 	{"foo.com", "xfoo.org"},
     99 	{"foo.com", "foo.org"},
    100 	{"foo.com", "oo.org"},
    101 	{"foo.com", "o.org"},
    102 	{"foo.com", ".org"},
    103 	{"foo.com", "org"},
    104 	{"foo.com", "rg"},
    105 }
    106 
    107 func TestHasDotSuffix(t *testing.T) {
    108 	for _, tc := range hasDotSuffixTests {
    109 		got := hasDotSuffix(tc.s, tc.suffix)
    110 		want := strings.HasSuffix(tc.s, "."+tc.suffix)
    111 		if got != want {
    112 			t.Errorf("s=%q, suffix=%q: got %v, want %v", tc.s, tc.suffix, got, want)
    113 		}
    114 	}
    115 }
    116 
    117 var canonicalHostTests = map[string]string{
    118 	"www.example.com":         "www.example.com",
    119 	"WWW.EXAMPLE.COM":         "www.example.com",
    120 	"wWw.eXAmple.CoM":         "www.example.com",
    121 	"www.example.com:80":      "www.example.com",
    122 	"192.168.0.10":            "192.168.0.10",
    123 	"192.168.0.5:8080":        "192.168.0.5",
    124 	"2001:4860:0:2001::68":    "2001:4860:0:2001::68",
    125 	"[2001:4860:0:::68]:8080": "2001:4860:0:::68",
    126 	"www.bcher.de":           "www.xn--bcher-kva.de",
    127 	"www.example.com.":        "www.example.com",
    128 	"[bad.unmatched.bracket:": "error",
    129 }
    130 
    131 func TestCanonicalHost(t *testing.T) {
    132 	for h, want := range canonicalHostTests {
    133 		got, err := canonicalHost(h)
    134 		if want == "error" {
    135 			if err == nil {
    136 				t.Errorf("%q: got nil error, want non-nil", h)
    137 			}
    138 			continue
    139 		}
    140 		if err != nil {
    141 			t.Errorf("%q: %v", h, err)
    142 			continue
    143 		}
    144 		if got != want {
    145 			t.Errorf("%q: got %q, want %q", h, got, want)
    146 			continue
    147 		}
    148 	}
    149 }
    150 
    151 var hasPortTests = map[string]bool{
    152 	"www.example.com":      false,
    153 	"www.example.com:80":   true,
    154 	"127.0.0.1":            false,
    155 	"127.0.0.1:8080":       true,
    156 	"2001:4860:0:2001::68": false,
    157 	"[2001::0:::68]:80":    true,
    158 }
    159 
    160 func TestHasPort(t *testing.T) {
    161 	for host, want := range hasPortTests {
    162 		if got := hasPort(host); got != want {
    163 			t.Errorf("%q: got %t, want %t", host, got, want)
    164 		}
    165 	}
    166 }
    167 
    168 var jarKeyTests = map[string]string{
    169 	"foo.www.example.com": "example.com",
    170 	"www.example.com":     "example.com",
    171 	"example.com":         "example.com",
    172 	"com":                 "com",
    173 	"foo.www.bbc.co.uk":   "bbc.co.uk",
    174 	"www.bbc.co.uk":       "bbc.co.uk",
    175 	"bbc.co.uk":           "bbc.co.uk",
    176 	"co.uk":               "co.uk",
    177 	"uk":                  "uk",
    178 	"192.168.0.5":         "192.168.0.5",
    179 }
    180 
    181 func TestJarKey(t *testing.T) {
    182 	for host, want := range jarKeyTests {
    183 		if got := jarKey(host, testPSL{}); got != want {
    184 			t.Errorf("%q: got %q, want %q", host, got, want)
    185 		}
    186 	}
    187 }
    188 
    189 var jarKeyNilPSLTests = map[string]string{
    190 	"foo.www.example.com": "example.com",
    191 	"www.example.com":     "example.com",
    192 	"example.com":         "example.com",
    193 	"com":                 "com",
    194 	"foo.www.bbc.co.uk":   "co.uk",
    195 	"www.bbc.co.uk":       "co.uk",
    196 	"bbc.co.uk":           "co.uk",
    197 	"co.uk":               "co.uk",
    198 	"uk":                  "uk",
    199 	"192.168.0.5":         "192.168.0.5",
    200 }
    201 
    202 func TestJarKeyNilPSL(t *testing.T) {
    203 	for host, want := range jarKeyNilPSLTests {
    204 		if got := jarKey(host, nil); got != want {
    205 			t.Errorf("%q: got %q, want %q", host, got, want)
    206 		}
    207 	}
    208 }
    209 
    210 var isIPTests = map[string]bool{
    211 	"127.0.0.1":            true,
    212 	"1.2.3.4":              true,
    213 	"2001:4860:0:2001::68": true,
    214 	"example.com":          false,
    215 	"1.1.1.300":            false,
    216 	"www.foo.bar.net":      false,
    217 	"123.foo.bar.net":      false,
    218 }
    219 
    220 func TestIsIP(t *testing.T) {
    221 	for host, want := range isIPTests {
    222 		if got := isIP(host); got != want {
    223 			t.Errorf("%q: got %t, want %t", host, got, want)
    224 		}
    225 	}
    226 }
    227 
    228 var defaultPathTests = map[string]string{
    229 	"/":           "/",
    230 	"/abc":        "/",
    231 	"/abc/":       "/abc",
    232 	"/abc/xyz":    "/abc",
    233 	"/abc/xyz/":   "/abc/xyz",
    234 	"/a/b/c.html": "/a/b",
    235 	"":            "/",
    236 	"strange":     "/",
    237 	"//":          "/",
    238 	"/a//b":       "/a/",
    239 	"/a/./b":      "/a/.",
    240 	"/a/../b":     "/a/..",
    241 }
    242 
    243 func TestDefaultPath(t *testing.T) {
    244 	for path, want := range defaultPathTests {
    245 		if got := defaultPath(path); got != want {
    246 			t.Errorf("%q: got %q, want %q", path, got, want)
    247 		}
    248 	}
    249 }
    250 
    251 var domainAndTypeTests = [...]struct {
    252 	host         string // host Set-Cookie header was received from
    253 	domain       string // domain attribute in Set-Cookie header
    254 	wantDomain   string // expected domain of cookie
    255 	wantHostOnly bool   // expected host-cookie flag
    256 	wantErr      error  // expected error
    257 }{
    258 	{"www.example.com", "", "www.example.com", true, nil},
    259 	{"127.0.0.1", "", "127.0.0.1", true, nil},
    260 	{"2001:4860:0:2001::68", "", "2001:4860:0:2001::68", true, nil},
    261 	{"www.example.com", "example.com", "example.com", false, nil},
    262 	{"www.example.com", ".example.com", "example.com", false, nil},
    263 	{"www.example.com", "www.example.com", "www.example.com", false, nil},
    264 	{"www.example.com", ".www.example.com", "www.example.com", false, nil},
    265 	{"foo.sso.example.com", "sso.example.com", "sso.example.com", false, nil},
    266 	{"bar.co.uk", "bar.co.uk", "bar.co.uk", false, nil},
    267 	{"foo.bar.co.uk", ".bar.co.uk", "bar.co.uk", false, nil},
    268 	{"127.0.0.1", "127.0.0.1", "", false, errNoHostname},
    269 	{"2001:4860:0:2001::68", "2001:4860:0:2001::68", "2001:4860:0:2001::68", false, errNoHostname},
    270 	{"www.example.com", ".", "", false, errMalformedDomain},
    271 	{"www.example.com", "..", "", false, errMalformedDomain},
    272 	{"www.example.com", "other.com", "", false, errIllegalDomain},
    273 	{"www.example.com", "com", "", false, errIllegalDomain},
    274 	{"www.example.com", ".com", "", false, errIllegalDomain},
    275 	{"foo.bar.co.uk", ".co.uk", "", false, errIllegalDomain},
    276 	{"127.www.0.0.1", "127.0.0.1", "", false, errIllegalDomain},
    277 	{"com", "", "com", true, nil},
    278 	{"com", "com", "com", true, nil},
    279 	{"com", ".com", "com", true, nil},
    280 	{"co.uk", "", "co.uk", true, nil},
    281 	{"co.uk", "co.uk", "co.uk", true, nil},
    282 	{"co.uk", ".co.uk", "co.uk", true, nil},
    283 }
    284 
    285 func TestDomainAndType(t *testing.T) {
    286 	jar := newTestJar()
    287 	for _, tc := range domainAndTypeTests {
    288 		domain, hostOnly, err := jar.domainAndType(tc.host, tc.domain)
    289 		if err != tc.wantErr {
    290 			t.Errorf("%q/%q: got %q error, want %q",
    291 				tc.host, tc.domain, err, tc.wantErr)
    292 			continue
    293 		}
    294 		if err != nil {
    295 			continue
    296 		}
    297 		if domain != tc.wantDomain || hostOnly != tc.wantHostOnly {
    298 			t.Errorf("%q/%q: got %q/%t want %q/%t",
    299 				tc.host, tc.domain, domain, hostOnly,
    300 				tc.wantDomain, tc.wantHostOnly)
    301 		}
    302 	}
    303 }
    304 
    305 // expiresIn creates an expires attribute delta seconds from tNow.
    306 func expiresIn(delta int) string {
    307 	t := tNow.Add(time.Duration(delta) * time.Second)
    308 	return "expires=" + t.Format(time.RFC1123)
    309 }
    310 
    311 // mustParseURL parses s to an URL and panics on error.
    312 func mustParseURL(s string) *url.URL {
    313 	u, err := url.Parse(s)
    314 	if err != nil || u.Scheme == "" || u.Host == "" {
    315 		panic(fmt.Sprintf("Unable to parse URL %s.", s))
    316 	}
    317 	return u
    318 }
    319 
    320 // jarTest encapsulates the following actions on a jar:
    321 //   1. Perform SetCookies with fromURL and the cookies from setCookies.
    322 //      (Done at time tNow + 0 ms.)
    323 //   2. Check that the entries in the jar matches content.
    324 //      (Done at time tNow + 1001 ms.)
    325 //   3. For each query in tests: Check that Cookies with toURL yields the
    326 //      cookies in want.
    327 //      (Query n done at tNow + (n+2)*1001 ms.)
    328 type jarTest struct {
    329 	description string   // The description of what this test is supposed to test
    330 	fromURL     string   // The full URL of the request from which Set-Cookie headers where received
    331 	setCookies  []string // All the cookies received from fromURL
    332 	content     string   // The whole (non-expired) content of the jar
    333 	queries     []query  // Queries to test the Jar.Cookies method
    334 }
    335 
    336 // query contains one test of the cookies returned from Jar.Cookies.
    337 type query struct {
    338 	toURL string // the URL in the Cookies call
    339 	want  string // the expected list of cookies (order matters)
    340 }
    341 
    342 // run runs the jarTest.
    343 func (test jarTest) run(t *testing.T, jar *Jar) {
    344 	now := tNow
    345 
    346 	// Populate jar with cookies.
    347 	setCookies := make([]*http.Cookie, len(test.setCookies))
    348 	for i, cs := range test.setCookies {
    349 		cookies := (&http.Response{Header: http.Header{"Set-Cookie": {cs}}}).Cookies()
    350 		if len(cookies) != 1 {
    351 			panic(fmt.Sprintf("Wrong cookie line %q: %#v", cs, cookies))
    352 		}
    353 		setCookies[i] = cookies[0]
    354 	}
    355 	jar.setCookies(mustParseURL(test.fromURL), setCookies, now)
    356 	now = now.Add(1001 * time.Millisecond)
    357 
    358 	// Serialize non-expired entries in the form "name1=val1 name2=val2".
    359 	var cs []string
    360 	for _, submap := range jar.entries {
    361 		for _, cookie := range submap {
    362 			if !cookie.Expires.After(now) {
    363 				continue
    364 			}
    365 			cs = append(cs, cookie.Name+"="+cookie.Value)
    366 		}
    367 	}
    368 	sort.Strings(cs)
    369 	got := strings.Join(cs, " ")
    370 
    371 	// Make sure jar content matches our expectations.
    372 	if got != test.content {
    373 		t.Errorf("Test %q Content\ngot  %q\nwant %q",
    374 			test.description, got, test.content)
    375 	}
    376 
    377 	// Test different calls to Cookies.
    378 	for i, query := range test.queries {
    379 		now = now.Add(1001 * time.Millisecond)
    380 		var s []string
    381 		for _, c := range jar.cookies(mustParseURL(query.toURL), now) {
    382 			s = append(s, c.Name+"="+c.Value)
    383 		}
    384 		if got := strings.Join(s, " "); got != query.want {
    385 			t.Errorf("Test %q #%d\ngot  %q\nwant %q", test.description, i, got, query.want)
    386 		}
    387 	}
    388 }
    389 
    390 // basicsTests contains fundamental tests. Each jarTest has to be performed on
    391 // a fresh, empty Jar.
    392 var basicsTests = [...]jarTest{
    393 	{
    394 		"Retrieval of a plain host cookie.",
    395 		"http://www.host.test/",
    396 		[]string{"A=a"},
    397 		"A=a",
    398 		[]query{
    399 			{"http://www.host.test", "A=a"},
    400 			{"http://www.host.test/", "A=a"},
    401 			{"http://www.host.test/some/path", "A=a"},
    402 			{"https://www.host.test", "A=a"},
    403 			{"https://www.host.test/", "A=a"},
    404 			{"https://www.host.test/some/path", "A=a"},
    405 			{"ftp://www.host.test", ""},
    406 			{"ftp://www.host.test/", ""},
    407 			{"ftp://www.host.test/some/path", ""},
    408 			{"http://www.other.org", ""},
    409 			{"http://sibling.host.test", ""},
    410 			{"http://deep.www.host.test", ""},
    411 		},
    412 	},
    413 	{
    414 		"Secure cookies are not returned to http.",
    415 		"http://www.host.test/",
    416 		[]string{"A=a; secure"},
    417 		"A=a",
    418 		[]query{
    419 			{"http://www.host.test", ""},
    420 			{"http://www.host.test/", ""},
    421 			{"http://www.host.test/some/path", ""},
    422 			{"https://www.host.test", "A=a"},
    423 			{"https://www.host.test/", "A=a"},
    424 			{"https://www.host.test/some/path", "A=a"},
    425 		},
    426 	},
    427 	{
    428 		"Explicit path.",
    429 		"http://www.host.test/",
    430 		[]string{"A=a; path=/some/path"},
    431 		"A=a",
    432 		[]query{
    433 			{"http://www.host.test", ""},
    434 			{"http://www.host.test/", ""},
    435 			{"http://www.host.test/some", ""},
    436 			{"http://www.host.test/some/", ""},
    437 			{"http://www.host.test/some/path", "A=a"},
    438 			{"http://www.host.test/some/paths", ""},
    439 			{"http://www.host.test/some/path/foo", "A=a"},
    440 			{"http://www.host.test/some/path/foo/", "A=a"},
    441 		},
    442 	},
    443 	{
    444 		"Implicit path #1: path is a directory.",
    445 		"http://www.host.test/some/path/",
    446 		[]string{"A=a"},
    447 		"A=a",
    448 		[]query{
    449 			{"http://www.host.test", ""},
    450 			{"http://www.host.test/", ""},
    451 			{"http://www.host.test/some", ""},
    452 			{"http://www.host.test/some/", ""},
    453 			{"http://www.host.test/some/path", "A=a"},
    454 			{"http://www.host.test/some/paths", ""},
    455 			{"http://www.host.test/some/path/foo", "A=a"},
    456 			{"http://www.host.test/some/path/foo/", "A=a"},
    457 		},
    458 	},
    459 	{
    460 		"Implicit path #2: path is not a directory.",
    461 		"http://www.host.test/some/path/index.html",
    462 		[]string{"A=a"},
    463 		"A=a",
    464 		[]query{
    465 			{"http://www.host.test", ""},
    466 			{"http://www.host.test/", ""},
    467 			{"http://www.host.test/some", ""},
    468 			{"http://www.host.test/some/", ""},
    469 			{"http://www.host.test/some/path", "A=a"},
    470 			{"http://www.host.test/some/paths", ""},
    471 			{"http://www.host.test/some/path/foo", "A=a"},
    472 			{"http://www.host.test/some/path/foo/", "A=a"},
    473 		},
    474 	},
    475 	{
    476 		"Implicit path #3: no path in URL at all.",
    477 		"http://www.host.test",
    478 		[]string{"A=a"},
    479 		"A=a",
    480 		[]query{
    481 			{"http://www.host.test", "A=a"},
    482 			{"http://www.host.test/", "A=a"},
    483 			{"http://www.host.test/some/path", "A=a"},
    484 		},
    485 	},
    486 	{
    487 		"Cookies are sorted by path length.",
    488 		"http://www.host.test/",
    489 		[]string{
    490 			"A=a; path=/foo/bar",
    491 			"B=b; path=/foo/bar/baz/qux",
    492 			"C=c; path=/foo/bar/baz",
    493 			"D=d; path=/foo"},
    494 		"A=a B=b C=c D=d",
    495 		[]query{
    496 			{"http://www.host.test/foo/bar/baz/qux", "B=b C=c A=a D=d"},
    497 			{"http://www.host.test/foo/bar/baz/", "C=c A=a D=d"},
    498 			{"http://www.host.test/foo/bar", "A=a D=d"},
    499 		},
    500 	},
    501 	{
    502 		"Creation time determines sorting on same length paths.",
    503 		"http://www.host.test/",
    504 		[]string{
    505 			"A=a; path=/foo/bar",
    506 			"X=x; path=/foo/bar",
    507 			"Y=y; path=/foo/bar/baz/qux",
    508 			"B=b; path=/foo/bar/baz/qux",
    509 			"C=c; path=/foo/bar/baz",
    510 			"W=w; path=/foo/bar/baz",
    511 			"Z=z; path=/foo",
    512 			"D=d; path=/foo"},
    513 		"A=a B=b C=c D=d W=w X=x Y=y Z=z",
    514 		[]query{
    515 			{"http://www.host.test/foo/bar/baz/qux", "Y=y B=b C=c W=w A=a X=x Z=z D=d"},
    516 			{"http://www.host.test/foo/bar/baz/", "C=c W=w A=a X=x Z=z D=d"},
    517 			{"http://www.host.test/foo/bar", "A=a X=x Z=z D=d"},
    518 		},
    519 	},
    520 	{
    521 		"Sorting of same-name cookies.",
    522 		"http://www.host.test/",
    523 		[]string{
    524 			"A=1; path=/",
    525 			"A=2; path=/path",
    526 			"A=3; path=/quux",
    527 			"A=4; path=/path/foo",
    528 			"A=5; domain=.host.test; path=/path",
    529 			"A=6; domain=.host.test; path=/quux",
    530 			"A=7; domain=.host.test; path=/path/foo",
    531 		},
    532 		"A=1 A=2 A=3 A=4 A=5 A=6 A=7",
    533 		[]query{
    534 			{"http://www.host.test/path", "A=2 A=5 A=1"},
    535 			{"http://www.host.test/path/foo", "A=4 A=7 A=2 A=5 A=1"},
    536 		},
    537 	},
    538 	{
    539 		"Disallow domain cookie on public suffix.",
    540 		"http://www.bbc.co.uk",
    541 		[]string{
    542 			"a=1",
    543 			"b=2; domain=co.uk",
    544 		},
    545 		"a=1",
    546 		[]query{{"http://www.bbc.co.uk", "a=1"}},
    547 	},
    548 	{
    549 		"Host cookie on IP.",
    550 		"http://192.168.0.10",
    551 		[]string{"a=1"},
    552 		"a=1",
    553 		[]query{{"http://192.168.0.10", "a=1"}},
    554 	},
    555 	{
    556 		"Port is ignored #1.",
    557 		"http://www.host.test/",
    558 		[]string{"a=1"},
    559 		"a=1",
    560 		[]query{
    561 			{"http://www.host.test", "a=1"},
    562 			{"http://www.host.test:8080/", "a=1"},
    563 		},
    564 	},
    565 	{
    566 		"Port is ignored #2.",
    567 		"http://www.host.test:8080/",
    568 		[]string{"a=1"},
    569 		"a=1",
    570 		[]query{
    571 			{"http://www.host.test", "a=1"},
    572 			{"http://www.host.test:8080/", "a=1"},
    573 			{"http://www.host.test:1234/", "a=1"},
    574 		},
    575 	},
    576 }
    577 
    578 func TestBasics(t *testing.T) {
    579 	for _, test := range basicsTests {
    580 		jar := newTestJar()
    581 		test.run(t, jar)
    582 	}
    583 }
    584 
    585 // updateAndDeleteTests contains jarTests which must be performed on the same
    586 // Jar.
    587 var updateAndDeleteTests = [...]jarTest{
    588 	{
    589 		"Set initial cookies.",
    590 		"http://www.host.test",
    591 		[]string{
    592 			"a=1",
    593 			"b=2; secure",
    594 			"c=3; httponly",
    595 			"d=4; secure; httponly"},
    596 		"a=1 b=2 c=3 d=4",
    597 		[]query{
    598 			{"http://www.host.test", "a=1 c=3"},
    599 			{"https://www.host.test", "a=1 b=2 c=3 d=4"},
    600 		},
    601 	},
    602 	{
    603 		"Update value via http.",
    604 		"http://www.host.test",
    605 		[]string{
    606 			"a=w",
    607 			"b=x; secure",
    608 			"c=y; httponly",
    609 			"d=z; secure; httponly"},
    610 		"a=w b=x c=y d=z",
    611 		[]query{
    612 			{"http://www.host.test", "a=w c=y"},
    613 			{"https://www.host.test", "a=w b=x c=y d=z"},
    614 		},
    615 	},
    616 	{
    617 		"Clear Secure flag from a http.",
    618 		"http://www.host.test/",
    619 		[]string{
    620 			"b=xx",
    621 			"d=zz; httponly"},
    622 		"a=w b=xx c=y d=zz",
    623 		[]query{{"http://www.host.test", "a=w b=xx c=y d=zz"}},
    624 	},
    625 	{
    626 		"Delete all.",
    627 		"http://www.host.test/",
    628 		[]string{
    629 			"a=1; max-Age=-1",                    // delete via MaxAge
    630 			"b=2; " + expiresIn(-10),             // delete via Expires
    631 			"c=2; max-age=-1; " + expiresIn(-10), // delete via both
    632 			"d=4; max-age=-1; " + expiresIn(10)}, // MaxAge takes precedence
    633 		"",
    634 		[]query{{"http://www.host.test", ""}},
    635 	},
    636 	{
    637 		"Refill #1.",
    638 		"http://www.host.test",
    639 		[]string{
    640 			"A=1",
    641 			"A=2; path=/foo",
    642 			"A=3; domain=.host.test",
    643 			"A=4; path=/foo; domain=.host.test"},
    644 		"A=1 A=2 A=3 A=4",
    645 		[]query{{"http://www.host.test/foo", "A=2 A=4 A=1 A=3"}},
    646 	},
    647 	{
    648 		"Refill #2.",
    649 		"http://www.google.com",
    650 		[]string{
    651 			"A=6",
    652 			"A=7; path=/foo",
    653 			"A=8; domain=.google.com",
    654 			"A=9; path=/foo; domain=.google.com"},
    655 		"A=1 A=2 A=3 A=4 A=6 A=7 A=8 A=9",
    656 		[]query{
    657 			{"http://www.host.test/foo", "A=2 A=4 A=1 A=3"},
    658 			{"http://www.google.com/foo", "A=7 A=9 A=6 A=8"},
    659 		},
    660 	},
    661 	{
    662 		"Delete A7.",
    663 		"http://www.google.com",
    664 		[]string{"A=; path=/foo; max-age=-1"},
    665 		"A=1 A=2 A=3 A=4 A=6 A=8 A=9",
    666 		[]query{
    667 			{"http://www.host.test/foo", "A=2 A=4 A=1 A=3"},
    668 			{"http://www.google.com/foo", "A=9 A=6 A=8"},
    669 		},
    670 	},
    671 	{
    672 		"Delete A4.",
    673 		"http://www.host.test",
    674 		[]string{"A=; path=/foo; domain=host.test; max-age=-1"},
    675 		"A=1 A=2 A=3 A=6 A=8 A=9",
    676 		[]query{
    677 			{"http://www.host.test/foo", "A=2 A=1 A=3"},
    678 			{"http://www.google.com/foo", "A=9 A=6 A=8"},
    679 		},
    680 	},
    681 	{
    682 		"Delete A6.",
    683 		"http://www.google.com",
    684 		[]string{"A=; max-age=-1"},
    685 		"A=1 A=2 A=3 A=8 A=9",
    686 		[]query{
    687 			{"http://www.host.test/foo", "A=2 A=1 A=3"},
    688 			{"http://www.google.com/foo", "A=9 A=8"},
    689 		},
    690 	},
    691 	{
    692 		"Delete A3.",
    693 		"http://www.host.test",
    694 		[]string{"A=; domain=host.test; max-age=-1"},
    695 		"A=1 A=2 A=8 A=9",
    696 		[]query{
    697 			{"http://www.host.test/foo", "A=2 A=1"},
    698 			{"http://www.google.com/foo", "A=9 A=8"},
    699 		},
    700 	},
    701 	{
    702 		"No cross-domain delete.",
    703 		"http://www.host.test",
    704 		[]string{
    705 			"A=; domain=google.com; max-age=-1",
    706 			"A=; path=/foo; domain=google.com; max-age=-1"},
    707 		"A=1 A=2 A=8 A=9",
    708 		[]query{
    709 			{"http://www.host.test/foo", "A=2 A=1"},
    710 			{"http://www.google.com/foo", "A=9 A=8"},
    711 		},
    712 	},
    713 	{
    714 		"Delete A8 and A9.",
    715 		"http://www.google.com",
    716 		[]string{
    717 			"A=; domain=google.com; max-age=-1",
    718 			"A=; path=/foo; domain=google.com; max-age=-1"},
    719 		"A=1 A=2",
    720 		[]query{
    721 			{"http://www.host.test/foo", "A=2 A=1"},
    722 			{"http://www.google.com/foo", ""},
    723 		},
    724 	},
    725 }
    726 
    727 func TestUpdateAndDelete(t *testing.T) {
    728 	jar := newTestJar()
    729 	for _, test := range updateAndDeleteTests {
    730 		test.run(t, jar)
    731 	}
    732 }
    733 
    734 func TestExpiration(t *testing.T) {
    735 	jar := newTestJar()
    736 	jarTest{
    737 		"Expiration.",
    738 		"http://www.host.test",
    739 		[]string{
    740 			"a=1",
    741 			"b=2; max-age=3",
    742 			"c=3; " + expiresIn(3),
    743 			"d=4; max-age=5",
    744 			"e=5; " + expiresIn(5),
    745 			"f=6; max-age=100",
    746 		},
    747 		"a=1 b=2 c=3 d=4 e=5 f=6", // executed at t0 + 1001 ms
    748 		[]query{
    749 			{"http://www.host.test", "a=1 b=2 c=3 d=4 e=5 f=6"}, // t0 + 2002 ms
    750 			{"http://www.host.test", "a=1 d=4 e=5 f=6"},         // t0 + 3003 ms
    751 			{"http://www.host.test", "a=1 d=4 e=5 f=6"},         // t0 + 4004 ms
    752 			{"http://www.host.test", "a=1 f=6"},                 // t0 + 5005 ms
    753 			{"http://www.host.test", "a=1 f=6"},                 // t0 + 6006 ms
    754 		},
    755 	}.run(t, jar)
    756 }
    757 
    758 //
    759 // Tests derived from Chromium's cookie_store_unittest.h.
    760 //
    761 
    762 // See http://src.chromium.org/viewvc/chrome/trunk/src/net/cookies/cookie_store_unittest.h?revision=159685&content-type=text/plain
    763 // Some of the original tests are in a bad condition (e.g.
    764 // DomainWithTrailingDotTest) or are not RFC 6265 conforming (e.g.
    765 // TestNonDottedAndTLD #1 and #6) and have not been ported.
    766 
    767 // chromiumBasicsTests contains fundamental tests. Each jarTest has to be
    768 // performed on a fresh, empty Jar.
    769 var chromiumBasicsTests = [...]jarTest{
    770 	{
    771 		"DomainWithTrailingDotTest.",
    772 		"http://www.google.com/",
    773 		[]string{
    774 			"a=1; domain=.www.google.com.",
    775 			"b=2; domain=.www.google.com.."},
    776 		"",
    777 		[]query{
    778 			{"http://www.google.com", ""},
    779 		},
    780 	},
    781 	{
    782 		"ValidSubdomainTest #1.",
    783 		"http://a.b.c.d.com",
    784 		[]string{
    785 			"a=1; domain=.a.b.c.d.com",
    786 			"b=2; domain=.b.c.d.com",
    787 			"c=3; domain=.c.d.com",
    788 			"d=4; domain=.d.com"},
    789 		"a=1 b=2 c=3 d=4",
    790 		[]query{
    791 			{"http://a.b.c.d.com", "a=1 b=2 c=3 d=4"},
    792 			{"http://b.c.d.com", "b=2 c=3 d=4"},
    793 			{"http://c.d.com", "c=3 d=4"},
    794 			{"http://d.com", "d=4"},
    795 		},
    796 	},
    797 	{
    798 		"ValidSubdomainTest #2.",
    799 		"http://a.b.c.d.com",
    800 		[]string{
    801 			"a=1; domain=.a.b.c.d.com",
    802 			"b=2; domain=.b.c.d.com",
    803 			"c=3; domain=.c.d.com",
    804 			"d=4; domain=.d.com",
    805 			"X=bcd; domain=.b.c.d.com",
    806 			"X=cd; domain=.c.d.com"},
    807 		"X=bcd X=cd a=1 b=2 c=3 d=4",
    808 		[]query{
    809 			{"http://b.c.d.com", "b=2 c=3 d=4 X=bcd X=cd"},
    810 			{"http://c.d.com", "c=3 d=4 X=cd"},
    811 		},
    812 	},
    813 	{
    814 		"InvalidDomainTest #1.",
    815 		"http://foo.bar.com",
    816 		[]string{
    817 			"a=1; domain=.yo.foo.bar.com",
    818 			"b=2; domain=.foo.com",
    819 			"c=3; domain=.bar.foo.com",
    820 			"d=4; domain=.foo.bar.com.net",
    821 			"e=5; domain=ar.com",
    822 			"f=6; domain=.",
    823 			"g=7; domain=/",
    824 			"h=8; domain=http://foo.bar.com",
    825 			"i=9; domain=..foo.bar.com",
    826 			"j=10; domain=..bar.com",
    827 			"k=11; domain=.foo.bar.com?blah",
    828 			"l=12; domain=.foo.bar.com/blah",
    829 			"m=12; domain=.foo.bar.com:80",
    830 			"n=14; domain=.foo.bar.com:",
    831 			"o=15; domain=.foo.bar.com#sup",
    832 		},
    833 		"", // Jar is empty.
    834 		[]query{{"http://foo.bar.com", ""}},
    835 	},
    836 	{
    837 		"InvalidDomainTest #2.",
    838 		"http://foo.com.com",
    839 		[]string{"a=1; domain=.foo.com.com.com"},
    840 		"",
    841 		[]query{{"http://foo.bar.com", ""}},
    842 	},
    843 	{
    844 		"DomainWithoutLeadingDotTest #1.",
    845 		"http://manage.hosted.filefront.com",
    846 		[]string{"a=1; domain=filefront.com"},
    847 		"a=1",
    848 		[]query{{"http://www.filefront.com", "a=1"}},
    849 	},
    850 	{
    851 		"DomainWithoutLeadingDotTest #2.",
    852 		"http://www.google.com",
    853 		[]string{"a=1; domain=www.google.com"},
    854 		"a=1",
    855 		[]query{
    856 			{"http://www.google.com", "a=1"},
    857 			{"http://sub.www.google.com", "a=1"},
    858 			{"http://something-else.com", ""},
    859 		},
    860 	},
    861 	{
    862 		"CaseInsensitiveDomainTest.",
    863 		"http://www.google.com",
    864 		[]string{
    865 			"a=1; domain=.GOOGLE.COM",
    866 			"b=2; domain=.www.gOOgLE.coM"},
    867 		"a=1 b=2",
    868 		[]query{{"http://www.google.com", "a=1 b=2"}},
    869 	},
    870 	{
    871 		"TestIpAddress #1.",
    872 		"http://1.2.3.4/foo",
    873 		[]string{"a=1; path=/"},
    874 		"a=1",
    875 		[]query{{"http://1.2.3.4/foo", "a=1"}},
    876 	},
    877 	{
    878 		"TestIpAddress #2.",
    879 		"http://1.2.3.4/foo",
    880 		[]string{
    881 			"a=1; domain=.1.2.3.4",
    882 			"b=2; domain=.3.4"},
    883 		"",
    884 		[]query{{"http://1.2.3.4/foo", ""}},
    885 	},
    886 	{
    887 		"TestIpAddress #3.",
    888 		"http://1.2.3.4/foo",
    889 		[]string{"a=1; domain=1.2.3.4"},
    890 		"",
    891 		[]query{{"http://1.2.3.4/foo", ""}},
    892 	},
    893 	{
    894 		"TestNonDottedAndTLD #2.",
    895 		"http://com./index.html",
    896 		[]string{"a=1"},
    897 		"a=1",
    898 		[]query{
    899 			{"http://com./index.html", "a=1"},
    900 			{"http://no-cookies.com./index.html", ""},
    901 		},
    902 	},
    903 	{
    904 		"TestNonDottedAndTLD #3.",
    905 		"http://a.b",
    906 		[]string{
    907 			"a=1; domain=.b",
    908 			"b=2; domain=b"},
    909 		"",
    910 		[]query{{"http://bar.foo", ""}},
    911 	},
    912 	{
    913 		"TestNonDottedAndTLD #4.",
    914 		"http://google.com",
    915 		[]string{
    916 			"a=1; domain=.com",
    917 			"b=2; domain=com"},
    918 		"",
    919 		[]query{{"http://google.com", ""}},
    920 	},
    921 	{
    922 		"TestNonDottedAndTLD #5.",
    923 		"http://google.co.uk",
    924 		[]string{
    925 			"a=1; domain=.co.uk",
    926 			"b=2; domain=.uk"},
    927 		"",
    928 		[]query{
    929 			{"http://google.co.uk", ""},
    930 			{"http://else.co.com", ""},
    931 			{"http://else.uk", ""},
    932 		},
    933 	},
    934 	{
    935 		"TestHostEndsWithDot.",
    936 		"http://www.google.com",
    937 		[]string{
    938 			"a=1",
    939 			"b=2; domain=.www.google.com."},
    940 		"a=1",
    941 		[]query{{"http://www.google.com", "a=1"}},
    942 	},
    943 	{
    944 		"PathTest",
    945 		"http://www.google.izzle",
    946 		[]string{"a=1; path=/wee"},
    947 		"a=1",
    948 		[]query{
    949 			{"http://www.google.izzle/wee", "a=1"},
    950 			{"http://www.google.izzle/wee/", "a=1"},
    951 			{"http://www.google.izzle/wee/war", "a=1"},
    952 			{"http://www.google.izzle/wee/war/more/more", "a=1"},
    953 			{"http://www.google.izzle/weehee", ""},
    954 			{"http://www.google.izzle/", ""},
    955 		},
    956 	},
    957 }
    958 
    959 func TestChromiumBasics(t *testing.T) {
    960 	for _, test := range chromiumBasicsTests {
    961 		jar := newTestJar()
    962 		test.run(t, jar)
    963 	}
    964 }
    965 
    966 // chromiumDomainTests contains jarTests which must be executed all on the
    967 // same Jar.
    968 var chromiumDomainTests = [...]jarTest{
    969 	{
    970 		"Fill #1.",
    971 		"http://www.google.izzle",
    972 		[]string{"A=B"},
    973 		"A=B",
    974 		[]query{{"http://www.google.izzle", "A=B"}},
    975 	},
    976 	{
    977 		"Fill #2.",
    978 		"http://www.google.izzle",
    979 		[]string{"C=D; domain=.google.izzle"},
    980 		"A=B C=D",
    981 		[]query{{"http://www.google.izzle", "A=B C=D"}},
    982 	},
    983 	{
    984 		"Verify A is a host cookie and not accessible from subdomain.",
    985 		"http://unused.nil",
    986 		[]string{},
    987 		"A=B C=D",
    988 		[]query{{"http://foo.www.google.izzle", "C=D"}},
    989 	},
    990 	{
    991 		"Verify domain cookies are found on proper domain.",
    992 		"http://www.google.izzle",
    993 		[]string{"E=F; domain=.www.google.izzle"},
    994 		"A=B C=D E=F",
    995 		[]query{{"http://www.google.izzle", "A=B C=D E=F"}},
    996 	},
    997 	{
    998 		"Leading dots in domain attributes are optional.",
    999 		"http://www.google.izzle",
   1000 		[]string{"G=H; domain=www.google.izzle"},
   1001 		"A=B C=D E=F G=H",
   1002 		[]query{{"http://www.google.izzle", "A=B C=D E=F G=H"}},
   1003 	},
   1004 	{
   1005 		"Verify domain enforcement works #1.",
   1006 		"http://www.google.izzle",
   1007 		[]string{"K=L; domain=.bar.www.google.izzle"},
   1008 		"A=B C=D E=F G=H",
   1009 		[]query{{"http://bar.www.google.izzle", "C=D E=F G=H"}},
   1010 	},
   1011 	{
   1012 		"Verify domain enforcement works #2.",
   1013 		"http://unused.nil",
   1014 		[]string{},
   1015 		"A=B C=D E=F G=H",
   1016 		[]query{{"http://www.google.izzle", "A=B C=D E=F G=H"}},
   1017 	},
   1018 }
   1019 
   1020 func TestChromiumDomain(t *testing.T) {
   1021 	jar := newTestJar()
   1022 	for _, test := range chromiumDomainTests {
   1023 		test.run(t, jar)
   1024 	}
   1025 
   1026 }
   1027 
   1028 // chromiumDeletionTests must be performed all on the same Jar.
   1029 var chromiumDeletionTests = [...]jarTest{
   1030 	{
   1031 		"Create session cookie a1.",
   1032 		"http://www.google.com",
   1033 		[]string{"a=1"},
   1034 		"a=1",
   1035 		[]query{{"http://www.google.com", "a=1"}},
   1036 	},
   1037 	{
   1038 		"Delete sc a1 via MaxAge.",
   1039 		"http://www.google.com",
   1040 		[]string{"a=1; max-age=-1"},
   1041 		"",
   1042 		[]query{{"http://www.google.com", ""}},
   1043 	},
   1044 	{
   1045 		"Create session cookie b2.",
   1046 		"http://www.google.com",
   1047 		[]string{"b=2"},
   1048 		"b=2",
   1049 		[]query{{"http://www.google.com", "b=2"}},
   1050 	},
   1051 	{
   1052 		"Delete sc b2 via Expires.",
   1053 		"http://www.google.com",
   1054 		[]string{"b=2; " + expiresIn(-10)},
   1055 		"",
   1056 		[]query{{"http://www.google.com", ""}},
   1057 	},
   1058 	{
   1059 		"Create persistent cookie c3.",
   1060 		"http://www.google.com",
   1061 		[]string{"c=3; max-age=3600"},
   1062 		"c=3",
   1063 		[]query{{"http://www.google.com", "c=3"}},
   1064 	},
   1065 	{
   1066 		"Delete pc c3 via MaxAge.",
   1067 		"http://www.google.com",
   1068 		[]string{"c=3; max-age=-1"},
   1069 		"",
   1070 		[]query{{"http://www.google.com", ""}},
   1071 	},
   1072 	{
   1073 		"Create persistent cookie d4.",
   1074 		"http://www.google.com",
   1075 		[]string{"d=4; max-age=3600"},
   1076 		"d=4",
   1077 		[]query{{"http://www.google.com", "d=4"}},
   1078 	},
   1079 	{
   1080 		"Delete pc d4 via Expires.",
   1081 		"http://www.google.com",
   1082 		[]string{"d=4; " + expiresIn(-10)},
   1083 		"",
   1084 		[]query{{"http://www.google.com", ""}},
   1085 	},
   1086 }
   1087 
   1088 func TestChromiumDeletion(t *testing.T) {
   1089 	jar := newTestJar()
   1090 	for _, test := range chromiumDeletionTests {
   1091 		test.run(t, jar)
   1092 	}
   1093 }
   1094 
   1095 // domainHandlingTests tests and documents the rules for domain handling.
   1096 // Each test must be performed on an empty new Jar.
   1097 var domainHandlingTests = [...]jarTest{
   1098 	{
   1099 		"Host cookie",
   1100 		"http://www.host.test",
   1101 		[]string{"a=1"},
   1102 		"a=1",
   1103 		[]query{
   1104 			{"http://www.host.test", "a=1"},
   1105 			{"http://host.test", ""},
   1106 			{"http://bar.host.test", ""},
   1107 			{"http://foo.www.host.test", ""},
   1108 			{"http://other.test", ""},
   1109 			{"http://test", ""},
   1110 		},
   1111 	},
   1112 	{
   1113 		"Domain cookie #1",
   1114 		"http://www.host.test",
   1115 		[]string{"a=1; domain=host.test"},
   1116 		"a=1",
   1117 		[]query{
   1118 			{"http://www.host.test", "a=1"},
   1119 			{"http://host.test", "a=1"},
   1120 			{"http://bar.host.test", "a=1"},
   1121 			{"http://foo.www.host.test", "a=1"},
   1122 			{"http://other.test", ""},
   1123 			{"http://test", ""},
   1124 		},
   1125 	},
   1126 	{
   1127 		"Domain cookie #2",
   1128 		"http://www.host.test",
   1129 		[]string{"a=1; domain=.host.test"},
   1130 		"a=1",
   1131 		[]query{
   1132 			{"http://www.host.test", "a=1"},
   1133 			{"http://host.test", "a=1"},
   1134 			{"http://bar.host.test", "a=1"},
   1135 			{"http://foo.www.host.test", "a=1"},
   1136 			{"http://other.test", ""},
   1137 			{"http://test", ""},
   1138 		},
   1139 	},
   1140 	{
   1141 		"Host cookie on IDNA domain #1",
   1142 		"http://www.bcher.test",
   1143 		[]string{"a=1"},
   1144 		"a=1",
   1145 		[]query{
   1146 			{"http://www.bcher.test", "a=1"},
   1147 			{"http://www.xn--bcher-kva.test", "a=1"},
   1148 			{"http://bcher.test", ""},
   1149 			{"http://xn--bcher-kva.test", ""},
   1150 			{"http://bar.bcher.test", ""},
   1151 			{"http://bar.xn--bcher-kva.test", ""},
   1152 			{"http://foo.www.bcher.test", ""},
   1153 			{"http://foo.www.xn--bcher-kva.test", ""},
   1154 			{"http://other.test", ""},
   1155 			{"http://test", ""},
   1156 		},
   1157 	},
   1158 	{
   1159 		"Host cookie on IDNA domain #2",
   1160 		"http://www.xn--bcher-kva.test",
   1161 		[]string{"a=1"},
   1162 		"a=1",
   1163 		[]query{
   1164 			{"http://www.bcher.test", "a=1"},
   1165 			{"http://www.xn--bcher-kva.test", "a=1"},
   1166 			{"http://bcher.test", ""},
   1167 			{"http://xn--bcher-kva.test", ""},
   1168 			{"http://bar.bcher.test", ""},
   1169 			{"http://bar.xn--bcher-kva.test", ""},
   1170 			{"http://foo.www.bcher.test", ""},
   1171 			{"http://foo.www.xn--bcher-kva.test", ""},
   1172 			{"http://other.test", ""},
   1173 			{"http://test", ""},
   1174 		},
   1175 	},
   1176 	{
   1177 		"Domain cookie on IDNA domain #1",
   1178 		"http://www.bcher.test",
   1179 		[]string{"a=1; domain=xn--bcher-kva.test"},
   1180 		"a=1",
   1181 		[]query{
   1182 			{"http://www.bcher.test", "a=1"},
   1183 			{"http://www.xn--bcher-kva.test", "a=1"},
   1184 			{"http://bcher.test", "a=1"},
   1185 			{"http://xn--bcher-kva.test", "a=1"},
   1186 			{"http://bar.bcher.test", "a=1"},
   1187 			{"http://bar.xn--bcher-kva.test", "a=1"},
   1188 			{"http://foo.www.bcher.test", "a=1"},
   1189 			{"http://foo.www.xn--bcher-kva.test", "a=1"},
   1190 			{"http://other.test", ""},
   1191 			{"http://test", ""},
   1192 		},
   1193 	},
   1194 	{
   1195 		"Domain cookie on IDNA domain #2",
   1196 		"http://www.xn--bcher-kva.test",
   1197 		[]string{"a=1; domain=xn--bcher-kva.test"},
   1198 		"a=1",
   1199 		[]query{
   1200 			{"http://www.bcher.test", "a=1"},
   1201 			{"http://www.xn--bcher-kva.test", "a=1"},
   1202 			{"http://bcher.test", "a=1"},
   1203 			{"http://xn--bcher-kva.test", "a=1"},
   1204 			{"http://bar.bcher.test", "a=1"},
   1205 			{"http://bar.xn--bcher-kva.test", "a=1"},
   1206 			{"http://foo.www.bcher.test", "a=1"},
   1207 			{"http://foo.www.xn--bcher-kva.test", "a=1"},
   1208 			{"http://other.test", ""},
   1209 			{"http://test", ""},
   1210 		},
   1211 	},
   1212 	{
   1213 		"Host cookie on TLD.",
   1214 		"http://com",
   1215 		[]string{"a=1"},
   1216 		"a=1",
   1217 		[]query{
   1218 			{"http://com", "a=1"},
   1219 			{"http://any.com", ""},
   1220 			{"http://any.test", ""},
   1221 		},
   1222 	},
   1223 	{
   1224 		"Domain cookie on TLD becomes a host cookie.",
   1225 		"http://com",
   1226 		[]string{"a=1; domain=com"},
   1227 		"a=1",
   1228 		[]query{
   1229 			{"http://com", "a=1"},
   1230 			{"http://any.com", ""},
   1231 			{"http://any.test", ""},
   1232 		},
   1233 	},
   1234 	{
   1235 		"Host cookie on public suffix.",
   1236 		"http://co.uk",
   1237 		[]string{"a=1"},
   1238 		"a=1",
   1239 		[]query{
   1240 			{"http://co.uk", "a=1"},
   1241 			{"http://uk", ""},
   1242 			{"http://some.co.uk", ""},
   1243 			{"http://foo.some.co.uk", ""},
   1244 			{"http://any.uk", ""},
   1245 		},
   1246 	},
   1247 	{
   1248 		"Domain cookie on public suffix is ignored.",
   1249 		"http://some.co.uk",
   1250 		[]string{"a=1; domain=co.uk"},
   1251 		"",
   1252 		[]query{
   1253 			{"http://co.uk", ""},
   1254 			{"http://uk", ""},
   1255 			{"http://some.co.uk", ""},
   1256 			{"http://foo.some.co.uk", ""},
   1257 			{"http://any.uk", ""},
   1258 		},
   1259 	},
   1260 }
   1261 
   1262 func TestDomainHandling(t *testing.T) {
   1263 	for _, test := range domainHandlingTests {
   1264 		jar := newTestJar()
   1265 		test.run(t, jar)
   1266 	}
   1267 }
   1268