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