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