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