Function wait [src]
Waits for a response from the server and parses any headers that are sent.
This function will block until the final response is received.
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.
Must be called after send and, if any data was written to the request
body, then also after finish.
Prototype
pub fn wait(req: *Request) WaitError!void
Parameters
req: *Request
Possible Errors
The input was empty or contained an invalid character
The result cannot fit in the type specified
Source
pub fn wait(req: *Request) WaitError!void {
while (true) {
// 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 = req.connection.?;
while (true) { // read headers
try connection.fill();
const nchecked = try req.response.parser.checkCompleteHead(connection.peek());
connection.drop(@intCast(nchecked));
if (req.response.parser.state.isContent()) break;
}
try req.response.parse(req.response.parser.get());
if (req.response.status == .@"continue") {
// We're done parsing the continue response; reset to prepare
// for the real response.
req.response.parser.done = true;
req.response.parser.reset();
if (req.handle_continue)
continue;
return; // we're not handling the 100-continue
}
// we're switching protocols, so this connection is no longer doing http
if (req.method == .CONNECT and req.response.status.class() == .success) {
connection.closing = false;
req.response.parser.done = true;
return; // the connection is not HTTP past this point
}
connection.closing = !req.response.keep_alive or !req.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 (req.method == .HEAD or req.response.status.class() == .informational or
req.response.status == .no_content or req.response.status == .not_modified)
{
req.response.parser.done = true;
return; // The response is empty; no further setup or redirection is necessary.
}
switch (req.response.transfer_encoding) {
.none => {
if (req.response.content_length) |cl| {
req.response.parser.next_chunk_length = cl;
if (cl == 0) req.response.parser.done = true;
} else {
// read until the connection is closed
req.response.parser.next_chunk_length = std.math.maxInt(u64);
}
},
.chunked => {
req.response.parser.next_chunk_length = 0;
req.response.parser.state = .chunk_head_size;
},
}
if (req.response.status.class() == .redirect and req.redirect_behavior != .unhandled) {
// skip the body of the redirect response, this will at least
// leave the connection in a known good state.
req.response.skip = true;
assert(try req.transferRead(&.{}) == 0); // we're skipping, no buffer is necessary
if (req.redirect_behavior == .not_allowed) return error.TooManyHttpRedirects;
const location = req.response.location orelse
return error.HttpRedirectLocationMissing;
// This mutates the beginning of header_bytes_buffer and uses that
// for the backing memory of the returned Uri.
try req.redirect(req.uri.resolve_inplace(
location,
&req.response.parser.header_bytes_buffer,
) catch |err| switch (err) {
error.UnexpectedCharacter,
error.InvalidFormat,
error.InvalidPort,
=> return error.HttpRedirectLocationInvalid,
error.NoSpaceLeft => return error.HttpHeadersOversize,
});
try req.send();
} else {
req.response.skip = false;
if (!req.response.parser.done) {
switch (req.response.transfer_compression) {
.identity => req.response.compression = .none,
.compress, .@"x-compress" => return error.CompressionUnsupported,
.deflate => req.response.compression = .{
.deflate = std.compress.zlib.decompressor(req.transferReader()),
},
.gzip, .@"x-gzip" => req.response.compression = .{
.gzip = std.compress.gzip.decompressor(req.transferReader()),
},
// https://github.com/ziglang/zig/issues/18937
//.zstd => req.response.compression = .{
// .zstd = std.compress.zstd.decompressStream(req.client.allocator, req.transferReader()),
//},
.zstd => return error.CompressionUnsupported,
}
}
break;
}
}
}