Open a connection to the host specified by uri and prepare to send a HTTP request.
The caller is responsible for calling deinit() on the Request.
This function is threadsafe.
Asserts that "\r\n" does not occur in any header name or value.
pub fn request(
client: *Client,
method: http.Method,
uri: Uri,
options: RequestOptions,
) RequestError!Request
pub fn request(
client: *Client,
method: http.Method,
uri: Uri,
options: RequestOptions,
) RequestError!Request {
const io = client.io;
if (std.debug.runtime_safety) {
for (options.extra_headers) |header| {
assert(header.name.len != 0);
assert(std.mem.findScalar(u8, header.name, ':') == null);
assert(std.mem.findPosLinear(u8, header.name, 0, "\r\n") == null);
assert(std.mem.findPosLinear(u8, header.value, 0, "\r\n") == null);
}
for (options.privileged_headers) |header| {
assert(header.name.len != 0);
assert(std.mem.findPosLinear(u8, header.name, 0, "\r\n") == null);
assert(std.mem.findPosLinear(u8, header.value, 0, "\r\n") == null);
}
}
const protocol = Protocol.fromUri(uri) orelse return error.UnsupportedUriScheme;
if (protocol == .tls) tls: {
if (disable_tls) unreachable;
{
try client.ca_bundle_lock.lockShared(io);
defer client.ca_bundle_lock.unlockShared(io);
if (client.now != null) break :tls;
}
var bundle: std.crypto.Certificate.Bundle = .empty;
defer bundle.deinit(client.allocator);
const now = Io.Clock.real.now(io);
bundle.rescan(client.allocator, io, now) catch |err| switch (err) {
error.Canceled => |e| return e,
else => return error.CertificateBundleLoadFailure,
};
try client.ca_bundle_lock.lock(io);
defer client.ca_bundle_lock.unlock(io);
client.now = now;
std.mem.swap(std.crypto.Certificate.Bundle, &client.ca_bundle, &bundle);
}
const connection = options.connection orelse c: {
var host_name_buffer: [HostName.max_len]u8 = undefined;
const host_name = HostName.fromUri(uri, &host_name_buffer) catch |err| switch (err) {
error.UriMissingHost => |e| return e,
error.NameTooLong, error.InvalidHostName => return error.InvalidHostName,
};
break :c try client.connect(host_name, uriPort(uri, protocol), protocol);
};
return .{
.uri = uri,
.client = client,
.connection = connection,
.reader = .{
.in = connection.reader(),
.state = .ready,
// Populated when `http.Reader.bodyReader` is called.
.interface = undefined,
.max_head_len = client.read_buffer_size,
},
.keep_alive = options.keep_alive,
.method = method,
.version = options.version,
.transfer_encoding = .none,
.redirect_behavior = options.redirect_behavior,
.handle_continue = options.handle_continue,
.headers = options.headers,
.extra_headers = options.extra_headers,
.privileged_headers = options.privileged_headers,
};
}