EV-YACurl
view release on metacpan or search on metacpan
NAME
EV::YACurl - Yet Another curl binding for EV
SYNOPSIS
use EV;
use EV::YACurl ':constants';
my $client = EV::YACurl->new({});
my ($done, $failed, $body) = (0, undef, '');
$client->request(sub {
my ($response, $error) = @_;
$done = 1;
return $failed = $error if $error;
printf "%d, %d bytes\n", $response->getinfo(CURLINFO_RESPONSE_CODE), length $body;
}, {
CURLOPT_URL => 'https://www.perl.org',
CURLOPT_WRITEFUNCTION => sub { $body .= $_[0] },
CURLOPT_HTTPHEADER => ['My-Super-Awesome-Header: forty-two'],
});
EV::run until $done;
die "Request failed: $failed\n" if $failed;
DESCRIPTION
This module binds libcurl's "multi" interface
<https://curl.se/libcurl/c/libcurl-multi.html> to EV. Transfers run on
EV's default loop alongside everything else it drives, and libcurl's
sockets and timeouts are managed by C watchers registered directly through
EV's C API, without a round trip through Perl.
METHODS
EV::YACurl
"new"
my $client = EV::YACurl->new(\%options);
Returns a new client, which is a binding over one curl multi handle.
The required hashref holds "CURLM*" options such as
"CURLMOPT_MAX_TOTAL_CONNECTIONS"; see the curl documentation
<https://curl.se/libcurl/c/curl_multi_setopt.html> for the full list.
Options this module cannot translate are rejected rather than silently
ignored, as are names belonging to another namespace: the numbers
collide, so a "CURLOPT_*" name here would otherwise set an unrelated
multi option.
A client owns a connection pool, so reusing one across requests is
what enables keep alive and HTTP/2 multiplexing.
"request"
$client->request($callback, \%options);
Starts a request. %options holds "CURLOPT_*" options and must contain
at least "CURLOPT_URL"; see the curl documentation
<https://curl.se/libcurl/c/curl_easy_setopt.html>.
Returns nothing. $callback is invoked once the request finishes, with
two arguments, $response and $error, exactly one of which is defined.
$response is an "EV::YACurl::Response" object; $error is a human
readable description of what went wrong, taken from libcurl's error
buffer when it has something more specific to say than the generic
message for the error code.
The client is kept alive for the duration of the request, so it is
safe to let the last reference to it go out of scope while transfers
are in flight.
A callback that dies does not propagate: the exception is caught and
reported as a warning, and the loop carries on. Record what went wrong
and act on it after "EV::run" returns, as the synopsis does, rather
than dying inside the callback.
Start follow-up requests from this completion callback. "request"
croaks when called from inside a per-request data callback
("CURLOPT_WRITEFUNCTION" and friends), for any client, because libcurl
is inside its own API while those run; the croak is reported as a
warning like any other callback death. Do not run a nested event loop
from one either, for the same reason.
A request that fails before it reaches the network, a malformed URL
for instance, is finished before "request" returns, so its callback
runs on the caller's stack rather than from the loop. A callback that
retries such a request unconditionally therefore recurses instead of
unwinding; bound the retries, or arm an "EV::timer" and retry from
that.
"priority"
my $current = $client->priority;
my $previous = $client->priority($new_priority);
Queries, and optionally sets, the EV priority of every watcher this
client owns: the "ev_io" watcher behind each socket libcurl asks to
poll, and the client's "ev_timer". Values outside "EV::MINPRI" ..
"EV::MAXPRI" are clamped. Returns the priority that was in effect
before the call.
libcurl invokes the per request callbacks ("CURLOPT_WRITEFUNCTION" and
friends, and the completion callback given to "request") synchronously
from inside those watchers, so this is also the priority at which your
callbacks run.
Priority belongs to the client rather than to an individual request,
because one socket can carry several transfers at once under keep
alive and HTTP/2 multiplexing. To run two groups of transfers at
different priorities, use two clients.
Setting it takes effect immediately, including on watchers the client
already owns. A watcher that has already received an event keeps its
old priority for that one event, since re-sorting it would discard the
event; the new priority reaches it as soon as that event has been
dispatched.
"default_priority"
my $current = EV::YACurl->default_priority;
my $previous = EV::YACurl->default_priority($new_priority);
Class method. Queries, and optionally sets, the priority handed to
clients created from now on. Defaults to 0, which is EV's own default.
Existing clients are not affected, so set this during startup rather
than mid run.
EV::YACurl::Response
"getinfo"
my $value = $response->getinfo(CURLINFO_RESPONSE_CODE);
Queries libcurl for information about the finished transfer. See the
curl documentation <https://curl.se/libcurl/c/curl_easy_getinfo.html>
for the available "CURLINFO_*" options.
String, integer and floating point results come back as plain scalars,
and the ones that return a "curl_slist", "CURLINFO_COOKIELIST" for
instance, come back as an array reference of strings. The remaining
kinds, the ones handing out C pointers and sockets, are refused.
CURL OPTIONS
Some translation between Perl and curl value types has to be done. Options
taking a number or a string are converted from plain scalars. Options
taking a "curl_slist" take an array reference instead, as
"CURLOPT_HTTPHEADER" does in the synopsis. "CURLOPT_MIMEPOST" takes an
array of hashrefs, each with a "name" and one of "value" or "file".
"CURLOPT_POSTFIELDS" is copied by libcurl along with its length, so a body
containing zero bytes survives; there is no need to set
"CURLOPT_POSTFIELDSIZE" yourself.
Each request is its own libcurl easy handle, which is what a cookie jar is
flushed from. A "CURLOPT_COOKIEJAR" file is therefore not written until
the response object is freed, so a follow-up request started from inside
the completion callback will not see it yet: carry the cookie across
yourself with "CURLOPT_COOKIE", or start the follow-up after the response
has gone.
Options that take a function need a Perl signature of their own,
documented below.
CURLOPT_WRITEFUNCTION
(See curl documentation
<https://curl.se/libcurl/c/CURLOPT_WRITEFUNCTION.html>)
Called with the received data as its only argument. Its return value
is ignored, so it cannot abort a transfer; use "CURLOPT_TIMEOUT_MS"
and friends, or return "undef" from "CURLOPT_READFUNCTION" on an
upload.
( run in 1.367 second using v1.01-cache-2.11-cpan-14f38c9f855 )