File Coverage

blib/lib/HTTP/Cookies/ChromeDevTools.pm
Criterion Covered Total %
statement 21 90 23.3
branch 0 10 0.0
condition 0 6 0.0
subroutine 7 13 53.8
pod 4 5 80.0
total 32 124 25.8


line stmt bran cond sub pod time code
1             package HTTP::Cookies::ChromeDevTools;
2 68     68   519 use strict;
  68         154  
  68         2282  
3 68     68   389 use Carp qw[croak];
  68         157  
  68         4782  
4              
5             our $VERSION = '0.70';
6             our @CARP_NOT;
7              
8 68     68   468 use Moo 2;
  68         1323  
  68         477  
9 68     68   23748 use JSON;
  68         180  
  68         471  
10 68     68   7889 use Filter::signatures;
  68         206  
  68         611  
11 68     68   2361 use feature 'signatures';
  68         225  
  68         5283  
12 68     68   493 no warnings 'experimental::signatures';
  68         193  
  68         60667  
13              
14             extends 'HTTP::Cookies';
15              
16             =head1 NAME
17              
18             HTTP::Cookies::ChromeDevTools - retrieve cookies from a live Chrome instance
19              
20             =head1 SYNOPSIS
21              
22             use HTTP::Cookies::ChromeDevTools;
23             my $cookie_jar = HTTP::Cookies::ChromeDevTools->new();
24             # use just like HTTP::Cookies
25              
26             =head1 DESCRIPTION
27              
28             This package overrides the load() and save() methods of HTTP::Cookies
29             so it can work with a live Chrome instance.
30              
31             =head1 Reusing an existing connection
32              
33             If you already have an existing connection to Chrome
34             that you want to reuse, just pass the L<Chrome::DevToolsProtocol>
35             instance to the cookie jar constructor in the C<driver> parameter:
36              
37             my $cookie_jar = HTTP::Cookies::ChromeDevTools->new(
38             driver => $driver
39             );
40              
41             =cut
42              
43             has 'transport' => (
44             is => 'lazy',
45             default => sub {
46             $ENV{ WWW_MECHANIZE_CHROME_TRANSPORT }
47             },
48             );
49              
50             has 'driver' => (
51             is => 'lazy',
52             default => sub {
53             my( $self ) = @_;
54              
55             # Connect to it
56             Chrome::DevToolsProtocol->new(
57             'port' => $self->{ port },
58             host => $self->{ host },
59             auto_close => 0,
60             error_handler => sub {
61             #warn ref$_[0];
62             #warn "<<@CARP_NOT>>";
63             #warn ((caller($_))[0,1,2])
64             # for 1..4;
65             local @CARP_NOT = (@CARP_NOT, ref $_[0],'Try::Tiny');
66             # Reraise the error
67             croak $_[1]
68             },
69             transport => $self->transport,
70             log => $self->{ log },
71             )
72             },
73             );
74              
75             has '_loading' => (
76             is => 'rw',
77             default => 0,
78             );
79              
80             =head2 C<< ->load( $file, %options ) >>
81              
82             $jar->load( undef, driver => $driver );
83              
84             Loads the cookies from the Chrome instance. Passing in a filename to load
85             cookies from is currently unsupported.
86              
87             =cut
88              
89 0     0 1   sub load($self, $file=undef, %options) {
  0            
  0            
  0            
  0            
90 0   0       my $driver = $options{ driver } || $self->driver;
91             # Alternative: Storage.getCookies
92 0           my $cookies = $driver->send_message('Network.getAllCookies')->get();
93 0           $cookies = $cookies->{cookies};
94 0           $self->clear();
95 0           local $self->{_loading} = 1;
96 0           for my $c (@$cookies) {
97 0 0         if( $c->{expires} == -1 ) {
98 0           $c->{expires} = 1; # we need to do it this way or HTTP::Cookies will discard our cookie immediately :(
99             };
100              
101             $self->set_cookie(
102             1,
103             $c->{name},
104             $c->{value},
105             $c->{path},
106             $c->{domain},
107             undef, # Chrome doesn't support port numbers?!
108             undef,
109             $c->{secure},
110             $c->{expires},
111             #$c->{session},
112             undef,
113 0           );
114             };
115 0 0         if( $file ) {
116 0           my $jar = HTTP::Cookies->new( file => $file );
117 0           $self->load_jar( $jar );
118             };
119             }
120              
121             =head2 C<< ->load_jar( $jar, %options ) >>
122              
123             $jar->load( $jar, replace => 1;
124              
125             Imports the cookies from another cookie jar into Chrome.
126              
127             B<replace> will clear out the cookie jar before loading the fresh cookies.
128              
129             =cut
130              
131 0     0 1   sub load_jar($self, $jar, %options) {
  0            
  0            
  0            
  0            
132 0   0       my $driver = $options{ driver } || $self->driver;
133              
134 0 0         if( $options{ replace }) {
135 0           $driver->send_message('Network.clearBrowserCookies')->get();
136 0           $self->clear();
137             };
138              
139 0           local $self->{_loading} = 0;
140 0     0     $jar->scan( sub(@c) {
  0            
  0            
141 0           my $c = {};
142 0           @{$c}{qw(version name value path domain port path_spec secure expires discard hash)} = @c;
  0            
143             $self->set_cookie(
144             1,
145             $c->{name},
146             $c->{value},
147             $c->{path},
148             $c->{domain},
149             undef, # Chrome doesn't support port numbers
150             undef,
151             $c->{secure},
152             $c->{expires},
153             undef,
154 0           );
155 0           });
156             }
157              
158 0     0 1   sub set_cookie($self, $version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard) {
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
159             # We've just read from Chrome, so just update our local variables
160             #$self->debug_set_cookie($version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard);
161 0           $self->SUPER::set_cookie( $version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard );
162              
163 0 0         if( ! $self->_loading ) {
164             # Update Chrome
165 0           $maxage += time();
166 0           $self
167             ->set_cookie_in_chrome($version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard)
168             ->get();
169             };
170             };
171              
172 0     0 0   sub set_cookie_in_chrome($self, $version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard) {
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
173             # Update Chrome
174 0           my $driver = $self->driver;
175              
176 0           $maxage += time();
177              
178 0 0         $driver->send_message('Network.setCookie',
179             name => $key,
180             value => $val,
181             path => $path,
182             domain => $domain,
183             httpOnly => JSON::false,
184             expires => $maxage,
185             secure => ($secure ? JSON::true : JSON::false),
186             );
187             };
188              
189             sub save {
190 0     0 1   croak 'save is not yet implemented'
191             }
192              
193             1;
194              
195             __END__
196              
197             =head1 SEE ALSO
198              
199             L<HTTP::Cookies> - the interface used
200              
201             L<HTTP::Cookies::Chrome> - offline access to Chrome cookies
202              
203             =head1 REPOSITORY
204              
205             The public repository of this module is
206             L<http://github.com/Corion/www-mechanize-chrome>.
207              
208             =head1 AUTHOR
209              
210             Max Maischein C<corion@cpan.org>
211              
212             =head1 COPYRIGHT (c)
213              
214             Copyright 2009-2023 by Max Maischein C<corion@cpan.org>.
215              
216             =head1 LICENSE
217              
218             This module is released under the same terms as Perl itself.
219              
220             =cut