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