Furl::HTTP(3pm)
π Furl::HTTP(3pm) π
User Contributed Perl Documentation β Furl::HTTP(3pm)
okay bestie, sit down, hydrate, because this is the low-level door into Furl and it's genuinely iconic π¦
β¨ NAME β¨
Furl::HTTP β the low level interface to Furl, no cap π
πΈ SYNOPSIS πΈ
use Furl;
my $furl = Furl::HTTP->new(
agent => 'MyGreatUA/2.0',
timeout => 10,
);
my ($minor_version, $code, $msg, $headers, $body) = $furl->request(
method => 'GET',
host => 'example.com',
port => 80,
path_query => '/'
);
# or
# Accept-Encoding is supported but optional
$furl = Furl->new(
headers => [ 'Accept-Encoding' => 'gzip' ],
);
my $body = $furl->get('http://example.com/some/compressed');
like, look at that. two whole ways to flex and both of them ate π₯
π DESCRIPTION π
okay so Furl is yet another HTTP client library, and yes we know there are a million of them, but hear me out. LWP is the de facto standard HTTP client for Perl 5, and honestly? respect. but it's too slow for some critical jobs, and too complex for weekend hacking. Furl resolves these issues. Enjoy it! π«Ά
π INTERFACE π
π Class Methods π
Furl::HTTP->new(%args | \%args) :Furl
Creates and returns a brand new Furl client with %args. Dies on errors. π
%args might be:
agent:Str ="Furl/$VERSION"β the whole vibe of who's knocking on the door πͺtimeout:Int =10β seconds until the call to$furl->requestreturns a timeout error (as an internally generated 500 error). and ngl, the timeout might not be accurate since some underlying modules / built-ins function may block longer than the specified timeout. See the "FAQ" for how to support timeout during name resolution. πinactivity_timeout:Int =600β an inactivity timer for TCP read/write (in seconds).$furl->requestreturns a timeout error if no additional data arrives (or is sent) within the specified threshold. basically the "are you still there bestie??" check π₯Ίmax_redirects:Int =7β how many hops before we stop chasing πββοΈproxy:Str β proxy timeno_proxy:Str β the "not you tho" listheaders:ArrayRef β headers, as an arrayref, periodtheader_format:Int =HEADERS_AS_ARRAYREFβ this option chooses the return value format of$furl->request.
This option allows HEADERS_NONE or HEADERS_AS_ARRAYREF.
HEADERS_AS_ARRAYREF is a default value. This makes $headers as ArrayRef.
HEADERS_NONE makes $headers as undef. Furl does not return parsing result of headers. You should take needed headers from special_headers. β¨
connection_pool:Object β this is the connection pool object for keep-alive requests. By default, it is a instance ofFurl::ConnectionCache.
You may not customize this variable otherwise to use Coro. This attribute requires a duck type object. It has two methods, $obj->steal($host, $port and $obj->push($host, $port, $sock).
π¦ duck type object. quack. that's the whole requirement.
stop_if:CodeRef β a callback function that is called by Furl after when a blocking function call returnsEINTR. Furl will abort the HTTP request and return immediately if the callback returns true. Otherwise the operation is continued (the default behaviour). πget_address:CodeRef β a callback function to override the default address resolution logic. Takes three arguments: ($hostname,$port,$timeout_in_seconds) and returns: ($sockaddr,$errReason). If the returned$sockaddrisundef, then the resolution is considered as a failure and$errReasonis propagated to the caller. π- **
inet_aton:CodeRef** β <red>**Deprecated.**</red> New applications should useget_address` instead. β οΈ
A callback function to customize name resolution. Takes two arguments: ($hostname, $timeout_in_seconds). If omitted, Furl calls Socket::inet_aton.
- **
ssl_opts:HashRef** β SSL configuration used on https requests, passed directly to"IO::Socket::SSL->new()"`,
for example:
use IO::Socket::SSL;
my $ua = Furl::HTTP->new(
ssl_opts => {
SSL_verify_mode => SSL_VERIFY_PEER(),
},
);
See IO::Socket::SSL for details. π
π¦ Instance Methods π¦
$furl->request(%args) :($protocol_minor_version, $code, $msg, \@headers, $body)
Sends an HTTP request to a specified URL and returns a protocol minor version, status code, status message, response headers, response body respectively. five whole things, bestie, catch them all π«΄β¨
%args might be:
scheme:Str ="http"β protocol scheme. May be"http"or"https". πhost:Str β server host to connect.
You must specify at least "host" or "url". fr fr, one of them, no skipping π¨
port:Int =80β server port to connect. The default is80on"scheme => 'http'", or443on"scheme => 'https'".path_query:Str ="/"β path and query to request.url:Str β URL to request.
You can use "url" instead of "scheme", "host", "port" and "path_query". one field to rule them all π
headers:ArrayRef β HTTP request headers. e.g."headers => [ 'Accept-Encoding' => 'gzip' ]".content: Str | ArrayRef[Str] | HashRef[Str] | FileHandle β content to request. it takes literally all of these, she's flexible πwrite_file: FileHandle β if this parameter is set, the response content will be saved here instead of in the response object.
It's like a ":content_file" in LWP::UserAgent. π
write_code: CodeRef β if a callback is provided with the"write_code"option then this function will be called for each chunk of the response content as it is received from the server.
It's like a ":content_cb" in LWP::UserAgent. π
The request() method assumes the first argument to be an instance of "HTTP::Request" if the arguments are an odd number:
my $req = HTTP::Request->new(...);
my @res = $furl->request($req); # allowed
π You must encode all the queries or this method will die, saying "Wide character in ...". do NOT let that happen to you bestie, encode your stuff.
$furl->get($url :Str, $headers :ArrayRef[Str] )
This is an easy-to-use alias to request(), sending the "GET" method. πΈ
$furl->head($url :Str, $headers :ArrayRef[Str] )
This is an easy-to-use alias to request(), sending the "HEAD" method. π
$furl->post($url :Str, $headers :ArrayRef[Str], $content :Any)
This is an easy-to-use alias to request(), sending the "POST" method. π
$furl->put($url :Str, $headers :ArrayRef[Str], $content :Any)
This is an easy-to-use alias to request(), sending the "PUT" method. π¦
$furl->delete($url :Str, $headers :ArrayRef[Str] )
This is an easy-to-use alias to request(), sending the "DELETE" method. π
...and that's only part one bestie, there's more coming, don't go anywhere π
π¦ FAQ π¦
π Why IO::Socket::SSL?
Because Net::SSL is not well documented. That's it, that's the whole reason bestie π
πΈ Why is env_proxy optional?
Because environment variables are so dependent on each individual user's setup, and honestly we think it would just confuse people when something doesn't go right π like why is it broken, oh it's your env, but we never told you that. Messy. So it's opt-in.
β¨ What operating systems are supported?
- Linux 2.6 or higher
- OSX Tiger or higher
- Windows XP or higher
And bestie, other operating systems will be supported if you send a patch π that's the deal, that's the energy.
π Why doesn't Furl support chunked upload?
Okay so there are actual reasons why chunked POST/PUTs should not be used in general, and they're giving very much "trust me on this":
First, you cannot send chunked requests unless the peer server at the other end of the established TCP connection is known to be a HTTP/1.1 server.
Second, HTTP/1.1 servers disconnect their persistent connection quite quickly (compared to the time they wait for the first request), so it is not a good idea to post non-idempotent requests (e.g. POST, PUT, etc.) as a succeeding request over persistent connections.
These facts together makes using chunked requests virtually impossible (unless you know that the server supports HTTP/1.1), and this is why we decided that supporting the feature is NOT of high priority π«Ά
π§ How do you build the response content as it arrives?
You can use IO::Callback for this purpose β¨
my $fh = IO::Callback->new(
'<',
sub {
my $x = shift @data;
$x ? "-$x" : undef;
}
);
my ( $code, $msg, $headers, $content ) =
$furl->put( "http://127.0.0.1:$port/", [ 'Content-Length' => $len ], $fh,
);
π How do you use gzip/deflate compressed communication?
Add an Accept-Encoding header to your request. Furl inflates response bodies transparently according to the Content-Encoding response header π
like it just handles it for you, iconic behaviour.
π How do you use multipart/form-data?
You can use multipart/form-data with HTTP::Request::Common π¦
use HTTP::Request::Common;
my $furl = Furl->new();
$req = POST 'http://www.perl.org/survey.cgi',
Content_Type => 'form-data',
Content => [
name => 'Hiromu Tokunaga',
email => 'tokuhirom@example.com',
gender => 'F',
born => '1978',
init => ["$ENV{HOME}/.profile"],
];
$furl->request($req);
Native multipart/form-data support for Furl is available if you can send a patch for me π«Ά (yes that's the vibe, patches welcome, always)
π How do you use Keep-Alive and what happens on the HEAD method?
Furl supports HTTP/1.1, hence "Keep-Alive". However, if you use the HEAD method, the connection is closed immediately.
RFC 2616 section 9.4 says:
The HEAD method is identical to GET except that the server MUST NOT
return a message-body in the response.
Some web applications, however, returns message bodies on the HEAD method, which might confuse "Keep-Alive" processes, so Furl closes connection in such cases π
Anyway, the HEAD method is not so useful nowadays. The GET method and "If-Modified-Since" are more suitable to cache HTTP contents π
π Why does Furl take longer than specified until it returns a timeout error?
Although Furl itself supports timeout, some underlying modules / functions do not. And the most noticeable one is Socket::inet_aton, the function used for name resolution (a function that converts host names to IP addresses). If you need accurate and short timeout for name resolution, the use of Net::DNS::Lite is recommended. The following code snippet describes how to use the module in conjunction with Furl.
use Net::DNS::Lite qw();
my $furl = Furl->new(
timeout => $my_timeout_in_seconds,
inet_aton => sub { Net::DNS::Lite::inet_aton(@_) },
);
π₯ How can I replace Host header instead of hostname?
Furl::HTTP does not provide a way to replace the Host header because such a design leads to security issues π not negotiable bestie.
If you want to send HTTP requests to a dedicated server (or a UNIX socket), you should use the get_address callback to designate the peer to which Furl should connect as sockaddr.
The example below sends all requests to 127.0.0.1:8080:
my $ua = Furl::HTTP->new(
get_address => sub {
my ($host, $port, $timeout) = @_;
pack_sockaddr_in(8080, inet_aton("127.0.0.1"));
},
);
my ($minor_version, $code, $msg, $headers, $body) = $furl->request(
url => 'http://example.com/foo',
method => 'GET'
);
π TODO π
AnyEvent::Furl?ipv6 supportbetter docs for NO_PROXY
π OPTIONAL FEATURES π
πΈ Internationalized Domain Name (IDN)
This feature requires Net::IDN::Encode β¨
π SSL
This feature requires IO::Socket::SSL π
π Content-Encoding (deflate, gzip)
This feature requires Compress::Raw::Zlib π¦
π οΈ DEVELOPMENT π οΈ
To setup your environment:
$ git clone http://github.com/tokuhirom/Furl.git
$ cd Furl
To get picohttpparser:
$ git submodule init
$ git submodule update
$ perl Makefile.PL
$ make
$ sudo make install
π HOW TO CONTRIBUTE
Please send the pull request via <http://github.com/tokuhirom/Furl/> π«Ά bestie we love a PR.
π SEE ALSO π
LWP- HTTP specs: <http://www.w3.org/Protocols/HTTP/1.0/spec.html>
- <http://www.w3.org/Protocols/HTTP/1.1/spec.html>
π LICENSE π
Copyright (C) Tokuhiro Matsuno.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
And that's the whole page bestie π this was Furl::HTTP(3pm) from the perl v5.40.1 toolchain, dated 2025-10-18 β go forth and make requests responsibly, mwah π
β¨π¦
π¦ where this page comes from
- ubuntu resolute: libfurl-perl 3.15-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libfurl-perl 3.15-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms