DoxigAlpha

receiveHead

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.

Function parameters

Parameters

#
r:*Request
redirect_buffer:[]u8

A Least-Recently-Used cache of open connections to be reused.

Types

#
ConnectionPool
A Least-Recently-Used cache of open connections to be reused.

Release all associated resources with the client.

Functions

#
deinit
Release all associated resources with the client.
initDefaultProxies
Populates `http_proxy` and `https_proxy` via standard proxy environment variables.
connectTcp
Reuses a `Connection` if one matching `host` and `port` is already open.
connectUnix
Connect to `path` as a unix domain socket.
connectProxied
Connect to `proxied_host:proxied_port` using the specified proxy with HTTP
connect
Connect to `host:port` using the specified protocol.
request
Open a connection to the host specified by `uri` and prepare to send a HTTP request.
fetch
Perform a one-shot HTTP request with the provided options.

Error sets in this namespace

Error Sets

#

= std.options.http_disable_tls

Values

#
disable_tls
= std.options.http_disable_tls

Source

Implementation

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