NAME
Unblock::HTTP1::Transaction - One HTTP/1 request/response exchange
SYNOPSIS
Server side:
on_request => sub {
my ($tx, $request) = @_;
$tx->respond(
status => 200,
body => "hello\n",
);
};
Client side:
my $tx = $client->request(
method => 'GET',
target => '/',
on_complete => sub {
my ($tx) = @_;
print $tx->response->status, "\n";
},
);
RECEIVE AND FINISH CALLBACKS
$tx->on_data(sub {
my ($tx, $bytes) = @_;
consume_chunk($bytes);
});
Register during the incoming-header callback (server on_request or client on_response). This selects streaming for this transaction. Only decoded HTTP body bytes are passed; content encodings such as gzip are not decoded. No full body is accumulated. Registering after body delivery starts or ends, registering twice, or combining this callback with on_body is an error. Client request() also accepts on_data before the request is dispatched.
$tx->on_finish(sub {
my ($tx) = @_;
record_outcome($tx->state, $tx->error);
});
Runs once after the applicable completion or error callbacks for a terminal complete, cancelled, or error transaction. The state is committed before the callback. Cancellation alone does not call on_error. A completed incoming request can still have an unfinished response; it is not terminal until both sides required by the engine have finished.
Client request() also accepts on_finish. Register it before the transaction becomes terminal. Duplicate and late registration are errors. An exception from this terminal observer is ignored so cleanup and other transactions can continue. Earlier callbacks keep the engine's exception policy, but cannot suppress this notification.
DESCRIPTION
A Transaction represents one HTTP/1 request and its response.
Applications do not construct Transaction objects directly. A client gets one from $client->request(). A server receives one in on_request.
The same class is used on both sides:
- Client Transaction
-
Owns one outgoing request and the incoming response.
For a streaming request body,
write()andend()send request body bytes. - Server Transaction
-
Owns one incoming request and the outgoing response.
respond()starts the final response. For a streaming response body,write()andend()send response body bytes.
A Transaction does not own the socket or event loop. It delegates wire work to its owning Client or Server connection.
MESSAGE ACCESSORS
request
my $request = $tx->request;
Returns the canonical Uniform::HTTP::Request for this exchange.
On the client this is the request supplied to, or constructed by, Client->request().
On the server this is the parsed request delivered by on_request.
response
my $response = $tx->response;
Returns the canonical Uniform::HTTP::Response once a final response exists.
Before that point it returns undef.
On a client, the response becomes available when the final response head is received.
On a server, it becomes available after respond() starts the final response.
Informational responses do not replace the final response() value.
SERVER RESPONSE METHODS
These methods are meaningful on a server Transaction.
respond
Concise form:
$tx->respond(
status => 200,
headers => [
[ 'Content-Type' => 'text/plain' ],
],
body => "hello\n",
);
Existing-object form:
$tx->respond($response);
Starts the final response and returns the Transaction.
The concise form constructs a canonical Uniform::HTTP::Response internally.
respond() may be called before the complete request body has arrived. This is useful for early rejection or any response which does not depend on the full request body.
A Transaction can have only one final response.
Informational status codes other than 101 must use send_informational() instead.
For a streaming response:
$tx->respond(
status => 200,
stream_body => 1,
on_drain => sub {
produce_more();
},
);
The response head is sent immediately and body data is supplied later with write() and end().
on_drain is valid only with stream_body => 1.
Calling respond() on a client Transaction is an error.
send_informational
Concise form:
$tx->send_informational(
status => 103,
headers => [
[ Link => '</style.css>; rel=preload' ],
],
);
Existing-object form:
$tx->send_informational($response);
Sends one informational response and returns the Transaction.
The status must be from 100 through 199, except 101. A 101 response is a final protocol-switch response and uses respond().
More than one informational response may be sent before the final response.
HTTP/1.0 clients cannot receive informational responses through this method.
Calling send_informational() on a client Transaction is an error.
STREAMING BODY METHODS
write
my $ok = $tx->write($bytes);
Adds one chunk of a streaming body.
On a client Transaction, this writes an outgoing request body.
On a server Transaction, this writes an outgoing response body after respond(stream_body => 1).
The supplied bytes are accepted even when the return value is false.
A true return means the output path remains writable.
A false return means backpressure is active. The producer should stop creating more body data and resume from its on_drain callback.
write() is valid only for a transaction created or started with stream_body => 1.
The engine applies HTTP transfer framing. Applications provide body bytes, not chunk framing.
When Content-Length is explicitly declared, writing more than that length is an error.
end
my $ok = $tx->end;
my $ok = $tx->end($last_bytes);
Finishes a streaming body.
$last_bytes, when supplied, are accepted as the final body bytes before the stream is ended.
On a client this finishes the request body.
On a server this finishes the response body.
For chunked HTTP/1.1 output, end() writes the final chunk and any configured trailers.
For an explicit Content-Length, ending before exactly that many bytes have been written is an error.
After end() the local streaming body is complete and additional write() or end() calls are invalid.
The boolean return has the same backpressure meaning as write().
CANCELLATION
cancel
$tx->cancel;
Cancels the Transaction and returns it.
HTTP/1 transactions share connection ordering and framing state, so cancellation closes the HTTP/1 connection rather than attempting to skip an arbitrary exchange in place.
On a client, queued requests which depended on that connection are failed.
Calling cancel() again after the Transaction is terminal is harmless.
Cancellation is distinct from an error. A cancelled Transaction has state cancelled and error() remains undef.
STATE
state
my $state = $tx->state;
Returns one of:
active
complete
cancelled
error
active means the exchange is still in progress.
complete means both sides required by the exchange have finished.
cancelled means cancel() terminated the exchange.
error means the exchange failed.
error
my $error = $tx->error;
Returns the transaction error string when state() is error.
Returns undef for active, complete, and cancelled Transactions.
is_complete
if ($tx->is_complete) { ... }
True only when state() is complete.
is_cancelled
if ($tx->is_cancelled) { ... }
True only when state() is cancelled.
is_error
if ($tx->is_error) { ... }
True only when state() is error.
is_terminal
if ($tx->is_terminal) { ... }
True for complete, cancelled, or error.
False only while the Transaction is active.
CLIENT LIFECYCLE
For a normal buffered client request:
$client->request()creates the Transaction and queues or sends the request.on_informationalmay run zero or more times.on_responseruns when the final response head arrives.on_bodyruns zero or more times.The response completes, and
on_completeruns once the local request side is also complete.
For stream_body => 1, the local side remains incomplete until end() or until an early final response makes further request-body output impossible.
SERVER LIFECYCLE
For a normal server request:
The Transaction is created and passed to
on_request.on_bodymay run zero or more times as request body bytes arrive.on_request_endruns when the full request and trailers are complete.The application starts the final response with
respond().If the response streams,
write()andend()finish the local response side.The Transaction becomes complete when both the request and response sides are done.
The response may begin before steps 2 and 3 finish.
BACKPRESSURE
Backpressure is advisory to the producer, not rejection of the bytes passed to write() or end().
When either the HTTP queue or an attached transport becomes congested:
my $ok = $tx->write($bytes);
returns false.
The producer should stop until on_drain runs.
With a manual integration, draining Client->output() or Server->output() below the low-water mark can cause on_drain.
With an attached transport, the adapter calls $http->resume_output() when the transport becomes writable again.
PROTOCOL SWITCH
A server Transaction can cause a switch by sending a valid 101 response or a successful CONNECT response.
A client Transaction can receive the corresponding switch response.
The Transaction completes its HTTP lifecycle before the connection reports is_switched(). With an attached transport, a server's on_switch is delayed until the complete outgoing handshake has been accepted by the host.
Bytes after the HTTP boundary belong to the next protocol and are obtained from the owning Client or Server with take_remainder().
SEE ALSO
Unblock::HTTP1::Integration, Unblock::HTTP1, Unblock::HTTP1::Client, Unblock::HTTP1::Server, Uniform::HTTP::Request, Uniform::HTTP::Response