File Coverage

blib/lib/HTTP/Cookies/PhantomJS.pm
Criterion Covered Total %
statement 121 125 96.8
branch 32 42 76.1
condition 12 19 63.1
subroutine 13 13 100.0
pod 2 2 100.0
total 180 201 89.5


line stmt bran cond sub pod time code
1             package HTTP::Cookies::PhantomJS;
2              
3 1     1   820 use strict;
  1         2  
  1         29  
4 1     1   2077 use HTTP::Cookies;
  1         16882  
  1         31  
5 1     1   1987 use HTTP::Response;
  1         45247  
  1         35  
6 1     1   752 use HTTP::Request;
  1         903  
  1         27  
7 1     1   7 use HTTP::Headers::Util qw/split_header_words join_header_words/;
  1         2  
  1         68  
8 1     1   5 use HTTP::Date qw/time2str/;
  1         2  
  1         68  
9              
10             our @ISA = 'HTTP::Cookies';
11             our $VERSION = '0.02';
12              
13 1     1   6 use constant MAGIC => 'cookies="@Variant(\0\0\0\x7f\0\0\0\x16QList\0\0\0\0\x1';
  1         2  
  1         1534  
14             my %ESCAPES = (
15             'b' => "\b",
16             'f' => "\f",
17             'n' => "\n",
18             'r' => "\r",
19             't' => "\t",
20             '\\' => '\\',
21             );
22              
23             sub _read_length_block {
24 298     298   445 my $str_ref = shift;
25            
26 298         368 my $bytes;
27 298         639 for (1..4) {
28 1192         2090 my $c = substr($$str_ref, 0, 1, '');
29 1192 100       2538 if ($c ne '\\') {
30 107         204 $bytes .= sprintf '%x', ord($c);
31 107         203 next;
32             }
33            
34 1085         1705 $c = substr($$str_ref, 0, 1, '');
35 1085 100       2098 if ($c ne 'x') {
36 892 100       1740 if (exists $ESCAPES{$c}) {
37 4         12 $bytes .= sprintf '%x', ord($ESCAPES{$c});
38             }
39             else {
40 888         2132 $bytes .= sprintf '%x', int $c;
41             }
42 892         1417 next;
43             }
44            
45 193         291 $c = substr($$str_ref, 0, 1, '');
46 193 100       799 if (substr($$str_ref, 0, 1) =~ /[a-f0-9]/) {
47 185         315 $c .= substr($$str_ref, 0, 1, '');
48             }
49 193 50 66     554 if (length($c) == 1 && $bytes && substr($bytes, -2) ne '\0') {
      66        
50             # \0\0\x1\x4 -> 00104
51 8         17 $c = '0'.$c;
52             }
53 193         439 $bytes .= $c;
54             }
55            
56 298         631 hex($bytes);
57             }
58              
59             sub load {
60 3     3 1 1777 my $self = shift;
61 3   100     18 my $file = shift || $self->{'file'} || return;
62            
63 2 50       94 open my $fh, '<', $file or return;
64 2         55 <$fh>; # omit header
65 2         140 my $data = <$fh>;
66 2         112 $data =~ s/\\"/"/g;
67 2         16 close $fh;
68 2 50       13 unless (substr($data, 0, length(MAGIC), '') eq MAGIC) {
69 0         0 warn "$file does not seem to contain cookies";
70 0         0 return;
71             }
72            
73 2         7 my $cnt = _read_length_block(\$data);
74 2         3 my ($len, $cookie, $cookie_str);
75 2         9 for (my $i=0; $i<$cnt; $i++) {
76 296         122160 $len = _read_length_block(\$data);
77 296         615 $cookie_str = substr($data, 0, $len, '');
78            
79             # beginning may be in hex notation
80 296         432 my $additional = 0;
81 296         1016 while ((my $c = substr($cookie_str, $additional, 4)) =~ /\\x[a-f0-9]{2}/) {
82 21         57 substr($cookie_str, $additional, 4) = chr hex substr $c, 2;
83 21         77 $additional++;
84             }
85 296         509 $cookie_str .= substr($data, 0, $additional*3, '');
86            
87 296 50       751 if ($additional = $cookie_str =~ s/\\\\/\\/g) {
88 0         0 $cookie_str .= substr($data, 0, $additional, '');
89             }
90             #print $cookie_str, "\n";
91            
92 296 50       610 unless ($cookie_str) {
93 0         0 warn "Ooops, looks like we can't read cookie. Please report this bug with cookies file attached to author of ".__PACKAGE__;
94             }
95            
96             # properly process quoted values
97             # however anyway it is broken in HTTP::Cookies 6.01 - rt70721
98 296         780 my ($key_val) = split_header_words($cookie_str);
99 296         39382 $key_val = join_header_words($key_val->[0], $key_val->[1]);
100 296         7665 my $tmp = $cookie_str;
101             # value inside key_val may be quoted, but original may be not, so check it
102 296 100       869 substr($tmp, 0, substr($tmp, length($key_val), 1) eq ';' ? length($key_val)+1 : length($key_val)-1) = '';
103 296         910 my @cookie_parts = split ';', $tmp;
104            
105 296         401 my ($domain, $path);
106 296         880 for (my $i=0; $i<@cookie_parts; $i++) {
107 861 50 33     1999 last if $path && $domain;
108 861 100 100     4367 if (!$domain and ($domain) = $cookie_parts[$i] =~ /domain=(.+)/) {
109 296         943 next;
110             }
111 565 50       1123 if (!$path) {
112 565         2719 ($path) = $cookie_parts[$i] =~ /path=(.+)/
113             }
114             }
115            
116             # generate fake request, so we can reuse extract_cookies() method
117 296 100       1558 my $req = HTTP::Request->new(GET => "http://".(substr($domain, 0, 1) eq '.' ? 'www' : '')."$domain$path");
118 296         36136 my $resp = HTTP::Response->new(200, 'OK', ['Set-Cookie', $cookie_str]);
119 296         25428 $resp->request($req);
120            
121 296         2963 $self->extract_cookies($resp);
122             }
123            
124 2         763 1;
125             }
126              
127             sub _generate_length_block {
128 149     149   202 my $length = shift;
129            
130             my $normalize = sub {
131 152     152   231 my $str = shift;
132 152 100       321 return $str if length($str) != 2;
133 149         208 $str =~ s/^0//;
134 149         415 $str;
135 149         410 };
136            
137 149         199 my $bytes;
138 149         286 my $hex = sprintf '%x', $length;
139 149         170 my $part;
140 149         281 for (1..4) {
141 596 100       1507 $bytes = (length($hex) ? '\x'.$normalize->(substr($hex, -2, 2, '')) : '\0'). $bytes;
142             }
143            
144 149         456 $bytes;
145             }
146              
147             sub save {
148 1     1 1 930 my $self = shift;
149 1   0     7 my $file = shift || $self->{'file'} || return;
150 1 50       54 open my $fh, '>', $file or die "Can't open $file: $!";
151            
152 1         3 my $res = MAGIC;
153 1         2 my @cookies;
154            
155             $self->scan(sub {
156 148     148   1817 my ($version,$key,$val,$path,$domain,$port,
157             $path_spec,$secure,$expires,$discard,$rest) = @_;
158            
159 148 50 66     422 return if $discard && !$self->{ignore_discard};
160 148         180 my @cookie_parts;
161            
162 148 100       550 push @cookie_parts, $val =~ /^"/ ? "$key=$val" : join_header_words($key, $val);
163 148 50       3599 push @cookie_parts, 'secure' if $secure;
164 148         274 push @cookie_parts, keys %$rest;
165 148 100       471 push @cookie_parts, 'expires='.time2str($expires) if $expires;
166 148         1488 push @cookie_parts, 'domain='.$domain;
167 148         235 push @cookie_parts, 'path='.$path;
168            
169 148         821 push @cookies, join '; ', @cookie_parts;
170 1         11 });
171            
172 1         16 $res .= _generate_length_block(scalar @cookies);
173 1         3 for my $cookie (@cookies) {
174 148         298 $res .= _generate_length_block(length $cookie);
175 148         269 $cookie =~ s/\\/\\\\/g;
176 148         259 $cookie =~ s/"/\\"/g;
177             # any valid hex symbol at the beginning should be replaced with \x notation
178 148         202 my $i = 0;
179 148         454 while ((my $c = substr($cookie, $i, 1)) =~ /[A-Fa-f0-9]/) {
180 19         54 substr($cookie, $i, 1) = sprintf '\x%x', ord($c);
181 19         73 $i += 4;
182             }
183 148         273 $res .= $cookie;
184             }
185 1         4 $res .= ')"';
186            
187 1         16 print $fh "[General]\n";
188 1         159 print $fh $res, "\n";
189 1         81 close $fh;
190            
191 1         22 1;
192             }
193              
194             1;
195              
196             __END__