File Coverage

blib/lib/HTTP/Cookies.pm
Criterion Covered Total %
statement 344 370 92.9
branch 176 216 81.4
condition 54 71 76.0
subroutine 22 23 95.6
pod 12 13 92.3
total 608 693 87.7


line stmt bran cond sub pod time code
1             package HTTP::Cookies;
2              
3 6     6   347360 use strict;
  6         60  
  6         211  
4 6     6   2887 use HTTP::Date qw(str2time parse_date time2str);
  6         28068  
  6         413  
5 6     6   2716 use HTTP::Headers::Util qw(_split_header_words join_header_words);
  6         6144  
  6         27036  
6              
7             our $EPOCH_OFFSET;
8             our $VERSION = '6.09';
9              
10             # Legacy: because "use "HTTP::Cookies" used be the ONLY way
11             # to load the class HTTP::Cookies::Netscape.
12             require HTTP::Cookies::Netscape;
13              
14             $EPOCH_OFFSET = 0; # difference from Unix epoch
15              
16             # A HTTP::Cookies object is a hash. The main attribute is the
17             # COOKIES 3 level hash: $self->{COOKIES}{$domain}{$path}{$key}.
18              
19             sub new
20             {
21 32     32 1 11815 my $class = shift;
22 32         122 my $self = bless {
23             COOKIES => {},
24             }, $class;
25 32         81 my %cnf = @_;
26 32         100 for (keys %cnf) {
27 7         23 $self->{lc($_)} = $cnf{$_};
28             }
29 32         113 $self->load;
30 32         138 $self;
31             }
32              
33              
34             sub add_cookie_header
35             {
36 70     70 1 27723 my $self = shift;
37 70   50     183 my $request = shift || return;
38 70         168 my $url = $request->uri;
39 70         562 my $scheme = $url->scheme;
40 70 100       1515 unless ($scheme =~ /^https?\z/) {
41 3         8 return;
42             }
43              
44 67         154 my $domain = _host($request, $url);
45 67 100       1726 $domain = "$domain.local" unless $domain =~ /\./;
46 67         121 my $secure_request = ($scheme eq "https");
47 67         127 my $req_path = _url_path($url);
48 67         193 my $req_port = $url->port;
49 67         1637 my $now = time();
50 67 100       167 _normalize_path($req_path) if $req_path =~ /%/;
51              
52 67         107 my @cval; # cookie values for the "Cookie" header
53             my $set_ver;
54 67         99 my $netscape_only = 0; # An exact domain match applies to any cookie
55              
56 67         184 while ($domain =~ /\./) {
57             # Checking $domain for cookies"
58 252         527 my $cookies = $self->{COOKIES}{$domain};
59 252 100       474 next unless $cookies;
60 57 50 33     137 if ($self->{delayload} && defined($cookies->{'//+delayload'})) {
61 0         0 my $cookie_data = $cookies->{'//+delayload'}{'cookie'};
62 0         0 delete $self->{COOKIES}{$domain};
63 0         0 $self->load_cookie($cookie_data->[1]);
64 0         0 $cookies = $self->{COOKIES}{$domain};
65 0 0       0 next unless $cookies; # should not really happen
66             }
67              
68             # Want to add cookies corresponding to the most specific paths
69             # first (i.e. longest path first)
70 57         90 my $path;
71 57         223 for $path (sort {length($b) <=> length($a) } keys %$cookies) {
  10         34  
72 67 100       250 if (index($req_path, $path) != 0) {
73 7         16 next;
74             }
75              
76 60         94 my($key,$array);
77 60         88 while (($key,$array) = each %{$cookies->{$path}}) {
  135         495  
78 75         187 my($version,$val,$port,$path_spec,$secure,$expires) = @$array;
79 75 100 100     197 if ($secure && !$secure_request) {
80 1         2 next;
81             }
82 74 50 66     183 if ($expires && $expires < $now) {
83 0         0 next;
84             }
85 74 100       139 if ($port) {
86 7         9 my $found;
87 7 100       32 if ($port =~ s/^_//) {
88             # The corresponding Set-Cookie attribute was empty
89 4 50       14 $found++ if $port eq $req_port;
90 4         7 $port = "";
91             }
92             else {
93 3         47 my $p;
94 3         15 for $p (split(/,/, $port)) {
95 7 100       18 $found++, last if $p eq $req_port;
96             }
97             }
98 7 50       21 unless ($found) {
99 0         0 next;
100             }
101             }
102 74 50 66     219 if ($version > 0 && $netscape_only) {
103 0         0 next;
104             }
105              
106             # set version number of cookie header.
107             # XXX: What should it be if multiple matching
108             # Set-Cookie headers have different versions themselves
109 74 100       168 if (!$set_ver++) {
110 50 100       130 if ($version >= 1) {
    50          
111 18         50 push(@cval, "\$Version=$version");
112             }
113             elsif (!$self->{hide_cookie2}) {
114 32         90 $request->header(Cookie2 => '$Version="1"');
115             }
116             }
117              
118             # do we need to quote the value
119 74 50 66     2233 if ($val =~ /\W/ && $version) {
120 0         0 $val =~ s/([\\\"])/\\$1/g;
121 0         0 $val = qq("$val");
122             }
123              
124             # and finally remember this cookie
125 74         188 push(@cval, "$key=$val");
126 74 100       156 if ($version >= 1) {
127 31 100       67 push(@cval, qq(\$Path="$path")) if $path_spec;
128 31 100       76 push(@cval, qq(\$Domain="$domain")) if $domain =~ /^\./;
129 31 100       75 if (defined $port) {
130 7         9 my $p = '$Port';
131 7 100       31 $p .= qq(="$port") if length $port;
132 7         15 push(@cval, $p);
133             }
134             }
135              
136             }
137             }
138              
139             } continue {
140             # Try with a more general domain, alternately stripping
141             # leading name components and leading dots. When this
142             # results in a domain with no leading dot, it is for
143             # Netscape cookie compatibility only:
144             #
145             # a.b.c.net Any cookie
146             # .b.c.net Any cookie
147             # b.c.net Netscape cookie only
148             # .c.net Any cookie
149              
150 252 100       607 if ($domain =~ s/^\.+//) {
151 126         319 $netscape_only = 1;
152             }
153             else {
154 126         382 $domain =~ s/[^.]*//;
155 126         345 $netscape_only = 0;
156             }
157             }
158              
159 67 100       147 if (@cval) {
160 50 100       139 if (my $old = $request->header("Cookie")) {
161 2         85 unshift(@cval, $old);
162             }
163 50         2681 $request->header(Cookie => join("; ", @cval));
164 50 100       2458 if (my $hash = $request->{_http_cookies}) {
165 8         43 %$hash = (map split(/=/, $_, 2), @cval);
166             }
167             }
168              
169 67         242 $request;
170             }
171              
172              
173             sub get_cookies
174             {
175 9     9 1 121 my $self = shift;
176 9         20 my $url = shift;
177 9 100       46 $url = "https://$url" unless $url =~ m,^[a-zA-Z][a-zA-Z0-9.+\-]*:,;
178 9         55 require HTTP::Request;
179 9         31 my $req = HTTP::Request->new(GET => $url);
180 9         1002 my $cookies = $req->{_http_cookies} = {};
181 9         25 $self->add_cookie_header($req);
182 9 100       22 if (@_) {
183 8 100       24 return map $cookies->{$_}, @_ if wantarray;
184 7         59 return $cookies->{$_[0]};
185             }
186 1         9 return $cookies;
187             }
188              
189              
190             sub extract_cookies
191             {
192 69     69 1 63308 my $self = shift;
193 69   50     198 my $response = shift || return;
194              
195 69         220 my @set = _split_header_words($response->_header("Set-Cookie2"));
196 69         4919 my @ns_set = $response->_header("Set-Cookie");
197              
198 69 100 100     2478 return $response unless @set || @ns_set; # quick exit
199              
200 62         176 my $request = $response->request;
201 62         719 my $url = $request->uri;
202 62         522 my $req_host = _host($request, $url);
203 62 100       1630 $req_host = "$req_host.local" unless $req_host =~ /\./;
204 62         170 my $req_port = $url->port;
205 62         1853 my $req_path = _url_path($url);
206 62 100       210 _normalize_path($req_path) if $req_path =~ /%/;
207              
208 62 100       156 if (@ns_set) {
209             # The old Netscape cookie format for Set-Cookie
210             # http://curl.haxx.se/rfc/cookie_spec.html
211             # can for instance contain an unquoted "," in the expires
212             # field, so we have to use this ad-hoc parser.
213 32         60 my $now = time();
214              
215             # Build a hash of cookies that was present in Set-Cookie2
216             # headers. We need to skip them if we also find them in a
217             # Set-Cookie header.
218 32         45 my %in_set2;
219 32         77 for (@set) {
220 2         7 $in_set2{$_->[0]}++;
221             }
222              
223 32         42 my $set;
224 32         57 for $set (@ns_set) {
225 42         144 $set =~ s/^\s+//;
226 42         95 my @cur;
227             my $param;
228 42         0 my $expires;
229 42         68 my $first_param = 1;
230 42         60 for $param (@{_split_text($set)}) {
  42         87  
231 106 100       201 next unless length($param);
232 105         409 my($k,$v) = split(/\s*=\s*/, $param, 2);
233 105 100       208 if (defined $v) {
234 103         197 $v =~ s/\s+$//;
235             #print "$k => $v\n";
236             }
237             else {
238 2         6 $k =~ s/\s+$//;
239             #print "$k => undef";
240             }
241 105 100 100     471 if (!$first_param && lc($k) eq "expires") {
    100 100        
242 14         47 my $etime = str2time($v);
243 14 100       1628 if (defined $etime) {
244 12         36 push(@cur, "Max-Age" => $etime - $now);
245 12         25 $expires++;
246             }
247             else {
248             # parse_date can deal with years outside the range of time_t,
249 2         6 my($year, $mon, $day, $hour, $min, $sec, $tz) = parse_date($v);
250 2 50       64 if ($year) {
251 2         11 my $thisyear = (gmtime)[5] + 1900;
252 2 50       8 if ($year < $thisyear) {
    0          
253 2         5 push(@cur, "Max-Age" => -1); # any negative value will do
254 2         4 $expires++;
255             }
256             elsif ($year >= $thisyear + 10) {
257             # the date is at least 10 years into the future, just replace
258             # it with something approximate
259 0         0 push(@cur, "Max-Age" => 10 * 365 * 24 * 60 * 60);
260 0         0 $expires++;
261             }
262             }
263             }
264             }
265             elsif (!$first_param && lc($k) =~ /^(?:version|discard|ns-cookie)/) {
266             # ignore
267             }
268             else {
269 89         181 push(@cur, $k => $v);
270             }
271 105         188 $first_param = 0;
272             }
273 42 100       119 next unless @cur;
274 41 100       103 next if $in_set2{$cur[0]};
275              
276             # push(@cur, "Port" => $req_port);
277 40 100       124 push(@cur, "Discard" => undef) unless $expires;
278 40         81 push(@cur, "Version" => 0);
279 40         87 push(@cur, "ns-cookie" => 1);
280 40         107 push(@set, \@cur);
281             }
282             }
283              
284             SET_COOKIE:
285 62         122 for my $set (@set) {
286 76 50       168 next unless @$set >= 2;
287              
288 76         136 my $key = shift @$set;
289 76         112 my $val = shift @$set;
290              
291 76         114 my %hash;
292 76         154 while (@$set) {
293 234         347 my $k = shift @$set;
294 234         359 my $v = shift @$set;
295 234         643 my $lc = lc($k);
296             # don't loose case distinction for unknown fields
297 234 100       831 $k = $lc if $lc =~ /^(?:discard|domain|max-age|
298             path|port|secure|version)$/x;
299 234 100 100     714 if ($k eq "discard" || $k eq "secure") {
300 33 50       73 $v = 1 unless defined $v;
301             }
302 234 50       474 next if exists $hash{$k}; # only first value is significant
303 234         614 $hash{$k} = $v;
304             };
305              
306 76         286 my %orig_hash = %hash;
307 76         171 my $version = delete $hash{version};
308 76 100       160 $version = 1 unless defined($version);
309 76         133 my $discard = delete $hash{discard};
310 76         117 my $secure = delete $hash{secure};
311 76         105 my $maxage = delete $hash{'max-age'};
312 76         103 my $ns_cookie = delete $hash{'ns-cookie'};
313              
314             # Check domain
315 76         138 my $domain = delete $hash{domain};
316 76 100       161 $domain = lc($domain) if defined $domain;
317 76 100 100     307 if (defined($domain)
      100        
318             && $domain ne $req_host && $domain ne ".$req_host") {
319 17 50 33     90 if ($domain !~ /\./ && $domain ne "local") {
320 0         0 next SET_COOKIE;
321             }
322 17 100       54 $domain = ".$domain" unless $domain =~ /^\./;
323 17 100       56 if ($domain =~ /\.\d+$/) {
324 1         4 next SET_COOKIE;
325             }
326 16         26 my $len = length($domain);
327 16 50       45 unless (substr($req_host, -$len) eq $domain) {
328 0         0 next SET_COOKIE;
329             }
330 16         33 my $hostpre = substr($req_host, 0, length($req_host) - $len);
331 16 100 100     51 if ($hostpre =~ /\./ && !$ns_cookie) {
332 2         7 next SET_COOKIE;
333             }
334             }
335             else {
336 59         89 $domain = $req_host;
337             }
338              
339 73         124 my $path = delete $hash{path};
340 73         101 my $path_spec;
341 73 100 100     226 if (defined $path && $path ne '') {
342 49         74 $path_spec++;
343 49 100       111 _normalize_path($path) if $path =~ /%/;
344 49 100 100     152 if (!$ns_cookie &&
345             substr($req_path, 0, length($path)) ne $path) {
346 4         16 next SET_COOKIE;
347             }
348             }
349             else {
350 24         39 $path = $req_path;
351 24         113 $path =~ s,/[^/]*$,,;
352 24 100       67 $path = "/" unless length($path);
353             }
354              
355 69         110 my $port;
356 69 100       188 if (exists $hash{port}) {
357 5         13 $port = delete $hash{port};
358 5 100       18 if (defined $port) {
359 3         10 $port =~ s/\s+//g;
360 3         5 my $found;
361 3         11 for my $p (split(/,/, $port)) {
362 7 50       24 unless ($p =~ /^\d+$/) {
363 0         0 next SET_COOKIE;
364             }
365 7 100       24 $found++ if $p eq $req_port;
366             }
367 3 100       13 unless ($found) {
368 1         4 next SET_COOKIE;
369             }
370             }
371             else {
372 2         5 $port = "_$req_port";
373             }
374             }
375 68 50       196 $self->set_cookie($version,$key,$val,$path,$domain,$port,$path_spec,$secure,$maxage,$discard, \%hash)
376             if $self->set_cookie_ok(\%orig_hash);
377             }
378              
379 62         186 $response;
380             }
381              
382             sub set_cookie_ok
383             {
384 68     68 0 230 1;
385             }
386              
387              
388             sub set_cookie
389             {
390 77     77 1 124 my $self = shift;
391 77         219 my($version,
392             $key, $val, $path, $domain, $port,
393             $path_spec, $secure, $maxage, $discard, $rest) = @_;
394              
395             # path and key can not be empty (key can't start with '$')
396 77 50 33     600 return $self if !defined($path) || $path !~ m,^/, ||
      33        
397             !defined($key) || $key =~ m,^\$,;
398              
399             # ensure legal port
400 77 100       157 if (defined $port) {
401 4 50       19 return $self unless $port =~ /^_?\d+(?:,\d+)*$/;
402             }
403              
404 77         111 my $expires;
405 77 100       142 if (defined $maxage) {
406 27 100       72 if ($maxage <= 0) {
407 8         18 delete $self->{COOKIES}{$domain}{$path}{$key};
408 8         29 return $self;
409             }
410 19         30 $expires = time() + $maxage;
411             }
412 69 100       127 $version = 0 unless defined $version;
413              
414 69         210 my @array = ($version, $val,$port,
415             $path_spec,
416             $secure, $expires, $discard);
417 69 100 100     223 push(@array, {%$rest}) if defined($rest) && %$rest;
418             # trim off undefined values at end
419 69         216 pop(@array) while !defined $array[-1];
420              
421 69         240 $self->{COOKIES}{$domain}{$path}{$key} = \@array;
422 69         321 $self;
423             }
424              
425              
426             sub save
427             {
428 2     2 1 125 my $self = shift;
429             my %args = (
430             file => $self->{'file'},
431 2 100       19 ignore_discard => $self->{'ignore_discard'},
432             @_ == 1 ? ( file => $_[0] ) : @_
433             );
434 2 50       9 Carp::croak('Unexpected argument to save method') if keys %args > 2;
435 2   50     8 my $file = $args{'file'} || return;
436 2 50       229 open(my $fh, '>', $file) or die "Can't open $file: $!";
437 2         7 print {$fh} "#LWP-Cookies-1.0\n";
  2         41  
438 2         7 print {$fh} $self->as_string(!$args{'ignore_discard'});
  2         10  
439 2 50       104 close $fh or die "Can't close $file: $!";
440 2         16 1;
441             }
442              
443              
444             sub load
445             {
446 29     29 1 52 my $self = shift;
447 29   50     176 my $file = shift || $self->{'file'} || return;
448              
449 2         9 local $/ = "\n"; # make sure we got standard record separator
450 2 50       72 open(my $fh, '<', $file) or return;
451              
452             # check that we have the proper header
453 2         43 my $magic = <$fh>;
454 2         12 chomp $magic;
455 2 50       17 unless ($magic =~ /^#LWP-Cookies-\d+\.\d+/) {
456 0         0 warn "$file does not seem to contain cookies";
457 0         0 return;
458             }
459              
460             # go through the file
461 2         9 while (my $line = <$fh>) {
462 7         14 chomp $line;
463 7 50       57 next unless $line =~ s/^Set-Cookie3:\s*//;
464 7         15 my $cookie;
465 7         19 for $cookie (_split_header_words($line)) {
466 7         739 my($key,$val) = splice(@$cookie, 0, 2);
467 7         12 my %hash;
468 7         16 while (@$cookie) {
469 29         46 my $k = shift @$cookie;
470 29         40 my $v = shift @$cookie;
471 29         70 $hash{$k} = $v;
472             }
473 7         14 my $version = delete $hash{version};
474 7         11 my $path = delete $hash{path};
475 7         13 my $domain = delete $hash{domain};
476 7         11 my $port = delete $hash{port};
477 7         19 my $expires = str2time(delete $hash{expires});
478              
479 7         252 my $path_spec = exists $hash{path_spec}; delete $hash{path_spec};
  7         11  
480 7         11 my $secure = exists $hash{secure}; delete $hash{secure};
  7         11  
481 7         9 my $discard = exists $hash{discard}; delete $hash{discard};
  7         10  
482              
483 7         29 my @array = ($version, $val, $port, $path_spec, $secure, $expires,
484             $discard);
485 7 100       17 push(@array, \%hash) if %hash;
486 7         61 $self->{COOKIES}{$domain}{$path}{$key} = \@array;
487             }
488             }
489 2         32 1;
490             }
491              
492              
493             sub revert
494             {
495 0     0 1 0 my $self = shift;
496 0         0 $self->clear->load;
497 0         0 $self;
498             }
499              
500              
501             sub clear
502             {
503 5     5 1 2554 my $self = shift;
504 5 50       20 if (@_ == 0) {
    0          
    0          
    0          
505 5         27 $self->{COOKIES} = {};
506             }
507             elsif (@_ == 1) {
508 0         0 delete $self->{COOKIES}{$_[0]};
509             }
510             elsif (@_ == 2) {
511 0         0 delete $self->{COOKIES}{$_[0]}{$_[1]};
512             }
513             elsif (@_ == 3) {
514 0         0 delete $self->{COOKIES}{$_[0]}{$_[1]}{$_[2]};
515             }
516             else {
517 0         0 require Carp;
518 0         0 Carp::carp('Usage: $c->clear([domain [,path [,key]]])');
519             }
520 5         13 $self;
521             }
522              
523              
524             sub clear_temporary_cookies
525             {
526 2     2 1 165 my($self) = @_;
527              
528             $self->scan(sub {
529 6 100 66 6   26 if($_[9] or # "Discard" flag set
530             not $_[8]) { # No expire field?
531 3         4 $_[8] = -1; # Set the expire/max_age field
532 3         6 $self->set_cookie(@_); # Clear the cookie
533             }
534 2         12 });
535             }
536              
537              
538             sub DESTROY
539             {
540 28     28   1870 my $self = shift;
541 28         223 local($., $@, $!, $^E, $?);
542 28 50       497 $self->save if $self->{'autosave'};
543             }
544              
545              
546             sub scan
547             {
548 59     59 1 623 my($self, $cb) = @_;
549 59         96 my($domain,$path,$key);
550 59         90 for $domain (sort keys %{$self->{COOKIES}}) {
  59         249  
551 89         986 for $path (sort keys %{$self->{COOKIES}{$domain}}) {
  89         238  
552 109         601 for $key (sort keys %{$self->{COOKIES}{$domain}{$path}}) {
  109         311  
553             my($version,$val,$port,$path_spec,
554             $secure,$expires,$discard,$rest) =
555 133         744 @{$self->{COOKIES}{$domain}{$path}{$key}};
  133         355  
556 133 100       331 $rest = {} unless defined($rest);
557 133         271 &$cb($version,$key,$val,$path,$domain,$port,
558             $path_spec,$secure,$expires,$discard,$rest);
559             }
560             }
561             }
562             }
563              
564              
565             sub as_string
566             {
567 22     22 1 1103 my($self, $skip_discard) = @_;
568 22         37 my @res;
569             $self->scan(sub {
570 48     48   133 my($version,$key,$val,$path,$domain,$port,
571             $path_spec,$secure,$expires,$discard,$rest) = @_;
572 48 50 66     150 return if $discard && $skip_discard;
573 48         111 my @h = ($key, $val);
574 48         88 push(@h, "path", $path);
575 48         93 push(@h, "domain" => $domain);
576 48 100       96 push(@h, "port" => $port) if defined $port;
577 48 100       90 push(@h, "path_spec" => undef) if $path_spec;
578 48 50       94 push(@h, "secure" => undef) if $secure;
579 48 100       116 push(@h, "expires" => HTTP::Date::time2isoz($expires)) if $expires;
580 48 100       241 push(@h, "discard" => undef) if $discard;
581 48         59 my $k;
582 48         120 for $k (sort keys %$rest) {
583 3         8 push(@h, $k, $rest->{$k});
584             }
585 48         114 push(@h, "version" => $version);
586 48         125 push(@res, "Set-Cookie3: " . join_header_words(\@h));
587 22         168 });
588 22         1907 join("\n", @res, "");
589             }
590              
591             sub _host
592             {
593 129     129   286 my($request, $url) = @_;
594 129 100       317 if (my $h = $request->header("Host")) {
595 32         1427 $h =~ s/:\d+$//; # might have a port as well
596 32         106 return lc($h);
597             }
598 97         4322 return lc($url->host);
599             }
600              
601             sub _url_path
602             {
603 129     129   187 my $url = shift;
604 129         172 my $path;
605 129 50       447 if($url->can('epath')) {
606 0         0 $path = $url->epath; # URI::URL method
607             }
608             else {
609 129         354 $path = $url->path; # URI::_generic method
610             }
611 129 100       1451 $path = "/" unless length $path;
612 129         260 $path;
613             }
614              
615             sub _normalize_path # so that plain string compare can be used
616             {
617 6     6   9 my $x;
618 6         23 $_[0] =~ s/%([0-9a-fA-F][0-9a-fA-F])/
619 35         66 $x = uc($1);
620 35 100 100     179 $x eq "2F" || $x eq "25" ? "%$x" :
621             pack("C", hex($x));
622             /eg;
623 6         24 $_[0] =~ s/([\0-\x20\x7f-\xff])/sprintf("%%%02X",ord($1))/eg;
  21         77  
624             }
625              
626             # deals with splitting values by ; and the fact that they could
627             # be in quotes which can also have escaping.
628             sub _split_text {
629 44     44   69 my $val = shift;
630 44         217 my @vals = grep { $_ ne q{} } split(/([;\\"])/, $val);
  214         701  
631 44         83 my @chunks;
632             # divide it up into chunks to be processed.
633 44         61 my $in_string = 0;
634 44         52 my @current_string;
635 44         106 for(my $i = 0; $i < @vals; $i++) {
636 203         314 my $chunk = $vals[$i];
637 203 100       295 if($in_string) {
638 18 100       37 if($chunk eq q{\\}) {
    100          
639             # don't care about next char probably.
640             # having said that, probably need to be appending to the chunks
641             # just dropping this.
642 2         4 $i++;
643 2 50       5 if($i < @vals) {
644 2         5 push @current_string, $vals[$i];
645             }
646             } elsif($chunk eq q{"}) {
647 4         24 $in_string = 0;
648             }
649             else {
650 12         23 push @current_string, $chunk;
651             }
652             } else {
653 185 100       376 if($chunk eq q{"}) {
    100          
654 4         10 $in_string = 1;
655             }
656             elsif($chunk eq q{;}) {
657 71         168 push @chunks, join(q{}, @current_string);
658 71         161 @current_string = ();
659             }
660             else {
661 110         257 push @current_string, $chunk;
662             }
663             }
664             }
665 44 100       171 push @chunks, join(q{}, @current_string) if @current_string;
666 44         222 s/^\s+// for @chunks;
667 44         204 return \@chunks;
668             }
669              
670             1;
671              
672             =pod
673              
674             =encoding UTF-8
675              
676             =head1 NAME
677              
678             HTTP::Cookies - HTTP cookie jars
679              
680             =head1 VERSION
681              
682             version 6.09
683              
684             =head1 SYNOPSIS
685              
686             use HTTP::Cookies;
687             $cookie_jar = HTTP::Cookies->new(
688             file => "$ENV{'HOME'}/lwp_cookies.dat",
689             autosave => 1,
690             );
691              
692             use LWP;
693             my $browser = LWP::UserAgent->new;
694             $browser->cookie_jar($cookie_jar);
695              
696             Or for an empty and temporary cookie jar:
697              
698             use LWP;
699             my $browser = LWP::UserAgent->new;
700             $browser->cookie_jar( {} );
701              
702             =head1 DESCRIPTION
703              
704             This class is for objects that represent a "cookie jar" -- that is, a
705             database of all the HTTP cookies that a given LWP::UserAgent object
706             knows about.
707              
708             Cookies are a general mechanism which server side connections can use
709             to both store and retrieve information on the client side of the
710             connection. For more information about cookies refer to
711             L and
712             L. This module also implements the
713             new style cookies described in L.
714             The two variants of cookies are supposed to be able to coexist happily.
715              
716             Instances of the class I are able to store a collection
717             of Set-Cookie2: and Set-Cookie: headers and are able to use this
718             information to initialize Cookie-headers in I objects.
719             The state of a I object can be saved in and restored from
720             files.
721              
722             =head1 LIMITATIONS
723              
724             This module does not support L<< Public Suffix|https://publicsuffix.org/
725             >> encouraged by a more recent standard, L<< RFC
726             6265|https://tools.ietf.org/html/rfc6265 >>.
727              
728             This module's shortcomings mean that a malicious Web site can set
729             cookies to track your user agent across all sites under a top level
730             domain. See F<< t/publicsuffix.t >> in this module's distribution for
731             details.
732              
733             L<< HTTP::CookieJar::LWP >> supports Public Suffix, but only provides a
734             limited subset of this module's functionality and L<< does not
735             support|HTTP::CookieJar/LIMITATIONS-AND-CAVEATS >> standards older than
736             I.
737              
738             =head1 METHODS
739              
740             The following methods are provided:
741              
742             =over 4
743              
744             =item $cookie_jar = HTTP::Cookies->new
745              
746             The constructor takes hash style parameters. The following
747             parameters are recognized:
748              
749             file: name of the file to restore cookies from and save cookies to
750             autosave: save during destruction (bool)
751             ignore_discard: save even cookies that are requested to be discarded (bool)
752             hide_cookie2: do not add Cookie2 header to requests
753              
754             Future parameters might include (not yet implemented):
755              
756             max_cookies 300
757             max_cookies_per_domain 20
758             max_cookie_size 4096
759              
760             no_cookies list of domain names that we never return cookies to
761              
762             =item $cookie_jar->get_cookies( $url_or_domain )
763              
764             =item $cookie_jar->get_cookies( $url_or_domain, $cookie_key,... )
765              
766             Returns a hash of the cookies that applies to the given URL. If a
767             domainname is given as argument, then a prefix of "https://" is assumed.
768              
769             If one or more $cookie_key parameters are provided return the given values,
770             or C if the cookie isn't available.
771              
772             =item $cookie_jar->add_cookie_header( $request )
773              
774             The add_cookie_header() method will set the appropriate Cookie:-header
775             for the I object given as argument. The $request must
776             have a valid url attribute before this method is called.
777              
778             =item $cookie_jar->extract_cookies( $response )
779              
780             The extract_cookies() method will look for Set-Cookie: and
781             Set-Cookie2: headers in the I object passed as
782             argument. Any of these headers that are found are used to update
783             the state of the $cookie_jar.
784              
785             =item $cookie_jar->set_cookie( $version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard, \%rest )
786              
787             The set_cookie() method updates the state of the $cookie_jar. The
788             $key, $val, $domain, $port and $path arguments are strings. The
789             $path_spec, $secure, $discard arguments are boolean values. The $maxage
790             value is a number indicating number of seconds that this cookie will
791             live. A value of $maxage <= 0 will delete this cookie. The $version argument
792             sets the version of the cookie; the default value is 0 ( original Netscape
793             spec ). Setting $version to another value indicates the RFC to which the
794             cookie conforms (e.g. version 1 for RFC 2109). %rest defines various other
795             attributes like "Comment" and "CommentURL".
796              
797             =item $cookie_jar->save
798              
799             =item $cookie_jar->save( $file )
800              
801             =item $cookie_jar->save( file => $file, ignore_discard => $ignore_discard )
802              
803             This method file saves the state of the $cookie_jar to a file.
804             The state can then be restored later using the load() method. If a
805             filename is not specified we will use the name specified during
806             construction. If the $ignore_discard value is true (or not specified,
807             but attribute I was set at cookie jar construction),
808             then we will even save cookies that are marked to be discarded.
809              
810             The default is to save a sequence of "Set-Cookie3" lines.
811             "Set-Cookie3" is a proprietary LWP format, not known to be compatible
812             with any browser. The I sub-class can
813             be used to save in a format compatible with Netscape.
814              
815             =item $cookie_jar->load
816              
817             =item $cookie_jar->load( $file )
818              
819             This method reads the cookies from the file and adds them to the
820             $cookie_jar. The file must be in the format written by the save()
821             method.
822              
823             =item $cookie_jar->revert
824              
825             This method empties the $cookie_jar and re-loads the $cookie_jar
826             from the last save file.
827              
828             =item $cookie_jar->clear
829              
830             =item $cookie_jar->clear( $domain )
831              
832             =item $cookie_jar->clear( $domain, $path )
833              
834             =item $cookie_jar->clear( $domain, $path, $key )
835              
836             Invoking this method without arguments will empty the whole
837             $cookie_jar. If given a single argument only cookies belonging to
838             that domain will be removed. If given two arguments, cookies
839             belonging to the specified path within that domain are removed. If
840             given three arguments, then the cookie with the specified key, path
841             and domain is removed.
842              
843             =item $cookie_jar->clear_temporary_cookies
844              
845             Discard all temporary cookies. Scans for all cookies in the jar
846             with either no expire field or a true C flag. To be
847             called when the user agent shuts down according to RFC 2965.
848              
849             =item $cookie_jar->scan( \&callback )
850              
851             The argument is a subroutine that will be invoked for each cookie
852             stored in the $cookie_jar. The subroutine will be invoked with
853             the following arguments:
854              
855             0 version
856             1 key
857             2 val
858             3 path
859             4 domain
860             5 port
861             6 path_spec
862             7 secure
863             8 expires
864             9 discard
865             10 hash
866              
867             =item $cookie_jar->as_string
868              
869             =item $cookie_jar->as_string( $skip_discardables )
870              
871             The as_string() method will return the state of the $cookie_jar
872             represented as a sequence of "Set-Cookie3" header lines separated by
873             "\n". If $skip_discardables is TRUE, it will not return lines for
874             cookies with the I attribute.
875              
876             =back
877              
878             =head1 SEE ALSO
879              
880             L, L
881              
882             =head1 AUTHOR
883              
884             Gisle Aas
885              
886             =head1 COPYRIGHT AND LICENSE
887              
888             This software is copyright (c) 2002 by Gisle Aas.
889              
890             This is free software; you can redistribute it and/or modify it under
891             the same terms as the Perl 5 programming language system itself.
892              
893             =cut
894              
895             __END__