ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-HTTP/HTTP.pm
(Generate patch)

Comparing AnyEvent-HTTP/HTTP.pm (file contents):
Revision 1.3 by root, Wed Jun 4 11:58:36 2008 UTC vs.
Revision 1.9 by root, Wed Jun 4 13:51:53 2008 UTC

52=item http_get $url, key => value..., $cb->($data, $headers) 52=item http_get $url, key => value..., $cb->($data, $headers)
53 53
54Executes an HTTP-GET request. See the http_request function for details on 54Executes an HTTP-GET request. See the http_request function for details on
55additional parameters. 55additional parameters.
56 56
57=item http_head $url, key => value..., $cb->($data, $headers)
58
59Executes an HTTP-HEAD request. See the http_request function for details on
60additional parameters.
61
57=item http_get $url, $body, key => value..., $cb->($data, $headers) 62=item http_post $url, $body, key => value..., $cb->($data, $headers)
58 63
59Executes an HTTP-POST request with a requets body of C<$bod>. See the 64Executes an HTTP-POST request with a request body of C<$bod>. See the
60http_request function for details on additional parameters. 65http_request function for details on additional parameters.
61 66
62=item http_request $method => $url, key => value..., $cb->($data, $headers) 67=item http_request $method => $url, key => value..., $cb->($data, $headers)
63 68
64Executes a HTTP request of type C<$method> (e.g. C<GET>, C<POST>). The URL 69Executes a HTTP request of type C<$method> (e.g. C<GET>, C<POST>). The URL
66 71
67The callback will be called with the response data as first argument 72The callback will be called with the response data as first argument
68(or C<undef> if it wasn't available due to errors), and a hash-ref with 73(or C<undef> if it wasn't available due to errors), and a hash-ref with
69response headers as second argument. 74response headers as second argument.
70 75
71All the headers in that has are lowercased. In addition to the response 76All the headers in that hash are lowercased. In addition to the response
72headers, the three "pseudo-headers" C<HTTPVersion>, C<Status> and 77headers, the three "pseudo-headers" C<HTTPVersion>, C<Status> and
73C<Reason> contain the three parts of the HTTP Status-Line of the same 78C<Reason> contain the three parts of the HTTP Status-Line of the same
74name. 79name.
75 80
76If an internal error occurs, such as not being able to resolve a hostname, 81If an internal error occurs, such as not being able to resolve a hostname,
77then C<$data> will be C<undef>, C<< $headers->{Status} >> will be C<599> 82then C<$data> will be C<undef>, C<< $headers->{Status} >> will be C<599>
78and the C<Reason> pseudo-header will contain an error message. 83and the C<Reason> pseudo-header will contain an error message.
79 84
85A typical callback might look like this:
86
87 sub {
88 my ($body, $hdr) = @_;
89
90 if ($hdr->{Status} =~ /^2/) {
91 ... everything should be ok
92 } else {
93 print "error, $hdr->{Status} $hdr->{Reason}\n";
94 }
95 }
96
80Additional parameters are key-value pairs, and are fully optional. They 97Additional parameters are key-value pairs, and are fully optional. They
81include: 98include:
82 99
83=over 4 100=over 4
84 101
109The request body, usually empty. Will be-sent as-is (future versions of 126The request body, usually empty. Will be-sent as-is (future versions of
110this module might offer more options). 127this module might offer more options).
111 128
112=back 129=back
113 130
114=back 131Example: make a simple HTTP GET request for http://www.nethype.de/
132
133 http_request GET => "http://www.nethype.de/", sub {
134 my ($body, $hdr) = @_;
135 print "$body\n";
136 };
137
138Example: make a HTTP HEAD request on https://www.google.com/, use a
139timeout of 30 seconds.
140
141 http_request
142 GET => "https://www.google.com",
143 timeout => 30,
144 sub {
145 my ($body, $hdr) = @_;
146 use Data::Dumper;
147 print Dumper $hdr;
148 }
149 ;
115 150
116=cut 151=cut
117 152
118sub http_request($$$;@) { 153sub http_request($$$;@) {
119 my $cb = pop; 154 my $cb = pop;
121 156
122 my %hdr; 157 my %hdr;
123 158
124 $method = uc $method; 159 $method = uc $method;
125 160
126 if (my $hdr = delete $arg{headers}) { 161 if (my $hdr = $arg{headers}) {
127 while (my ($k, $v) = each %$hdr) { 162 while (my ($k, $v) = each %$hdr) {
128 $hdr{lc $k} = $v; 163 $hdr{lc $k} = $v;
129 } 164 }
130 } 165 }
131 166
167 my $recurse = exists $arg{recurse} ? $arg{recurse} : $MAX_RECURSE;
168
169 return $cb->(undef, { Status => 599, Reason => "recursion limit reached" })
170 if $recurse < 0;
171
132 my $proxy = $arg{proxy} || $PROXY; 172 my $proxy = $arg{proxy} || $PROXY;
133 my $timeout = $arg{timeout} || $TIMEOUT; 173 my $timeout = $arg{timeout} || $TIMEOUT;
134 my $recurse = exists $arg{recurse} ? $arg{recurse} : $MAX_RECURSE;
135 174
136 $hdr{"user-agent"} ||= $USERAGENT; 175 $hdr{"user-agent"} ||= $USERAGENT;
137 176
138 my ($host, $port, $path, $scheme); 177 my ($host, $port, $path, $scheme);
139 178
144 ($scheme, my $authority, $path, my $query, my $fragment) = 183 ($scheme, my $authority, $path, my $query, my $fragment) =
145 $url =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|; 184 $url =~ m|(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|;
146 185
147 $port = $scheme eq "http" ? 80 186 $port = $scheme eq "http" ? 80
148 : $scheme eq "https" ? 443 187 : $scheme eq "https" ? 443
149 : croak "$url: only http and https URLs supported"; 188 : return $cb->(undef, { Status => 599, Reason => "$url: only http and https URLs supported" });
150 189
151 $authority =~ /^(?: .*\@ )? ([^\@:]+) (?: : (\d+) )?$/x 190 $authority =~ /^(?: .*\@ )? ([^\@:]+) (?: : (\d+) )?$/x
152 or croak "$authority: unparsable URL"; 191 or return $cb->(undef, { Status => 599, Reason => "$url: unparsable URL" });
153 192
154 $host = $1; 193 $host = $1;
155 $port = $2 if defined $2; 194 $port = $2 if defined $2;
156 195
157 $host =~ s/^\[(.*)\]$/$1/; 196 $host =~ s/^\[(.*)\]$/$1/;
164 203
165 $scheme = lc $scheme; 204 $scheme = lc $scheme;
166 205
167 my %state; 206 my %state;
168 207
169 $state{body} = delete $arg{body};
170
171 $hdr{"content-length"} = length $state{body}; 208 $hdr{"content-length"} = length $arg{body};
172 209
173 $state{connect_guard} = AnyEvent::Socket::tcp_connect $host, $port, sub { 210 $state{connect_guard} = AnyEvent::Socket::tcp_connect $host, $port, sub {
174 $state{fh} = shift 211 $state{fh} = shift
175 or return $cb->(undef, { Status => 599, Reason => "$!" }); 212 or return $cb->(undef, { Status => 599, Reason => "$!" });
176 213
205 # send request 242 # send request
206 $state{handle}->push_write ( 243 $state{handle}->push_write (
207 "$method $path HTTP/1.0\015\012" 244 "$method $path HTTP/1.0\015\012"
208 . (join "", map "$_: $hdr{$_}\015\012", keys %hdr) 245 . (join "", map "$_: $hdr{$_}\015\012", keys %hdr)
209 . "\015\012" 246 . "\015\012"
210 . (delete $state{body}) 247 . (delete $arg{body})
211 ); 248 );
212 249
213 %hdr = (); # reduce memory usage, save a kitten 250 %hdr = (); # reduce memory usage, save a kitten
214 251
215 # status line 252 # status line
241 } 278 }
242 279
243 substr $_, 0, 1, "" 280 substr $_, 0, 1, ""
244 for values %hdr; 281 for values %hdr;
245 282
246 if ($method ne "HEAD") { 283 my $finish = sub {
284 if ($_[1]{Status} =~ /^30[12]$/ && $recurse) {
285 http_request ($method, $_[1]{location}, %arg, recurse => $recurse - 1, $cb);
286 } else {
287 $cb->($_[0], $_[1]);
288 }
289 };
290
291 if ($hdr{Status} =~ /^(?:1..|204|304)$/ or $method eq "HEAD") {
292 %state = ();
293 $finish->(undef, \%hdr);
294 } else {
247 if (exists $hdr{"content-length"}) { 295 if (exists $hdr{"content-length"}) {
248 $_[0]->unshift_read (chunk => $hdr{"content-length"}, sub { 296 $_[0]->unshift_read (chunk => $hdr{"content-length"}, sub {
249 # could cache persistent connection now 297 # could cache persistent connection now
250 if ($hdr{connection} =~ /\bkeep-alive\b/i) { 298 if ($hdr{connection} =~ /\bkeep-alive\b/i) {
251 # but we don't, due to misdesigns, this is annoyingly complex 299 # but we don't, due to misdesigns, this is annoyingly complex
252 }; 300 };
253 301
254 %state = (); 302 %state = ();
255 $cb->($_[1], \%hdr); 303 $finish->($_[1], \%hdr);
256 }); 304 });
257 } else { 305 } else {
258 # too bad, need to read until we get an error or EOF, 306 # too bad, need to read until we get an error or EOF,
259 # no way to detect winged data. 307 # no way to detect winged data.
260 $_[0]->on_error (sub { 308 $_[0]->on_error (sub {
261 %state = (); 309 %state = ();
262 $cb->($_[0]{rbuf}, \%hdr); 310 $finish->($_[0]{rbuf}, \%hdr);
263 }); 311 });
264 $_[0]->on_eof (undef); 312 $_[0]->on_eof (undef);
265 $_[0]->on_read (sub { }); 313 $_[0]->on_read (sub { });
266 } 314 }
267 } 315 }
277sub http_get($$;@) { 325sub http_get($$;@) {
278 unshift @_, "GET"; 326 unshift @_, "GET";
279 &http_request 327 &http_request
280} 328}
281 329
330sub http_head($$;@) {
331 unshift @_, "HEAD";
332 &http_request
333}
334
282sub http_post($$$;@) { 335sub http_post($$$;@) {
283 unshift @_, "POST", "body"; 336 unshift @_, "POST", "body";
284 &http_request 337 &http_request
285} 338}
286 339
340=back
341
287=head2 GLOBAL FUNCTIONS AND VARIABLES 342=head2 GLOBAL FUNCTIONS AND VARIABLES
288 343
289=over 4 344=over 4
290 345
291=item AnyEvent::HTTP::set_proxy "proxy-url" 346=item AnyEvent::HTTP::set_proxy "proxy-url"

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines