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   357527 use strict;
  6         65  
  6         208  
4 6     6   3245 use HTTP::Date qw(str2time parse_date time2str);
  6         28961  
  6         414  
5 6     6   2892 use HTTP::Headers::Util qw(_split_header_words join_header_words);
  6         6315  
  6         27235  
6              
7             our $EPOCH_OFFSET;
8             our $VERSION = '6.10';
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 12312 my $class = shift;
22 33         114 my $self = bless {
23             COOKIES => {},
24             }, $class;
25 33         95 my %cnf = @_;
26 33         98 for (keys %cnf) {
27 7         28 $self->{lc($_)} = $cnf{$_};
28             }
29 33         110 $self->load;
30 33         129 $self;
31             }
32              
33              
34             sub add_cookie_header
35             {
36 70     70 1 27739 my $self = shift;
37 70   50     181 my $request = shift || return;
38 70         155 my $url = $request->uri;
39 70         591 my $scheme = $url->scheme;
40 70 100       1399 unless ($scheme =~ /^https?\z/) {
41 3         7 return;
42             }
43              
44 67         174 my $domain = _host($request, $url);
45 67 100       1673 $domain = "$domain.local" unless $domain =~ /\./;
46 67         126 my $secure_request = ($scheme eq "https");
47 67         136 my $req_path = _url_path($url);
48 67         181 my $req_port = $url->port;
49 67         1591 my $now = time();
50 67 100       162 _normalize_path($req_path) if $req_path =~ /%/;
51              
52 67         105 my @cval; # cookie values for the "Cookie" header
53             my $set_ver;
54 67         102 my $netscape_only = 0; # An exact domain match applies to any cookie
55              
56 67         166 while ($domain =~ /\./) {
57             # Checking $domain for cookies"
58 252         453 my $cookies = $self->{COOKIES}{$domain};
59 252 100       495 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         93 my $path;
71 57         212 for $path (sort {length($b) <=> length($a) } keys %$cookies) {
  10         51  
72 67 100       203 if (index($req_path, $path) != 0) {
73 7         16 next;
74             }
75              
76 60         102 my($key,$array);
77 60         87 while (($key,$array) = each %{$cookies->{$path}}) {
  135         468  
78 75         199 my($version,$val,$port,$path_spec,$secure,$expires) = @$array;
79 75 100 100     163 if ($secure && !$secure_request) {
80 1         3 next;
81             }
82 74 50 66     178 if ($expires && $expires < $now) {
83 0         0 next;
84             }
85 74 100       123 if ($port) {
86 7         12 my $found;
87 7 100       24 if ($port =~ s/^_//) {
88             # The corresponding Set-Cookie attribute was empty
89 4 50       13 $found++ if $port eq $req_port;
90 4         6 $port = "";
91             }
92             else {
93 3         5 my $p;
94 3         11 for $p (split(/,/, $port)) {
95 7 100       18 $found++, last if $p eq $req_port;
96             }
97             }
98 7 50       17 unless ($found) {
99 0         0 next;
100             }
101             }
102 74 50 66     213 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       175 if (!$set_ver++) {
110 50 100       131 if ($version >= 1) {
    50          
111 18         47 push(@cval, "\$Version=$version");
112             }
113             elsif (!$self->{hide_cookie2}) {
114 32         86 $request->header(Cookie2 => '$Version="1"');
115             }
116             }
117              
118             # do we need to quote the value
119 74 50 66     2228 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         195 push(@cval, "$key=$val");
126 74 100       174 if ($version >= 1) {
127 31 100       61 push(@cval, qq(\$Path="$path")) if $path_spec;
128 31 100       78 push(@cval, qq(\$Domain="$domain")) if $domain =~ /^\./;
129 31 100       62 if (defined $port) {
130 7         11 my $p = '$Port';
131 7 100       18 $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       619 if ($domain =~ s/^\.+//) {
151 126         308 $netscape_only = 1;
152             }
153             else {
154 126         356 $domain =~ s/[^.]*//;
155 126         350 $netscape_only = 0;
156             }
157             }
158              
159 67 100       147 if (@cval) {
160 50 100       152 if (my $old = $request->header("Cookie")) {
161 2         82 unshift(@cval, $old);
162             }
163 50         2564 $request->header(Cookie => join("; ", @cval));
164 50 100       2491 if (my $hash = $request->{_http_cookies}) {
165 8         42 %$hash = (map split(/=/, $_, 2), @cval);
166             }
167             }
168              
169 67         184 $request;
170             }
171              
172              
173             sub get_cookies
174             {
175 9     9 1 91 my $self = shift;
176 9         14 my $url = shift;
177 9 100       41 $url = "https://$url" unless $url =~ m,^[a-zA-Z][a-zA-Z0-9.+\-]*:,;
178 9         65 require HTTP::Request;
179 9         32 my $req = HTTP::Request->new(GET => $url);
180 9         1043 my $cookies = $req->{_http_cookies} = {};
181 9         22 $self->add_cookie_header($req);
182 9 100       20 if (@_) {
183 8 100       24 return map $cookies->{$_}, @_ if wantarray;
184 7         52 return $cookies->{$_[0]};
185             }
186 1         11 return $cookies;
187             }
188              
189              
190             sub extract_cookies
191             {
192 70     70 1 65173 my $self = shift;
193 70   50     182 my $response = shift || return;
194              
195 70         213 my @set = _split_header_words($response->_header("Set-Cookie2"));
196 70         4816 my @ns_set = $response->_header("Set-Cookie");
197              
198 70 100 100     2387 return $response unless @set || @ns_set; # quick exit
199              
200 63         187 my $request = $response->request;
201 63         677 my $url = $request->uri;
202 63         550 my $req_host = _host($request, $url);
203 63 100       1612 $req_host = "$req_host.local" unless $req_host =~ /\./;
204 63         170 my $req_port = $url->port;
205 63         1864 my $req_path = _url_path($url);
206 63 100       160 _normalize_path($req_path) if $req_path =~ /%/;
207              
208 63 100       134 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         58 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         48 my %in_set2;
219 33         69 for (@set) {
220 2         8 $in_set2{$_->[0]}++;
221             }
222              
223 33         46 my $set;
224 33         54 for $set (@ns_set) {
225 43         96 $set =~ s/^\s+//;
226 43         99 my @cur;
227             my $param;
228 43         0 my $expires;
229 43         65 my $first_param = 1;
230 43         58 for $param (@{_split_text($set)}) {
  43         88  
231 108 100       217 next unless length($param);
232 107         391 my($k,$v) = split(/\s*=\s*/, $param, 2);
233 107 100       215 if (defined $v) {
234 105         198 $v =~ s/\s+$//;
235             #print "$k => $v\n";
236             }
237             else {
238 2         5 $k =~ s/\s+$//;
239             #print "$k => undef";
240             }
241 107 100 100     582 if (!$first_param && lc($k) eq "expires") {
    100 100        
    100 100        
242 14         50 my $etime = str2time($v);
243 14 100       1396 if (defined $etime) {
244 12         35 push(@cur, "Max-Age" => $etime - $now);
245 12         40 $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       62 if ($year) {
251 2         12 my $thisyear = (gmtime)[5] + 1900;
252 2 50       7 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) 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         184 push(@cur, $k => $v);
273             }
274 107         197 $first_param = 0;
275             }
276 43 100       114 next unless @cur;
277 42 100       104 next if $in_set2{$cur[0]};
278              
279             # push(@cur, "Port" => $req_port);
280 41 100       114 push(@cur, "Discard" => undef) unless $expires;
281 41         87 push(@cur, "Version" => 0);
282 41         69 push(@cur, "ns-cookie" => 1);
283 41         118 push(@set, \@cur);
284             }
285             }
286              
287             SET_COOKIE:
288 63         121 for my $set (@set) {
289 77 50       168 next unless @$set >= 2;
290              
291 77         136 my $key = shift @$set;
292 77         122 my $val = shift @$set;
293              
294 77         104 my %hash;
295 77         181 while (@$set) {
296 236         350 my $k = shift @$set;
297 236         364 my $v = shift @$set;
298 236         384 my $lc = lc($k);
299             # don't loose case distinction for unknown fields
300 236 100       783 $k = $lc if $lc =~ /^(?:discard|domain|max-age|
301             path|port|secure|version)$/x;
302 236 100 100     759 if ($k eq "discard" || $k eq "secure") {
303 33 50       80 $v = 1 unless defined $v;
304             }
305 236 50       446 next if exists $hash{$k}; # only first value is significant
306 236         913 $hash{$k} = $v;
307             };
308              
309 77         329 my %orig_hash = %hash;
310 77         175 my $version = delete $hash{version};
311 77 100       161 $version = 1 unless defined($version);
312 77         131 my $discard = delete $hash{discard};
313 77         106 my $secure = delete $hash{secure};
314 77         115 my $maxage = delete $hash{'max-age'};
315 77         108 my $ns_cookie = delete $hash{'ns-cookie'};
316              
317             # Check domain
318 77         101 my $domain = delete $hash{domain};
319 77 100       155 $domain = lc($domain) if defined $domain;
320 77 100 100     263 if (defined($domain)
      100        
321             && $domain ne $req_host && $domain ne ".$req_host") {
322 17 50 33     53 if ($domain !~ /\./ && $domain ne "local") {
323 0         0 next SET_COOKIE;
324             }
325 17 100       47 $domain = ".$domain" unless $domain =~ /^\./;
326 17 100       56 if ($domain =~ /\.\d+$/) {
327 1         5 next SET_COOKIE;
328             }
329 16         27 my $len = length($domain);
330 16 50       45 unless (substr($req_host, -$len) eq $domain) {
331 0         0 next SET_COOKIE;
332             }
333 16         34 my $hostpre = substr($req_host, 0, length($req_host) - $len);
334 16 100 100     46 if ($hostpre =~ /\./ && !$ns_cookie) {
335 2         8 next SET_COOKIE;
336             }
337             }
338             else {
339 60         104 $domain = $req_host;
340             }
341              
342 74         112 my $path = delete $hash{path};
343 74         106 my $path_spec;
344 74 100 100     246 if (defined $path && $path ne '') {
345 49         77 $path_spec++;
346 49 100       122 _normalize_path($path) if $path =~ /%/;
347 49 100 100     171 if (!$ns_cookie &&
348             substr($req_path, 0, length($path)) ne $path) {
349 4         16 next SET_COOKIE;
350             }
351             }
352             else {
353 25         50 $path = $req_path;
354 25         99 $path =~ s,/[^/]*$,,;
355 25 100       75 $path = "/" unless length($path);
356             }
357              
358 70         88 my $port;
359 70 100       147 if (exists $hash{port}) {
360 5         9 $port = delete $hash{port};
361 5 100       11 if (defined $port) {
362 3         8 $port =~ s/\s+//g;
363 3         6 my $found;
364 3         42 for my $p (split(/,/, $port)) {
365 7 50       24 unless ($p =~ /^\d+$/) {
366 0         0 next SET_COOKIE;
367             }
368 7 100       18 $found++ if $p eq $req_port;
369             }
370 3 100       8 unless ($found) {
371 1         6 next SET_COOKIE;
372             }
373             }
374             else {
375 2         6 $port = "_$req_port";
376             }
377             }
378 69 50       204 $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         192 $response;
383             }
384              
385             sub set_cookie_ok
386             {
387 69     69 0 238 1;
388             }
389              
390              
391             sub set_cookie
392             {
393 78     78 1 125 my $self = shift;
394 78         226 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     585 return $self if !defined($path) || $path !~ m,^/, ||
      33        
400             !defined($key) || $key =~ m,^\$,;
401              
402             # ensure legal port
403 78 100       169 if (defined $port) {
404 4 50       29 return $self unless $port =~ /^_?\d+(?:,\d+)*$/;
405             }
406              
407 78         96 my $expires;
408 78 100       153 if (defined $maxage) {
409 27 100       65 if ($maxage <= 0) {
410 8         18 delete $self->{COOKIES}{$domain}{$path}{$key};
411 8         27 return $self;
412             }
413 19         37 $expires = time() + $maxage;
414             }
415 70 100       133 $version = 0 unless defined $version;
416              
417 70         186 my @array = ($version, $val,$port,
418             $path_spec,
419             $secure, $expires, $discard);
420 70 100 100     242 push(@array, {%$rest}) if defined($rest) && %$rest;
421             # trim off undefined values at end
422 70         213 pop(@array) while !defined $array[-1];
423              
424 70         262 $self->{COOKIES}{$domain}{$path}{$key} = \@array;
425 70         311 $self;
426             }
427              
428              
429             sub save
430             {
431 2     2 1 124 my $self = shift;
432             my %args = (
433             file => $self->{'file'},
434 2 100       18 ignore_discard => $self->{'ignore_discard'},
435             @_ == 1 ? ( file => $_[0] ) : @_
436             );
437 2 50       11 Carp::croak('Unexpected argument to save method') if keys %args > 2;
438 2   50     8 my $file = $args{'file'} || return;
439 2 50       345 open(my $fh, '>', $file) or die "Can't open $file: $!";
440 2         8 print {$fh} "#LWP-Cookies-1.0\n";
  2         53  
441 2         8 print {$fh} $self->as_string(!$args{'ignore_discard'});
  2         12  
442 2 50       1130 close $fh or die "Can't close $file: $!";
443 2         21 1;
444             }
445              
446              
447             sub load
448             {
449 30     30 1 55 my $self = shift;
450 30   50     186 my $file = shift || $self->{'file'} || return;
451              
452 2         11 local $/ = "\n"; # make sure we got standard record separator
453 2 50       87 open(my $fh, '<', $file) or return;
454              
455             # check that we have the proper header
456 2         62 my $magic = <$fh>;
457 2         8 chomp $magic;
458 2 50       17 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         10 while (my $line = <$fh>) {
465 7         11 chomp $line;
466 7 50       39 next unless $line =~ s/^Set-Cookie3:\s*//;
467 7         11 my $cookie;
468 7         19 for $cookie (_split_header_words($line)) {
469 7         686 my($key,$val) = splice(@$cookie, 0, 2);
470 7         11 my %hash;
471 7         19 while (@$cookie) {
472 29         43 my $k = shift @$cookie;
473 29         42 my $v = shift @$cookie;
474 29         70 $hash{$k} = $v;
475             }
476 7         14 my $version = delete $hash{version};
477 7         11 my $path = delete $hash{path};
478 7         13 my $domain = delete $hash{domain};
479 7         12 my $port = delete $hash{port};
480 7         22 my $expires = str2time(delete $hash{expires});
481              
482 7         325 my $path_spec = exists $hash{path_spec}; delete $hash{path_spec};
  7         12  
483 7         10 my $secure = exists $hash{secure}; delete $hash{secure};
  7         10  
484 7         9 my $discard = exists $hash{discard}; delete $hash{discard};
  7         10  
485              
486 7         22 my @array = ($version, $val, $port, $path_spec, $secure, $expires,
487             $discard);
488 7 100       16 push(@array, \%hash) if %hash;
489 7         65 $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 2576 my $self = shift;
507 5 50       25 if (@_ == 0) {
    0          
    0          
    0          
508 5         30 $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         12 $self;
524             }
525              
526              
527             sub clear_temporary_cookies
528             {
529 2     2 1 153 my($self) = @_;
530              
531             $self->scan(sub {
532 6 100 66 6   27 if($_[9] or # "Discard" flag set
533             not $_[8]) { # No expire field?
534 3         4 $_[8] = -1; # Set the expire/max_age field
535 3         7 $self->set_cookie(@_); # Clear the cookie
536             }
537 2         14 });
538             }
539              
540              
541             sub DESTROY
542             {
543 29     29   1692 my $self = shift;
544 29         224 local($., $@, $!, $^E, $?);
545 29 50       553 $self->save if $self->{'autosave'};
546             }
547              
548              
549             sub scan
550             {
551 60     60 1 627 my($self, $cb) = @_;
552 60         144 my($domain,$path,$key);
553 60         103 for $domain (sort keys %{$self->{COOKIES}}) {
  60         255  
554 90         936 for $path (sort keys %{$self->{COOKIES}{$domain}}) {
  90         261  
555 110         596 for $key (sort keys %{$self->{COOKIES}{$domain}{$path}}) {
  110         274  
556             my($version,$val,$port,$path_spec,
557             $secure,$expires,$discard,$rest) =
558 134         753 @{$self->{COOKIES}{$domain}{$path}{$key}};
  134         377  
559 134 100       381 $rest = {} unless defined($rest);
560 134         310 &$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 1082 my($self, $skip_discard) = @_;
571 23         33 my @res;
572             $self->scan(sub {
573 49     49   154 my($version,$key,$val,$path,$domain,$port,
574             $path_spec,$secure,$expires,$discard,$rest) = @_;
575 49 50 66     152 return if $discard && $skip_discard;
576 49         109 my @h = ($key, $val);
577 49         84 push(@h, "path", $path);
578 49         91 push(@h, "domain" => $domain);
579 49 100       100 push(@h, "port" => $port) if defined $port;
580 49 100       94 push(@h, "path_spec" => undef) if $path_spec;
581 49 50       80 push(@h, "secure" => undef) if $secure;
582 49 100       108 push(@h, "expires" => HTTP::Date::time2isoz($expires)) if $expires;
583 49 100       278 push(@h, "discard" => undef) if $discard;
584 49         70 my $k;
585 49         126 for $k (sort keys %$rest) {
586 3         7 push(@h, $k, $rest->{$k});
587             }
588 49         121 push(@h, "version" => $version);
589 49         135 push(@res, "Set-Cookie3: " . join_header_words(\@h));
590 23         185 });
591 23         2077 join("\n", @res, "");
592             }
593              
594             sub _host
595             {
596 130     130   282 my($request, $url) = @_;
597 130 100       339 if (my $h = $request->header("Host")) {
598 32         1486 $h =~ s/:\d+$//; # might have a port as well
599 32         116 return lc($h);
600             }
601 98         4193 return lc($url->host);
602             }
603              
604             sub _url_path
605             {
606 130     130   201 my $url = shift;
607 130         165 my $path;
608 130 50       479 if($url->can('epath')) {
609 0         0 $path = $url->epath; # URI::URL method
610             }
611             else {
612 130         461 $path = $url->path; # URI::_generic method
613             }
614 130 100       1447 $path = "/" unless length $path;
615 130         252 $path;
616             }
617              
618             sub _normalize_path # so that plain string compare can be used
619             {
620 6     6   12 my $x;
621 6         23 $_[0] =~ s/%([0-9a-fA-F][0-9a-fA-F])/
622 35         84 $x = uc($1);
623 35 100 100     166 $x eq "2F" || $x eq "25" ? "%$x" :
624             pack("C", hex($x));
625             /eg;
626 6         23 $_[0] =~ s/([\0-\x20\x7f-\xff])/sprintf("%%%02X",ord($1))/eg;
  21         72  
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   70 my $val = shift;
633 45         232 my @vals = grep { $_ ne q{} } split(/([;\\"])/, $val);
  217         463  
634 45         79 my @chunks;
635             # divide it up into chunks to be processed.
636 45         63 my $in_string = 0;
637 45         74 my @current_string;
638 45         130 for(my $i = 0; $i < @vals; $i++) {
639 206         291 my $chunk = $vals[$i];
640 206 100       329 if($in_string) {
641 18 100       57 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       5 if($i < @vals) {
647 2         5 push @current_string, $vals[$i];
648             }
649             } elsif($chunk eq q{"}) {
650 4         11 $in_string = 0;
651             }
652             else {
653 12         26 push @current_string, $chunk;
654             }
655             } else {
656 188 100       366 if($chunk eq q{"}) {
    100          
657 4         10 $in_string = 1;
658             }
659             elsif($chunk eq q{;}) {
660 72         167 push @chunks, join(q{}, @current_string);
661 72         165 @current_string = ();
662             }
663             else {
664 112         279 push @current_string, $chunk;
665             }
666             }
667             }
668 45 100       140 push @chunks, join(q{}, @current_string) if @current_string;
669 45         225 s/^\s+// for @chunks;
670 45         158 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.10
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 file 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__