Function receiveHead [src]
If handling redirects and the request has no payload, then this
function will automatically follow redirects.
If a request payload is present, then this function will error with
error.RedirectRequiresResend.
This function takes an auxiliary buffer to store the arbitrarily large
URI which may need to be merged with the previous URI, and that data
needs to survive across different connections, which is where the input
buffer lives.
redirect_buffer must outlive accesses to Request.uri. If this
buffer capacity would be exceeded, error.HttpRedirectLocationOversize
is returned instead. This buffer may be empty if no redirects are to be
handled.
If this fails with error.ReadFailed then the Connection.getReadError
method of r.connection can be used to get more detailed information.
Prototype
pub fn receiveHead(r: *Request, redirect_buffer: []u8) ReceiveHeadError!Response
Parameters
r: *Request
redirect_buffer: []u8
Possible Errors
The client sent 0 bytes of headers before closing the stream. This happens when a keep-alive connection is finally closed.
Server sent headers that did not conform to the HTTP protocol.
To find out more detailed diagnostics, http.Reader.head_buffer
can be
passed directly to Request.Head.parse
.
Too many bytes of HTTP headers.
The HTTP specification suggests to respond with a 431 status code before closing the connection.
Partial HTTP request was received but the connection was closed before fully receiving the headers.
Transitive error occurred reading from in
.
This can be avoided by calling receiveHead
before sending the
request body.
Sending the request failed. Error code can be found on the
Connection
object.
Source
pub fn receiveHead(r: *Request, redirect_buffer: []u8) ReceiveHeadError!Response {
var aux_buf = redirect_buffer;
while (true) {
const head_buffer = try r.reader.receiveHead();
const response: Response = .{
.request = r,
.head = Response.Head.parse(head_buffer) catch return error.HttpHeadersInvalid,
};
const head = &response.head;
if (head.status == .@"continue") {
if (r.handle_continue) continue;
r.response_transfer_encoding = head.transfer_encoding;
r.response_content_length = head.content_length;
return response; // we're not handling the 100-continue
}
// This while loop is for handling redirects, which means the request's
// connection may be different than the previous iteration. However, it
// is still guaranteed to be non-null with each iteration of this loop.
const connection = r.connection.?;
if (r.method == .CONNECT and head.status.class() == .success) {
// This connection is no longer doing HTTP.
connection.closing = false;
r.response_transfer_encoding = head.transfer_encoding;
r.response_content_length = head.content_length;
return response;
}
connection.closing = !head.keep_alive or !r.keep_alive;
// Any response to a HEAD request and any response with a 1xx
// (Informational), 204 (No Content), or 304 (Not Modified) status
// code is always terminated by the first empty line after the
// header fields, regardless of the header fields present in the
// message.
if (r.method == .HEAD or head.status.class() == .informational or
head.status == .no_content or head.status == .not_modified)
{
r.response_transfer_encoding = head.transfer_encoding;
r.response_content_length = head.content_length;
return response;
}
if (head.status.class() == .redirect and r.redirect_behavior != .unhandled) {
if (r.redirect_behavior == .not_allowed) {
// Connection can still be reused by skipping the body.
const reader = r.reader.bodyReader(&.{}, head.transfer_encoding, head.content_length);
_ = reader.discardRemaining() catch |err| switch (err) {
error.ReadFailed => connection.closing = true,
};
return error.TooManyHttpRedirects;
}
try r.redirect(head, &aux_buf);
try r.sendBodiless();
continue;
}
if (!r.accept_encoding[@intFromEnum(head.content_encoding)])
return error.HttpContentEncodingUnsupported;
r.response_transfer_encoding = head.transfer_encoding;
r.response_content_length = head.content_length;
return response;
}
}