File Coverage

blib/lib/AnyEvent/UserAgent.pm
Criterion Covered Total %
statement 97 113 85.8
branch 29 38 76.3
condition 18 36 50.0
subroutine 18 22 81.8
pod 6 6 100.0
total 168 215 78.1


line stmt bran cond sub pod time code
1             package AnyEvent::UserAgent;
2              
3             # This module based on original AnyEvent::HTTP::Simple module by punytan
4             # (punytan@gmail.com): http://github.com/punytan/AnyEvent-HTTP-Simple
5              
6 7     7   288828 use Moo;
  7         169382  
  7         50  
7              
8 7     7   25269 use AnyEvent::HTTP ();
  7         326812  
  7         298  
9 7     7   7928 use HTTP::Cookies ();
  7         153192  
  7         219  
10 7     7   13725 use HTTP::Request ();
  7         255303  
  7         235  
11 7     7   9089 use HTTP::Request::Common ();
  7         17528  
  7         176  
12 7     7   9730 use HTTP::Response ();
  7         62286  
  7         221  
13              
14 7     7   8589 use namespace::clean;
  7         114752  
  7         61  
15              
16             our $VERSION = '0.06';
17              
18              
19             has agent => (is => 'rw', default => sub { $AnyEvent::HTTP::USERAGENT . ' AnyEvent-UserAgent/' . $VERSION });
20              
21             has cookie_jar => (is => 'rw', default => sub { HTTP::Cookies->new });
22              
23             has max_redirects => (is => 'rw', default => sub { 5 });
24              
25             has inactivity_timeout => (is => 'rw', default => sub { 20 });
26              
27             has request_timeout => (is => 'rw', default => sub { 0 });
28              
29             sub request {
30 6     6 1 66108 my $cb = pop();
31 6         68 my ($self, $req, %opts) = @_;
32              
33             $self->_request($req, \%opts, sub {
34 6     6   44 $self->_response($req, @_, $cb);
35 6         78 });
36             }
37              
38 5     5 1 37425 sub get { _make_request(GET => @_) }
39 0     0 1 0 sub head { _make_request(HEAD => @_) }
40 0     0 1 0 sub put { _make_request(PUT => @_) }
41 0     0 1 0 sub delete { _make_request(DELETE => @_) }
42 0     0 1 0 sub post { _make_request(POST => @_) }
43              
44             sub _make_request {
45 5     5   15 my $cb = pop();
46 5         18 my $meth = shift();
47 5         17 my $self = shift();
48              
49 7     7   4527 no strict 'refs';
  7         16  
  7         9468  
50 5         14 $self->request(&{'HTTP::Request::Common::' . $meth}(@_), $cb);
  5         80  
51             }
52              
53             sub _request {
54 7     7   24 my ($self, $req, $opts, $cb) = @_;
55              
56 7         42 my $uri = $req->uri;
57 7         169 my $hdrs = $req->headers;
58              
59 7 100       86 unless ($hdrs->user_agent) {
60 6         349 $hdrs->user_agent($self->agent);
61             }
62              
63 7 50 66     333 if ($uri->can('userinfo') && $uri->userinfo && !$hdrs->authorization) {
      33        
64 0         0 $hdrs->authorization_basic(split(':', $uri->userinfo, 2));
65             }
66 7 100       2279 if ($uri->scheme) {
67 6         294 $self->cookie_jar->add_cookie_header($req);
68             }
69              
70 7         1507 for (qw(max_redirects inactivity_timeout request_timeout)) {
71 21 100       140 $opts->{$_} = $self->$_() unless exists($opts->{$_});
72             }
73              
74 7         18 my ($grd, $tmr);
75              
76 7 100       47 if ($opts->{request_timeout}) {
77             $tmr = AE::timer $opts->{request_timeout}, 0, sub {
78 1     1   486708 undef($grd);
79 1         13 $cb->($opts, undef, {Status => 597, Reason => 'Request timeout'});
80 1         23 };
81             }
82 8         330 $grd = AnyEvent::HTTP::http_request(
83             $req->method,
84             $req->uri,
85 1         11 headers => {map { $_ => $hdrs->header($_) } $hdrs->header_field_names},
86             body => $req->content,
87             recurse => 0,
88             timeout => $opts->{inactivity_timeout},
89 84         551 (map { $_ => $opts->{$_} } grep { exists($opts->{$_}) }
90             qw(proxy tls_ctx session timeout on_prepare tcp_connect on_header
91             on_body want_body_handle persistent keepalive handle_params)),
92             sub {
93 6     6   189711 undef($grd);
94 6         16 undef($tmr);
95 6         59 $cb->($opts, @_);
96             }
97 7         101 );
98             }
99              
100             sub _response {
101 7     7   20 my $cb = pop();
102 7         22 my ($self, $req, $opts, $body, $hdrs, $prev, $count) = @_;
103              
104 7         100 my $res = HTTP::Response->new(delete($hdrs->{Status}), delete($hdrs->{Reason}));
105              
106 7         571 $res->request($req);
107 7 100       99 $res->previous($prev) if $prev;
108              
109 7         25 delete($hdrs->{URL});
110 7 50       42 if (defined($hdrs->{HTTPVersion})) {
111 0         0 $res->protocol('HTTP/' . delete($hdrs->{HTTPVersion}));
112             }
113 7 50       29 if (my $cookies = $hdrs->{'set-cookie'}) {
114 0         0 local @_ = split(/,(\w+=)/, ',' . $cookies);
115 0         0 shift();
116 0         0 my @val;
117 0         0 push(@val, join('', shift(), shift())) while @_;
118 0         0 $hdrs->{'set-cookie'} = \@val;
119             }
120 7 100       48 if (keys(%$hdrs)) {
121 2         14 $res->header(%$hdrs);
122             }
123 7 50 66     173 if ($res->code >= 590 && $res->code <= 599 && $res->message) {
      66        
124 3 50       129 if ($res->message eq 'Connection timed out') {
125 0         0 $res->message('Inactivity timeout');
126             }
127 3 50       62 unless ($res->header('client-warning')) {
128 3         316 $res->header('client-warning' => $res->message);
129             }
130             }
131 7 100       303 if (defined($body)) {
132 4         39 $res->content_ref(\$body);
133             }
134 7         148 $self->cookie_jar->extract_cookies($res);
135              
136 7         894 my $code = $res->code;
137              
138 7 100 66     225 if ($code == 301 || $code == 302 || $code == 303 || $code == 307 || $code == 308) {
      66        
      66        
      33        
139 2         9 $self->_redirect($req, $opts, $code, $res, $count, $cb);
140             }
141             else {
142 5         27 $cb->($res);
143             }
144             }
145              
146             sub _redirect {
147 2     2   5 my ($self, $req, $opts, $code, $prev, $count, $cb) = @_;
148              
149 2 100       15 unless (defined($count) ? $count : ($count = $opts->{max_redirects})) {
    100          
150 1         8 $prev->header('client-warning' => 'Redirect loop detected (max_redirects = ' . $opts->{max_redirects} . ')');
151 1         61 $cb->($prev);
152 1         889 return;
153             }
154              
155 1         6 my $meth = $req->method;
156 1         14 my $proto = $req->uri->scheme;
157 1         25 my $uri = $prev->header('location');
158              
159 1         31 $req = $req->clone();
160 1         232 $req->remove_header('cookie');
161 1 50 33     44 if (($code == 302 || $code == 303) && !($meth eq 'GET' || $meth eq 'HEAD')) {
      33        
      33        
162 0         0 $req->method('GET');
163 0         0 $req->content('');
164 0         0 $req->remove_content_headers();
165             }
166             {
167             # Support for relative URL for redirect.
168             # Not correspond to RFC.
169 1         1 local $URI::ABS_ALLOW_RELATIVE_SCHEME = 1;
  1         3  
170 1         5 my $base = $prev->base;
171 1 50       438 $uri = $HTTP::URI_CLASS->new(defined($uri) ? $uri : '', $base)->abs($base);
172             }
173 1         140 $req->uri($uri);
174 1 50 33     19 if ($proto eq 'https' && $uri->scheme eq 'http') {
175             # Suppress 'Referer' header for HTTPS to HTTP redirect.
176             # RFC 2616, section 15.1.3.
177 0         0 $req->remove_header('referer');
178             }
179              
180             $self->_request($req, $opts, sub {
181 1     1   24 $self->_response($req, @_, $prev, $count - 1, sub { return $cb->(@_); });
  1         7  
182 1         8 });
183             }
184              
185              
186             1;
187              
188              
189             __END__