1 # vim: ts=4 sts=4 sw=4 et:
5 # ABSTRACT: A small, simple, correct HTTP/1.1 client
6 our $VERSION = '0.016'; # VERSION
13 @attributes = qw(agent default_headers max_redirect max_size proxy timeout);
15 for my $accessor ( @attributes ) {
17 @_ > 1 ? $_[0]->{$accessor} = $_[1] : $_[0]->{$accessor};
23 my($class, %args) = @_;
24 (my $agent = $class) =~ s{::}{-}g;
26 agent => $agent . "/" . ($class->VERSION || 0),
30 for my $key ( @attributes ) {
31 $self->{$key} = $args{$key} if exists $args{$key}
34 # Never override proxy argument as this breaks backwards compat.
35 if (!exists $self->{proxy} && (my $http_proxy = $ENV{http_proxy})) {
36 if ($http_proxy =~ m{\Ahttp://[^/?#:@]+:\d+/?\z}) {
37 $self->{proxy} = $http_proxy;
40 Carp::croak(qq{Environment 'http_proxy' must be in format http://<host>:<port>/\n});
44 return bless $self, $class;
48 for my $sub_name ( qw/get head put post delete/ ) {
49 my $req_method = uc $sub_name;
53 my (\$self, \$url, \$args) = \@_;
54 \@_ == 2 || (\@_ == 3 && ref \$args eq 'HASH')
55 or Carp::croak(q/Usage: \$http->$sub_name(URL, [HASHREF])/ . "\n");
56 return \$self->request('$req_method', \$url, \$args || {});
63 my ($self, $url, $data, $args) = @_;
64 (@_ == 3 || @_ == 4 && ref $args eq 'HASH')
65 or Carp::croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n");
68 while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
69 $headers->{lc $key} = $value;
71 delete $args->{headers};
73 return $self->request('POST', $url, {
75 content => $self->www_form_urlencode($data),
78 'content-type' => 'application/x-www-form-urlencoded'
86 my ($self, $url, $file, $args) = @_;
87 @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
88 or Carp::croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");
89 if ( -e $file and my $mtime = (stat($file))[9] ) {
90 $args->{headers}{'if-modified-since'} ||= $self->_http_date($mtime);
92 my $tempfile = $file . int(rand(2**31));
93 open my $fh, ">", $tempfile
94 or Carp::croak(qq/Error: Could not open temporary file $tempfile for downloading: $!\n/);
96 $args->{data_callback} = sub { print {$fh} $_[0] };
97 my $response = $self->request('GET', $url, $args);
99 or Carp::croak(qq/Error: Could not close temporary file $tempfile: $!\n/);
100 if ( $response->{success} ) {
101 rename $tempfile, $file
102 or Carp::croak(qq/Error replacing $file with $tempfile: $!\n/);
103 my $lm = $response->{headers}{'last-modified'};
104 if ( $lm and my $mtime = $self->_parse_http_date($lm) ) {
105 utime $mtime, $mtime, $file;
108 $response->{success} ||= $response->{status} eq '304';
114 my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/;
117 my ($self, $method, $url, $args) = @_;
118 @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
119 or Carp::croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/ . "\n");
120 $args ||= {}; # we keep some state in this during _request
122 # RFC 2616 Section 8.1.4 mandates a single retry on broken socket
125 $response = eval { $self->_request($method, $url, $args) };
126 last unless $@ && $idempotent{$method}
127 && $@ =~ m{^(?:Socket closed|Unexpected end)};
134 reason => 'Internal Exception',
137 'content-type' => 'text/plain',
138 'content-length' => length $e,
146 sub www_form_urlencode {
147 my ($self, $data) = @_;
148 (@_ == 2 && ref $data)
149 or Carp::croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n");
150 (ref $data eq 'HASH' || ref $data eq 'ARRAY')
151 or Carp::croak("form data must be a hash or array reference");
153 my @params = ref $data eq 'HASH' ? %$data : @$data;
155 or Carp::croak("form data reference must have an even number of terms\n");
159 my ($key, $value) = splice(@params, 0, 2);
160 if ( ref $value eq 'ARRAY' ) {
161 unshift @params, map { $key => $_ } @$value;
164 push @terms, join("=", map { $self->_uri_escape($_) } $key, $value);
168 return join("&", sort @terms);
171 #--------------------------------------------------------------------------#
173 #--------------------------------------------------------------------------#
181 my ($self, $method, $url, $args) = @_;
183 my ($scheme, $host, $port, $path_query) = $self->_split_url($url);
188 host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
193 my $handle = HTTP::Tiny::Handle->new(timeout => $self->{timeout});
195 if ($self->{proxy}) {
196 $request->{uri} = "$scheme://$request->{host_port}$path_query";
197 die(qq/HTTPS via proxy is not supported\n/)
198 if $request->{scheme} eq 'https';
199 $handle->connect(($self->_split_url($self->{proxy}))[0..2]);
202 $handle->connect($scheme, $host, $port);
205 $self->_prepare_headers_and_cb($request, $args);
206 $handle->write_request($request);
209 do { $response = $handle->read_response_header }
210 until (substr($response->{status},0,1) ne '1');
212 if ( my @redir_args = $self->_maybe_redirect($request, $response, $args) ) {
214 return $self->_request(@redir_args, $args);
217 if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
218 # response has no message body
221 my $data_cb = $self->_prepare_data_cb($response, $args);
222 $handle->read_body($data_cb, $response);
226 $response->{success} = substr($response->{status},0,1) eq '2';
230 sub _prepare_headers_and_cb {
231 my ($self, $request, $args) = @_;
233 for ($self->{default_headers}, $args->{headers}) {
235 while (my ($k, $v) = each %$_) {
236 $request->{headers}{lc $k} = $v;
239 $request->{headers}{'host'} = $request->{host_port};
240 $request->{headers}{'connection'} = "close";
241 $request->{headers}{'user-agent'} ||= $self->{agent};
243 if (defined $args->{content}) {
244 $request->{headers}{'content-type'} ||= "application/octet-stream";
245 if (ref $args->{content} eq 'CODE') {
246 $request->{headers}{'transfer-encoding'} = 'chunked'
247 unless $request->{headers}{'content-length'}
248 || $request->{headers}{'transfer-encoding'};
249 $request->{cb} = $args->{content};
252 my $content = $args->{content};
253 if ( $] ge '5.008' ) {
254 utf8::downgrade($content, 1)
255 or die(qq/Wide character in request message body\n/);
257 $request->{headers}{'content-length'} = length $content
258 unless $request->{headers}{'content-length'}
259 || $request->{headers}{'transfer-encoding'};
260 $request->{cb} = sub { substr $content, 0, length $content, '' };
262 $request->{trailer_cb} = $args->{trailer_callback}
263 if ref $args->{trailer_callback} eq 'CODE';
268 sub _prepare_data_cb {
269 my ($self, $response, $args) = @_;
270 my $data_cb = $args->{data_callback};
271 $response->{content} = '';
273 if (!$data_cb || $response->{status} !~ /^2/) {
274 if (defined $self->{max_size}) {
276 $_[1]->{content} .= $_[0];
277 die(qq/Size of response body exceeds the maximum allowed of $self->{max_size}\n/)
278 if length $_[1]->{content} > $self->{max_size};
282 $data_cb = sub { $_[1]->{content} .= $_[0] };
288 sub _maybe_redirect {
289 my ($self, $request, $response, $args) = @_;
290 my $headers = $response->{headers};
291 my ($status, $method) = ($response->{status}, $request->{method});
292 if (($status eq '303' or ($status =~ /^30[127]/ && $method =~ /^GET|HEAD$/))
293 and $headers->{location}
294 and ++$args->{redirects} <= $self->{max_redirect}
296 my $location = ($headers->{location} =~ /^\//)
297 ? "$request->{scheme}://$request->{host_port}$headers->{location}"
298 : $headers->{location} ;
299 return (($status eq '303' ? 'GET' : $method), $location);
307 # URI regex adapted from the URI module
308 my ($scheme, $authority, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)>
309 or die(qq/Cannot parse URL: '$url'\n/);
311 $scheme = lc $scheme;
312 $path_query = "/$path_query" unless $path_query =~ m<\A/>;
314 my $host = (length($authority)) ? lc $authority : 'localhost';
315 $host =~ s/\A[^@]*@//; # userinfo
317 $host =~ s/:([0-9]*)\z// && length $1
319 : ($scheme eq 'http' ? 80 : $scheme eq 'https' ? 443 : undef);
322 return ($scheme, $host, $port, $path_query);
325 # Date conversions adapted from HTTP::Date
326 my $DoW = "Sun|Mon|Tue|Wed|Thu|Fri|Sat";
327 my $MoY = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
329 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($_[1]);
330 return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
331 substr($DoW,$wday*4,3),
332 $mday, substr($MoY,$mon*4,3), $year+1900,
337 sub _parse_http_date {
338 my ($self, $str) = @_;
341 if ($str =~ /^[SMTWF][a-z]+, +(\d{1,2}) ($MoY) +(\d\d\d\d) +(\d\d):(\d\d):(\d\d) +GMT$/) {
342 @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
344 elsif ($str =~ /^[SMTWF][a-z]+, +(\d\d)-($MoY)-(\d{2,4}) +(\d\d):(\d\d):(\d\d) +GMT$/ ) {
345 @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
347 elsif ($str =~ /^[SMTWF][a-z]+ +($MoY) +(\d{1,2}) +(\d\d):(\d\d):(\d\d) +(?:[^0-9]+ +)?(\d\d\d\d)$/ ) {
348 @tl_parts = ($5, $4, $3, $2, (index($MoY,$1)/4), $6);
351 my $t = @tl_parts ? Time::Local::timegm(@tl_parts) : -1;
356 # URI escaping adapted from URI::Escape
357 # c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
358 # perl 5.6 ready UTF-8 encoding adapted from JSON::PP
359 my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
361 my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;
364 my ($self, $str) = @_;
365 if ( $] ge '5.008' ) {
369 $str = pack("U*", unpack("C*", $str)) # UTF-8 encode a byte string
370 if ( length $str == do { use bytes; length $str } );
371 $str = pack("C*", unpack("C*", $str)); # clear UTF-8 flag
373 $str =~ s/($unsafe_char)/$escapes{$1}/ge;
378 HTTP::Tiny::Handle; # hide from PAUSE/indexers
382 use Errno qw[EINTR EPIPE];
383 use IO::Socket qw[SOCK_STREAM];
385 sub BUFSIZE () { 32768 }
387 my $Printable = sub {
392 s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge;
396 my $Token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
399 my ($class, %args) = @_;
403 max_line_size => 16384,
404 max_header_lines => 64,
409 my $ssl_verify_args = {
410 check_cn => "when_only",
411 wildcards_in_alt => "anywhere",
412 wildcards_in_cn => "anywhere"
416 @_ == 4 || die(q/Usage: $handle->connect(scheme, host, port)/ . "\n");
417 my ($self, $scheme, $host, $port) = @_;
419 if ( $scheme eq 'https' ) {
420 eval "require IO::Socket::SSL"
421 unless exists $INC{'IO/Socket/SSL.pm'};
422 die(qq/IO::Socket::SSL must be installed for https support\n/)
423 unless $INC{'IO/Socket/SSL.pm'};
425 elsif ( $scheme ne 'http' ) {
426 die(qq/Unsupported URL scheme '$scheme'\n/);
429 $self->{fh} = 'IO::Socket::INET'->new(
434 Timeout => $self->{timeout}
435 ) or die(qq/Could not connect to '$host:$port': $@\n/);
438 or die(qq/Could not binmode() socket: '$!'\n/);
440 if ( $scheme eq 'https') {
441 IO::Socket::SSL->start_SSL($self->{fh});
442 ref($self->{fh}) eq 'IO::Socket::SSL'
443 or die(qq/SSL connection failed for $host\n/);
444 $self->{fh}->verify_hostname( $host, $ssl_verify_args )
445 or die(qq/SSL certificate not valid for $host\n/);
448 $self->{host} = $host;
449 $self->{port} = $port;
455 @_ == 1 || die(q/Usage: $handle->close()/ . "\n");
457 CORE::close($self->{fh})
458 or die(qq/Could not close socket: '$!'\n/);
462 @_ == 2 || die(q/Usage: $handle->write(buf)/ . "\n");
463 my ($self, $buf) = @_;
465 if ( $] ge '5.008' ) {
466 utf8::downgrade($buf, 1)
467 or die(qq/Wide character in write()\n/);
470 my $len = length $buf;
473 local $SIG{PIPE} = 'IGNORE';
477 or die(qq/Timed out while waiting for socket to become ready for writing\n/);
478 my $r = syswrite($self->{fh}, $buf, $len, $off);
482 last unless $len > 0;
484 elsif ($! == EPIPE) {
485 die(qq/Socket closed by remote server: $!\n/);
487 elsif ($! != EINTR) {
488 die(qq/Could not write to socket: '$!'\n/);
495 @_ == 2 || @_ == 3 || die(q/Usage: $handle->read(len [, allow_partial])/ . "\n");
496 my ($self, $len, $allow_partial) = @_;
499 my $got = length $self->{rbuf};
502 my $take = ($got < $len) ? $got : $len;
503 $buf = substr($self->{rbuf}, 0, $take, '');
509 or die(q/Timed out while waiting for socket to become ready for reading/ . "\n");
510 my $r = sysread($self->{fh}, $buf, $len, length $buf);
515 elsif ($! != EINTR) {
516 die(qq/Could not read from socket: '$!'\n/);
519 if ($len && !$allow_partial) {
520 die(qq/Unexpected end of stream\n/);
526 @_ == 1 || die(q/Usage: $handle->readline()/ . "\n");
530 if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) {
533 if (length $self->{rbuf} >= $self->{max_line_size}) {
534 die(qq/Line size exceeds the maximum allowed size of $self->{max_line_size}\n/);
537 or die(qq/Timed out while waiting for socket to become ready for reading\n/);
538 my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf});
542 elsif ($! != EINTR) {
543 die(qq/Could not read from socket: '$!'\n/);
546 die(qq/Unexpected end of stream while looking for line\n/);
549 sub read_header_lines {
550 @_ == 1 || @_ == 2 || die(q/Usage: $handle->read_header_lines([headers])/ . "\n");
551 my ($self, $headers) = @_;
557 my $line = $self->readline;
559 if (++$lines >= $self->{max_header_lines}) {
560 die(qq/Header lines exceeds maximum number allowed of $self->{max_header_lines}\n/);
562 elsif ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) {
563 my ($field_name) = lc $1;
564 if (exists $headers->{$field_name}) {
565 for ($headers->{$field_name}) {
566 $_ = [$_] unless ref $_ eq "ARRAY";
572 $val = \($headers->{$field_name} = $2);
575 elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) {
577 or die(qq/Unexpected header continuation line\n/);
578 next unless length $1;
579 $$val .= ' ' if length $$val;
582 elsif ($line =~ /\A \x0D?\x0A \z/x) {
586 die(q/Malformed header line: / . $Printable->($line) . "\n");
593 @_ == 2 || die(q/Usage: $handle->write_request(request)/ . "\n");
594 my($self, $request) = @_;
595 $self->write_request_header(@{$request}{qw/method uri headers/});
596 $self->write_body($request) if $request->{cb};
601 'content-md5' => 'Content-MD5',
604 'www-authenticate' => 'WWW-Authenticate',
605 'x-xss-protection' => 'X-XSS-Protection',
608 sub write_header_lines {
609 (@_ == 2 && ref $_[1] eq 'HASH') || die(q/Usage: $handle->write_header_lines(headers)/ . "\n");
610 my($self, $headers) = @_;
613 while (my ($k, $v) = each %$headers) {
614 my $field_name = lc $k;
615 if (exists $HeaderCase{$field_name}) {
616 $field_name = $HeaderCase{$field_name};
619 $field_name =~ /\A $Token+ \z/xo
620 or die(q/Invalid HTTP header field name: / . $Printable->($field_name) . "\n");
621 $field_name =~ s/\b(\w)/\u$1/g;
622 $HeaderCase{lc $field_name} = $field_name;
624 for (ref $v eq 'ARRAY' ? @$v : $v) {
626 or die(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_). "\n");
627 $buf .= "$field_name: $_\x0D\x0A";
631 return $self->write($buf);
635 @_ == 3 || die(q/Usage: $handle->read_body(callback, response)/ . "\n");
636 my ($self, $cb, $response) = @_;
637 my $te = $response->{headers}{'transfer-encoding'} || '';
638 if ( grep { /chunked/i } ( ref $te eq 'ARRAY' ? @$te : $te ) ) {
639 $self->read_chunked_body($cb, $response);
642 $self->read_content_body($cb, $response);
648 @_ == 2 || die(q/Usage: $handle->write_body(request)/ . "\n");
649 my ($self, $request) = @_;
650 if ($request->{headers}{'content-length'}) {
651 return $self->write_content_body($request);
654 return $self->write_chunked_body($request);
658 sub read_content_body {
659 @_ == 3 || @_ == 4 || die(q/Usage: $handle->read_content_body(callback, response, [read_length])/ . "\n");
660 my ($self, $cb, $response, $content_length) = @_;
661 $content_length ||= $response->{headers}{'content-length'};
663 if ( $content_length ) {
664 my $len = $content_length;
666 my $read = ($len > BUFSIZE) ? BUFSIZE : $len;
667 $cb->($self->read($read, 0), $response);
673 $cb->($chunk, $response) while length( $chunk = $self->read(BUFSIZE, 1) );
679 sub write_content_body {
680 @_ == 2 || die(q/Usage: $handle->write_content_body(request)/ . "\n");
681 my ($self, $request) = @_;
683 my ($len, $content_length) = (0, $request->{headers}{'content-length'});
685 my $data = $request->{cb}->();
687 defined $data && length $data
690 if ( $] ge '5.008' ) {
691 utf8::downgrade($data, 1)
692 or die(qq/Wide character in write_content()\n/);
695 $len += $self->write($data);
698 $len == $content_length
699 or die(qq/Content-Length missmatch (got: $len expected: $content_length)\n/);
704 sub read_chunked_body {
705 @_ == 3 || die(q/Usage: $handle->read_chunked_body(callback, $response)/ . "\n");
706 my ($self, $cb, $response) = @_;
709 my $head = $self->readline;
711 $head =~ /\A ([A-Fa-f0-9]+)/x
712 or die(q/Malformed chunk head: / . $Printable->($head) . "\n");
717 $self->read_content_body($cb, $response, $len);
719 $self->read(2) eq "\x0D\x0A"
720 or die(qq/Malformed chunk: missing CRLF after chunk data\n/);
722 $self->read_header_lines($response->{headers});
726 sub write_chunked_body {
727 @_ == 2 || die(q/Usage: $handle->write_chunked_body(request)/ . "\n");
728 my ($self, $request) = @_;
732 my $data = $request->{cb}->();
734 defined $data && length $data
737 if ( $] ge '5.008' ) {
738 utf8::downgrade($data, 1)
739 or die(qq/Wide character in write_chunked_body()\n/);
742 $len += length $data;
744 my $chunk = sprintf '%X', length $data;
745 $chunk .= "\x0D\x0A";
747 $chunk .= "\x0D\x0A";
749 $self->write($chunk);
751 $self->write("0\x0D\x0A");
752 $self->write_header_lines($request->{trailer_cb}->())
753 if ref $request->{trailer_cb} eq 'CODE';
757 sub read_response_header {
758 @_ == 1 || die(q/Usage: $handle->read_response_header()/ . "\n");
761 my $line = $self->readline;
763 $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x
764 or die(q/Malformed Status-Line: / . $Printable->($line). "\n");
766 my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
768 die (qq/Unsupported HTTP protocol: $protocol\n/)
769 unless $version =~ /0*1\.0*[01]/;
774 headers => $self->read_header_lines,
775 protocol => $protocol,
779 sub write_request_header {
780 @_ == 4 || die(q/Usage: $handle->write_request_header(method, request_uri, headers)/ . "\n");
781 my ($self, $method, $request_uri, $headers) = @_;
783 return $self->write("$method $request_uri HTTP/1.1\x0D\x0A")
784 + $self->write_header_lines($headers);
788 my ($self, $type, $timeout) = @_;
789 $timeout = $self->{timeout}
790 unless defined $timeout && $timeout >= 0;
792 my $fd = fileno $self->{fh};
793 defined $fd && $fd >= 0
794 or die(qq/select(2): 'Bad file descriptor'\n/);
797 my $pending = $timeout;
800 vec(my $fdset = '', $fd, 1) = 1;
803 $nfound = ($type eq 'read')
804 ? select($fdset, undef, undef, $pending)
805 : select(undef, $fdset, undef, $pending) ;
808 or die(qq/select(2): '$!'\n/);
809 redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0;
819 @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_read([timeout])/ . "\n");
821 return $self->_do_timeout('read', @_)
825 @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_write([timeout])/ . "\n");
827 return $self->_do_timeout('write', @_)
839 HTTP::Tiny - A small, simple, correct HTTP/1.1 client
849 my $response = HTTP::Tiny->new->get('http://example.com/');
851 die "Failed!\n" unless $response->{success};
853 print "$response->{status} $response->{reason}\n";
855 while (my ($k, $v) = each %{$response->{headers}}) {
856 for (ref $v eq 'ARRAY' ? @$v : $v) {
861 print $response->{content} if length $response->{content};
865 This is a very simple HTTP/1.1 client, designed for doing simple GET
866 requests without the overhead of a large framework like L<LWP::UserAgent>.
868 It is more correct and more complete than L<HTTP::Lite>. It supports
869 proxies (currently only non-authenticating ones) and redirection. It
870 also correctly resumes after EINTR.
876 $http = HTTP::Tiny->new( %attributes );
878 This constructor returns a new HTTP::Tiny object. Valid attributes include:
886 A user-agent string (defaults to 'HTTP::Tiny/$VERSION')
892 A hashref of default headers to apply to requests
898 Maximum number of redirects allowed (defaults to 5)
904 Maximum response size (only when not using a data callback). If defined,
905 responses larger than this will die with an error message
911 URL of a proxy server to use (default is C<$ENV{http_proxy}> if set)
917 Request timeout in seconds (default is 60)
921 =head2 get|head|put|post|delete
923 $response = $http->get($url);
924 $response = $http->get($url, \%options);
925 $response = $http->head($url);
927 These methods are shorthand for calling C<request()> for the given method. The
928 URL must have unsafe characters escaped and international domain names encoded.
929 See C<request()> for valid options and a description of the response.
933 $response = $http->post_form($url, $form_data);
934 $response = $http->post_form($url, $form_data, \%options);
936 This method executes a C<POST> request and sends the key/value pairs from a
937 form data hash or array reference to the given URL with a C<content-type> of
938 C<application/x-www-form-urlencoded>. See documentation for the
939 C<www_form_urlencode> method for details on the encoding.
941 The URL must have unsafe characters escaped and international domain names
942 encoded. See C<request()> for valid options and a description of the response.
943 Any C<content-type> header or content in the options hashref will be ignored.
947 $response = $http->mirror($url, $file, \%options)
948 if ( $response->{success} ) {
949 print "$file is up to date\n";
952 Executes a C<GET> request for the URL and saves the response body to the file
953 name provided. The URL must have unsafe characters escaped and international
954 domain names encoded. If the file already exists, the request will includes an
955 C<If-Modified-Since> header with the modification timestamp of the file. You
956 may specificy a different C<If-Modified-Since> header yourself in the C<<
957 $options->{headers} >> hash.
959 The C<success> field of the response will be true if the status code is 2XX
962 If the file was modified and the server response includes a properly
963 formatted C<Last-Modified> header, the file modification time will
964 be updated accordingly.
968 $response = $http->request($method, $url);
969 $response = $http->request($method, $url, \%options);
971 Executes an HTTP request of the given method type ('GET', 'HEAD', 'POST',
972 'PUT', etc.) on the given URL. The URL must have unsafe characters escaped and
973 international domain names encoded. A hashref of options may be appended to
984 A hashref containing headers to include with the request. If the value for
985 a header is an array reference, the header will be output multiple times with
986 each value in the array. These headers over-write any default headers.
992 A scalar to include as the body of the request OR a code reference
993 that will be called iteratively to produce the body of the response
999 A code reference that will be called if it exists to provide a hashref
1000 of trailing headers (only used with chunked transfer-encoding)
1006 A code reference that will be called for each chunks of the response
1011 If the C<content> option is a code reference, it will be called iteratively
1012 to provide the content body of the request. It should return the empty
1013 string or undef when the iterator is exhausted.
1015 If the C<data_callback> option is provided, it will be called iteratively until
1016 the entire response body is received. The first argument will be a string
1017 containing a chunk of the response body, the second argument will be the
1018 in-progress response hash reference, as described below. (This allows
1019 customizing the action of the callback based on the C<status> or C<headers>
1020 received prior to the content body.)
1022 The C<request> method returns a hashref containing the response. The hashref
1023 will have the following keys:
1031 Boolean indicating whether the operation returned a 2XX status code
1037 The HTTP status code of the response
1043 The response phrase returned by the server
1049 The body of the response. If the response does not have any content
1050 or if a data callback is provided to consume the response body,
1051 this will be the empty string
1057 A hashref of header fields. All header field names will be normalized
1058 to be lower case. If a header is repeated, the value will be an arrayref;
1059 it will otherwise be a scalar string containing the value
1063 On an exception during the execution of the request, the C<status> field will
1064 contain 599, and the C<content> field will contain the text of the exception.
1066 =head2 www_form_urlencode
1068 $params = $http->www_form_urlencode( $data );
1069 $response = $http->get("http://example.com/query?$params");
1071 This method converts the key/value pairs from a data hash or array reference
1072 into a C<x-www-form-urlencoded> string. The keys and values from the data
1073 reference will be UTF-8 encoded and escaped per RFC 3986. If a value is an
1074 array reference, the key will be repeated with each of the values of the array
1075 reference. The key/value pairs in the resulting string will be sorted by key
1078 =for Pod::Coverage agent
1087 HTTP::Tiny is I<conditionally compliant> with the
1088 L<HTTP/1.1 specification|http://www.w3.org/Protocols/rfc2616/rfc2616.html>.
1089 It attempts to meet all "MUST" requirements of the specification, but does not
1090 implement all "SHOULD" requirements.
1092 Some particular limitations of note include:
1098 HTTP::Tiny focuses on correct transport. Users are responsible for ensuring
1099 that user-defined headers and content are compliant with the HTTP/1.1
1104 Users must ensure that URLs are properly escaped for unsafe characters and that
1105 international domain names are properly encoded to ASCII. See L<URI::Escape>,
1106 L<URI::_punycode> and L<Net::IDN::Encode>.
1110 Redirection is very strict against the specification. Redirection is only
1111 automatic for response codes 301, 302 and 307 if the request method is 'GET' or
1112 'HEAD'. Response code 303 is always converted into a 'GET' redirection, as
1113 mandated by the specification. There is no automatic support for status 305
1114 ("Use proxy") redirections.
1118 Persistent connections are not supported. The C<Connection> header will
1119 always be set to C<close>.
1123 Direct C<https> connections are supported only if L<IO::Socket::SSL> is
1124 installed. There is no support for C<https> connections via proxy.
1125 Any SSL certificate that matches the host is accepted -- SSL certificates
1126 are not verified against certificate authorities.
1130 Cookies are not directly supported. Users that set a C<Cookie> header
1131 should also set C<max_redirect> to zero to ensure cookies are not
1132 inappropriately re-transmitted.
1136 Only the C<http_proxy> environment variable is supported in the format
1137 C<http://HOST:PORT/>. If a C<proxy> argument is passed to C<new> (including
1138 undef), then the C<http_proxy> environment variable is ignored.
1142 There is no provision for delaying a request body using an C<Expect> header.
1143 Unexpected C<1XX> responses are silently ignored as per the specification.
1147 Only 'chunked' C<Transfer-Encoding> is supported.
1151 There is no support for a Request-URI of '*' for the 'OPTIONS' request.
1165 =for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders
1169 =head2 Bugs / Feature Requests
1171 Please report any bugs or feature requests by email to C<bug-http-tiny at rt.cpan.org>, or through
1172 the web interface at L<http://rt.cpan.org/Public/Dist/Display.html?Name=HTTP-Tiny>. You will be automatically notified of any
1173 progress on the request by the system.
1177 This is open source software. The code repository is available for
1178 public review and contribution under the terms of the license.
1180 L<https://github.com/dagolden/p5-http-tiny>
1182 git clone https://github.com/dagolden/p5-http-tiny.git
1190 Christian Hansen <chansen@cpan.org>
1194 David Golden <dagolden@cpan.org>
1198 =head1 COPYRIGHT AND LICENSE
1200 This software is copyright (c) 2011 by Christian Hansen.
1202 This is free software; you can redistribute it and/or modify it under
1203 the same terms as the Perl 5 programming language system itself.