File Coverage

blib/lib/HTTP/Cookies.pm
Criterion Covered Total %
statement 345 371 92.9
branch 178 218 81.6
condition 57 74 77.0
subroutine 22 23 95.6
pod 12 13 92.3
total 614 699 87.8


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