authorgravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2023-10-20 20:13:25-05:00
committergravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2023-10-21 20:53:00-05:00
log93e1f8c8e583b3140bc1985e8b346fd7aca8cf6b
treef080bbe41e9a0cdfb457bd75a437e06c36fea0a2
parentdd010e9e90c5ff6cbd5f390dbbb534ddf2fc87b6
signaturelock-open Commit is signed but in an unrecognized format.

std.http.Client: documentaion fixes


2 files changed, 31 insertions(+), 15 deletions(-)

lib/std/http/Client.zig+31-12
......@@ -14,7 +14,11 @@ const proto = @import("protocol.zig");
1414
1515pub const disable_tls = std.options.http_disable_tls;
1616
17/// Allocator used for all allocations made by the client.
18///
19/// This allocator must be thread-safe.
1720allocator: Allocator,
21
1822ca_bundle: if (disable_tls) void else std.crypto.Certificate.Bundle = if (disable_tls) {} else .{},
1923ca_bundle_mutex: std.Thread.Mutex = .{},
2024
......@@ -26,10 +30,10 @@ next_https_rescan_certs: bool = true,
2630connection_pool: ConnectionPool = .{},
2731
2832/// This is the proxy that will handle http:// connections. It *must not* be modified when the client has any active connections.
29http_proxy: ?ProxyInformation = null,
33http_proxy: ?Proxy = null,
3034
3135/// This is the proxy that will handle https:// connections. It *must not* be modified when the client has any active connections.
32https_proxy: ?ProxyInformation = null,
36https_proxy: ?Proxy = null,
3337
3438/// A set of linked lists of connections that can be reused.
3539pub const ConnectionPool = struct {
......@@ -61,6 +65,8 @@ pub const ConnectionPool = struct {
6165 while (next) |node| : (next = node.prev) {
6266 if (node.data.protocol != criteria.protocol) continue;
6367 if (node.data.port != criteria.port) continue;
68
69 // Domain names are case-insensitive (RFC 5890, Section 2.3.2.4)
6470 if (!std.ascii.eqlIgnoreCase(node.data.host, criteria.host)) continue;
6571
6672 pool.acquireUnsafe(node);
......@@ -88,6 +94,9 @@ pub const ConnectionPool = struct {
8894
8995 /// Tries to release a connection back to the connection pool. This function is threadsafe.
9096 /// If the connection is marked as closing, it will be closed instead.
97 ///
98 /// The allocator must be the owner of all nodes in this pool.
99 /// The allocator must be the owner of all resources associated with the connection.
91100 pub fn release(pool: *ConnectionPool, allocator: Allocator, connection: *Connection) void {
92101 pool.mutex.lock();
93102 defer pool.mutex.unlock();
......@@ -195,7 +204,7 @@ pub const Connection = struct {
195204
196205 pub fn readvDirectTls(conn: *Connection, buffers: []std.os.iovec) ReadError!usize {
197206 return conn.tls_client.readv(conn.stream, buffers) catch |err| {
198 // TODO: https://github.com/ziglang/zig/issues/2473
207 // https://github.com/ziglang/zig/issues/2473
199208 if (mem.startsWith(u8, @errorName(err), "TlsAlert")) return error.TlsAlert;
200209
201210 switch (err) {
......@@ -978,7 +987,7 @@ pub const Request = struct {
978987 }
979988};
980989
981pub const ProxyInformation = struct {
990pub const Proxy = struct {
982991 allocator: Allocator,
983992 headers: http.Headers,
984993
......@@ -990,8 +999,12 @@ pub const ProxyInformation = struct {
990999};
9911000
9921001/// Release all associated resources with the client.
993/// TODO: currently leaks all request allocated data
1002///
1003/// All pending requests must be de-initialized and all active connections released
1004/// before calling this function.
9941005pub fn deinit(client: *Client) void {
1006 assert(client.connection_pool.used.first == null); // There are still active requests.
1007
9951008 client.connection_pool.deinit(client.allocator);
9961009
9971010 if (client.http_proxy) |*proxy| {
......@@ -1013,6 +1026,12 @@ pub fn deinit(client: *Client) void {
10131026/// Uses the *_proxy environment variable to set any unset proxies for the client.
10141027/// This function *must not* be called when the client has any active connections.
10151028pub fn loadDefaultProxies(client: *Client) !void {
1029 // Prevent any new connections from being created.
1030 client.connection_pool.mutex.lock();
1031 defer client.connection_pool.mutex.unlock();
1032
1033 assert(client.connection_pool.used.first == null); // There are still active requests.
1034
10161035 if (client.http_proxy == null) http: {
10171036 const content: []const u8 = if (std.process.hasEnvVarConstant("http_proxy"))
10181037 try std.process.getEnvVarOwned(client.allocator, "http_proxy")
......@@ -1203,7 +1222,7 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti
12031222/// This function is threadsafe.
12041223pub fn connectTunnel(
12051224 client: *Client,
1206 proxy: *ProxyInformation,
1225 proxy: *Proxy,
12071226 tunnel_host: []const u8,
12081227 tunnel_port: u16,
12091228) !*Connection {
......@@ -1217,7 +1236,7 @@ pub fn connectTunnel(
12171236 return node;
12181237
12191238 var maybe_valid = false;
1220 _ = tunnel: {
1239 (tunnel: {
12211240 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);
12221241 errdefer {
12231242 conn.closing = true;
......@@ -1241,7 +1260,7 @@ pub fn connectTunnel(
12411260 var req = client.open(.CONNECT, uri, proxy.headers, .{
12421261 .handle_redirects = false,
12431262 .connection = conn,
1244 .header_strategy = .{ .static = buffer[0..] },
1263 .header_strategy = .{ .static = &buffer },
12451264 }) catch |err| {
12461265 std.log.debug("err {}", .{err});
12471266 break :tunnel err;
......@@ -1269,7 +1288,7 @@ pub fn connectTunnel(
12691288 conn.closing = false;
12701289
12711290 return conn;
1272 } catch {
1291 }) catch {
12731292 // something went wrong with the tunnel
12741293 proxy.supports_connect = maybe_valid;
12751294 return error.TunnelNotSupported;
......@@ -1287,7 +1306,7 @@ pub const ConnectError = ConnectErrorPartial || RequestError;
12871306/// This function is threadsafe.
12881307pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*Connection {
12891308 // pointer required so that `supports_connect` can be updated if a CONNECT fails
1290 const potential_proxy: ?*ProxyInformation = switch (protocol) {
1309 const potential_proxy: ?*Proxy = switch (protocol) {
12911310 .plain => if (client.http_proxy) |*proxy_info| proxy_info else null,
12921311 .tls => if (client.https_proxy) |*proxy_info| proxy_info else null,
12931312 };
......@@ -1298,12 +1317,12 @@ pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connectio
12981317 return client.connectTcp(host, port, protocol);
12991318 }
13001319
1301 _ = if (proxy.supports_connect) tunnel: {
1320 if (proxy.supports_connect) tunnel: {
13021321 return connectTunnel(client, proxy, host, port) catch |err| switch (err) {
13031322 error.TunnelNotSupported => break :tunnel,
13041323 else => |e| return e,
13051324 };
1306 };
1325 }
13071326
13081327 // fall back to using the proxy as a normal http proxy
13091328 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);
test/standalone/http.zig-3
......@@ -634,9 +634,6 @@ pub fn main() !void {
634634 req.transfer_encoding = .chunked;
635635
636636 try req.send(.{});
637 try req.wait();
638 try testing.expectEqual(http.Status.@"continue", req.response.status);
639
640637 try req.writeAll("Hello, ");
641638 try req.writeAll("World!\n");
642639 try req.finish();