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