| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package AnyEvent::UA::Req; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
sub new { |
|
4
|
0
|
|
|
0
|
|
|
my $pk = shift; |
|
5
|
0
|
|
|
|
|
|
my ($method,$uri) = (shift,shift); |
|
6
|
0
|
|
|
|
|
|
my $self = bless {@_}, $pk; |
|
7
|
0
|
|
|
|
|
|
$self->{method} = $method; |
|
8
|
0
|
|
|
|
|
|
$self->{uri} = $uri; |
|
9
|
0
|
|
|
|
|
|
$self; |
|
10
|
|
|
|
|
|
|
} |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub error { |
|
13
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
14
|
0
|
|
|
|
|
|
$self->{cb}( undef, HTTP::Easy::Headers->new->HTTP(@_) ); |
|
15
|
0
|
|
|
|
|
|
%$self = (); |
|
16
|
|
|
|
|
|
|
} |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package AnyEvent::UA::Con; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new { |
|
21
|
0
|
|
|
0
|
|
|
my $pk = shift; |
|
22
|
0
|
|
|
|
|
|
my $self = bless {@_}, $pk; |
|
23
|
0
|
|
|
|
|
|
$self; |
|
24
|
|
|
|
|
|
|
} |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
package AnyEvent::UA; |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
#use strict; |
|
29
|
|
|
|
|
|
|
#use warnings; |
|
30
|
1
|
|
|
1
|
|
26196
|
use common::sense; |
|
|
1
|
|
|
|
|
10
|
|
|
|
1
|
|
|
|
|
7
|
|
|
31
|
|
|
|
|
|
|
|
|
32
|
1
|
|
|
1
|
|
879
|
use AE; |
|
|
1
|
|
|
|
|
16080
|
|
|
|
1
|
|
|
|
|
37
|
|
|
33
|
1
|
|
|
1
|
|
1199
|
use AnyEvent::DNS; |
|
|
1
|
|
|
|
|
41417
|
|
|
|
1
|
|
|
|
|
47
|
|
|
34
|
1
|
|
|
1
|
|
14
|
use AnyEvent::Socket; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
114
|
|
|
35
|
1
|
|
|
1
|
|
1266
|
use AnyEvent::Handle; |
|
|
1
|
|
|
|
|
9242
|
|
|
|
1
|
|
|
|
|
41
|
|
|
36
|
1
|
|
|
1
|
|
427
|
use HTTP::Easy::Headers; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
use HTTP::Easy::Cookies; |
|
38
|
|
|
|
|
|
|
use Scalar::Util 'weaken'; |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head1 NAME |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
AnyEvent::UA - HTTP/1.1 UserAgent using AnyEvent |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=cut |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
our $VERSION = '0.01_01';#$VERSION = eval($VERSION); |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
Full docs to be done, so just an example. |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my $ua = AnyEvent::UA->new(); |
|
54
|
|
|
|
|
|
|
$ua->req(GET => 'HTTP://www.google.ru:80', cb => sub { |
|
55
|
|
|
|
|
|
|
my ($body,$headers) = @_; |
|
56
|
|
|
|
|
|
|
}); |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
This module is alpha quality. It was not tested perfectly. Use it on your own risk. Interfaces and implementation may be changed. |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=cut |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub new { |
|
65
|
|
|
|
|
|
|
my $pk = shift; |
|
66
|
|
|
|
|
|
|
my $self = bless {}, $pk; |
|
67
|
|
|
|
|
|
|
my %args = @_; |
|
68
|
|
|
|
|
|
|
$self->{headers} = { |
|
69
|
|
|
|
|
|
|
# 'accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', |
|
70
|
|
|
|
|
|
|
# 'user-agent' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042315 Firefox/3.0.10', |
|
71
|
|
|
|
|
|
|
'referer' => undef, |
|
72
|
|
|
|
|
|
|
# 'accept-language' => 'ru,en-us;q=0.8,en;q=0.5,ru-ru;q=0.3', |
|
73
|
|
|
|
|
|
|
# 'accept-encoding' => 'gzip', |
|
74
|
|
|
|
|
|
|
'accept-charset' => 'utf-8,windows-1251;q=0.7,*;q=0.7', |
|
75
|
|
|
|
|
|
|
'connection' => 'keep-alive', |
|
76
|
|
|
|
|
|
|
%{ $args{headers} || {} }, |
|
77
|
|
|
|
|
|
|
}; |
|
78
|
|
|
|
|
|
|
$self->{cv} = $args{cv} || AE::cv; |
|
79
|
|
|
|
|
|
|
$self->{cookie} //= HTTP::Easy::Cookies->new(); |
|
80
|
|
|
|
|
|
|
#$self->{auth} = {}; |
|
81
|
|
|
|
|
|
|
#$self->{requests} = []; |
|
82
|
|
|
|
|
|
|
#$self->{domain} = $args{domain} || '.odnoklassniki.ru'; |
|
83
|
|
|
|
|
|
|
$self->{debug} = $args{debug} // 1; |
|
84
|
|
|
|
|
|
|
$self->{proxy} = $args{proxy} if exists $args{proxy}; |
|
85
|
|
|
|
|
|
|
$self; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
our $TIMEOUT = 10; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub connect : method { |
|
92
|
|
|
|
|
|
|
my ($self,$host,$port,%args) = @_; |
|
93
|
|
|
|
|
|
|
# TODO: |
|
94
|
|
|
|
|
|
|
# * slots (max-open-con) |
|
95
|
|
|
|
|
|
|
# * single resolve queue |
|
96
|
|
|
|
|
|
|
$self->{cv}->begin; |
|
97
|
|
|
|
|
|
|
my %state; |
|
98
|
|
|
|
|
|
|
my $con = sub { |
|
99
|
|
|
|
|
|
|
if (my $ra = shift) { |
|
100
|
|
|
|
|
|
|
warn "ready to con $ra $port"; |
|
101
|
|
|
|
|
|
|
$state{connect} = tcp_connect $ra,$port,sub { |
|
102
|
|
|
|
|
|
|
my $fh = shift; |
|
103
|
|
|
|
|
|
|
@_ = (); |
|
104
|
|
|
|
|
|
|
if( $fh ) { |
|
105
|
|
|
|
|
|
|
$args{cb}($fh); |
|
106
|
|
|
|
|
|
|
} else { |
|
107
|
|
|
|
|
|
|
$args{cb}(undef,"$!"); |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
%state = (); |
|
110
|
|
|
|
|
|
|
},$args{on_prepare} || sub { $args{timeout} || $TIMEOUT }; |
|
111
|
|
|
|
|
|
|
} else { |
|
112
|
|
|
|
|
|
|
$args{cb}(undef,@_); |
|
113
|
|
|
|
|
|
|
$self->{cv}->end; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
}; |
|
116
|
|
|
|
|
|
|
my $ip = $self->{dns}{$host}; |
|
117
|
|
|
|
|
|
|
if ($ip) { |
|
118
|
|
|
|
|
|
|
push @$ip, my $ra = shift @$ip; |
|
119
|
|
|
|
|
|
|
$con->($ra); |
|
120
|
|
|
|
|
|
|
} else { |
|
121
|
|
|
|
|
|
|
AnyEvent::DNS::a $host, sub { |
|
122
|
|
|
|
|
|
|
if (@_) { |
|
123
|
|
|
|
|
|
|
$self->{dns}{$host} = [@_]; |
|
124
|
|
|
|
|
|
|
$con->($_[-1]); |
|
125
|
|
|
|
|
|
|
} else { |
|
126
|
|
|
|
|
|
|
$con->(undef, "$!"); |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
}; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
return defined wantarray ? AnyEvent::Util::guard { %state = (); } : undef; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
our $qr_nl = qr{\015?\012}o; |
|
134
|
|
|
|
|
|
|
our $qr_nlnl = qr{(?
|
|
135
|
|
|
|
|
|
|
our $MAX_RECURSE = 10; |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub decode_uri { |
|
138
|
|
|
|
|
|
|
my $self = shift; |
|
139
|
|
|
|
|
|
|
my $uri = shift; |
|
140
|
|
|
|
|
|
|
my $port = { http => 80, https => 443, }->{ lc $uri->scheme } or return; |
|
141
|
|
|
|
|
|
|
my $realport = $uri->port; |
|
142
|
|
|
|
|
|
|
my $host = lc $uri->host; |
|
143
|
|
|
|
|
|
|
#warn "$host : $port"; |
|
144
|
|
|
|
|
|
|
my $host_header = $port != $realport ? "$host:$realport" : $host; |
|
145
|
|
|
|
|
|
|
my $proxy; |
|
146
|
|
|
|
|
|
|
my ($rhost, $rport, $rscheme, $rpath); # request host, port, path |
|
147
|
|
|
|
|
|
|
if ($proxy) { |
|
148
|
|
|
|
|
|
|
($rpath, $rhost, $rport, $rscheme) = ("$uri", @$proxy); |
|
149
|
|
|
|
|
|
|
$rscheme = "http" unless defined $rscheme; |
|
150
|
|
|
|
|
|
|
# don't support https requests over https-proxy transport, |
|
151
|
|
|
|
|
|
|
# can't be done with tls as spec'ed, unless you double-encrypt. |
|
152
|
|
|
|
|
|
|
$rscheme = "http" if $uri->scheme eq "https" && $rscheme eq "https"; |
|
153
|
|
|
|
|
|
|
} else { |
|
154
|
|
|
|
|
|
|
($rhost, $rport, $rscheme, $rpath) = ($host,$realport,$uri->scheme,$uri->path); |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
return ($rhost, $rport, $rscheme, $rpath, $host_header); |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub req { |
|
160
|
|
|
|
|
|
|
my $self = shift; |
|
161
|
|
|
|
|
|
|
my ($method, $uri, %args) = @_; |
|
162
|
|
|
|
|
|
|
use URI; |
|
163
|
|
|
|
|
|
|
$uri = URI->new($uri) unless ref $uri; |
|
164
|
|
|
|
|
|
|
$uri->path('/') unless length $uri->path; |
|
165
|
|
|
|
|
|
|
my %state; |
|
166
|
|
|
|
|
|
|
my $e = sub { my ($code,$mess) = @_; %state = (); $args{cb}(undef, { Status => $code, Reason => $mess, URL => $uri }); }; |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
my ($host, $port, $scheme, $path, $host_header) = $self->decode_uri($uri) |
|
169
|
|
|
|
|
|
|
or return $e->(599); |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
my $headers = HTTP::Easy::Headers->new( { %{$self->{headers}}, host => $host_header } ); |
|
172
|
|
|
|
|
|
|
warn "($host, $port, $scheme, $path) \n"; |
|
173
|
|
|
|
|
|
|
my $conkey = "$host:$port"; |
|
174
|
|
|
|
|
|
|
my $id; |
|
175
|
|
|
|
|
|
|
if (exists $self->{ka}{$conkey}) { |
|
176
|
|
|
|
|
|
|
$id = $self->{ka}{$conkey}; |
|
177
|
|
|
|
|
|
|
warn "Have KA for $conkey: $self->{con}{ $id }"; |
|
178
|
|
|
|
|
|
|
push @{ $self->{con}{ $id }{r} }, AnyEvent::UA::Req->new( |
|
179
|
|
|
|
|
|
|
$method, $uri, %args, headers => $headers, |
|
180
|
|
|
|
|
|
|
); |
|
181
|
|
|
|
|
|
|
#$self->rr($h, $method, $uri, %args, path => $path, headers => $headers); |
|
182
|
|
|
|
|
|
|
$self->rr2($id); |
|
183
|
|
|
|
|
|
|
return; |
|
184
|
|
|
|
|
|
|
} else { |
|
185
|
|
|
|
|
|
|
# TODO: |
|
186
|
|
|
|
|
|
|
# push req to r, connect, handle all |
|
187
|
|
|
|
|
|
|
{ |
|
188
|
|
|
|
|
|
|
weaken( my $this = $self ); |
|
189
|
|
|
|
|
|
|
my $con = { |
|
190
|
|
|
|
|
|
|
host => $host, |
|
191
|
|
|
|
|
|
|
port => $port, |
|
192
|
|
|
|
|
|
|
r => [], |
|
193
|
|
|
|
|
|
|
# TODO |
|
194
|
|
|
|
|
|
|
# $self->{keep_alive} ? ( |
|
195
|
|
|
|
|
|
|
# ka => AE::timer 300,0,sub { |
|
196
|
|
|
|
|
|
|
# $self or return; |
|
197
|
|
|
|
|
|
|
# delete $self->{con}{$id}; |
|
198
|
|
|
|
|
|
|
# }, |
|
199
|
|
|
|
|
|
|
# ) : (), |
|
200
|
|
|
|
|
|
|
}; |
|
201
|
|
|
|
|
|
|
$id = int $con; |
|
202
|
|
|
|
|
|
|
$con->{id} = $id; |
|
203
|
|
|
|
|
|
|
$self->{con}{$id} = $con; |
|
204
|
|
|
|
|
|
|
$self->{ka}{$conkey} = $id; |
|
205
|
|
|
|
|
|
|
$con->{close} = sub { |
|
206
|
|
|
|
|
|
|
$this or return; |
|
207
|
|
|
|
|
|
|
exists $this->{con}{$id} or return; |
|
208
|
|
|
|
|
|
|
for(@{ $this->{con}{$id}{r} }) { |
|
209
|
|
|
|
|
|
|
$_->error(599,$_[0]); |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
delete $this->{con}{$id}; |
|
212
|
|
|
|
|
|
|
}; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
push @{ $self->{con}{ $id }{r} }, AnyEvent::UA::Req->new( |
|
215
|
|
|
|
|
|
|
$method, $uri, %args, headers => $headers, |
|
216
|
|
|
|
|
|
|
); |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
my $timeout = $args{timeout} || $TIMEOUT; |
|
219
|
|
|
|
|
|
|
my $proxy = $args{proxy};# || $PROXY; |
|
220
|
|
|
|
|
|
|
$state{connect} = |
|
221
|
|
|
|
|
|
|
$self->connect( |
|
222
|
|
|
|
|
|
|
$host, $port, |
|
223
|
|
|
|
|
|
|
timeout => $timeout, |
|
224
|
|
|
|
|
|
|
on_prepare => $args{on_prepare}, |
|
225
|
|
|
|
|
|
|
cb => sub { |
|
226
|
|
|
|
|
|
|
if (my $fh = shift) { |
|
227
|
|
|
|
|
|
|
warn "connected 1"; |
|
228
|
|
|
|
|
|
|
return unless delete $state{connect}; |
|
229
|
|
|
|
|
|
|
warn "connected 2. id = $id"; |
|
230
|
|
|
|
|
|
|
my $h = AnyEvent::Handle->new( |
|
231
|
|
|
|
|
|
|
fh => $fh, |
|
232
|
|
|
|
|
|
|
timeout => $timeout, |
|
233
|
|
|
|
|
|
|
peername => $host, |
|
234
|
|
|
|
|
|
|
on_eof => sub { warn "EOF"; delete($self->{con}{$id})->{close}("Unexpected end-of-file") }, |
|
235
|
|
|
|
|
|
|
on_error => sub { warn "ERR @_"; delete($self->{con}{$id})->{close}( $_[2]); }, |
|
236
|
|
|
|
|
|
|
#tls_ctx => $arg{tls_ctx}, |
|
237
|
|
|
|
|
|
|
); |
|
238
|
|
|
|
|
|
|
$self->{con}{$id}{h} = $h; |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# TODO: limit KA conns |
|
241
|
|
|
|
|
|
|
# (re-)configure handle |
|
242
|
|
|
|
|
|
|
my $request = sub { |
|
243
|
|
|
|
|
|
|
# Connection initially established |
|
244
|
|
|
|
|
|
|
#$self->rr($h, $method, $uri, %args, path => $path, headers => $headers); |
|
245
|
|
|
|
|
|
|
$self->rr2($id); |
|
246
|
|
|
|
|
|
|
};#END $request |
|
247
|
|
|
|
|
|
|
# now handle proxy-CONNECT method |
|
248
|
|
|
|
|
|
|
$h->starttls ("connect") if $scheme eq "https"; |
|
249
|
|
|
|
|
|
|
if ($proxy and $scheme eq "https") { |
|
250
|
|
|
|
|
|
|
my $peer = (my $uhost = $uri->host).':'.$uri->port; |
|
251
|
|
|
|
|
|
|
$h->push_write ("CONNECT $peer HTTP/1.0\015\012Host: $uhost\015\012\015\012"); |
|
252
|
|
|
|
|
|
|
$h->push_read (line => $qr_nlnl, sub { |
|
253
|
|
|
|
|
|
|
$_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ix |
|
254
|
|
|
|
|
|
|
or return $e->(599, "Invalid proxy connect response ($_[1])"); |
|
255
|
|
|
|
|
|
|
if ($2 == 200) { |
|
256
|
|
|
|
|
|
|
$path = $uri->path; |
|
257
|
|
|
|
|
|
|
$self->{con}{$id}{type} = 'raw'; |
|
258
|
|
|
|
|
|
|
$self->rr2($id); |
|
259
|
|
|
|
|
|
|
} else { |
|
260
|
|
|
|
|
|
|
return $e->($2,$3); |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
}); |
|
263
|
|
|
|
|
|
|
} else { |
|
264
|
|
|
|
|
|
|
$h->starttls ("connect") if $scheme eq "https" && !exists $state{handle}{tls}; |
|
265
|
|
|
|
|
|
|
$self->rr2($id); |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
} else { |
|
268
|
|
|
|
|
|
|
warn "Got error @_"; |
|
269
|
|
|
|
|
|
|
return $e->(599,@_); |
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
); |
|
273
|
|
|
|
|
|
|
return; |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
sub rr2 { |
|
277
|
|
|
|
|
|
|
my $self = shift; |
|
278
|
|
|
|
|
|
|
my $id = shift; |
|
279
|
|
|
|
|
|
|
return warn "no such connection $id" unless exists $self->{con}{$id}; |
|
280
|
|
|
|
|
|
|
my $con = $self->{con}{$id}; |
|
281
|
|
|
|
|
|
|
return warn ("Not connected yet"), unless $con->{h}; |
|
282
|
|
|
|
|
|
|
return warn ("No more requests for $id"), $con->{h}->timeout(undef) unless @{ $con->{r} }; |
|
283
|
|
|
|
|
|
|
#while (@{ $con->{r} }) { |
|
284
|
|
|
|
|
|
|
my $r = shift @{ $con->{r} }; |
|
285
|
|
|
|
|
|
|
warn "Run request $r->{method} $r->{uri} over $con->{id}"; |
|
286
|
|
|
|
|
|
|
if ($con->{type} eq 'proxy') { |
|
287
|
|
|
|
|
|
|
return $r->error(599, "Proxy not implemented"); |
|
288
|
|
|
|
|
|
|
} else { |
|
289
|
|
|
|
|
|
|
my $path = $r->{uri}->path_query; |
|
290
|
|
|
|
|
|
|
$con->{h}->push_write ( |
|
291
|
|
|
|
|
|
|
"$r->{method} $path HTTP/1.1\015\012" . |
|
292
|
|
|
|
|
|
|
$r->{headers}->encode . "\015\012" . |
|
293
|
|
|
|
|
|
|
(delete $r->{body}) |
|
294
|
|
|
|
|
|
|
); |
|
295
|
|
|
|
|
|
|
$con->{h}->push_read (line => $qr_nl, sub { |
|
296
|
|
|
|
|
|
|
#return unless exists $self->{con}{$id}; |
|
297
|
|
|
|
|
|
|
$_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ixo |
|
298
|
|
|
|
|
|
|
or return $r->error( 599, "Invalid server response ($_[1])" ); |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
my $status = $2;my $reason = $3;my $http_version = $1; |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# headers, could be optimized a bit |
|
303
|
|
|
|
|
|
|
$con->{h}->unshift_read (line => $qr_nlnl, sub { |
|
304
|
|
|
|
|
|
|
my $uri = $r->{uri}; |
|
305
|
|
|
|
|
|
|
my $method = $r->{method}; |
|
306
|
|
|
|
|
|
|
my $hdr = HTTP::Easy::Headers->decode($_[1], base => $uri); |
|
307
|
|
|
|
|
|
|
$hdr->{Status} = $status; |
|
308
|
|
|
|
|
|
|
$hdr->{Reason} = $reason; |
|
309
|
|
|
|
|
|
|
# TODO: check correctness? |
|
310
|
|
|
|
|
|
|
# or return $r->error(599, "Garbled response headers"); |
|
311
|
|
|
|
|
|
|
$self->{cookie}->decode($hdr->{"set-cookie"}, host => $uri->host) if exists $hdr->{"set-cookie"}; |
|
312
|
|
|
|
|
|
|
$self->{cookie}->decode($hdr->{"set-cookie2"}, host => $uri->host) if exists $hdr->{"set-cookie2"}; |
|
313
|
|
|
|
|
|
|
$self->{cookie}->decode($hdr->{"set-cookie3"}, host => $uri->host) if exists $hdr->{"set-cookie3"}; |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
my $redirect; |
|
316
|
|
|
|
|
|
|
my $recurse = 0;# TODO: exists $args{recurse} ? delete $args{recurse} : $MAX_RECURSE; |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
if ($recurse) { |
|
319
|
|
|
|
|
|
|
if ($status =~ /^30[12]$/ and $method ne "POST") { |
|
320
|
|
|
|
|
|
|
# apparently, mozilla et al. just change POST to GET here |
|
321
|
|
|
|
|
|
|
# more research is needed before we do the same |
|
322
|
|
|
|
|
|
|
$redirect = 1; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
elsif ($status == 303) { |
|
325
|
|
|
|
|
|
|
# even http/1.1 is unclear on how to mutate the method |
|
326
|
|
|
|
|
|
|
$method = "GET" unless $method eq "HEAD"; |
|
327
|
|
|
|
|
|
|
$redirect = 1; |
|
328
|
|
|
|
|
|
|
} |
|
329
|
|
|
|
|
|
|
elsif ($status == 307 and $method =~ /^(?:GET|HEAD)$/) { |
|
330
|
|
|
|
|
|
|
$redirect = 1; |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
my $finish = sub { |
|
335
|
|
|
|
|
|
|
#$con->destroy if $con; |
|
336
|
|
|
|
|
|
|
#%state = (); |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
if ($redirect && exists $hdr->{location}) { |
|
339
|
|
|
|
|
|
|
# we ignore any errors, as it is very common to receive |
|
340
|
|
|
|
|
|
|
# Content-Length != 0 but no actual body |
|
341
|
|
|
|
|
|
|
# we also access %hdr, as $_[1] might be an erro |
|
342
|
|
|
|
|
|
|
#http_request ($method => $hdr{location}, %arg, recurse => $recurse - 1, $cb); |
|
343
|
|
|
|
|
|
|
warn "Redirect => $hdr->{location}"; |
|
344
|
|
|
|
|
|
|
} else { |
|
345
|
|
|
|
|
|
|
if (exists $_[1]{'content-encoding'}) { |
|
346
|
|
|
|
|
|
|
if (lc($_[1]{'content-encoding'}) =~ /^(?:x-)?gzip$/) { |
|
347
|
|
|
|
|
|
|
eval{ |
|
348
|
|
|
|
|
|
|
my $def = Compress::Zlib::memGunzip($_[0]); |
|
349
|
|
|
|
|
|
|
if (defined $def) { |
|
350
|
|
|
|
|
|
|
$_[0] = $def; |
|
351
|
|
|
|
|
|
|
#warn "Page deflated from $hdr->{'content-encoding'}" if $self->{debug}; |
|
352
|
|
|
|
|
|
|
1; |
|
353
|
|
|
|
|
|
|
} else { 0 } |
|
354
|
|
|
|
|
|
|
} or do { |
|
355
|
|
|
|
|
|
|
warn "Deflate failed: $@"; |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
} else { |
|
358
|
|
|
|
|
|
|
warn "Unsupported content-encoding method: $_[1]{'content-encoding'}"; |
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
} |
|
361
|
|
|
|
|
|
|
$r->{cb}($_[0], $_[1]); |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
$self->rr2($id); |
|
364
|
|
|
|
|
|
|
}; |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
my $len = $hdr->{"content-length"}; |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# if (!$redirect && $args{on_header} && !$args{on_header}($hdr)) { |
|
369
|
|
|
|
|
|
|
# $finish->(undef, { Status => 598, Reason => "Request cancelled by on_header", URL => $uri }); |
|
370
|
|
|
|
|
|
|
# } |
|
371
|
|
|
|
|
|
|
# elsif ( |
|
372
|
|
|
|
|
|
|
if( |
|
373
|
|
|
|
|
|
|
$status =~ /^(?:1..|[23]04)$/ |
|
374
|
|
|
|
|
|
|
or $method eq "HEAD" |
|
375
|
|
|
|
|
|
|
or (defined $len && !$len) |
|
376
|
|
|
|
|
|
|
) { |
|
377
|
|
|
|
|
|
|
# no body |
|
378
|
|
|
|
|
|
|
$finish->("", $hdr); |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
else { |
|
381
|
|
|
|
|
|
|
#warn dumper $hdr,$self->{cookie}; |
|
382
|
|
|
|
|
|
|
if (lc $hdr->{'transfer-encoding'} eq 'chunked') { |
|
383
|
|
|
|
|
|
|
my $body = ''; |
|
384
|
|
|
|
|
|
|
my $get_chunk;$get_chunk = sub { |
|
385
|
|
|
|
|
|
|
$con->{h}->unshift_read( regex => qr{([a-f0-9]{1,32})(?:[\011\040]+[^\012]{0,255})?\015?\012}o,sub { |
|
386
|
|
|
|
|
|
|
my $chunk = hex($1); |
|
387
|
|
|
|
|
|
|
if ($chunk > 0) { |
|
388
|
|
|
|
|
|
|
$get_chunk->(); |
|
389
|
|
|
|
|
|
|
#warn "need chunk $chunk"; |
|
390
|
|
|
|
|
|
|
$_[0]->unshift_read(chunk => $chunk, sub { |
|
391
|
|
|
|
|
|
|
$body .= $_[1]; |
|
392
|
|
|
|
|
|
|
}); |
|
393
|
|
|
|
|
|
|
} else { |
|
394
|
|
|
|
|
|
|
undef $get_chunk; |
|
395
|
|
|
|
|
|
|
#warn "Got all chunks, read trailer"; |
|
396
|
|
|
|
|
|
|
$_[0]->unshift_read(line => $qr_nlnl, sub { |
|
397
|
|
|
|
|
|
|
#warn "Got trailer $_[1]"; |
|
398
|
|
|
|
|
|
|
$finish->($body,$hdr); |
|
399
|
|
|
|
|
|
|
}); |
|
400
|
|
|
|
|
|
|
} |
|
401
|
|
|
|
|
|
|
}); |
|
402
|
|
|
|
|
|
|
}; |
|
403
|
|
|
|
|
|
|
$get_chunk->(); |
|
404
|
|
|
|
|
|
|
} else { |
|
405
|
|
|
|
|
|
|
$_[0]->on_eof (undef); |
|
406
|
|
|
|
|
|
|
if ($len) { |
|
407
|
|
|
|
|
|
|
warn "ready for body (+$len)"; |
|
408
|
|
|
|
|
|
|
$_[0]->on_error (sub { $finish->(undef, $hdr->HTTP(599,$_[2])) }); |
|
409
|
|
|
|
|
|
|
$_[0]->unshift_read(chunk => $len, sub { |
|
410
|
|
|
|
|
|
|
$finish->($_[1],$hdr); |
|
411
|
|
|
|
|
|
|
}); |
|
412
|
|
|
|
|
|
|
} else { |
|
413
|
|
|
|
|
|
|
warn "ready for body until eof"; |
|
414
|
|
|
|
|
|
|
$_[0]->on_error (sub { |
|
415
|
|
|
|
|
|
|
$! == Errno::EPIPE || !$! |
|
416
|
|
|
|
|
|
|
? $finish->(delete $_[0]{rbuf}, $hdr) |
|
417
|
|
|
|
|
|
|
: $finish->(undef, $hdr->HTTP(599,$_[2])); |
|
418
|
|
|
|
|
|
|
}); |
|
419
|
|
|
|
|
|
|
$_[0]->on_read (sub { }); |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
}); |
|
425
|
|
|
|
|
|
|
}); |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
#} |
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub rr { # request/response |
|
432
|
|
|
|
|
|
|
my $self = shift; |
|
433
|
|
|
|
|
|
|
my $con = shift; |
|
434
|
|
|
|
|
|
|
my ($method, $uri, %args) = @_;@_ = (); |
|
435
|
|
|
|
|
|
|
my $e = sub { my ($code,$mess) = @_; undef $con; $args{cb}(undef, { Status => $code, Reason => $mess, URL => $uri }); }; |
|
436
|
|
|
|
|
|
|
my $recurse = exists $args{recurse} ? delete $args{recurse} : $MAX_RECURSE; |
|
437
|
|
|
|
|
|
|
warn "Run request $method $uri"; |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# send request |
|
440
|
|
|
|
|
|
|
$con->push_write ( |
|
441
|
|
|
|
|
|
|
"$method $args{path} HTTP/1.1\015\012" |
|
442
|
|
|
|
|
|
|
. $args{headers}->encode |
|
443
|
|
|
|
|
|
|
. "\015\012" |
|
444
|
|
|
|
|
|
|
. (delete $args{body}) |
|
445
|
|
|
|
|
|
|
); |
|
446
|
|
|
|
|
|
|
if ($args{body_cb}) { |
|
447
|
|
|
|
|
|
|
my $written = 0; |
|
448
|
|
|
|
|
|
|
my $need = $args{headers}{"content-length"}; |
|
449
|
|
|
|
|
|
|
$con->on_drain(sub { |
|
450
|
|
|
|
|
|
|
$args{body_cb}(sub { |
|
451
|
|
|
|
|
|
|
shift if @_ and length $_[0] == 0; |
|
452
|
|
|
|
|
|
|
use bytes; |
|
453
|
|
|
|
|
|
|
if (@_) { |
|
454
|
|
|
|
|
|
|
my $chunk = shift; |
|
455
|
|
|
|
|
|
|
my $left = $need - $written; |
|
456
|
|
|
|
|
|
|
$written += ( my $length = length $chunk ); |
|
457
|
|
|
|
|
|
|
#warn "Written chunk=$length. now have written=$written and left=".($need - $written); |
|
458
|
|
|
|
|
|
|
if ($written >= $need) { |
|
459
|
|
|
|
|
|
|
if ($written > $need) { |
|
460
|
|
|
|
|
|
|
$chunk = substr($chunk,0,$left); |
|
461
|
|
|
|
|
|
|
warn "got more data $written, than content-length $need, truncated at @{[ (caller)[1,2] ]}\n"; |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
$con->on_drain(undef); |
|
464
|
|
|
|
|
|
|
undef $args{body_cb}; |
|
465
|
|
|
|
|
|
|
} |
|
466
|
|
|
|
|
|
|
$con->push_write($chunk); |
|
467
|
|
|
|
|
|
|
} else { |
|
468
|
|
|
|
|
|
|
$con->on_drain(undef); |
|
469
|
|
|
|
|
|
|
undef $args{body_cb}; |
|
470
|
|
|
|
|
|
|
if ($written < $need) { |
|
471
|
|
|
|
|
|
|
return $e->(599, "Insufficient ".($need-$written)." bytes data from body_cb. need $need, got $written"); |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
} |
|
474
|
|
|
|
|
|
|
}); |
|
475
|
|
|
|
|
|
|
}); |
|
476
|
|
|
|
|
|
|
# TODO |
|
477
|
|
|
|
|
|
|
#%state or return; |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
delete $args{headers}; |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# status line |
|
483
|
|
|
|
|
|
|
$con->push_read (line => $qr_nl, sub { |
|
484
|
|
|
|
|
|
|
$_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ixo |
|
485
|
|
|
|
|
|
|
or return $e->(599, "Invalid server response ($_[1])"); |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
my $status = $2;my $reason = $3;my $http_version = $1; |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
# headers, could be optimized a bit |
|
490
|
|
|
|
|
|
|
$con->unshift_read (line => $qr_nlnl, sub { |
|
491
|
|
|
|
|
|
|
my $hdr = HTTP::Easy::Headers->decode($_[1], base => $uri); |
|
492
|
|
|
|
|
|
|
$self->{cookie}->decode($hdr->{"set-cookie"}, host => $uri->host) if exists $hdr->{"set-cookie"}; |
|
493
|
|
|
|
|
|
|
$self->{cookie}->decode($hdr->{"set-cookie2"}, host => $uri->host) if exists $hdr->{"set-cookie2"}; |
|
494
|
|
|
|
|
|
|
$self->{cookie}->decode($hdr->{"set-cookie3"}, host => $uri->host) if exists $hdr->{"set-cookie3"}; |
|
495
|
|
|
|
|
|
|
# TODO: check correctness? |
|
496
|
|
|
|
|
|
|
# or return (%state = (), $cb->(undef, { Status => 599, Reason => "Garbled response headers", URL => $url })); |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
my $redirect; |
|
499
|
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
if ($recurse) { |
|
501
|
|
|
|
|
|
|
if ($status =~ /^30[12]$/ and $method ne "POST") { |
|
502
|
|
|
|
|
|
|
# apparently, mozilla et al. just change POST to GET here |
|
503
|
|
|
|
|
|
|
# more research is needed before we do the same |
|
504
|
|
|
|
|
|
|
$redirect = 1; |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
elsif ($status == 303) { |
|
507
|
|
|
|
|
|
|
# even http/1.1 is unclear on how to mutate the method |
|
508
|
|
|
|
|
|
|
$method = "GET" unless $method eq "HEAD"; |
|
509
|
|
|
|
|
|
|
$redirect = 1; |
|
510
|
|
|
|
|
|
|
} |
|
511
|
|
|
|
|
|
|
elsif ($status == 307 and $method =~ /^(?:GET|HEAD)$/) { |
|
512
|
|
|
|
|
|
|
$redirect = 1; |
|
513
|
|
|
|
|
|
|
} |
|
514
|
|
|
|
|
|
|
} |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
my $finish = sub { |
|
517
|
|
|
|
|
|
|
#$con->destroy if $con; |
|
518
|
|
|
|
|
|
|
#%state = (); |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
# set-cookie processing |
|
521
|
|
|
|
|
|
|
$self->{cookie}->decode($_[1]{"set-cookie"}, host => $uri->host); |
|
522
|
|
|
|
|
|
|
#$DEBUG_RECV->($_[1]{URL},$_[0],$_[1]) if defined $DEBUG_RECV; |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
if ($redirect && exists $hdr->{location}) { |
|
525
|
|
|
|
|
|
|
# we ignore any errors, as it is very common to receive |
|
526
|
|
|
|
|
|
|
# Content-Length != 0 but no actual body |
|
527
|
|
|
|
|
|
|
# we also access %hdr, as $_[1] might be an erro |
|
528
|
|
|
|
|
|
|
#http_request ($method => $hdr{location}, %arg, recurse => $recurse - 1, $cb); |
|
529
|
|
|
|
|
|
|
warn "Redirect => $hdr->{location}"; |
|
530
|
|
|
|
|
|
|
} else { |
|
531
|
|
|
|
|
|
|
warn "OK"; |
|
532
|
|
|
|
|
|
|
$args{cb}($_[0], $_[1]); |
|
533
|
|
|
|
|
|
|
} |
|
534
|
|
|
|
|
|
|
}; |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
my $len = $hdr->{"content-length"}; |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
if (!$redirect && $args{on_header} && !$args{on_header}($hdr)) { |
|
539
|
|
|
|
|
|
|
$finish->(undef, { Status => 598, Reason => "Request cancelled by on_header", URL => $uri }); |
|
540
|
|
|
|
|
|
|
} |
|
541
|
|
|
|
|
|
|
elsif ( |
|
542
|
|
|
|
|
|
|
$status =~ /^(?:1..|[23]04)$/ |
|
543
|
|
|
|
|
|
|
or $method eq "HEAD" |
|
544
|
|
|
|
|
|
|
or (defined $len && !$len) |
|
545
|
|
|
|
|
|
|
) { |
|
546
|
|
|
|
|
|
|
# no body |
|
547
|
|
|
|
|
|
|
$finish->("", $hdr); |
|
548
|
|
|
|
|
|
|
} |
|
549
|
|
|
|
|
|
|
else { |
|
550
|
|
|
|
|
|
|
#warn dumper $hdr,$self->{cookie}; |
|
551
|
|
|
|
|
|
|
if (lc $hdr->{'transfer-encoding'} eq 'chunked') { |
|
552
|
|
|
|
|
|
|
my $body = ''; |
|
553
|
|
|
|
|
|
|
my $get_chunk;$get_chunk = sub { |
|
554
|
|
|
|
|
|
|
$con->unshift_read( regex => qr{([a-f0-9]{1,255})\015?\012},sub { |
|
555
|
|
|
|
|
|
|
my $chunk = hex($1);@_ = (); |
|
556
|
|
|
|
|
|
|
if ($chunk > 0) { |
|
557
|
|
|
|
|
|
|
#warn "need chunk $chunk"; |
|
558
|
|
|
|
|
|
|
$get_chunk->(); |
|
559
|
|
|
|
|
|
|
$con->unshift_read(chunk => $chunk, sub { |
|
560
|
|
|
|
|
|
|
$body .= $_[1]; |
|
561
|
|
|
|
|
|
|
}); |
|
562
|
|
|
|
|
|
|
} else { |
|
563
|
|
|
|
|
|
|
undef $get_chunk; |
|
564
|
|
|
|
|
|
|
warn "Got all chunks"; |
|
565
|
|
|
|
|
|
|
$finish->($body,$hdr); |
|
566
|
|
|
|
|
|
|
} |
|
567
|
|
|
|
|
|
|
}); |
|
568
|
|
|
|
|
|
|
}; |
|
569
|
|
|
|
|
|
|
$get_chunk->(); |
|
570
|
|
|
|
|
|
|
} else { |
|
571
|
|
|
|
|
|
|
$_[0]->on_eof (undef); |
|
572
|
|
|
|
|
|
|
if ($len) { |
|
573
|
|
|
|
|
|
|
warn "ready for body (+$len)"; |
|
574
|
|
|
|
|
|
|
$_[0]->on_error (sub { $finish->(undef, { Status => 599, Reason => $_[2], URL => $uri }) }); |
|
575
|
|
|
|
|
|
|
$_[0]->unshift_read(chunk => $len, sub { |
|
576
|
|
|
|
|
|
|
$finish->($_[1],$hdr); |
|
577
|
|
|
|
|
|
|
}); |
|
578
|
|
|
|
|
|
|
} else { |
|
579
|
|
|
|
|
|
|
warn "ready for body until eof"; |
|
580
|
|
|
|
|
|
|
$_[0]->on_error (sub { |
|
581
|
|
|
|
|
|
|
$! == Errno::EPIPE || !$! |
|
582
|
|
|
|
|
|
|
? $finish->(delete $_[0]{rbuf}, $hdr) |
|
583
|
|
|
|
|
|
|
: $finish->(undef, { Status => 599, Reason => $_[2], URL => $uri }); |
|
584
|
|
|
|
|
|
|
}); |
|
585
|
|
|
|
|
|
|
$_[0]->on_read (sub { }); |
|
586
|
|
|
|
|
|
|
} |
|
587
|
|
|
|
|
|
|
} |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
} |
|
590
|
|
|
|
|
|
|
}); |
|
591
|
|
|
|
|
|
|
}); |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
} |
|
594
|
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
sub http_request; |
|
596
|
|
|
|
|
|
|
sub req1 { |
|
597
|
|
|
|
|
|
|
my $self = shift; |
|
598
|
|
|
|
|
|
|
my %args = @_; |
|
599
|
|
|
|
|
|
|
$self->{cv}->begin; |
|
600
|
|
|
|
|
|
|
http_request + |
|
601
|
|
|
|
|
|
|
( $args{form} ? 'POST' : 'GET') => "$args{uri}", |
|
602
|
|
|
|
|
|
|
$args{form} ? ( |
|
603
|
|
|
|
|
|
|
body => _postdata(@{ $args{form} }), |
|
604
|
|
|
|
|
|
|
) : (), |
|
605
|
|
|
|
|
|
|
headers => { |
|
606
|
|
|
|
|
|
|
%{ $self->{headers} }, |
|
607
|
|
|
|
|
|
|
$args{form} ? ( 'content-type' => 'application/x-www-form-urlencoded' ) : (), |
|
608
|
|
|
|
|
|
|
%{ $args{headers} || {} } |
|
609
|
|
|
|
|
|
|
}, |
|
610
|
|
|
|
|
|
|
cookie_jar => $self->{cookie}, |
|
611
|
|
|
|
|
|
|
timeout => 10, |
|
612
|
|
|
|
|
|
|
$self->next_proxy(), |
|
613
|
|
|
|
|
|
|
cb => sub { |
|
614
|
|
|
|
|
|
|
push @{$self->{requests}}, join(' ',$_[1]{Status}, ':', ($args{form} ? 'POST' : 'GET'), $args{uri} ); |
|
615
|
|
|
|
|
|
|
#$self->{requests}++; |
|
616
|
|
|
|
|
|
|
if( my $cookies = $_[1]{'set-cookie'} ) { |
|
617
|
|
|
|
|
|
|
local $self->{uri} = URI->new($_[1]{URL}); |
|
618
|
|
|
|
|
|
|
$self->_parse_cookies($cookies); |
|
619
|
|
|
|
|
|
|
} |
|
620
|
|
|
|
|
|
|
if (exists $args{raw}) { |
|
621
|
|
|
|
|
|
|
$args{raw}(@_); |
|
622
|
|
|
|
|
|
|
} else { |
|
623
|
|
|
|
|
|
|
my ($body,$hdr) = @_; |
|
624
|
|
|
|
|
|
|
if ($hdr->{Status} =~ /^(200|302)$/) { |
|
625
|
|
|
|
|
|
|
$self->{uri} = URI->new($hdr->{URL}); |
|
626
|
|
|
|
|
|
|
$self->{page} = $self->getpage; |
|
627
|
|
|
|
|
|
|
if (exists $hdr->{'content-encoding'}) { |
|
628
|
|
|
|
|
|
|
if (lc($hdr->{'content-encoding'}) eq 'gzip') { |
|
629
|
|
|
|
|
|
|
eval{ |
|
630
|
|
|
|
|
|
|
my $def = Compress::Zlib::memGunzip($body); |
|
631
|
|
|
|
|
|
|
if (defined $def) { |
|
632
|
|
|
|
|
|
|
$body = $def; |
|
633
|
|
|
|
|
|
|
#warn "Page deflated from $hdr->{'content-encoding'}" if $self->{debug}; |
|
634
|
|
|
|
|
|
|
1; |
|
635
|
|
|
|
|
|
|
} else { 0 } |
|
636
|
|
|
|
|
|
|
} or do { |
|
637
|
|
|
|
|
|
|
warn "Deflate failed: $@"; |
|
638
|
|
|
|
|
|
|
} |
|
639
|
|
|
|
|
|
|
} else { |
|
640
|
|
|
|
|
|
|
warn "Unsupported content-encoding method: $hdr->{'content-encoding'}"; |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
} |
|
643
|
|
|
|
|
|
|
warn "Req $self->{uri} / $self->{page}\n"._postdata(@{ $args{form} })."\n ok" if $self->{debug}; |
|
644
|
|
|
|
|
|
|
$args{cb}( { body => $body, head => $hdr } ); |
|
645
|
|
|
|
|
|
|
} else { |
|
646
|
|
|
|
|
|
|
$args{cb}(undef, "req($hdr->{URL}) failed: $hdr->{Status}: $hdr->{Reason}"); |
|
647
|
|
|
|
|
|
|
} |
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
$self->{cv}->end; |
|
650
|
|
|
|
|
|
|
}, |
|
651
|
|
|
|
|
|
|
; |
|
652
|
|
|
|
|
|
|
return; |
|
653
|
|
|
|
|
|
|
} |
|
654
|
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
=head1 AUTHOR |
|
656
|
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
Mons Anderson, C<< >> |
|
658
|
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
660
|
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
Many parts of this module was derived from L |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
=head1 LICENSE |
|
664
|
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
666
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
|
667
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=cut |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
1; # End of AnyEvent::UA |