github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/net/http/cookiejar/jar_test.go (about) 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.bücher.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.bücher.test", 1183 []string{"a=1"}, 1184 "a=1", 1185 []query{ 1186 {"http://www.bücher.test", "a=1"}, 1187 {"http://www.xn--bcher-kva.test", "a=1"}, 1188 {"http://bücher.test", ""}, 1189 {"http://xn--bcher-kva.test", ""}, 1190 {"http://bar.bücher.test", ""}, 1191 {"http://bar.xn--bcher-kva.test", ""}, 1192 {"http://foo.www.bücher.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.bücher.test", "a=1"}, 1205 {"http://www.xn--bcher-kva.test", "a=1"}, 1206 {"http://bücher.test", ""}, 1207 {"http://xn--bcher-kva.test", ""}, 1208 {"http://bar.bücher.test", ""}, 1209 {"http://bar.xn--bcher-kva.test", ""}, 1210 {"http://foo.www.bücher.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.bücher.test", 1219 []string{"a=1; domain=xn--bcher-kva.test"}, 1220 "a=1", 1221 []query{ 1222 {"http://www.bücher.test", "a=1"}, 1223 {"http://www.xn--bcher-kva.test", "a=1"}, 1224 {"http://bücher.test", "a=1"}, 1225 {"http://xn--bcher-kva.test", "a=1"}, 1226 {"http://bar.bücher.test", "a=1"}, 1227 {"http://bar.xn--bcher-kva.test", "a=1"}, 1228 {"http://foo.www.bücher.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.bücher.test", "a=1"}, 1241 {"http://www.xn--bcher-kva.test", "a=1"}, 1242 {"http://bücher.test", "a=1"}, 1243 {"http://xn--bcher-kva.test", "a=1"}, 1244 {"http://bar.bücher.test", "a=1"}, 1245 {"http://bar.xn--bcher-kva.test", "a=1"}, 1246 {"http://foo.www.bücher.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 }