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