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