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

CertificateBundleLoadFailure RequestError
CompressionInitializationFailed
CompressionUnsupported ParseError
ConnectionRefused ConnectTcpError
ConnectionResetByPeer ConnectTcpError
ConnectionTimedOut ConnectTcpError
EndOfStream ReadError
HostLacksNetworkAddresses ConnectTcpError
HttpChunkInvalid ReadError
HttpConnectionHeaderUnsupported ParseError
HttpHeaderContinuationsUnsupported ParseError
HttpHeadersInvalid ParseError
HttpHeadersOversize CheckCompleteHeadError
HttpRedirectLocationInvalid
HttpRedirectLocationMissing
HttpTransferEncodingUnsupported ParseError
InvalidCharacter ParseIntError

The input was empty or contained an invalid character

InvalidContentLength SendError
NameServerFailure ConnectTcpError
NetworkUnreachable ConnectTcpError
OutOfMemory Error
Overflow ParseIntError

The result cannot fit in the type specified

RedirectRequiresResend
TemporaryNameServerFailure ConnectTcpError
TlsAlert ReadError
TlsFailure ReadError
TlsInitializationFailed ConnectTcpError
TooManyHttpRedirects
UnexpectedConnectFailure ConnectTcpError
UnexpectedReadFailure ReadError
UnexpectedWriteFailure WriteError
UnknownHostName ConnectTcpError
UnsupportedTransferEncoding SendError
UnsupportedUriScheme ConnectErrorPartial
UriMissingHost RequestError

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; } } }