File Coverage

blib/lib/WWW/Mechanize.pm
Criterion Covered Total %
statement 840 876 95.8
branch 426 492 86.5
condition 227 264 85.9
subroutine 104 107 97.2
pod 75 75 100.0
total 1672 1814 92.1


line stmt bran cond sub pod time code
1             package WWW::Mechanize;
2              
3             #ABSTRACT: Handy web browsing in a Perl object
4              
5              
6 57     57   5059099 use strict;
  57         441  
  57         1471  
7 57     57   265 use warnings;
  57         93  
  57         2080  
8              
9             our $VERSION = '2.15';
10              
11 57     57   22882 use Tie::RefHash ();
  57         162813  
  57         1472  
12 57     57   15144 use HTTP::Request 1.30 ();
  57         516526  
  57         1562  
13 57     57   29061 use HTML::Form 1.00 ();
  57         862536  
  57         1454  
14 57     57   25515 use HTML::TokeParser ();
  57         498994  
  57         1539  
15 57     57   383 use Scalar::Util qw( tainted );
  57         120  
  57         2992  
16              
17 57     57   326 use base 'LWP::UserAgent';
  57         112  
  57         25355  
18              
19             our $HAS_ZLIB;
20             BEGIN {
21 57     57   950980 $HAS_ZLIB = eval {require Compress::Zlib; 1;};
  57         30494  
  57         3576790  
22             }
23              
24              
25             sub new {
26 75     75 1 3229352 my $class = shift;
27              
28 75         1253 my %parent_params = (
29             agent => "WWW-Mechanize/$VERSION",
30             cookie_jar => {},
31             );
32              
33 75 50       1954 my %mech_params = (
34             autocheck => ($class eq 'WWW::Mechanize' ? 1 : 0),
35             onwarn => \&WWW::Mechanize::_warn,
36             onerror => \&WWW::Mechanize::_die,
37             quiet => 0,
38             stack_depth => 8675309, # Arbitrarily humongous stack
39             headers => {},
40             noproxy => 0,
41             strict_forms => 0, # pass-through to HTML::Form
42             verbose_forms => 0, # pass-through to HTML::Form
43             marked_sections => 1,
44             );
45              
46 75         307 my %passed_params = @_;
47              
48             # Keep the mech-specific params before creating the object.
49 75         585 while ( my($key,$value) = each %passed_params ) {
50 60 100       203 if ( exists $mech_params{$key} ) {
51 19         97 $mech_params{$key} = $value;
52             }
53             else {
54 41         161 $parent_params{$key} = $value;
55             }
56             }
57              
58 75         1171 my $self = $class->SUPER::new( %parent_params );
59 75         344286 bless $self, $class;
60              
61             # Use the mech params now that we have a mech object.
62 75         489 for my $param ( keys %mech_params ) {
63 750         1231 $self->{$param} = $mech_params{$param};
64             }
65 75         322 $self->{page_stack} = [];
66 75 50       1012 $self->env_proxy() unless $mech_params{noproxy};
67              
68             # libwww-perl 5.800 (and before, I assume) has a problem where
69             # $ua->{proxy} can be undef and clone() doesn't handle it.
70 75 50       151967 $self->{proxy} = {} unless defined $self->{proxy};
71 75         161 push( @{$self->requests_redirectable}, 'POST' );
  75         644  
72              
73 75         1835 $self->_reset_page();
74              
75 75         601 return $self;
76             }
77              
78             # overriding LWP::UA's static method
79 1     1   2198 sub _agent { "WWW-Mechanize/$VERSION" }
80              
81              
82             my %known_agents = (
83             'Windows IE 6' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
84             'Windows Mozilla' => 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6',
85             'Mac Safari' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85 (KHTML, like Gecko) Safari/85',
86             'Mac Mozilla' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401',
87             'Linux Mozilla' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624',
88             'Linux Konqueror' => 'Mozilla/5.0 (compatible; Konqueror/3; Linux)',
89             );
90              
91             sub agent_alias {
92 2     2 1 1620 my $self = shift;
93 2         4 my $alias = shift;
94              
95 2 100       8 if ( defined $known_agents{$alias} ) {
96 1         3 return $self->agent( $known_agents{$alias} );
97             }
98             else {
99 1         5 $self->warn( qq{Unknown agent alias "$alias"} );
100 1         694 return $self->agent();
101             }
102             }
103              
104              
105             sub known_agent_aliases {
106 1     1 1 146 my @aliases = sort keys %known_agents;
107 1         18 return @aliases;
108             }
109              
110              
111             sub get {
112 140     140 1 1631859 my $self = shift;
113 140         502 my $uri = shift;
114              
115 140 50       774 $uri = $uri->url if ref($uri) eq 'WWW::Mechanize::Link';
116              
117 140 100       1057 $uri = $self->base
118             ? URI->new_abs( $uri, $self->base )
119             : URI->new( $uri );
120              
121             # It appears we are returning a super-class method,
122             # but it in turn calls the request() method here in Mechanize
123 140         39769 return $self->SUPER::get( $uri->as_string, @_ );
124             }
125              
126              
127             sub post {
128 1     1 1 463 my $self = shift;
129 1         2 my $uri = shift;
130              
131 1 50       5 $uri = $uri->url if ref($uri) eq 'WWW::Mechanize::Link';
132              
133 1 50       3 $uri = $self->base
134             ? URI->new_abs( $uri, $self->base )
135             : URI->new( $uri );
136              
137             # It appears we are returning a super-class method,
138             # but it in turn calls the request() method here in Mechanize
139 1         231 return $self->SUPER::post( $uri->as_string, @_ );
140             }
141              
142              
143             sub put {
144 0     0 1 0 my $self = shift;
145 0         0 my $uri = shift;
146              
147 0 0       0 $uri = $uri->url if ref($uri) eq 'WWW::Mechanize::Link';
148              
149 0 0       0 $uri = $self->base
150             ? URI->new_abs( $uri, $self->base )
151             : URI->new( $uri );
152              
153             # It appears we are returning a super-class method,
154             # but it in turn calls the request() method here in Mechanize
155 0         0 return $self->_SUPER_put( $uri->as_string, @_ );
156             }
157              
158              
159             # Added until LWP::UserAgent has it.
160             sub _SUPER_put {
161 0     0   0 require HTTP::Request::Common;
162 0         0 my($self, @parameters) = @_;
163 0         0 my @suff = $self->_process_colonic_headers(\@parameters,1);
164 0         0 return $self->request( HTTP::Request::Common::PUT( @parameters ), @suff );
165             }
166              
167              
168             sub head {
169 2     2 1 84 my $self = shift;
170 2         4 my $uri = shift;
171              
172 2 50       9 $uri = $uri->url if ref($uri) eq 'WWW::Mechanize::Link';
173              
174 2 50       8 $uri = $self->base
175             ? URI->new_abs( $uri, $self->base )
176             : URI->new( $uri );
177              
178             # It appears we are returning a super-class method,
179             # but it in turn calls the request() method here in Mechanize
180 2         415 return $self->SUPER::head( $uri->as_string, @_ );
181             }
182              
183              
184             sub reload {
185 4     4 1 858 my $self = shift;
186              
187 4 100       15 return unless my $req = $self->{req};
188              
189             # LWP::UserAgent sets up a request_prepare handler that calls
190             # $self->cookie_jar->add_cookie_header($req)
191             #
192             # HTTP::Cookies::add_cookie_header always preserves existing
193             # cookies in a request object
194             #
195             # we pass an existing request to _make_request
196             #
197             # result: cookies will get repeated every time someone calls
198             # ->reload, sooner or later leading to a "request too big" from
199             # the server
200             #
201             # until https://rt.cpan.org/Public/Bug/Display.html?id=75897 is
202             # fixed, let's clear the cookies from the existing request
203 3         26 $req->remove_header('Cookie');
204              
205 3         115 return $self->_update_page( $req, $self->_make_request( $req, @_ ) );
206             }
207              
208              
209             sub back {
210 27     27 1 128739 my $self = shift;
211              
212 27         84 my $stack = $self->{page_stack};
213 27 100 100     238 return unless $stack && @{$stack};
  26         172  
214              
215 24         51 my $popped = pop @{$self->{page_stack}};
  24         72  
216 24         58 my $req = $popped->{req};
217 24         60 my $res = $popped->{res};
218              
219 24         89 $self->_update_page( $req, $res );
220              
221 24         173 return 1;
222             }
223              
224              
225             sub clear_history {
226 1     1 1 1765 my $self = shift;
227              
228 1         14 delete $self->{page_stack};
229              
230 1         3 return 1;
231             }
232              
233              
234             sub history_count {
235 15     15 1 2424 my $self = shift;
236              
237             # If we don't have a "current" page, we certainly don't have any previous
238             # ones.
239 15 100 66     103 return 0 unless $self->{req} && $self->{res};
240              
241 14         28 my $stack = $self->{page_stack};
242              
243 14 100       31 return 1 unless $stack;
244              
245 13         66 return 1 + @$stack;
246             }
247              
248              
249             sub history {
250 10     10 1 1833 my $self = shift;
251 10         63 my $n = shift;
252              
253 10 100 66     83 return undef unless $self->{req} && $self->{res};
254              
255 9 100       29 if ($n == 0) {
256 8         72 return { req => $self->{req}, res => $self->{res} };
257             }
258              
259 1         4 my $stack = $self->{page_stack};
260 1 50 33     15 return undef unless $stack && @$stack >= $n;
261              
262 0         0 return { req => $stack->[-$n]{req}, res => $stack->[-$n]{res} };
263             }
264              
265              
266             sub success {
267 60     60 1 2670 my $self = shift;
268              
269 60   100     256 return $self->res && $self->res->is_success;
270             }
271              
272              
273              
274             sub uri {
275 51     51 1 29645 my $self = shift;
276 51 100       167 return $self->response ? $self->response->request->uri : undef;
277             }
278              
279 123     123 1 1876 sub res { my $self = shift; return $self->{res}; }
  123         742  
280 112     112 1 744 sub response { my $self = shift; return $self->{res}; }
  112         453  
281 11     11 1 78 sub status { my $self = shift; return $self->{status}; }
  11         99  
282 731     731 1 1345 sub ct { my $self = shift; return $self->{ct}; }
  731         3734  
283 5     5 1 15 sub content_type { my $self = shift; return $self->{ct}; }
  5         45  
284 537     537 1 3442 sub base { my $self = shift; return $self->{base}; }
  537         3470  
285             sub is_html {
286 351     351 1 10231 my $self = shift;
287 351   66     945 return defined $self->ct &&
288             ($self->ct eq 'text/html' || $self->ct eq 'application/xhtml+xml');
289             }
290              
291              
292             sub title {
293 23     23 1 4989 my $self = shift;
294              
295 23 100       62 return unless $self->is_html;
296              
297 21 100       80 if ( not defined $self->{title} ) {
298 20         211 require HTML::HeadParser;
299 20         125 my $p = HTML::HeadParser->new;
300 20         1977 $p->parse($self->content);
301 20         3467 $self->{title} = $p->header('Title');
302             }
303 21         1064 return $self->{title};
304             }
305              
306              
307             sub redirects {
308 2     2 1 10 my $self = shift;
309              
310 2         7 return $self->response->redirects;
311             }
312              
313              
314             sub content {
315 119     119 1 30388 my $self = shift;
316 119         295 my %params = @_;
317              
318 119         327 my $content = $self->{content};
319 119 100       792 if (delete $params{raw}) {
    100          
    100          
    100          
320 1         5 $content = $self->response()->content();
321             }
322             elsif (delete $params{decoded_by_headers}) {
323 2         80 $content = $self->response()->decoded_content(charset => 'none');
324             }
325             elsif (my $charset = delete $params{charset}) {
326 1         4 $content = $self->response()->decoded_content(charset => $charset);
327             }
328             elsif ( $self->is_html ) {
329 106 100       414 if ( exists $params{base_href} ) {
330 2   66     9 my $base_href = (delete $params{base_href}) || $self->base;
331 2         18 $content=~s//\n/i;
332             }
333              
334 106 100       333 if ( my $format = delete $params{format} ) {
335 2 100       8 if ( $format eq 'text' ) {
336 1         5 $content = $self->text;
337             }
338             else {
339 1         8 $self->die( qq{Unknown "format" parameter "$format"} );
340             }
341             }
342              
343 105         477 $self->_check_unhandled_params( %params );
344             }
345              
346 117         999 return $content;
347             }
348              
349              
350             sub text {
351 3     3 1 8 my $self = shift;
352              
353 3 100       17 if ( not defined $self->{text} ) {
354 2 50       16 unless ( exists $INC{'HTML::TreeBuilder'} ) {
355 2         831 require HTML::TreeBuilder;
356 2         20792 HTML::TreeBuilder->VERSION(5);
357 2         12 HTML::TreeBuilder->import('-weak');
358             }
359 2         75 my $tree = HTML::TreeBuilder->new();
360 2         563 $tree->parse( $self->content );
361 2         5312 $tree->eof();
362 2         460 $tree->elementify(); # just for safety
363 2         142 $self->{text} = $tree->as_text();
364             }
365              
366 3         226 return $self->{text};
367             }
368              
369             sub _check_unhandled_params {
370 105     105   228 my $self = shift;
371 105         258 my %params = @_;
372              
373 105         561 for my $cmd ( sort keys %params ) {
374 1         6 $self->die( qq{Unknown named argument "$cmd"} );
375             }
376             }
377              
378              
379             sub links {
380 80     80 1 3468 my $self = shift;
381              
382 80 100       316 $self->_extract_links() unless $self->{links};
383              
384 80 50       188 return @{$self->{links}} if wantarray;
  80         333  
385 0         0 return $self->{links};
386             }
387              
388              
389             sub follow_link {
390 16     16 1 17881 my $self = shift;
391 16 100       104 $self->die( qq{Needs to get key-value pairs of parameters.} ) if @_ % 2;
392 15         92 my %params = ( n=>1, @_ );
393              
394 15 50       60 if ( $params{n} eq 'all' ) {
395 0         0 delete $params{n};
396 0         0 $self->warn( q{follow_link(n=>"all") is not valid} );
397             }
398              
399 15         64 my $link = $self->find_link(%params);
400 15 100       50 if ( $link ) {
401 10         34 return $self->get( $link->url );
402             }
403              
404 5 100       13 if ( $self->{autocheck} ) {
405 1         3 $self->die( 'Link not found' );
406             }
407              
408 4         37 return;
409             }
410              
411              
412             sub find_link {
413 73     73 1 22703 my $self = shift;
414 73         316 my %params = ( n=>1, @_ );
415              
416 73         194 my $wantall = ( $params{n} eq 'all' );
417              
418 73         420 $self->_clean_keys( \%params, qr/^(n|(text|url|url_abs|name|tag|id|class|rel)(_regex)?)$/ );
419              
420 73 100       272 my @links = $self->links or return;
421              
422 70         114 my $nmatches = 0;
423 70         88 my @matches;
424 70         176 for my $link ( @links ) {
425 570 100       6480 if ( _match_any_link_params($link,\%params) ) {
426 107 100       234 if ( $wantall ) {
427 23         52 push( @matches, $link );
428             }
429             else {
430 84         109 ++$nmatches;
431 84 100       325 return $link if $nmatches >= $params{n};
432             }
433             }
434             } # for @links
435              
436 15 100       126 if ( $wantall ) {
437 6 100       46 return @matches if wantarray;
438 2         10 return \@matches;
439             }
440              
441 9         34 return;
442             } # find_link
443              
444             # Used by find_links to check for matches
445             # The logic is such that ALL param criteria that are given must match
446             sub _match_any_link_params {
447 570     570   661 my $link = shift;
448 570         583 my $p = shift;
449              
450             # No conditions, anything matches
451 570 50       924 return 1 unless keys %$p;
452              
453 570 100 100     1154 return if defined $p->{url} && !($link->url eq $p->{url} );
454 477 100 100     951 return if defined $p->{url_regex} && !($link->url =~ $p->{url_regex} );
455 414 100 66     745 return if defined $p->{url_abs} && !($link->url_abs eq $p->{url_abs} );
456 388 100 100     665 return if defined $p->{url_abs_regex} && !($link->url_abs =~ $p->{url_abs_regex} );
457 364 100 100     972 return if defined $p->{text} && !(defined($link->text) && $link->text eq $p->{text} );
      100        
458 297 100 100     645 return if defined $p->{text_regex} && !(defined($link->text) && $link->text =~ $p->{text_regex} );
      100        
459 152 100 66     368 return if defined $p->{name} && !(defined($link->name) && $link->name eq $p->{name} );
      100        
460 143 100 100     278 return if defined $p->{name_regex} && !(defined($link->name) && $link->name =~ $p->{name_regex} );
      100        
461 128 100 66     379 return if defined $p->{tag} && !($link->tag && $link->tag eq $p->{tag} );
      100        
462 124 100 66     246 return if defined $p->{tag_regex} && !($link->tag && $link->tag =~ $p->{tag_regex} );
      100        
463              
464 120 100 66     274 return if defined $p->{id} && !($link->attrs->{id} && $link->attrs->{id} eq $p->{id} );
      100        
465 117 100 66     230 return if defined $p->{id_regex} && !($link->attrs->{id} && $link->attrs->{id} =~ $p->{id_regex} );
      100        
466 114 100 66     225 return if defined $p->{class} && !($link->attrs->{class} && $link->attrs->{class} eq $p->{class} );
      100        
467 113 100 66     215 return if defined $p->{class_regex} && !($link->attrs->{class} && $link->attrs->{class} =~ $p->{class_regex} );
      100        
468              
469 112 100 100     215 return if defined $p->{rel} && !($link->attrs->{rel} && $link->attrs->{rel} eq $p->{rel} );
      100        
470 109 100 66     200 return if defined $p->{rel_regex} && !($link->attrs->{rel} && $link->attrs->{rel} =~ $p->{rel_regex} );
      100        
471              
472             # Success: everything that was defined passed.
473 107         249 return 1;
474              
475             }
476              
477             # Cleans the %params parameter for the find_link and find_image methods.
478             sub _clean_keys {
479 123     123   183 my $self = shift;
480 123         150 my $params = shift;
481 123         142 my $rx_keyname = shift;
482              
483 123         361 for my $key ( keys %$params ) {
484 237         380 my $val = $params->{$key};
485 237 100       2091 if ( $key !~ qr/$rx_keyname/ ) {
486 5         31 $self->warn( qq{Unknown link-finding parameter "$key"} );
487 5         3472 delete $params->{$key};
488 5         16 next;
489             }
490              
491 232         603 my $key_regex = ( $key =~ /_regex$/ );
492 232         350 my $val_regex = ( ref($val) eq 'Regexp' );
493              
494 232 100       416 if ( $key_regex ) {
495 49 100       135 if ( !$val_regex ) {
496 6         29 $self->warn( qq{$val passed as $key is not a regex} );
497 6         2968 delete $params->{$key};
498 6         14 next;
499             }
500             }
501             else {
502 183 100       347 if ( $val_regex ) {
503 5         26 $self->warn( qq{$val passed as '$key' is a regex} );
504 5         2561 delete $params->{$key};
505 5         13 next;
506             }
507 178 100       715 if ( $val =~ /^\s|\s$/ ) {
508 5         32 $self->warn( qq{'$val' is space-padded and cannot succeed} );
509 5         2479 delete $params->{$key};
510 5         11 next;
511             }
512             }
513             } # for keys %params
514              
515 123         279 return;
516             } # _clean_keys()
517              
518              
519              
520             sub find_all_links {
521 6     6 1 5269 my $self = shift;
522 6         22 return $self->find_link( @_, n=>'all' );
523             }
524              
525              
526             sub find_all_inputs {
527 8     8 1 2827 my $self = shift;
528 8         27 my %criteria = @_;
529              
530 8 50       29 my $form = $self->current_form() or return;
531              
532 8         10 my @found;
533 8         22 foreach my $input ( $form->inputs ) { # check every pattern for a match on the current hash
534 34         81 my $matched = 1;
535 34         98 foreach my $criterion ( sort keys %criteria ) { # Sort so we're deterministic
536 22         25 my $field = $criterion;
537 22         58 my $is_regex = ( $field =~ s/(?:_regex)$// );
538 22         46 my $what = $input->{$field};
539             $matched = defined($what) && (
540             $is_regex
541             ? ( $what =~ $criteria{$criterion} )
542 22   66     118 : ( $what eq $criteria{$criterion} )
543             );
544 22 100       52 last if !$matched;
545             }
546 34 100       68 push @found, $input if $matched;
547             }
548 8         47 return @found;
549             }
550              
551              
552             sub find_all_submits {
553 2     2 1 1678 my $self = shift;
554              
555 2         20 return $self->find_all_inputs( @_, type_regex => qr/^(submit|image)$/ );
556             }
557              
558              
559              
560             sub images {
561 55     55 1 862 my $self = shift;
562              
563 55 100       150 $self->_extract_images() unless $self->{images};
564              
565 55 100       121 return @{$self->{images}} if wantarray;
  54         206  
566 1         4 return $self->{images};
567             }
568              
569              
570             sub find_image {
571 50     50 1 28716 my $self = shift;
572 50         196 my %params = ( n=>1, @_ );
573              
574 50         120 my $wantall = ( $params{n} eq 'all' );
575              
576 50         243 $self->_clean_keys( \%params, qr/^(?:n|(?:alt|url|url_abs|tag|id|class)(?:_regex)?)$/ );
577              
578 50 50       108 my @images = $self->images or return;
579              
580 50         70 my $nmatches = 0;
581 50         60 my @matches;
582 50         90 for my $image ( @images ) {
583 429 100       14411 if ( _match_any_image_params($image,\%params) ) {
584 87 100       128 if ( $wantall ) {
585 66         128 push( @matches, $image );
586             }
587             else {
588 21         33 ++$nmatches;
589 21 100       97 return $image if $nmatches >= $params{n};
590             }
591             }
592             } # for @images
593              
594 30 100       1178 if ( $wantall ) {
595 18 100       114 return @matches if wantarray;
596 1         10 return \@matches;
597             }
598              
599 12         71 return;
600             }
601              
602             # Used by find_images to check for matches
603             # The logic is such that ALL param criteria that are given must match
604             sub _match_any_image_params {
605 429     429   508 my $image = shift;
606 429         434 my $p = shift;
607              
608             # No conditions, anything matches
609 429 50       711 return 1 unless keys %$p;
610              
611 429 100 100     921 return if defined $p->{url} && !(defined($image->url) && $image->url eq $p->{url} );
      100        
612 387 100 100     774 return if defined $p->{url_regex} && !(defined($image->url) && $image->url =~ $p->{url_regex} );
      100        
613 354 100 66     716 return if defined $p->{url_abs} && !(defined($image->url_abs) && $image->url_abs eq $p->{url_abs} );
      100        
614 324 100 66     712 return if defined $p->{url_abs_regex} && !(defined($image->url_abs) && $image->url_abs =~ $p->{url_abs_regex} );
      100        
615 299 100 100     1690 return if defined $p->{alt} && !(defined($image->alt) && $image->alt eq $p->{alt} );
      100        
616 275 100 100     615 return if defined $p->{alt_regex} && !(defined($image->alt) && $image->alt =~ $p->{alt_regex} );
      100        
617 251 100 66     516 return if defined $p->{tag} && !($image->tag && $image->tag eq $p->{tag} );
      100        
618 212 100 66     414 return if defined $p->{tag_regex} && !($image->tag && $image->tag =~ $p->{tag_regex} );
      100        
619 196 100 100     419 return if defined $p->{id} && !($image->attrs && $image->attrs->{id} && $image->attrs->{id} eq $p->{id} );
      100        
620 169 100 100     343 return if defined $p->{id_regex} && !($image->attrs && $image->attrs->{id} && $image->attrs->{id} =~ $p->{id_regex} );
      100        
621 143 100 100     299 return if defined $p->{class} && !($image->attrs && $image->attrs->{class} && $image->attrs->{class} eq $p->{class} );
      100        
622 116 100 100     219 return if defined $p->{class_regex} && !($image->attrs && $image->attrs->{class} && $image->attrs->{class} =~ $p->{class_regex} );
      100        
623              
624             # Success: everything that was defined passed.
625 87         233 return 1;
626             }
627              
628              
629              
630             sub find_all_images {
631 18     18 1 18117 my $self = shift;
632 18         59 return $self->find_image( @_, n=>'all' );
633             }
634              
635              
636             sub forms {
637 157     157 1 2749 my $self = shift;
638              
639 157 100       622 $self->_extract_forms() unless $self->{forms};
640              
641 155 100       424 return @{$self->{forms}} if wantarray;
  65         271  
642 90         250 return $self->{forms};
643             }
644              
645             sub current_form {
646 162     162 1 1012 my $self = shift;
647              
648 162 100       384 if ( !$self->{current_form} ) {
649 30         109 $self->form_number(1);
650             }
651              
652 161         491 return $self->{current_form};
653             }
654              
655              
656             sub form_number {
657 52     52 1 7781 my ($self, $form) = @_;
658             # XXX Should we die if no $form is defined? Same question for form_name()
659              
660 52         197 my $forms = $self->forms;
661 50 100       195 if ( $forms->[$form-1] ) {
662 48         140 $self->{current_form} = $forms->[$form-1];
663             return wantarray
664             ? ($self->{current_form}, $form)
665 48 100       200 : $self->{current_form};
666             }
667              
668 2 50       16 return wantarray ? () : undef;
669             }
670              
671              
672             sub form_action {
673 3     3 1 712 my ($self, $action) = @_;
674              
675 3         4 my $temp;
676 3 50       6 my @matches = grep {defined($temp = $_->action) and ($temp =~ m/$action/msx) } $self->forms;
  15         175  
677              
678 3         32 my $nmatches = @matches;
679 3 100       8 if ( $nmatches > 0 ) {
680 2 100       4 if ( $nmatches > 1 ) {
681 1         6 $self->warn( "There are $nmatches forms with action matching $action. The first one was used." )
682             }
683 2         7 return $self->{current_form} = $matches[0];
684             }
685              
686 1         4 return;
687             }
688              
689              
690             sub form_name {
691 8     8 1 1601 my ( $self, $name, $args ) = @_;
692 8   66     57 return $self->form_with( name => $name, $args || () );
693             }
694              
695              
696             sub form_id {
697 6     6 1 1627 my ( $self, $formid, $args ) = @_;
698 6 100 66     23 defined( my $form = $self->form_with( id => $formid, $args || () ) )
699             or $self->warn(qq{ There is no form with ID "$formid"});
700 6         16 return $form;
701             }
702              
703              
704              
705             sub all_forms_with_fields {
706 21     21 1 51 my ($self, @fields) = @_;
707 21 100       58 $self->die('no fields provided') unless scalar @fields;
708              
709 20         32 my @matches;
710 20         27 FORMS: for my $form (@{ $self->forms }) {
  20         68  
711 153         320 my @fields_in_form = $form->param();
712 153         7453 for my $field (@fields) {
713 171 100       265 next FORMS unless grep { $_ eq $field } @fields_in_form;
  618         1184  
714             }
715 29         70 push @matches, $form;
716             }
717 20         60 return @matches;
718             }
719              
720              
721              
722             sub form_with_fields {
723 12     12 1 34679 my ($self, @fields) = @_;
724 12 100       50 $self->die('no fields provided') unless scalar @fields;
725              
726 10         16 my $nth;
727 10 100 100     57 if ( @fields > 1 && ref $fields[-1] eq 'HASH' ) {
728 3         7 $nth = ( pop @fields )->{n};
729             }
730              
731 10         30 my @matches = $self->all_forms_with_fields(@fields);
732 10 100       26 if ( $nth ) {
733 3 100       17 @matches = ( @matches >= $nth ) ? ( $matches[ $nth - 1 ] ) : ();
734             }
735 10         18 my $nmatches = @matches;
736 10 100       26 if ( $nmatches > 0 ) {
737 9 100       26 if ( $nmatches > 1 ) {
738 4         28 $self->warn( "There are $nmatches forms with the named fields. The first one was used." )
739             }
740 9         306 return $self->{current_form} = $matches[0];
741             }
742             else {
743 1 50       7 $self->warn( $nth ? qq{There is no match \#$nth form with the requested fields}
744             : qq{There is no form with the requested fields} );
745 1         63 return undef;
746             }
747             }
748              
749              
750              
751             sub all_forms_with {
752 42     42 1 6854 my ( $self, %spec ) = @_;
753              
754 42         112 my $action = delete $spec{action};
755 42 100       117 my @forms = grep { !$action || $_->action eq $action } $self->forms;
  270         784  
756 42         196 foreach my $attr ( keys %spec ) {
757 45 100       177 @forms = grep _equal( $spec{$attr}, $_->attr($attr) ), @forms or return;
758             }
759 37         121 return @forms;
760             }
761              
762              
763             sub form_with {
764 20     20 1 766 my ( $self, @args ) = @_;
765              
766 20 50       39 return if not $self->forms;
767              
768             # Determine if we should return the nth instance
769 20         27 my $nth;
770 20 100 66     77 if ( @args % 2 && ref $args[-1] eq 'HASH' ) {
771 7         14 $nth = ( pop @args )->{n};
772             }
773              
774 20         54 my %spec = @args;
775              
776 20         55 my @forms = $self->all_forms_with(%spec);
777 20 100       39 if ( $nth ) {
778 7 100       18 @forms = ( @forms >= $nth ) ? $forms[ $nth - 1 ] : ();
779             }
780 20 100       34 if ( @forms > 1 ) { # Warn if several forms matched.
781             # For ->form_with( method => 'POST', action => '', id => undef ) we get:
782             # >>There are 2 forms with empty action and no id and method "POST".
783             # The first one was used.<<
784              
785             $self->warn(
786             'There are ' . @forms . ' forms ' . (
787             keys %spec # explain search criteria if there were any
788             ? 'with ' . join(
789             ' and ', # "with ... and ... and ..."
790             map {
791 3 100       20 unless ( defined $spec{$_} ) { # case $attr => undef
  5 100       11  
    50          
792 1         3 qq{no $_};
793             }
794 0         0 elsif ( $spec{$_} eq '' ) { # case $attr=> ''
795 1         7 qq{empty $_};
796             }
797             else { # case $attr => $value
798 3         14 qq{$_ "$spec{$_}"};
799             }
800             } # case $attr => undef
801             sort keys %spec # sort keys to get deterministic messages
802             )
803             : ''
804             )
805             . '. The first one was used.'
806             );
807             }
808              
809 20         81 return $self->{current_form} = $forms[0];
810             }
811              
812             # NOT an object method!
813             # Expects two values and returns true only when either
814             # both are defined and eq(ual) or when both are not defined.
815             sub _equal {
816 260     260   2273 my ( $x, $y ) = @_;
817 260 100 100     1210 defined $x ? defined $y && $x eq $y : !defined $y;
818             }
819              
820              
821              
822             sub field {
823 49     49 1 9851 my ($self, $name, $value, $number) = @_;
824 49   100     218 $number ||= 1;
825              
826 49         165 my $form = $self->current_form();
827 49 50       154 if ($number > 1) {
828 0         0 $form->find_input($name, undef, $number)->value($value);
829             }
830             else {
831 49 100       131 if ( ref($value) eq 'ARRAY' ) {
832 11         28 my $input = $form->find_input($name);
833              
834 11 100       294 if ( $input->type eq 'file' ) {
835 10         63 $input->file( shift @$value );
836 10         156 $input->filename( shift @$value );
837 10         160 $input->headers( @$value );
838             }
839             else {
840 1         15 $form->param($name, $value);
841             }
842             }
843             else {
844 38         169 $form->value($name => $value);
845             }
846             }
847             }
848              
849              
850             sub select {
851 9     9 1 6585 my ($self, $name, $value) = @_;
852              
853 9         25 my $form = $self->current_form();
854              
855 9         23 my $input = $form->find_input($name);
856 9 100       375 if (!$input) {
857 1         10 $self->warn( qq{Input "$name" not found} );
858 1         83 return;
859             }
860              
861 8 50       16 if ($input->type ne 'option') {
862 0         0 $self->warn( qq{Input "$name" is not type "select"} );
863 0         0 return;
864             }
865              
866             # For $mech->select($name, {n => 3}) or $mech->select($name, {n => [2,4]}),
867             # transform the 'n' number(s) into value(s) and put it in $value.
868 8 100       41 if (ref($value) eq 'HASH') {
869 4         12 for (keys %$value) {
870 4 50       53 $self->warn(qq{Unknown select value parameter "$_"})
871             unless $_ eq 'n';
872             }
873              
874 4 50       13 if (defined($value->{n})) {
875 4         11 my @inputs = $form->find_input($name, 'option');
876 4         274 my @values = ();
877             # distinguish between multiple and non-multiple selects
878             # (see INPUTS section of `perldoc HTML::Form`)
879 4 100       13 if (@inputs == 1) {
880 2         8 @values = $inputs[0]->possible_values();
881             }
882             else {
883 2         8 foreach my $input (@inputs) {
884 8         16 my @possible = $input->possible_values();
885 8         73 push @values, pop @possible;
886             }
887             }
888              
889 4         31 my $n = $value->{n};
890 4 100 33     35 if (ref($n) eq 'ARRAY') {
    50          
891 2         4 $value = [];
892 2         6 for (@$n) {
893 4 50       27 unless (/^\d+$/) {
894 0         0 $self->warn(qq{"n" value "$_" is not a positive integer});
895 0         0 return;
896             }
897 4         16 push @$value, $values[$_ - 1]; # might be undef
898             }
899             }
900             elsif (!ref($n) && $n =~ /^\d+$/) {
901 2         11 $value = $values[$n - 1]; # might be undef
902             }
903             else {
904 0         0 $self->warn('"n" value is not a positive integer or an array ref');
905 0         0 return;
906             }
907             }
908             else {
909 0         0 $self->warn('Hash value is invalid');
910 0         0 return;
911             }
912             } # hashref
913              
914 8 100       21 if (ref($value) eq 'ARRAY') {
915 4         14 $form->param($name, $value);
916 4         766 return 1;
917             }
918              
919 4         14 $form->value($name => $value);
920 4         315 return 1;
921             }
922              
923              
924             sub set_fields {
925 27     27 1 232 my $self = shift;
926 27         88 my %fields = @_;
927              
928 27 50       87 my $form = $self->current_form or $self->die( 'No form defined' );
929              
930             FIELD:
931 27         109 for my $field ( keys %fields ) {
932 32         360 my $value = $fields{$field};
933 32         48 my $number = 1;
934              
935 32 100       94 if ( ref $value eq 'ARRAY' ) {
936 9 100       37 my $input = $form->find_input($field) or next FIELD;
937              
938             # Honor &submit_form's documentation, that says that a
939             # "file" input's value can be in the form of
940             # "[[$filepath, $filename], 1]".
941 8 100 66     245 if (
      100        
942             $input->type ne 'file'
943             || ( $input->type eq 'file' && ref( $value->[0] ) eq 'ARRAY' )
944             ) {
945 4         48 ( $value, $number ) = ( $value->[0], $value->[1] );
946             }
947             }
948             else {
949 23 100       65 if ( ref $value eq 'SCALAR' ) {
950 2         8 my $input = $form->find_input( $field );
951              
952 2 50       64 if ( not defined int $$value ) {
953 0         0 warn "Only references to integers are supported. Using 0.";
954 0         0 $$value = 0;
955             }
956              
957 2         28 my @possible_values = $input->possible_values;
958 2 50       37 if ($#possible_values < $$value) {
959 0         0 warn "Not enough options for $field to select index $$value";
960 0         0 next FIELD;
961             }
962 2         7 $value = $possible_values[ $$value ];
963             }
964             }
965 31         208 $self->field($field, $value, $number);
966             }
967             }
968              
969              
970             sub set_visible {
971 2     2 1 1378 my $self = shift;
972              
973 2         16 my $form = $self->current_form;
974 2         13 my @inputs = $form->inputs;
975              
976 2         11 my $num_set = 0;
977 2         9 for my $value ( @_ ) {
978             # Handle type/value pairs an arrayref
979 4 100       11 if ( ref $value eq 'ARRAY' ) {
980 1         3 my ( $type, $value ) = @$value;
981 1         3 while ( my $input = shift @inputs ) {
982 3 50       13 next if $input->type eq 'hidden';
983 3 100       17 if ( $input->type eq $type ) {
984 1         11 $input->value( $value );
985 1         38 $num_set++;
986 1         2 last;
987             }
988             } # while
989             }
990             # by default, it's a value
991             else {
992 3         8 while ( my $input = shift @inputs ) {
993 3 50       6 next if $input->type eq 'hidden';
994 3         19 $input->value( $value );
995 3         43 $num_set++;
996 3         6 last;
997             } # while
998             }
999             } # for
1000              
1001 2         4 return $num_set;
1002             } # set_visible()
1003              
1004              
1005             sub tick {
1006 5     5 1 2860 my $self = shift;
1007 5         7 my $name = shift;
1008 5         7 my $value = shift;
1009 5 100       9 my $set = @_ ? shift : 1; # default to 1 if not passed
1010              
1011             # loop though all the inputs
1012 5         7 my $index = 1;
1013 5         15 while ( my $input = $self->current_form->find_input( $name, 'checkbox', $index ) ) {
1014             # Sometimes the HTML is malformed and there is no value for the check
1015             # box, so we just return if the value passed is an empty string
1016             # (and the form input is found)
1017 5 100       198 if ($value eq '') {
1018 1 50       4 $input->value($set ? $value : undef);
1019 1         64 return;
1020             }
1021             # Can't guarantee that the first element will be undef and the second
1022             # element will be the right name
1023 4         37 foreach my $val ($input->possible_values()) {
1024 8 100       47 next unless defined $val;
1025 4 100       10 if ($val eq $value) {
1026 3 100       22 $input->value($set ? $value : undef);
1027 3         108 return;
1028             }
1029             }
1030              
1031             # move onto the next input
1032 1         3 $index++;
1033             } # while
1034              
1035             # got this far? Didn't find anything
1036 1         91 $self->die( qq{No checkbox "$name" for value "$value" in form} );
1037             } # tick()
1038              
1039              
1040             sub untick {
1041 1     1 1 6 shift->tick(shift,shift,undef);
1042             }
1043              
1044              
1045             sub value {
1046 16     16 1 4209 my $self = shift;
1047 16         36 my $name = shift;
1048 16   100     63 my $number = shift || 1;
1049              
1050 16         49 my $form = $self->current_form;
1051 16 100       70 if ( $number > 1 ) {
1052 1         4 return $form->find_input( $name, undef, $number )->value();
1053             }
1054             else {
1055 15         39 return $form->value( $name );
1056             }
1057             } # value
1058              
1059              
1060             sub click {
1061 2     2 1 15 my ($self, $button, $x, $y) = @_;
1062 2 50       8 for ($x, $y) { $_ = 1 unless defined; }
  4         12  
1063 2         7 my $request = $self->current_form->click($button, $x, $y);
1064 2         2079 return $self->request( $request );
1065             }
1066              
1067              
1068             sub click_button {
1069 14     14 1 128231 my $self = shift;
1070 14         83 my %args = @_;
1071              
1072 14         55 for ( keys %args ) {
1073 15 50       122 if ( !/^(number|name|value|id|input|x|y)$/ ) {
1074 0         0 $self->warn( qq{Unknown click_button parameter "$_"} );
1075             }
1076             }
1077              
1078 14         106 my %exclusive_options = (
1079             id => 1,
1080             input => 1,
1081             name => 1,
1082             number => 1,
1083             value => 1,
1084             );
1085              
1086 14         57 my @present_exclusive_options = @exclusive_options{ keys %args };
1087              
1088 14 100       64 if ( scalar @present_exclusive_options > 1 ) {
1089 1         5 $self->die( 'click_button: More than one button selector has been used' );
1090             }
1091              
1092 13         75 for ($args{x}, $args{y}) {
1093 26 50       66 $_ = 1 unless defined;
1094             }
1095              
1096 13 50       84 my $form = $self->current_form or $self->die( 'click_button: No form has been selected' );
1097              
1098 12         20 my $request;
1099 12 100       49 if ( $args{name} ) {
    100          
    100          
    100          
    50          
1100 3         14 $request = $form->click( $args{name}, $args{x}, $args{y} );
1101             }
1102             # 0 is a valid id in HTML5
1103             elsif ( defined $args{id} ) {
1104             # HTML::Form expects ids to be prefixed with '#'
1105 2         13 my $input = $form->find_input('#' . $args{id});
1106 2         191 $request = $input->click( $form, $args{x}, $args{y} );
1107             }
1108             elsif ( $args{number} ) {
1109             # changing this 'submit' to qw/submit button image/ will probably break people's code
1110 2         12 my $input = $form->find_input( undef, 'submit', $args{number} );
1111 2         101 $request = $input->click( $form, $args{x}, $args{y} );
1112             }
1113             elsif ( $args{input} ) {
1114 1         5 $request = $args{input}->click( $form, $args{x}, $args{y} );
1115             }
1116             elsif ( $args{value} ) {
1117 4         10 my @inputs = map { $form->find_input(undef, $_) } qw/submit button image/;
  12         317  
1118 4         153 foreach my $input ( @inputs ) {
1119 9 100 66     102 if ( $input->value && ($args{value} eq $input->value) ) {
1120 3         55 $request = $input->click( $form, $args{x}, $args{y} );
1121 3         2313 last;
1122             }
1123             } # foreach
1124             } # $args{value}
1125              
1126 9         4246 return $self->request( $request );
1127             }
1128              
1129              
1130             sub submit {
1131 20     20 1 355 my $self = shift;
1132              
1133 20         59 my $request = $self->current_form->make_request;
1134 20         14030 return $self->request( $request );
1135             }
1136              
1137              
1138             sub submit_form {
1139 37     37 1 112942 my( $self, %args ) = @_;
1140              
1141 37         144 for ( keys %args ) {
1142 61 100       453 if ( !/^(form_(number|name|fields|id)|(with_)?fields|button|x|y|strict_forms)$/ ) {
1143 1         7 $self->die( qq{Unknown submit_form parameter "$_"} );
1144             }
1145             }
1146              
1147 36         87 my $fields;
1148 36         92 for (qw/with_fields fields/) {
1149 60 100       165 if ($args{$_}) {
1150 26 100       86 if ( ref $args{$_} eq 'HASH' ) {
1151 24         52 $fields = $args{$_};
1152             }
1153             else {
1154 2         7 $self->die("$_ arg to submit_form must be a hashref");
1155             }
1156 24         46 last;
1157             }
1158             }
1159              
1160 34         51 my @filtered_sets;
1161 34 100       103 if ( $args{with_fields} ) {
1162 11         23 my @got = $self->all_forms_with_fields(keys %{$fields});
  11         47  
1163 10 100       42 $self->die("There is no form with the requested fields") if not @got;
1164 8         39 push @filtered_sets, \@got;
1165             }
1166 31 100       115 if ( my $form_number = $args{form_number} ) {
1167 9         50 my $got = $self->form_number( $form_number );
1168 8 100       27 $self->die("There is no form numbered $form_number") if not $got;
1169 7         20 push @filtered_sets, [ $got ];
1170             }
1171 29 100       113 if ( my $form_name = $args{form_name} ) {
1172 17         87 my @got = $self->all_forms_with( name => $form_name );
1173 17 100       51 $self->die(qq{There is no form named "$form_name"}) if not @got;
1174 16         54 push @filtered_sets, \@got;
1175             }
1176 28 100       137 if ( my $form_id = $args{form_id} ) {
1177 2         15 my @got = $self->all_forms_with( id => $form_id );
1178 2 100       11 $self->die(qq{There is no form with ID "$form_id"}) if not @got;
1179 1         10 push @filtered_sets, \@got;
1180             }
1181              
1182 27 100       71 if (not @filtered_sets) {
1183             # No form selector was used.
1184             # Maybe a form was set separately, or we'll default to the first form.
1185             }
1186             else {
1187             # Need to intersect to apply all the various filters.
1188             # Assume that each filtered set only has a given form object once.
1189             # So we can count occurrences.
1190             #
1191 26 50       275 tie my %c, Tie::RefHash:: or $self->die('Cannot determine a form to use');
1192 26         474 foreach (@filtered_sets) {
1193 32         200 foreach (@$_) {
1194 42         414 ++$c{$_};
1195             }
1196             }
1197 26         593 my $expected_count = scalar @filtered_sets;
1198 26         150 my @matched = grep { $c{$_} == $expected_count } keys %c;
  40         1145  
1199 26 100       308 if (not @matched) {
1200 4         17 $self->die('There is no form that satisfies all the criteria');
1201             }
1202 22 100       68 if (@matched > 1) {
1203 2         9 $self->die('More than one form satisfies all the criteria');
1204             }
1205 20         127 $self->{current_form} = $matched[0];
1206             }
1207              
1208 21 100       88 if (defined($args{strict_forms})) {
1209             # Strict argument has been passed, set the flag as appropriate
1210             # this must be done prior to attempting to set the fields
1211 6         22 $self->current_form->strict($args{strict_forms});
1212             }
1213              
1214 21 100       287 $self->set_fields( %{$fields} ) if $fields;
  18         123  
1215              
1216 17         1173 my $response;
1217 17 50       55 if ( $args{button} ) {
1218 0   0     0 $response = $self->click( $args{button}, $args{x} || 0, $args{y} || 0 );
      0        
1219             }
1220             else {
1221 17         55 $response = $self->submit();
1222             }
1223              
1224 17         363 return $response;
1225             }
1226              
1227              
1228             sub add_header {
1229 5     5 1 3932 my $self = shift;
1230 5         9 my $npairs = 0;
1231              
1232 5         20 while ( @_ ) {
1233 5         12 my $key = shift;
1234 5         10 my $value = shift;
1235 5         8 ++$npairs;
1236              
1237 5         21 $self->{headers}{$key} = $value;
1238             }
1239              
1240 5         11 return $npairs;
1241             }
1242              
1243              
1244             sub delete_header {
1245 0     0 1 0 my $self = shift;
1246              
1247 0         0 while ( @_ ) {
1248 0         0 my $key = shift;
1249              
1250 0         0 delete $self->{headers}{$key};
1251             }
1252              
1253 0         0 return;
1254             }
1255              
1256              
1257              
1258             sub quiet {
1259 45     45 1 6794 my $self = shift;
1260              
1261 45 100       108 $self->{quiet} = $_[0] if @_;
1262              
1263 45         144 return $self->{quiet};
1264             }
1265              
1266              
1267             sub autocheck {
1268 6     6 1 824 my $self = shift;
1269              
1270 6 100       17 $self->{autocheck} = $_[0] if @_;
1271              
1272 6         24 return $self->{autocheck};
1273             }
1274              
1275              
1276             sub stack_depth {
1277 241     241 1 9844 my $self = shift;
1278 241 100       617 $self->{stack_depth} = shift if @_;
1279 241         860 return $self->{stack_depth};
1280             }
1281              
1282              
1283             sub save_content {
1284 2     2 1 2455 my $self = shift;
1285 2         9 my $filename = shift;
1286 2         19 my %opts = @_;
1287 2 100       8 if (delete $opts{binary}) {
1288 1         10 $opts{binmode} = ':raw';
1289 1         8 $opts{decoded_by_headers} = 1;
1290             }
1291              
1292 2 50       177 open( my $fh, '>', $filename ) or $self->die( "Unable to create $filename: $!" );
1293 2 100 100     32 if ((my $binmode = delete($opts{binmode}) || '') || ($self->content_type() !~ m{^text/})) {
      66        
1294 1 50 33     26 if (length($binmode) && (substr($binmode, 0, 1) eq ':')) {
1295 1         14 binmode $fh, $binmode;
1296             }
1297             else {
1298 0         0 binmode $fh;
1299             }
1300             }
1301 2 50       4 print {$fh} $self->content(%opts) or $self->die( "Unable to write to $filename: $!" );
  2         26  
1302 2 50       97 close $fh or $self->die( "Unable to close $filename: $!" );
1303              
1304 2         16 return;
1305             }
1306              
1307              
1308              
1309             sub _get_fh_default_stdout {
1310 3     3   5 my $self = shift;
1311 3   100     16 my $p = shift || '';
1312 3 100       12 if ( !$p ) {
    100          
1313 1         3 return \*STDOUT;
1314             } elsif ( !ref($p) ) {
1315 1 50       73 open my $fh, '>', $p or $self->die( "Unable to write to $p: $!" );;
1316 1         9 return $fh;
1317             } else {
1318 1         4 return $p;
1319             }
1320             }
1321              
1322             sub dump_headers {
1323 3     3 1 3914 my $self = shift;
1324 3         8 my $fh = $self->_get_fh_default_stdout(shift);
1325              
1326 3         6 print {$fh} $self->response->headers_as_string;
  3         9  
1327              
1328 3         359 return;
1329             }
1330              
1331              
1332              
1333             sub dump_links {
1334 2     2 1 2432 my $self = shift;
1335 2   100     16 my $fh = shift || \*STDOUT;
1336 2         5 my $absolute = shift;
1337              
1338 2         16 for my $link ( $self->links ) {
1339 52 50       130 my $url = $absolute ? $link->url_abs : $link->url;
1340 52 50       77 $url = '' if not defined $url;
1341 52         53 print {$fh} $url, "\n";
  52         294  
1342             }
1343 2         8 return;
1344             }
1345              
1346              
1347             sub dump_images {
1348 2     2 1 2350 my $self = shift;
1349 2   100     19 my $fh = shift || \*STDOUT;
1350 2         6 my $absolute = shift;
1351              
1352 2         14 for my $image ( $self->images ) {
1353 24 50       66 my $url = $absolute ? $image->url_abs : $image->url;
1354 24 100       45 $url = '' if not defined $url;
1355 24         24 print {$fh} $url, "\n";
  24         164  
1356             }
1357 2         7 return;
1358             }
1359              
1360              
1361             sub dump_forms {
1362 4     4 1 4968 my $self = shift;
1363 4   100     36 my $fh = shift || \*STDOUT;
1364              
1365 4         26 for my $form ( $self->forms ) {
1366 18         1941 print {$fh} $form->dump, "\n";
  18         57  
1367             }
1368 4         2022 return;
1369             }
1370              
1371              
1372             sub dump_text {
1373 2     2 1 2503 my $self = shift;
1374 2   100     17 my $fh = shift || \*STDOUT;
1375 2         8 my $absolute = shift;
1376              
1377 2         6 print {$fh} $self->text, "\n";
  2         16  
1378              
1379 2         8 return;
1380             }
1381              
1382              
1383              
1384             sub clone {
1385 2     2 1 2160 my $self = shift;
1386 2         16 my $clone = $self->SUPER::clone();
1387              
1388 2         589 $clone->cookie_jar( $self->cookie_jar );
1389 2         195 $clone->{headers} = { %{$self->{headers}} };
  2         6  
1390              
1391 2         5 return $clone;
1392             }
1393              
1394              
1395              
1396             sub redirect_ok {
1397 1     1 1 1998218 my $self = shift;
1398 1         3 my $prospective_request = shift;
1399 1         2 my $response = shift;
1400              
1401 1         18 my $ok = $self->SUPER::redirect_ok( $prospective_request, $response );
1402 1 50       63 if ( $ok ) {
1403 1         4 $self->{redirected_uri} = $prospective_request->uri;
1404             }
1405              
1406 1         7 return $ok;
1407             }
1408              
1409              
1410              
1411             sub request {
1412 176     176 1 157499 my $self = shift;
1413 176         412 my $request = shift;
1414              
1415 176 100       776 $self->die( '->request was called without a request parameter' )
1416             unless $request;
1417              
1418 174         997 $request = $self->_modify_request( $request );
1419              
1420 174 100 100     617 if ( $request->method eq 'GET' || $request->method eq 'POST' ) {
1421 172         2918 $self->_push_page_stack();
1422             }
1423              
1424 174         776 return $self->_update_page($request, $self->_make_request( $request, @_ ));
1425             }
1426              
1427              
1428             sub update_html {
1429 176     176 1 317 my $self = shift;
1430 176         440 my $html = shift;
1431              
1432 176         554 $self->_reset_page;
1433 176         424 $self->{ct} = 'text/html';
1434 176         444 $self->{content} = $html;
1435              
1436 176         360 return;
1437             }
1438              
1439              
1440             sub credentials {
1441 8     8 1 1542 my $self = shift;
1442              
1443             # The latest LWP::UserAgent also supports 2 arguments,
1444             # in which case the first is host:port
1445 8 100 100     58 if (@_ == 4 || (@_ == 2 && $_[0] =~ /:\d+$/)) {
      66        
1446 4         19 return $self->SUPER::credentials(@_);
1447             }
1448              
1449 4 100       13 @_ == 2
1450             or $self->die( 'Invalid # of args for overridden credentials()' );
1451              
1452 3         15 return @$self{qw( __username __password )} = @_;
1453             }
1454              
1455              
1456             sub get_basic_credentials {
1457 9     9 1 8269 my $self = shift;
1458 9         20 my @cred = grep { defined } @$self{qw( __username __password )};
  18         39  
1459 9 100       35 return @cred if @cred == 2;
1460 4         34 return $self->SUPER::get_basic_credentials(@_);
1461             }
1462              
1463              
1464             sub clear_credentials {
1465 1     1 1 587 my $self = shift;
1466 1         4 delete @$self{qw( __username __password )};
1467             }
1468              
1469              
1470             sub _update_page {
1471 201     201   46447126 my ($self, $request, $res) = @_;
1472              
1473 201         751 $self->{req} = $request;
1474 201         804 $self->{redirected_uri} = $request->uri->as_string;
1475              
1476 201         3439 $self->{res} = $res;
1477              
1478 201         629 $self->{status} = $res->code;
1479 201         2720 $self->{base} = $res->base;
1480 201   100     84009 $self->{ct} = $res->content_type || '';
1481              
1482 201 100       7131 if ( $res->is_success ) {
1483 184         2621 $self->{uri} = $self->{redirected_uri};
1484 184         539 $self->{last_uri} = $self->{uri};
1485             }
1486              
1487 201 100       955 if ( $res->is_error ) {
1488 17 100       163 if ( $self->{autocheck} ) {
1489 2         6 $self->die( 'Error ', $request->method, 'ing ', $request->uri, ': ', $res->message );
1490             }
1491             }
1492              
1493 199         2104 $self->_reset_page;
1494              
1495             # Try to decode the content. Undef will be returned if there's nothing to decompress.
1496             # See docs in HTTP::Message for details. Do we need to expose the options there?
1497 199         1315 my $content = $res->decoded_content();
1498 199 50       331344 $content = $res->content if (not defined $content);
1499              
1500 199         788 $content .= _taintedness();
1501              
1502 199 100       1018 if ($self->is_html) {
1503 175         744 $self->update_html($content);
1504             }
1505             else {
1506 24         84 $self->{content} = $content;
1507             }
1508              
1509 199         1567 return $res;
1510             } # _update_page
1511              
1512             our $_taintbrush;
1513              
1514             # This is lifted wholesale from Test::Taint
1515             sub _taintedness {
1516 199 100   199   1329 return $_taintbrush if defined $_taintbrush;
1517              
1518             # Somehow we need to get some taintedness into our $_taintbrush.
1519             # Let's try the easy way first. Either of these should be
1520             # tainted, unless somebody has untainted them, so this
1521             # will almost always work on the first try.
1522             # (Unless, of course, taint checking has been turned off!)
1523 43         305 $_taintbrush = substr("$0$^X", 0, 0);
1524 43 100       418 return $_taintbrush if tainted( $_taintbrush );
1525              
1526             # Let's try again. Maybe somebody cleaned those.
1527 24         442 $_taintbrush = substr(join('', grep { defined } @ARGV, %ENV), 0, 0);
  1620         2302  
1528 24 50       159 return $_taintbrush if tainted( $_taintbrush );
1529              
1530             # If those don't work, go try to open some file from some unsafe
1531             # source and get data from them. That data is tainted.
1532             # (Yes, even reading from /dev/null works!)
1533 24         642 for my $filename ( qw(/dev/null / . ..), values %INC, $0, $^X ) {
1534 4606 50       121577 if ( open my $fh, '<', $filename ) {
1535 4606         9077 my $data;
1536 4606 100       32983 if ( defined sysread $fh, $data, 1 ) {
1537 4534         10016 $_taintbrush = substr( $data, 0, 0 );
1538 4534 50       49172 last if tainted( $_taintbrush );
1539             }
1540             }
1541             }
1542              
1543             # Sanity check
1544 24 50       280 die("Our taintbrush should have zero length!") if length $_taintbrush;
1545              
1546 24         185 return $_taintbrush;
1547             }
1548              
1549              
1550              
1551             sub _modify_request {
1552 176     176   6988 my $self = shift;
1553 176         407 my $req = shift;
1554              
1555             # add correct Accept-Encoding header to restore compliance with
1556             # http://www.freesoft.org/CIE/RFC/2068/158.htm
1557             # http://use.perl.org/~rhesa/journal/25952
1558 176 100       1210 if (not $req->header( 'Accept-Encoding' ) ) {
1559             # "identity" means "please! unencoded content only!"
1560 174 50       15312 $req->header( 'Accept-Encoding', $HAS_ZLIB ? 'gzip' : 'identity' );
1561             }
1562              
1563 176         8867 my $last = $self->{last_uri};
1564 176 100       891 if ( $last ) {
1565 117 50       389 $last = $last->as_string if ref($last);
1566 117         353 $req->header( Referer => $last );
1567             }
1568 176         5629 while ( my($key,$value) = each %{$self->{headers}} ) {
  181         1249  
1569 5 100       17 if ( defined $value ) {
1570 4         40 $req->header( $key => $value );
1571             }
1572             else {
1573 1         16 $req->remove_header( $key );
1574             }
1575             }
1576              
1577 176         513 return $req;
1578             }
1579              
1580              
1581              
1582             sub _make_request {
1583 177     177   352 my $self = shift;
1584 177         1225 return $self->SUPER::request(@_);
1585             }
1586              
1587              
1588             sub _reset_page {
1589 450     450   836 my $self = shift;
1590              
1591 450         1224 $self->{links} = undef;
1592 450         940 $self->{images} = undef;
1593 450         3089 $self->{forms} = undef;
1594 450         1188 $self->{current_form} = undef;
1595 450         895 $self->{title} = undef;
1596 450         888 $self->{text} = undef;
1597              
1598 450         717 return;
1599             }
1600              
1601              
1602             my %link_tags = (
1603             a => 'href',
1604             area => 'href',
1605             frame => 'src',
1606             iframe => 'src',
1607             link => 'href',
1608             meta => 'content',
1609             );
1610              
1611             sub _new_parser {
1612 27     27   63 my $self = shift;
1613 27         47 my $content_ref = shift;
1614              
1615 27         450 my $parser = HTML::TokeParser->new($content_ref);
1616 27         5726 $parser->marked_sections( $self->{marked_sections});
1617 27         392 $parser->xml_mode( $$content_ref=~/^\s*<\?xml/ ); # NOT GENERALLY RELIABLE
1618              
1619 27         84 return $parser;
1620             }
1621              
1622             sub _extract_links {
1623 26     26   67 my $self = shift;
1624              
1625              
1626 26         81 $self->{links} = [];
1627 26 100       119 if ( defined $self->{content} ) {
1628 24         115 my $parser = $self->_new_parser(\$self->{content});
1629 24         344 while ( my $token = $parser->get_tag( keys %link_tags ) ) {
1630 200         19000 my $link = $self->_link_from_token( $token, $parser );
1631 200 100       630 push( @{$self->{links}}, $link ) if $link;
  186         818  
1632             } # while
1633             }
1634              
1635 26         14670 return;
1636             }
1637              
1638              
1639             my %image_tags = (
1640             img => 'src',
1641             input => 'src',
1642             );
1643              
1644             sub _extract_images {
1645 4     4   14 my $self = shift;
1646              
1647 4         13 $self->{images} = [];
1648              
1649 4 50       24 if ( defined $self->{content} ) {
1650 4 100       29 if ($self->content_type eq 'text/css') {
1651 1         6 push( @{$self->{images}}, $self->_images_from_css($self->{content}) );
  1         20  
1652             }
1653             else {
1654 3         18 my $parser = $self->_new_parser(\$self->{content});
1655 3         31 while ( my $token = $parser->get_tag() ) {
1656 102         3260 my ($tag_name, $attrs) = @{$token};
  102         201  
1657 102 100       302 next if $tag_name =~ m{^/};
1658              
1659 66 100       163 if ($image_tags{$tag_name}) {
    100          
1660 30         58 my $image = $self->_image_from_token( $token, $parser );
1661 30 100       94 push( @{$self->{images}}, $image ) if $image;
  27         69  
1662             }
1663             elsif ($tag_name eq 'style') {
1664 3         32 push( @{$self->{images}}, $self->_images_from_css($parser->get_text) );
  3         29  
1665             }
1666              
1667 66 100       235 if ($attrs->{style}) {
1668 6         18 push( @{$self->{images}}, $self->_images_from_css($attrs->{style}) );
  6         21  
1669             }
1670             } # while
1671             }
1672             }
1673              
1674 4         90 return;
1675             }
1676              
1677             sub _image_from_token {
1678 30     30   35 my $self = shift;
1679 30         39 my $token = shift;
1680 30         39 my $parser = shift;
1681              
1682 30         49 my $tag = $token->[0];
1683 30         37 my $attrs = $token->[1];
1684              
1685 30 100       60 if ( $tag eq 'input' ) {
1686 6 50       17 my $type = $attrs->{type} or return;
1687 6 100       22 return unless $type eq 'image';
1688             }
1689              
1690 27         91 require WWW::Mechanize::Image;
1691             return
1692             WWW::Mechanize::Image->new({
1693             tag => $tag,
1694             base => $self->base,
1695             url => $attrs->{src},
1696             name => $attrs->{name},
1697             height => $attrs->{height},
1698             width => $attrs->{width},
1699             alt => $attrs->{alt},
1700 27         57 attrs => $attrs,
1701             });
1702             }
1703              
1704             my $STYLE_URL_REGEXP = qr{
1705             # ex. "url('/site.css')"
1706             ( # capture non url path of the string
1707             url # url
1708             \s* #
1709             \( # (
1710             \s* #
1711             (['"]?) # opening ' or "
1712             )
1713             ( # the rest is url
1714             .+? # non greedy "everything"
1715             )
1716             (
1717             \2 # closing ' or "
1718             \s* #
1719             \) # )
1720             )
1721             }xmsi;
1722              
1723             sub _images_from_css {
1724 10     10   233 my $self = shift;
1725 10         24 my $css = shift;
1726              
1727 10         20 my @images;
1728 10         117 while ($css =~ m/$STYLE_URL_REGEXP/g) {
1729 11         34 my $url = $3;
1730 11         1740 require WWW::Mechanize::Image;
1731 11         48 push(
1732             @images,
1733             WWW::Mechanize::Image->new({
1734             tag => 'css',
1735             base => $self->base,
1736             url => $url,
1737             name => undef,
1738             height => undef,
1739             width => undef,
1740             alt => undef,
1741             })
1742             );
1743             }
1744              
1745 10         41 return @images;
1746             }
1747              
1748             sub _link_from_token {
1749 200     200   258 my $self = shift;
1750 200         234 my $token = shift;
1751 200         234 my $parser = shift;
1752              
1753 200         310 my $tag = $token->[0];
1754 200         247 my $attrs = $token->[1];
1755 200         409 my $url = $attrs->{$link_tags{$tag}};
1756              
1757 200         274 my $text;
1758             my $name;
1759 200 100       501 if ( $tag eq 'a' ) {
1760 147         419 $text = $parser->get_trimmed_text("/$tag");
1761 147 50       9350 $text = '' unless defined $text;
1762              
1763 147         220 my $onClick = $attrs->{onclick};
1764 147 100 100     753 if ( $onClick && ($onClick =~ /^window\.open\(\s*'([^']+)'/) ) {
    100 100        
1765 3         13 $url = $1;
1766             }
1767             elsif( $url && $url =~ /^javascript\:\s*(?:void\(\s*)?window\.open\(\s*'([^']+)'/s ){
1768 3         12 $url = $1;
1769             }
1770             } # a
1771              
1772             # Of the tags we extract from, only 'AREA' has an alt tag
1773             # The rest should have a 'name' attribute.
1774             # ... but we don't do anything with that bit of wisdom now.
1775              
1776 200         325 $name = $attrs->{name};
1777              
1778 200 100       433 if ( $tag eq 'meta' ) {
1779 17         32 my $equiv = $attrs->{'http-equiv'};
1780 17         31 my $content = $attrs->{'content'};
1781 17 100 100     177 return unless $equiv && (lc $equiv eq 'refresh') && defined $content;
      66        
1782              
1783 7 50       58 if ( $content =~ /^\d+\s*;\s*url\s*=\s*(\S+)/i ) {
1784 7         21 $url = $1;
1785 7 50       50 $url =~ s/^"(.+)"$/$1/ or $url =~ s/^'(.+)'$/$1/;
1786             }
1787             else {
1788 0         0 undef $url;
1789             }
1790             } # meta
1791              
1792 190 100       331 return unless defined $url; # probably just a name link or
1793              
1794 186         7150 require WWW::Mechanize::Link;
1795             return
1796 186         445 WWW::Mechanize::Link->new({
1797             url => $url,
1798             text => $text,
1799             name => $name,
1800             tag => $tag,
1801             base => $self->base,
1802             attrs => $attrs,
1803             });
1804             } # _link_from_token
1805              
1806              
1807             sub _extract_forms {
1808 75     75   150 my $self = shift;
1809              
1810             my @forms = HTML::Form->parse(
1811             $self->content,
1812             base => $self->base,
1813             strict => $self->{strict_forms},
1814             verbose => $self->{verbose_forms},
1815 75         354 );
1816 73         345664 $self->{forms} = \@forms;
1817 73         275 for my $form ( @forms ) {
1818 343         1418 for my $input ($form->inputs) {
1819 1149 100       5547 if ($input->type eq 'file') {
1820 28         293 $input->value( undef );
1821             }
1822             }
1823             }
1824              
1825 73         411 return;
1826             }
1827              
1828              
1829             sub _push_page_stack {
1830 175     175   1503 my $self = shift;
1831              
1832 175         425 my $req = $self->{req};
1833 175         388 my $res = $self->{res};
1834              
1835 175 100 66     1435 return unless $req && $res && $self->stack_depth;
      100        
1836              
1837             # Don't push anything if it's a virgin object
1838 117   100     420 my $stack = $self->{page_stack} ||= [];
1839 117 100       184 if ( @{$stack} >= $self->stack_depth ) {
  117         308  
1840 2         10 shift @{$stack};
  2         8  
1841             }
1842 117         241 push( @{$stack}, { req => $req, res => $res } );
  117         524  
1843              
1844 117         246 return 1;
1845             }
1846              
1847              
1848             sub warn {
1849 37     37 1 1039 my $self = shift;
1850              
1851 37 50       96 return unless my $handler = $self->{onwarn};
1852              
1853 37 100       123 return if $self->quiet;
1854              
1855 31         82 return $handler->(@_);
1856             }
1857              
1858              
1859             sub die {
1860 30     30 1 95 my $self = shift;
1861              
1862 30 100       109 return unless my $handler = $self->{onerror};
1863              
1864 29         103 return $handler->(@_);
1865             }
1866              
1867              
1868             # NOT an object method!
1869             sub _warn {
1870 29     29   163 require Carp;
1871 29         1783 return &Carp::carp; ## no critic
1872             }
1873              
1874             # NOT an object method!
1875             sub _die {
1876 29     29   258 require Carp;
1877 29         3759 return &Carp::croak; ## no critic
1878             }
1879              
1880             1; # End of module
1881              
1882             __END__