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 "Secure cookies are sent for localhost",
476 "http://localhost:8910/",
477 []string{"A=a; secure"},
478 "A=a",
479 []query{
480 {"http://localhost:8910", "A=a"},
481 {"http://localhost:8910/", "A=a"},
482 {"http://localhost:8910/some/path", "A=a"},
483 {"https://localhost:8910", "A=a"},
484 {"https://localhost:8910/", "A=a"},
485 {"https://localhost:8910/some/path", "A=a"},
486 },
487 },
488 {
489 "Secure cookies are sent for localhost (tld)",
490 "http://example.LOCALHOST:8910/",
491 []string{"A=a; secure"},
492 "A=a",
493 []query{
494 {"http://example.LOCALHOST:8910", "A=a"},
495 {"http://example.LOCALHOST:8910/", "A=a"},
496 {"http://example.LOCALHOST:8910/some/path", "A=a"},
497 {"https://example.LOCALHOST:8910", "A=a"},
498 {"https://example.LOCALHOST:8910/", "A=a"},
499 {"https://example.LOCALHOST:8910/some/path", "A=a"},
500 },
501 },
502 {
503 "Secure cookies are sent for localhost (ipv6)",
504 "http://[::1]:8910/",
505 []string{"A=a; secure"},
506 "A=a",
507 []query{
508 {"http://[::1]:8910", "A=a"},
509 {"http://[::1]:8910/", "A=a"},
510 {"http://[::1]:8910/some/path", "A=a"},
511 {"https://[::1]:8910", "A=a"},
512 {"https://[::1]:8910/", "A=a"},
513 {"https://[::1]:8910/some/path", "A=a"},
514 },
515 },
516 {
517 "Localhost only if it's a segment",
518 "http://notlocalhost/",
519 []string{"A=a; secure"},
520 "A=a",
521 []query{
522 {"http://notlocalhost", ""},
523 {"http://notlocalhost/", ""},
524 {"http://notlocalhost/some/path", ""},
525 {"https://notlocalhost", "A=a"},
526 {"https://notlocalhost/", "A=a"},
527 {"https://notlocalhost/some/path", "A=a"},
528 },
529 },
530 {
531 "Explicit path.",
532 "http://www.host.test/",
533 []string{"A=a; path=/some/path"},
534 "A=a",
535 []query{
536 {"http://www.host.test", ""},
537 {"http://www.host.test/", ""},
538 {"http://www.host.test/some", ""},
539 {"http://www.host.test/some/", ""},
540 {"http://www.host.test/some/path", "A=a"},
541 {"http://www.host.test/some/paths", ""},
542 {"http://www.host.test/some/path/foo", "A=a"},
543 {"http://www.host.test/some/path/foo/", "A=a"},
544 },
545 },
546 {
547 "Implicit path #1: path is a directory.",
548 "http://www.host.test/some/path/",
549 []string{"A=a"},
550 "A=a",
551 []query{
552 {"http://www.host.test", ""},
553 {"http://www.host.test/", ""},
554 {"http://www.host.test/some", ""},
555 {"http://www.host.test/some/", ""},
556 {"http://www.host.test/some/path", "A=a"},
557 {"http://www.host.test/some/paths", ""},
558 {"http://www.host.test/some/path/foo", "A=a"},
559 {"http://www.host.test/some/path/foo/", "A=a"},
560 },
561 },
562 {
563 "Implicit path #2: path is not a directory.",
564 "http://www.host.test/some/path/index.html",
565 []string{"A=a"},
566 "A=a",
567 []query{
568 {"http://www.host.test", ""},
569 {"http://www.host.test/", ""},
570 {"http://www.host.test/some", ""},
571 {"http://www.host.test/some/", ""},
572 {"http://www.host.test/some/path", "A=a"},
573 {"http://www.host.test/some/paths", ""},
574 {"http://www.host.test/some/path/foo", "A=a"},
575 {"http://www.host.test/some/path/foo/", "A=a"},
576 },
577 },
578 {
579 "Implicit path #3: no path in URL at all.",
580 "http://www.host.test",
581 []string{"A=a"},
582 "A=a",
583 []query{
584 {"http://www.host.test", "A=a"},
585 {"http://www.host.test/", "A=a"},
586 {"http://www.host.test/some/path", "A=a"},
587 },
588 },
589 {
590 "Cookies are sorted by path length.",
591 "http://www.host.test/",
592 []string{
593 "A=a; path=/foo/bar",
594 "B=b; path=/foo/bar/baz/qux",
595 "C=c; path=/foo/bar/baz",
596 "D=d; path=/foo"},
597 "A=a B=b C=c D=d",
598 []query{
599 {"http://www.host.test/foo/bar/baz/qux", "B=b C=c A=a D=d"},
600 {"http://www.host.test/foo/bar/baz/", "C=c A=a D=d"},
601 {"http://www.host.test/foo/bar", "A=a D=d"},
602 },
603 },
604 {
605 "Creation time determines sorting on same length paths.",
606 "http://www.host.test/",
607 []string{
608 "A=a; path=/foo/bar",
609 "X=x; path=/foo/bar",
610 "Y=y; path=/foo/bar/baz/qux",
611 "B=b; path=/foo/bar/baz/qux",
612 "C=c; path=/foo/bar/baz",
613 "W=w; path=/foo/bar/baz",
614 "Z=z; path=/foo",
615 "D=d; path=/foo"},
616 "A=a B=b C=c D=d W=w X=x Y=y Z=z",
617 []query{
618 {"http://www.host.test/foo/bar/baz/qux", "Y=y B=b C=c W=w A=a X=x Z=z D=d"},
619 {"http://www.host.test/foo/bar/baz/", "C=c W=w A=a X=x Z=z D=d"},
620 {"http://www.host.test/foo/bar", "A=a X=x Z=z D=d"},
621 },
622 },
623 {
624 "Sorting of same-name cookies.",
625 "http://www.host.test/",
626 []string{
627 "A=1; path=/",
628 "A=2; path=/path",
629 "A=3; path=/quux",
630 "A=4; path=/path/foo",
631 "A=5; domain=.host.test; path=/path",
632 "A=6; domain=.host.test; path=/quux",
633 "A=7; domain=.host.test; path=/path/foo",
634 },
635 "A=1 A=2 A=3 A=4 A=5 A=6 A=7",
636 []query{
637 {"http://www.host.test/path", "A=2 A=5 A=1"},
638 {"http://www.host.test/path/foo", "A=4 A=7 A=2 A=5 A=1"},
639 },
640 },
641 {
642 "Disallow domain cookie on public suffix.",
643 "http://www.bbc.co.uk",
644 []string{
645 "a=1",
646 "b=2; domain=co.uk",
647 },
648 "a=1",
649 []query{{"http://www.bbc.co.uk", "a=1"}},
650 },
651 {
652 "Host cookie on IP.",
653 "http://192.168.0.10",
654 []string{"a=1"},
655 "a=1",
656 []query{{"http://192.168.0.10", "a=1"}},
657 },
658 {
659 "Domain cookies on IP.",
660 "http://192.168.0.10",
661 []string{
662 "a=1; domain=192.168.0.10",
663 "b=2; domain=172.31.9.9",
664 "c=3; domain=.192.168.0.10",
665 },
666 "a=1",
667 []query{
668 {"http://192.168.0.10", "a=1"},
669 {"http://172.31.9.9", ""},
670 {"http://www.fancy.192.168.0.10", ""},
671 },
672 },
673 {
674 "Port is ignored #1.",
675 "http://www.host.test/",
676 []string{"a=1"},
677 "a=1",
678 []query{
679 {"http://www.host.test", "a=1"},
680 {"http://www.host.test:8080/", "a=1"},
681 },
682 },
683 {
684 "Port is ignored #2.",
685 "http://www.host.test:8080/",
686 []string{"a=1"},
687 "a=1",
688 []query{
689 {"http://www.host.test", "a=1"},
690 {"http://www.host.test:8080/", "a=1"},
691 {"http://www.host.test:1234/", "a=1"},
692 },
693 },
694 {
695 "IPv6 zone is not treated as a host.",
696 "https://example.com/",
697 []string{"a=1"},
698 "a=1",
699 []query{
700 {"https://[::1%25.example.com]:80/", ""},
701 },
702 },
703 {
704 "Retrieval of cookies with quoted values",
705 "http://www.host.test/",
706 []string{
707 `cookie-1="quoted"`,
708 `cookie-2="quoted with spaces"`,
709 `cookie-3="quoted,with,commas"`,
710 `cookie-4= ,`,
711 },
712 `cookie-1="quoted" cookie-2="quoted with spaces" cookie-3="quoted,with,commas" cookie-4=" ,"`,
713 []query{
714 {
715 "http://www.host.test",
716 `cookie-1="quoted" cookie-2="quoted with spaces" cookie-3="quoted,with,commas" cookie-4=" ,"`,
717 },
718 },
719 },
720 }
721
722 func TestBasics(t *testing.T) {
723 for _, test := range basicsTests {
724 jar := newTestJar()
725 test.run(t, jar)
726 }
727 }
728
729
730
731 var updateAndDeleteTests = [...]jarTest{
732 {
733 "Set initial cookies.",
734 "http://www.host.test",
735 []string{
736 "a=1",
737 "b=2; secure",
738 "c=3; httponly",
739 "d=4; secure; httponly"},
740 "a=1 b=2 c=3 d=4",
741 []query{
742 {"http://www.host.test", "a=1 c=3"},
743 {"https://www.host.test", "a=1 b=2 c=3 d=4"},
744 },
745 },
746 {
747 "Update value via http.",
748 "http://www.host.test",
749 []string{
750 "a=w",
751 "b=x; secure",
752 "c=y; httponly",
753 "d=z; secure; httponly"},
754 "a=w b=x c=y d=z",
755 []query{
756 {"http://www.host.test", "a=w c=y"},
757 {"https://www.host.test", "a=w b=x c=y d=z"},
758 },
759 },
760 {
761 "Clear Secure flag from an http.",
762 "http://www.host.test/",
763 []string{
764 "b=xx",
765 "d=zz; httponly"},
766 "a=w b=xx c=y d=zz",
767 []query{{"http://www.host.test", "a=w b=xx c=y d=zz"}},
768 },
769 {
770 "Delete all.",
771 "http://www.host.test/",
772 []string{
773 "a=1; max-Age=-1",
774 "b=2; " + expiresIn(-10),
775 "c=2; max-age=-1; " + expiresIn(-10),
776 "d=4; max-age=-1; " + expiresIn(10)},
777 "",
778 []query{{"http://www.host.test", ""}},
779 },
780 {
781 "Refill #1.",
782 "http://www.host.test",
783 []string{
784 "A=1",
785 "A=2; path=/foo",
786 "A=3; domain=.host.test",
787 "A=4; path=/foo; domain=.host.test"},
788 "A=1 A=2 A=3 A=4",
789 []query{{"http://www.host.test/foo", "A=2 A=4 A=1 A=3"}},
790 },
791 {
792 "Refill #2.",
793 "http://www.google.com",
794 []string{
795 "A=6",
796 "A=7; path=/foo",
797 "A=8; domain=.google.com",
798 "A=9; path=/foo; domain=.google.com"},
799 "A=1 A=2 A=3 A=4 A=6 A=7 A=8 A=9",
800 []query{
801 {"http://www.host.test/foo", "A=2 A=4 A=1 A=3"},
802 {"http://www.google.com/foo", "A=7 A=9 A=6 A=8"},
803 },
804 },
805 {
806 "Delete A7.",
807 "http://www.google.com",
808 []string{"A=; path=/foo; max-age=-1"},
809 "A=1 A=2 A=3 A=4 A=6 A=8 A=9",
810 []query{
811 {"http://www.host.test/foo", "A=2 A=4 A=1 A=3"},
812 {"http://www.google.com/foo", "A=9 A=6 A=8"},
813 },
814 },
815 {
816 "Delete A4.",
817 "http://www.host.test",
818 []string{"A=; path=/foo; domain=host.test; max-age=-1"},
819 "A=1 A=2 A=3 A=6 A=8 A=9",
820 []query{
821 {"http://www.host.test/foo", "A=2 A=1 A=3"},
822 {"http://www.google.com/foo", "A=9 A=6 A=8"},
823 },
824 },
825 {
826 "Delete A6.",
827 "http://www.google.com",
828 []string{"A=; max-age=-1"},
829 "A=1 A=2 A=3 A=8 A=9",
830 []query{
831 {"http://www.host.test/foo", "A=2 A=1 A=3"},
832 {"http://www.google.com/foo", "A=9 A=8"},
833 },
834 },
835 {
836 "Delete A3.",
837 "http://www.host.test",
838 []string{"A=; domain=host.test; max-age=-1"},
839 "A=1 A=2 A=8 A=9",
840 []query{
841 {"http://www.host.test/foo", "A=2 A=1"},
842 {"http://www.google.com/foo", "A=9 A=8"},
843 },
844 },
845 {
846 "No cross-domain delete.",
847 "http://www.host.test",
848 []string{
849 "A=; domain=google.com; max-age=-1",
850 "A=; path=/foo; domain=google.com; max-age=-1"},
851 "A=1 A=2 A=8 A=9",
852 []query{
853 {"http://www.host.test/foo", "A=2 A=1"},
854 {"http://www.google.com/foo", "A=9 A=8"},
855 },
856 },
857 {
858 "Delete A8 and A9.",
859 "http://www.google.com",
860 []string{
861 "A=; domain=google.com; max-age=-1",
862 "A=; path=/foo; domain=google.com; max-age=-1"},
863 "A=1 A=2",
864 []query{
865 {"http://www.host.test/foo", "A=2 A=1"},
866 {"http://www.google.com/foo", ""},
867 },
868 },
869 }
870
871 func TestUpdateAndDelete(t *testing.T) {
872 jar := newTestJar()
873 for _, test := range updateAndDeleteTests {
874 test.run(t, jar)
875 }
876 }
877
878 func TestExpiration(t *testing.T) {
879 jar := newTestJar()
880 jarTest{
881 "Expiration.",
882 "http://www.host.test",
883 []string{
884 "a=1",
885 "b=2; max-age=3",
886 "c=3; " + expiresIn(3),
887 "d=4; max-age=5",
888 "e=5; " + expiresIn(5),
889 "f=6; max-age=100",
890 },
891 "a=1 b=2 c=3 d=4 e=5 f=6",
892 []query{
893 {"http://www.host.test", "a=1 b=2 c=3 d=4 e=5 f=6"},
894 {"http://www.host.test", "a=1 d=4 e=5 f=6"},
895 {"http://www.host.test", "a=1 d=4 e=5 f=6"},
896 {"http://www.host.test", "a=1 f=6"},
897 {"http://www.host.test", "a=1 f=6"},
898 },
899 }.run(t, jar)
900 }
901
902
903
904
905
906
907
908
909
910
911
912
913 var chromiumBasicsTests = [...]jarTest{
914 {
915 "DomainWithTrailingDotTest.",
916 "http://www.google.com/",
917 []string{
918 "a=1; domain=.www.google.com.",
919 "b=2; domain=.www.google.com.."},
920 "",
921 []query{
922 {"http://www.google.com", ""},
923 },
924 },
925 {
926 "ValidSubdomainTest #1.",
927 "http://a.b.c.d.com",
928 []string{
929 "a=1; domain=.a.b.c.d.com",
930 "b=2; domain=.b.c.d.com",
931 "c=3; domain=.c.d.com",
932 "d=4; domain=.d.com"},
933 "a=1 b=2 c=3 d=4",
934 []query{
935 {"http://a.b.c.d.com", "a=1 b=2 c=3 d=4"},
936 {"http://b.c.d.com", "b=2 c=3 d=4"},
937 {"http://c.d.com", "c=3 d=4"},
938 {"http://d.com", "d=4"},
939 },
940 },
941 {
942 "ValidSubdomainTest #2.",
943 "http://a.b.c.d.com",
944 []string{
945 "a=1; domain=.a.b.c.d.com",
946 "b=2; domain=.b.c.d.com",
947 "c=3; domain=.c.d.com",
948 "d=4; domain=.d.com",
949 "X=bcd; domain=.b.c.d.com",
950 "X=cd; domain=.c.d.com"},
951 "X=bcd X=cd a=1 b=2 c=3 d=4",
952 []query{
953 {"http://b.c.d.com", "b=2 c=3 d=4 X=bcd X=cd"},
954 {"http://c.d.com", "c=3 d=4 X=cd"},
955 },
956 },
957 {
958 "InvalidDomainTest #1.",
959 "http://foo.bar.com",
960 []string{
961 "a=1; domain=.yo.foo.bar.com",
962 "b=2; domain=.foo.com",
963 "c=3; domain=.bar.foo.com",
964 "d=4; domain=.foo.bar.com.net",
965 "e=5; domain=ar.com",
966 "f=6; domain=.",
967 "g=7; domain=/",
968 "h=8; domain=http://foo.bar.com",
969 "i=9; domain=..foo.bar.com",
970 "j=10; domain=..bar.com",
971 "k=11; domain=.foo.bar.com?blah",
972 "l=12; domain=.foo.bar.com/blah",
973 "m=12; domain=.foo.bar.com:80",
974 "n=14; domain=.foo.bar.com:",
975 "o=15; domain=.foo.bar.com#sup",
976 },
977 "",
978 []query{{"http://foo.bar.com", ""}},
979 },
980 {
981 "InvalidDomainTest #2.",
982 "http://foo.com.com",
983 []string{"a=1; domain=.foo.com.com.com"},
984 "",
985 []query{{"http://foo.bar.com", ""}},
986 },
987 {
988 "DomainWithoutLeadingDotTest #1.",
989 "http://manage.hosted.filefront.com",
990 []string{"a=1; domain=filefront.com"},
991 "a=1",
992 []query{{"http://www.filefront.com", "a=1"}},
993 },
994 {
995 "DomainWithoutLeadingDotTest #2.",
996 "http://www.google.com",
997 []string{"a=1; domain=www.google.com"},
998 "a=1",
999 []query{
1000 {"http://www.google.com", "a=1"},
1001 {"http://sub.www.google.com", "a=1"},
1002 {"http://something-else.com", ""},
1003 },
1004 },
1005 {
1006 "CaseInsensitiveDomainTest.",
1007 "http://www.google.com",
1008 []string{
1009 "a=1; domain=.GOOGLE.COM",
1010 "b=2; domain=.www.gOOgLE.coM"},
1011 "a=1 b=2",
1012 []query{{"http://www.google.com", "a=1 b=2"}},
1013 },
1014 {
1015 "TestIpAddress #1.",
1016 "http://1.2.3.4/foo",
1017 []string{"a=1; path=/"},
1018 "a=1",
1019 []query{{"http://1.2.3.4/foo", "a=1"}},
1020 },
1021 {
1022 "TestIpAddress #2.",
1023 "http://1.2.3.4/foo",
1024 []string{
1025 "a=1; domain=.1.2.3.4",
1026 "b=2; domain=.3.4"},
1027 "",
1028 []query{{"http://1.2.3.4/foo", ""}},
1029 },
1030 {
1031 "TestIpAddress #3.",
1032 "http://1.2.3.4/foo",
1033 []string{"a=1; domain=1.2.3.3"},
1034 "",
1035 []query{{"http://1.2.3.4/foo", ""}},
1036 },
1037 {
1038 "TestIpAddress #4.",
1039 "http://1.2.3.4/foo",
1040 []string{"a=1; domain=1.2.3.4"},
1041 "a=1",
1042 []query{{"http://1.2.3.4/foo", "a=1"}},
1043 },
1044 {
1045 "TestNonDottedAndTLD #2.",
1046 "http://com./index.html",
1047 []string{"a=1"},
1048 "a=1",
1049 []query{
1050 {"http://com./index.html", "a=1"},
1051 {"http://no-cookies.com./index.html", ""},
1052 },
1053 },
1054 {
1055 "TestNonDottedAndTLD #3.",
1056 "http://a.b",
1057 []string{
1058 "a=1; domain=.b",
1059 "b=2; domain=b"},
1060 "",
1061 []query{{"http://bar.foo", ""}},
1062 },
1063 {
1064 "TestNonDottedAndTLD #4.",
1065 "http://google.com",
1066 []string{
1067 "a=1; domain=.com",
1068 "b=2; domain=com"},
1069 "",
1070 []query{{"http://google.com", ""}},
1071 },
1072 {
1073 "TestNonDottedAndTLD #5.",
1074 "http://google.co.uk",
1075 []string{
1076 "a=1; domain=.co.uk",
1077 "b=2; domain=.uk"},
1078 "",
1079 []query{
1080 {"http://google.co.uk", ""},
1081 {"http://else.co.com", ""},
1082 {"http://else.uk", ""},
1083 },
1084 },
1085 {
1086 "TestHostEndsWithDot.",
1087 "http://www.google.com",
1088 []string{
1089 "a=1",
1090 "b=2; domain=.www.google.com."},
1091 "a=1",
1092 []query{{"http://www.google.com", "a=1"}},
1093 },
1094 {
1095 "PathTest",
1096 "http://www.google.izzle",
1097 []string{"a=1; path=/wee"},
1098 "a=1",
1099 []query{
1100 {"http://www.google.izzle/wee", "a=1"},
1101 {"http://www.google.izzle/wee/", "a=1"},
1102 {"http://www.google.izzle/wee/war", "a=1"},
1103 {"http://www.google.izzle/wee/war/more/more", "a=1"},
1104 {"http://www.google.izzle/weehee", ""},
1105 {"http://www.google.izzle/", ""},
1106 },
1107 },
1108 }
1109
1110 func TestChromiumBasics(t *testing.T) {
1111 for _, test := range chromiumBasicsTests {
1112 jar := newTestJar()
1113 test.run(t, jar)
1114 }
1115 }
1116
1117
1118
1119 var chromiumDomainTests = [...]jarTest{
1120 {
1121 "Fill #1.",
1122 "http://www.google.izzle",
1123 []string{"A=B"},
1124 "A=B",
1125 []query{{"http://www.google.izzle", "A=B"}},
1126 },
1127 {
1128 "Fill #2.",
1129 "http://www.google.izzle",
1130 []string{"C=D; domain=.google.izzle"},
1131 "A=B C=D",
1132 []query{{"http://www.google.izzle", "A=B C=D"}},
1133 },
1134 {
1135 "Verify A is a host cookie and not accessible from subdomain.",
1136 "http://unused.nil",
1137 []string{},
1138 "A=B C=D",
1139 []query{{"http://foo.www.google.izzle", "C=D"}},
1140 },
1141 {
1142 "Verify domain cookies are found on proper domain.",
1143 "http://www.google.izzle",
1144 []string{"E=F; domain=.www.google.izzle"},
1145 "A=B C=D E=F",
1146 []query{{"http://www.google.izzle", "A=B C=D E=F"}},
1147 },
1148 {
1149 "Leading dots in domain attributes are optional.",
1150 "http://www.google.izzle",
1151 []string{"G=H; domain=www.google.izzle"},
1152 "A=B C=D E=F G=H",
1153 []query{{"http://www.google.izzle", "A=B C=D E=F G=H"}},
1154 },
1155 {
1156 "Verify domain enforcement works #1.",
1157 "http://www.google.izzle",
1158 []string{"K=L; domain=.bar.www.google.izzle"},
1159 "A=B C=D E=F G=H",
1160 []query{{"http://bar.www.google.izzle", "C=D E=F G=H"}},
1161 },
1162 {
1163 "Verify domain enforcement works #2.",
1164 "http://unused.nil",
1165 []string{},
1166 "A=B C=D E=F G=H",
1167 []query{{"http://www.google.izzle", "A=B C=D E=F G=H"}},
1168 },
1169 }
1170
1171 func TestChromiumDomain(t *testing.T) {
1172 jar := newTestJar()
1173 for _, test := range chromiumDomainTests {
1174 test.run(t, jar)
1175 }
1176
1177 }
1178
1179
1180 var chromiumDeletionTests = [...]jarTest{
1181 {
1182 "Create session cookie a1.",
1183 "http://www.google.com",
1184 []string{"a=1"},
1185 "a=1",
1186 []query{{"http://www.google.com", "a=1"}},
1187 },
1188 {
1189 "Delete sc a1 via MaxAge.",
1190 "http://www.google.com",
1191 []string{"a=1; max-age=-1"},
1192 "",
1193 []query{{"http://www.google.com", ""}},
1194 },
1195 {
1196 "Create session cookie b2.",
1197 "http://www.google.com",
1198 []string{"b=2"},
1199 "b=2",
1200 []query{{"http://www.google.com", "b=2"}},
1201 },
1202 {
1203 "Delete sc b2 via Expires.",
1204 "http://www.google.com",
1205 []string{"b=2; " + expiresIn(-10)},
1206 "",
1207 []query{{"http://www.google.com", ""}},
1208 },
1209 {
1210 "Create persistent cookie c3.",
1211 "http://www.google.com",
1212 []string{"c=3; max-age=3600"},
1213 "c=3",
1214 []query{{"http://www.google.com", "c=3"}},
1215 },
1216 {
1217 "Delete pc c3 via MaxAge.",
1218 "http://www.google.com",
1219 []string{"c=3; max-age=-1"},
1220 "",
1221 []query{{"http://www.google.com", ""}},
1222 },
1223 {
1224 "Create persistent cookie d4.",
1225 "http://www.google.com",
1226 []string{"d=4; max-age=3600"},
1227 "d=4",
1228 []query{{"http://www.google.com", "d=4"}},
1229 },
1230 {
1231 "Delete pc d4 via Expires.",
1232 "http://www.google.com",
1233 []string{"d=4; " + expiresIn(-10)},
1234 "",
1235 []query{{"http://www.google.com", ""}},
1236 },
1237 }
1238
1239 func TestChromiumDeletion(t *testing.T) {
1240 jar := newTestJar()
1241 for _, test := range chromiumDeletionTests {
1242 test.run(t, jar)
1243 }
1244 }
1245
1246
1247
1248 var domainHandlingTests = [...]jarTest{
1249 {
1250 "Host cookie",
1251 "http://www.host.test",
1252 []string{"a=1"},
1253 "a=1",
1254 []query{
1255 {"http://www.host.test", "a=1"},
1256 {"http://host.test", ""},
1257 {"http://bar.host.test", ""},
1258 {"http://foo.www.host.test", ""},
1259 {"http://other.test", ""},
1260 {"http://test", ""},
1261 },
1262 },
1263 {
1264 "Domain cookie #1",
1265 "http://www.host.test",
1266 []string{"a=1; domain=host.test"},
1267 "a=1",
1268 []query{
1269 {"http://www.host.test", "a=1"},
1270 {"http://host.test", "a=1"},
1271 {"http://bar.host.test", "a=1"},
1272 {"http://foo.www.host.test", "a=1"},
1273 {"http://other.test", ""},
1274 {"http://test", ""},
1275 },
1276 },
1277 {
1278 "Domain cookie #2",
1279 "http://www.host.test",
1280 []string{"a=1; domain=.host.test"},
1281 "a=1",
1282 []query{
1283 {"http://www.host.test", "a=1"},
1284 {"http://host.test", "a=1"},
1285 {"http://bar.host.test", "a=1"},
1286 {"http://foo.www.host.test", "a=1"},
1287 {"http://other.test", ""},
1288 {"http://test", ""},
1289 },
1290 },
1291 {
1292 "Host cookie on IDNA domain #1",
1293 "http://www.bücher.test",
1294 []string{"a=1"},
1295 "a=1",
1296 []query{
1297 {"http://www.bücher.test", "a=1"},
1298 {"http://www.xn--bcher-kva.test", "a=1"},
1299 {"http://bücher.test", ""},
1300 {"http://xn--bcher-kva.test", ""},
1301 {"http://bar.bücher.test", ""},
1302 {"http://bar.xn--bcher-kva.test", ""},
1303 {"http://foo.www.bücher.test", ""},
1304 {"http://foo.www.xn--bcher-kva.test", ""},
1305 {"http://other.test", ""},
1306 {"http://test", ""},
1307 },
1308 },
1309 {
1310 "Host cookie on IDNA domain #2",
1311 "http://www.xn--bcher-kva.test",
1312 []string{"a=1"},
1313 "a=1",
1314 []query{
1315 {"http://www.bücher.test", "a=1"},
1316 {"http://www.xn--bcher-kva.test", "a=1"},
1317 {"http://bücher.test", ""},
1318 {"http://xn--bcher-kva.test", ""},
1319 {"http://bar.bücher.test", ""},
1320 {"http://bar.xn--bcher-kva.test", ""},
1321 {"http://foo.www.bücher.test", ""},
1322 {"http://foo.www.xn--bcher-kva.test", ""},
1323 {"http://other.test", ""},
1324 {"http://test", ""},
1325 },
1326 },
1327 {
1328 "Domain cookie on IDNA domain #1",
1329 "http://www.bücher.test",
1330 []string{"a=1; domain=xn--bcher-kva.test"},
1331 "a=1",
1332 []query{
1333 {"http://www.bücher.test", "a=1"},
1334 {"http://www.xn--bcher-kva.test", "a=1"},
1335 {"http://bücher.test", "a=1"},
1336 {"http://xn--bcher-kva.test", "a=1"},
1337 {"http://bar.bücher.test", "a=1"},
1338 {"http://bar.xn--bcher-kva.test", "a=1"},
1339 {"http://foo.www.bücher.test", "a=1"},
1340 {"http://foo.www.xn--bcher-kva.test", "a=1"},
1341 {"http://other.test", ""},
1342 {"http://test", ""},
1343 },
1344 },
1345 {
1346 "Domain cookie on IDNA domain #2",
1347 "http://www.xn--bcher-kva.test",
1348 []string{"a=1; domain=xn--bcher-kva.test"},
1349 "a=1",
1350 []query{
1351 {"http://www.bücher.test", "a=1"},
1352 {"http://www.xn--bcher-kva.test", "a=1"},
1353 {"http://bücher.test", "a=1"},
1354 {"http://xn--bcher-kva.test", "a=1"},
1355 {"http://bar.bücher.test", "a=1"},
1356 {"http://bar.xn--bcher-kva.test", "a=1"},
1357 {"http://foo.www.bücher.test", "a=1"},
1358 {"http://foo.www.xn--bcher-kva.test", "a=1"},
1359 {"http://other.test", ""},
1360 {"http://test", ""},
1361 },
1362 },
1363 {
1364 "Host cookie on TLD.",
1365 "http://com",
1366 []string{"a=1"},
1367 "a=1",
1368 []query{
1369 {"http://com", "a=1"},
1370 {"http://any.com", ""},
1371 {"http://any.test", ""},
1372 },
1373 },
1374 {
1375 "Domain cookie on TLD becomes a host cookie.",
1376 "http://com",
1377 []string{"a=1; domain=com"},
1378 "a=1",
1379 []query{
1380 {"http://com", "a=1"},
1381 {"http://any.com", ""},
1382 {"http://any.test", ""},
1383 },
1384 },
1385 {
1386 "Host cookie on public suffix.",
1387 "http://co.uk",
1388 []string{"a=1"},
1389 "a=1",
1390 []query{
1391 {"http://co.uk", "a=1"},
1392 {"http://uk", ""},
1393 {"http://some.co.uk", ""},
1394 {"http://foo.some.co.uk", ""},
1395 {"http://any.uk", ""},
1396 },
1397 },
1398 {
1399 "Domain cookie on public suffix is ignored.",
1400 "http://some.co.uk",
1401 []string{"a=1; domain=co.uk"},
1402 "",
1403 []query{
1404 {"http://co.uk", ""},
1405 {"http://uk", ""},
1406 {"http://some.co.uk", ""},
1407 {"http://foo.some.co.uk", ""},
1408 {"http://any.uk", ""},
1409 },
1410 },
1411 }
1412
1413 func TestDomainHandling(t *testing.T) {
1414 for _, test := range domainHandlingTests {
1415 jar := newTestJar()
1416 test.run(t, jar)
1417 }
1418 }
1419
1420 func TestIssue19384(t *testing.T) {
1421 cookies := []*http.Cookie{{Name: "name", Value: "value"}}
1422 for _, host := range []string{"", ".", "..", "..."} {
1423 jar, _ := New(nil)
1424 u := &url.URL{Scheme: "http", Host: host, Path: "/"}
1425 if got := jar.Cookies(u); len(got) != 0 {
1426 t.Errorf("host %q, got %v", host, got)
1427 }
1428 jar.SetCookies(u, cookies)
1429 if got := jar.Cookies(u); len(got) != 1 || got[0].Value != "value" {
1430 t.Errorf("host %q, got %v", host, got)
1431 }
1432 }
1433 }
1434
View as plain text