NAME
UniEvent::HTTP::Request - HTTP client request class
SYNOPSIS
# explicit creation
my $request = UE::HTTP::Request->new({
uri => "http://example.com",
timeout => 3,
response_callback => sub {
my ($request, $response, $error) = @_;
...
},
});
http_request($request);
# implicit creation
http_request({
uri => "http://example.com",
timeout => 3,
response_callback => sub {
my ($request, $response, $error) = @_;
...
},
});
DESCRIPTION
UniEvent::HTTP::Request
is used to make client http requests. It holds all the properties and state of http request. UniEvent::HTTP::Request
object is passed then to http_request()
, http_request_sync()
, $pool->request, $client->request or $user_agent->request functions.
Once completed, a Request object can be used again to make another http request. However one request object cannot be run twice at a time.
UniEvent::HTTP::Request
inherits from Protocol::HTTP::Request. So for complete documenation you need to also read Protocol::HTTP::Request's docs.
Request supports chunked transmission. If you set chunked
property (see Protocol::HTTP::Request) to a true
value, then after you send this request via http_request()
, etc... you will need to send http chunks via send_chunk()
method and then send_final_chunk()
when you are done.
Request supports compression. There is nothing to do and document here about compression as everything is implemented and documented in Protocol::HTTP.
Request supports real-time partial body receival for streaming into storage without memory consumption or incremental parsing of sub-protocol. See partial_callback()
.
See detailed description in corresponding method docs.
METHODS
All methods of Protocol::HTTP::Request also apply.
new(\%params)
Constructs a request object from hashref of params.
This method is also called implicitly when you pass hashref of params to functions like http_request()
, $pool->request and so on, i.e. where an object of UniEvent::HTTP::Request is expected.
Params can contain:
- All params from Protocol::HTTP::Request::new() also apply
- timeout [=20]
- follow_redirect [=true]
- redirection_limit [=20]
- tcp_nodelay [=false]
- tcp_hints
- ssl_ctx
- proxy
- response_callback
- partial_callback
- redirect_callback
- continue_callback
-
See corresponding description of all parameters above in their setter-getter methods below.
- form
-
Although Protocol::HTTP::Request::new() supports the
form
parameter, UniEvent::HTTP::Request extends its possibilities to support real-time streaming of data to form.Form fields values from Protocol::HTTP::Request are required to be available upfront, i.e.:
my $pdf_content = ...; # obtain file content somehow form => [ 'key1' => $value1, 'key2' => ['a.pdf' => $pdf_content, 'application/pdf'], ... ]});
In the UniEvent::HTTP it is possible to specify any input stream, which will push bytes lately, as soon as they become available. Usually, this file input, but the data can be also be taken from TCP connection via UniEvent::Streamer::StreamInput. This way it is possible to avoid reading huge files in-memory before streaming them to peer.
my $pdf_content = UE::Streamer::FileInput->new("path/to/my.pdf"); form => [ 'key1' => $value1, 'key2' => ['a.pdf' => $pdf_content, 'application/pdf'], ... ]});
The streaming is availabe only for
multipart/form-data
method of posting data. In other words,multipart/form-data
will always be forced for you, if any streaming content is detected.
NOTE: If you create your own request class inherited from UniEvent::HTTP::Request
, you must proxy to original new()
method and use its result as an object you return. By default it is a reference to undef, you can upgrade it to hash-based object via XS::Framework::obj2hv
:
package MyRequest;
use parent 'UniEvent::HTTP::Request';
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
XS::Framework::obj2hv($self);
$self->{prop} = "val";
return $self;
}
timeout([$timeout])
Get/set timeout for the whole request (connect + sending request + receiving response) in seconds (can be fractional). To disable timeout, set zero.
If time is up, request will finish with error UniEvent::SystemError::timed_out
.
follow_redirect([$bool])
Get/set follow_redirect
flag.
If set to true and the server's response code is one of 300
, 301
, 302
, 303
, 307
or 308
, will transparently make another request to the destination described in response and use that another response.
New request will be made to a location specified in Location
header in the response. Headers Authorization
, Cookie
, Referer
in original request get removed for security reasons; so does ssl_ctx
if ssl is in use. If precise control over this process is needed, consider setting redirect_callback
(see docs below).
If new response is a redirection again, will repeat this procedure up to redirection_limit
times. If this limit is exceeded, request will finish with error UniEvent::HTTP::Error::redirection_limit
. If the limit is set to 0, then request will finish with error UniEvent::HTTP::Error::unexpected_redirect
immediately on first redirection response.
If set to false, then just content of redirection response will be returned.
redirection_limit([$cnt])
Get/set redirection limit, see follow_redirect()
.
tcp_nodelay([$bool])
Get/set tcp nodelay feature.
tcp_hints([$hints])
Get/set DNS resolving hints. Hints
can be used to disambiguate domain name resolution in certain cases. $hints
should be either a binary string created via UniEvent::Resolver::hints()
$request->tcp_hints(UniEvent::Resolver::hints(AF_INET, SOCK_STREAM, PF_INET));
Or a hashref with the corresponding info
$request->tcp_hints({
family => AF_INET,
socktype => SOCK_STREAM,
protocol => PF_INET,
flags => 0,
});
See UniEvent::Resolver for more info.
ssl_ctx([$ssl_ctx])
Get/set ssl context. By default, ssl context is autocreated when HTTPS location is requested, but for more precise control (validating server's certificate, authorizing via ssl, etc) ssl context can be created by hand via Net::SSLeay module and passed here.
After creating context via Net::SSLeay and passing to this method, you can release context via CTX_free()
function from Net::SSLeay
as it is refcounted and held by request object.
my $ctx = Net::SSLeay::CTX_new();
Net::SSLeay::CTX_use_certificate_file($ctx, "cert/ca.pem", Net::SSLeay::FILETYPE_PEM);
Net::SSLeay::CTX_use_PrivateKey_file($ctx, "cert/ca.key", Net::SSLeay::FILETYPE_PEM);
Net::SSLeay::CTX_check_private_key($ctx) or die "wtf?";
$request->ssl_ctx($ctx);
Net::SSLeay::CTX_free($ctx);
proxy([$url])
Get/set socks5 proxy url as string or URI::XS object. Url scheme must be socks5
.
$request->proxy("socks5://proxy.com:1234");
$request->proxy("socks5://login:pass@proxy.com:1234");
response_callback($sub)
response_event()
Callbacks set via these methods will be invoked when response is fully received including all body or if an error occurs.
Callback signature:
my ($request, $response, $error) = @_;
Where $request
is the original request object being executed.
$response
is a UniEvent::HTTP::Response object containing all http response properties.
$error
is an optional XS::ErrorCode object and if it is present then $response
may be undefined. If the error occured while receiving response, then $response
will present and contain everything parsed till that moment. $error
can be one of listed in UniEvent::HTTP::Error, Protocol::HTTP::Error or UniEvent::SystemError and it can be nested, see XS::ErrorCode.
See "EVENT CALLBACKS" in UniEvent for differences between _callback
and _event
versions of methods.
partial_callback($sub)
partial_event()
Invoked one or more times, every time data arrives from network.
Callback signature and meaning of params are the same as for response_callback
:
my ($request, $response, $error) = @_;
First time it is called when all headers arrived. From call to call response's body will grow until it's done or error occurs. If $response->is_done() is true or $error
is set, then it's the last call.
The actual body part arrived is the difference between current body value and previous body value. If you only need that part, not the whole growing body (for writing to disk / incremental parsing / saving memory) then just clear the body on each call (because new parts just append to current $response->body value).
$request->partial_callback(sub {
my ($req, $res, $error) = @_;
if ($error) {
...
return;
}
print $fh $res->body; # or asynchronously
$res->body("");
if ($res->is_done) {
close $fh;
...
}
})
If response_callback
is set, it will also be called after the last call to partial_callback
. The response body in response_callback
will not be the full response body if you cleared it in partial_callback
.
See "EVENT CALLBACKS" in UniEvent for differences between _callback
and _event
versions of methods.
redirect_callback($sub)
redirect_event()
Invoked right before redirection response will be followed (if follow_redirect
is true).
This callback gives user a control over redirection process.
Callback signature:
my ($request, $response, $redirect_context) = @_;
Where $request
is the original request object with some properties modified (uri, headers, ssl_ctx).
$response
is the current redirection response.
$redirect_context
is an UniEvent::HTTP::RedirectContext object which stores some of original properties of request which got replaced with new ones.
When this callback is called, $request
has already been modified for new http request which will be made after this callback returns. Request uri is changed to point to the new location, headers Authorization
, Cookie
, Referer
are removed for security reasons and ssl_ctx
is cleared also if any. No heuristics are made in order to determine if new location is the same server or not, to keep those properties intact. You are free to change any request properties here (restore those headers back again or set ssl_ctx
or whatsoever) and they will be used. If you want to access original values of those properties, they are stored in $redirect_context
- see UniEvent::HTTP::RedirectContext.
You are also free to cancel()
request here if needed.
See "EVENT CALLBACKS" in UniEvent for differences between _callback
and _event
versions of methods.
continue_callback($sub)
continue_event()
Invoked when server sends 100 continue
intermediate message.
Normally, server can only send 100 continue
if client agrees to receive such messages via setting Expect: 100-continue
header. So you will also need to set
$request->header("Expect", "100-continue")
To use this callback.
Callback signature:
my $request = shift; # the request object itself
See "EVENT CALLBACKS" in UniEvent for differences between _callback
and _event
versions of methods.
cancel([$error = UniEvent::SystemError::operation_canceled])
Cancels request if it's active. All network activity gets stopped and response_callback
and partial_callback
are called with $error
which is UniEvent::SystemError::operation_canceled
by default.
If request is not active (finished or not yet started) does nothing.
transfer_completed()
Returns true if request has been fully send to network including all the body. For example, if you make a chunked request, it will return false from this method until you finish the sequence send_chunk()
, send_chunk()
, ..., send_final_chunk()
.
send_chunk($data)
Should only be called on requests where chunked
is true. Sends an http chunk (applying possible compression, etc).
send_final_chunk([$data])
Should only be called on requests where chunked
is true. Sends final (empty) http chunk and finishes sending chunked http request. If optional $data
is provided, then sends $data
as normal chunk before final chunk.
response_factory([$sub])
Get/set response factory subroutine. Allows for customization of response object. If factory is set, it will be called (once per http request) and its result will be used as response object. It can be of any class but it must inherit UniEvent::HTTP::Response and it must proxy to original new()
method of UniEvent::HTTP::Response
if you override it, see UniEvent::HTTP::Response.
Factory subroutine receives single argument - the request object and is expected to return single value - the response object.
$request->response_factory(sub {
my $request = shift;
my $response = MyResponse->new;
...
return $response;
});