File Coverage

blib/lib/LWP/Protocol.pm
Criterion Covered Total %
statement 100 110 90.9
branch 35 44 79.5
condition 6 9 66.6
subroutine 16 20 80.0
pod 6 8 75.0
total 163 191 85.3


line stmt bran cond sub pod time code
1             package LWP::Protocol;
2              
3 15     15   87 use base 'LWP::MemberMixin';
  15         27  
  15         1574  
4              
5             our $VERSION = '6.29';
6              
7 15     15   84 use strict;
  15         26  
  15         250  
8 15     15   60 use Carp ();
  15         23  
  15         186  
9 15     15   58 use HTTP::Status ();
  15         26  
  15         181  
10 15     15   62 use HTTP::Response ();
  15         25  
  15         254  
11 15     15   3753 use Try::Tiny qw(try catch);
  15         20796  
  15         4155  
12              
13             my %ImplementedBy = (); # scheme => classname
14              
15             sub new
16             {
17 69     69 1 186 my($class, $scheme, $ua) = @_;
18              
19             my $self = bless {
20             scheme => $scheme,
21             ua => $ua,
22              
23             # historical/redundant
24             max_size => $ua->{max_size},
25 69         303 }, $class;
26              
27 69         145 $self;
28             }
29              
30              
31             sub create
32             {
33 69     69 1 167 my($scheme, $ua) = @_;
34 69 100       166 my $impclass = LWP::Protocol::implementor($scheme) or
35             Carp::croak("Protocol scheme '$scheme' is not supported");
36              
37             # hand-off to scheme specific implementation sub-class
38 68         377 my $protocol = $impclass->new($scheme, $ua);
39              
40 68         767 return $protocol;
41             }
42              
43              
44             sub implementor
45             {
46 74     74 1 1008 my($scheme, $impclass) = @_;
47              
48 74 100       202 if ($impclass) {
49 2         7 $ImplementedBy{$scheme} = $impclass;
50             }
51 74         160 my $ic = $ImplementedBy{$scheme};
52 74 100       274 return $ic if $ic;
53              
54 14 50       93 return '' unless $scheme =~ /^([.+\-\w]+)$/; # check valid URL schemes
55 14         41 $scheme = $1; # untaint
56 14         42 $scheme =~ s/[.+\-]/_/g; # make it a legal module name
57              
58             # scheme not yet known, look for a 'use'd implementation
59 14         39 $ic = "LWP::Protocol::$scheme"; # default location
60 14 50       49 $ic = "LWP::Protocol::nntp" if $scheme eq 'news'; #XXX ugly hack
61 15     15   112 no strict 'refs';
  15         28  
  15         11991  
62             # check we actually have one for the scheme:
63 14 100       26 unless (@{"${ic}::ISA"}) {
  14         142  
64             # try to autoload it
65             try {
66 13     13   561 (my $class = $ic) =~ s{::}{/}g;
67 13 50       56 $class .= '.pm' unless $class =~ /\.pm$/;
68 13         4205 require $class;
69             }
70             catch {
71 2     2   30 my $error = $_;
72 2 50       10 if ($error =~ /Can't locate/) {
73 2         9 $ic = '';
74             }
75             else {
76 0         0 die "$error\n";
77             }
78 13         112 };
79             }
80 14 100       307 $ImplementedBy{$scheme} = $ic if $ic;
81 14         255 $ic;
82             }
83              
84              
85             sub request
86             {
87 0     0 1 0 my($self, $request, $proxy, $arg, $size, $timeout) = @_;
88 0         0 Carp::croak('LWP::Protocol::request() needs to be overridden in subclasses');
89             }
90              
91              
92             # legacy
93 0     0 0 0 sub timeout { shift->_elem('timeout', @_); }
94 0     0 0 0 sub max_size { shift->_elem('max_size', @_); }
95              
96              
97             sub collect
98             {
99 63     63 1 160 my ($self, $arg, $response, $collector) = @_;
100 63         93 my $content;
101 63         101 my($ua, $max_size) = @{$self}{qw(ua max_size)};
  63         188  
102              
103             try {
104 63     63   2989 local $\; # protect the print below from surprises
105 63 100 66     259 if (!defined($arg) || !$response->is_success) {
    100 66        
    50          
106 61         159 $response->{default_add_content} = 1;
107             }
108             elsif (!ref($arg) && length($arg)) {
109 1 50       49 open(my $fh, ">", $arg) or die "Can't write to '$arg': $!";
110 1         3 binmode($fh);
111 1         6 push(@{$response->{handlers}{response_data}}, {
112             callback => sub {
113 1 50       10 print $fh $_[3] or die "Can't write to '$arg': $!";
114 1         3 1;
115             },
116 1         1 });
117 1         4 push(@{$response->{handlers}{response_done}}, {
118             callback => sub {
119 1 50       26 close($fh) or die "Can't write to '$arg': $!";
120 1         5 undef($fh);
121             },
122 1         2 });
123             }
124             elsif (ref($arg) eq 'CODE') {
125 1         6 push(@{$response->{handlers}{response_data}}, {
126             callback => sub {
127 1         3 &$arg($_[3], $_[0], $self);
128 1         4 1;
129             },
130 1         16 });
131             }
132             else {
133 0         0 die "Unexpected collect argument '$arg'";
134             }
135              
136 63         315 $ua->run_handlers("response_header", $response);
137              
138 63 100       206 if (delete $response->{default_add_content}) {
139 61         400 push(@{$response->{handlers}{response_data}}, {
140             callback => sub {
141 44         255 $_[0]->add_content($_[3]);
142 44         990 1;
143             },
144 61         98 });
145             }
146              
147              
148 63         169 my $content_size = 0;
149 63         245 my $length = $response->content_length;
150 63         2216 my %skip_h;
151              
152 63         159 while ($content = &$collector, length $$content) {
153 46         149 for my $h ($ua->handlers("response_data", $response)) {
154 54 50       190 next if $skip_h{$h};
155 54 100       151 unless ($h->{callback}->($response, $ua, $h, $$content)) {
156             # XXX remove from $response->{handlers}{response_data} if present
157 8         36 $skip_h{$h}++;
158             }
159             }
160 46         92 $content_size += length($$content);
161 46 100       231 $ua->progress(($length ? ($content_size / $length) : "tick"), $response);
162 46 100 66     178 if (defined($max_size) && $content_size > $max_size) {
163 1         4 $response->push_header("Client-Aborted", "max_size");
164 1         38 last;
165             }
166             }
167             }
168             catch {
169 0     0   0 my $error = $_;
170 0         0 chomp($error);
171 0         0 $response->push_header('X-Died' => $error);
172 0         0 $response->push_header("Client-Aborted", "die");
173 63         688 };
174 63         1670 delete $response->{handlers}{response_data};
175 63 100       124 delete $response->{handlers} unless %{$response->{handlers}};
  63         182  
176 63         273 return $response;
177             }
178              
179              
180             sub collect_once
181             {
182 17     17 1 3151 my($self, $arg, $response) = @_;
183 17         34 my $content = \ $_[3];
184 17         23 my $first = 1;
185             $self->collect($arg, $response, sub {
186 34 100   34   93 return $content if $first--;
187 17         73 return \ "";
188 17         92 });
189             }
190              
191             1;
192              
193              
194             __END__