File Coverage

blib/lib/LWP/Protocol/AnyEvent/http.pm
Criterion Covered Total %
statement 78 102 76.4
branch 15 44 34.0
condition 0 11 0.0
subroutine 15 16 93.7
pod 1 1 100.0
total 109 174 62.6


line stmt bran cond sub pod time code
1              
2             package LWP::Protocol::AnyEvent::http;
3              
4 9     9   525985 use strict;
  9         64  
  9         217  
5 9     9   38 use warnings;
  9         16  
  9         196  
6              
7 9     9   3096 use version; our $VERSION = qv('v1.10.0');
  9         13265  
  9         39  
8              
9 9     9   2197 use AnyEvent qw( );
  9         8640  
  9         158  
10 9     9   4439 use AnyEvent::HTTP qw( http_request );
  9         206732  
  9         532  
11 9     9   3113 use HTTP::Response qw( );
  9         179337  
  9         181  
12 9     9   2969 use LWP::Protocol qw( );
  9         28885  
  9         151  
13 9     9   3068 use LWP::Protocol::http qw( );
  9         256035  
  9         8175  
14              
15             our @ISA = 'LWP::Protocol';
16              
17             LWP::Protocol::implementor($_, __PACKAGE__) for qw( http https );
18              
19              
20             # This code was based on _extra_sock_opts in LWP::Protocol::https
21             sub _get_tls_ctx {
22 0     0   0 my ($self) = @_;
23 0 0       0 my %ssl_opts = %{ $self->{ua}{ssl_opts} || {} };
  0         0  
24 0         0 my %tls_ctx;
25              
26             # Convert various ssl_opts values to corresponding AnyEvent::TLS tls_ctx values.
27 0         0 $tls_ctx{ verify } = $ssl_opts{SSL_verify_mode};
28 0 0 0     0 $tls_ctx{ verify_peername } = 'http' if defined($ssl_opts{SSL_verifycn_scheme}) && $ssl_opts{SSL_verifycn_scheme} eq 'www';
29 0 0       0 $tls_ctx{ ca_file } = $ssl_opts{SSL_ca_file} if exists($ssl_opts{SSL_ca_file});
30 0 0       0 $tls_ctx{ ca_path } = $ssl_opts{SSL_ca_path} if exists($ssl_opts{SSL_ca_path});
31 0 0       0 $tls_ctx{ cert_file } = $ssl_opts{SSL_cert_file} if exists($ssl_opts{SSL_cert_file});
32 0 0       0 $tls_ctx{ cert } = $ssl_opts{SSL_cert} if exists($ssl_opts{SSL_cert});
33 0 0       0 $tls_ctx{ key_file } = $ssl_opts{SSL_key_file} if exists($ssl_opts{SSL_key_file});
34 0 0       0 $tls_ctx{ key } = $ssl_opts{SSL_key} if exists($ssl_opts{SSL_key});
35              
36 0 0       0 if ($ssl_opts{verify_hostname}) {
37 0   0     0 $tls_ctx{verify} ||= 1;
38 0         0 $tls_ctx{verify_peername} = 'http';
39             }
40              
41             # We are verifying certificates, but don't have any CA specified, so we try using Mozilla::CA.
42 0 0 0     0 if ($tls_ctx{verify} && !( exists($tls_ctx{ca_file}) || exists($tls_ctx{ca_path}) )) {
      0        
43 0 0       0 if (!eval { require Mozilla::CA }) {
  0         0  
44 0 0       0 if ($@ !~ /^Can\'t locate Mozilla\/CA\.pm/) {
45 0         0 die 'Unable to find a list of Certificate Authorities to trust. '
46             . 'To fix this error, either install Mozilla::CA or configure '
47             . 'the ssl_opts as documented in LWP::UserAgent';
48             } else {
49 0         0 die $@;
50             }
51             }
52              
53 0         0 $tls_ctx{ca_file} = Mozilla::CA::SSL_ca_file();
54             }
55              
56 0         0 return \%tls_ctx;
57             }
58              
59              
60             sub _set_response_headers {
61 31     31   95 my ($response, $headers) = @_;
62              
63 31         196 my %headers = %$headers;
64              
65             $response->protocol( "HTTP/".delete($headers{ HTTPVersion }) )
66 31 100       354 if $headers{ HTTPVersion };
67 31         501 $response->code( delete($headers{ Status }) );
68 31         353 $response->message( delete($headers{ Reason }) );
69              
70             # Uppercase headers are pseudo headers added by AnyEvent::HTTP.
71 31         516 $headers{"X-AE-$_"} = delete($headers{$_}) for grep /^(?!X-)[A-Z]/, keys(%headers);
72              
73 31 100       101 if (exists($headers->{'set-cookie'})) {
74             # Set-Cookie headers are very non-standard.
75             # They cannot be safely joined.
76             # Try to undo their joining for HTTP::Cookies.
77             $headers{'set-cookie'} = [
78 2         8 split(/,(?=\s*\w+\s*(?:[=,;]|\z))/, $headers{'set-cookie'})
79             ];
80             }
81              
82             # Imitate Net::HTTP's removal of newlines.
83             s/\s*\n\s+/ /g
84 31         225 for values %headers;
85              
86 31         434 $response->header(%headers);
87             }
88              
89              
90             sub request {
91 16     16 1 38900 my ($self, $request, $proxy, $arg, $size, $timeout) = @_;
92              
93 16         65 my $method = $request->method();
94 16         179 my $url = $request->uri();
95              
96 16         100 my %headers;
97             {
98 16         33 my $headers_obj = $request->headers->clone();
  16         51  
99              
100             # Convert user:pass in url into an Authorization header.
101 16         1493 LWP::Protocol::http->_fixup_header($headers_obj, $url, $proxy);
102              
103             $headers_obj->scan(sub {
104 33     33   589 my ($k, $v) = @_;
105             # Imitate LWP::Protocol::http's removal of newlines.
106 33         115 $v =~ s/\n/ /g;
107 33         110 $headers{ lc($k) } = $v;
108 16         1107 });
109             }
110              
111 16         270 my $body = $request->content_ref();
112              
113             # Fix AnyEvent::HTTP setting Referer to the request URL
114 16 100       329 $headers{referer} = undef unless exists $headers{referer};
115              
116             # The status code will be replaced.
117 16         129 my $response = HTTP::Response->new(599, 'Internal Server Error');
118 16         934 $response->request($request);
119              
120 16         542 my $headers_avail = AnyEvent->condvar();
121 16         5219 my $data_avail = AnyEvent->condvar();
122 16         83 my @data_queue;
123              
124             my %handle_opts;
125 16 50       65 $handle_opts{read_size} = $size if defined($size);
126 16 50       58 $handle_opts{max_read_size} = $size if defined($size);
127              
128 16         83 my %opts = ( handle_params => \%handle_opts );
129 16 50       86 $opts{body} = $$body if defined($body);
130 16 50       391 $opts{timeout} = $timeout if defined($timeout);
131              
132 16 50       59 if ($url->scheme eq 'https') {
133 0         0 $opts{tls_ctx} = $self->_get_tls_ctx();
134             }
135              
136 16 100       297 if ($proxy) {
137 1         9 my $proxy_uri = URI->new($proxy);
138 1         60 $opts{proxy} = [ $proxy_uri->host, $proxy_uri->port, $proxy_uri->scheme ];
139             }
140              
141             # Let LWP handle redirects and cookies.
142             http_request(
143             $method => $url,
144             headers => \%headers,
145             %opts,
146             recurse => 0,
147             on_header => sub {
148             #my ($headers) = @_;
149 15     15   10086354 _set_response_headers($response, $_[0]);
150 15         2783 $headers_avail->send();
151 15         158 return 1;
152             },
153             on_body => sub {
154             #my ($chunk, $headers) = @_;
155 16     16   6996684 push @data_queue, \$_[0];
156 16         82 $data_avail->send();
157 16         167 return 1;
158             },
159             sub { # On completion
160             # On successful completion: @_ = ( '', $headers )
161             # On error: @_ = ( undef, $headers )
162              
163             # It is possible for the request to complete without
164             # calling the header callback in the event of error.
165             # It is also possible for the Status to change as the
166             # result of an error. This handles these events.
167 16     16   4966963 _set_response_headers($response, $_[1]);
168 16         2636 $headers_avail->send();
169              
170 16         149 push @data_queue, \''; # '
171 16         48 $data_avail->send();
172             },
173 16         344 );
174              
175             # We need to wait for the headers so the response code
176             # is set up properly. LWP::Protocol decides on ->is_success
177             # whether to call the :content_cb or not.
178 16         115389 $headers_avail->recv();
179              
180             return $self->collect($arg, $response, sub {
181 32 100   32   18930 if (!@data_queue) {
182             # Re-prime our channel, in case there is more.
183 13         467 $data_avail = AnyEvent->condvar();
184              
185             # Wait for more data to arrive
186 13         173 $data_avail->recv();
187             };
188              
189 32         1882 return shift(@data_queue);
190 16         2091 });
191             }
192              
193              
194             1;
195              
196              
197             __END__