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");...@@ -14,7 +14,11 @@ const proto = @import("protocol.zig");
1414
15pub const disable_tls = std.options.http_disable_tls;15pub 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.
17allocator: Allocator,20allocator: Allocator,
21
18ca_bundle: if (disable_tls) void else std.crypto.Certificate.Bundle = if (disable_tls) {} else .{},22ca_bundle: if (disable_tls) void else std.crypto.Certificate.Bundle = if (disable_tls) {} else .{},
19ca_bundle_mutex: std.Thread.Mutex = .{},23ca_bundle_mutex: std.Thread.Mutex = .{},
2024
...@@ -26,10 +30,10 @@ next_https_rescan_certs: bool = true,...@@ -26,10 +30,10 @@ next_https_rescan_certs: bool = true,
26connection_pool: ConnectionPool = .{},30connection_pool: ConnectionPool = .{},
2731
28/// This is the proxy that will handle http:// connections. It *must not* be modified when the client has any active connections.32/// 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
31/// This is the proxy that will handle https:// connections. It *must not* be modified when the client has any active connections.35/// 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
34/// A set of linked lists of connections that can be reused.38/// A set of linked lists of connections that can be reused.
35pub const ConnectionPool = struct {39pub const ConnectionPool = struct {
...@@ -61,6 +65,8 @@ pub const ConnectionPool = struct {...@@ -61,6 +65,8 @@ pub const ConnectionPool = struct {
61 while (next) |node| : (next = node.prev) {65 while (next) |node| : (next = node.prev) {
62 if (node.data.protocol != criteria.protocol) continue;66 if (node.data.protocol != criteria.protocol) continue;
63 if (node.data.port != criteria.port) continue;67 if (node.data.port != criteria.port) continue;
68
69 // Domain names are case-insensitive (RFC 5890, Section 2.3.2.4)
64 if (!std.ascii.eqlIgnoreCase(node.data.host, criteria.host)) continue;70 if (!std.ascii.eqlIgnoreCase(node.data.host, criteria.host)) continue;
6571
66 pool.acquireUnsafe(node);72 pool.acquireUnsafe(node);
...@@ -88,6 +94,9 @@ pub const ConnectionPool = struct {...@@ -88,6 +94,9 @@ pub const ConnectionPool = struct {
8894
89 /// Tries to release a connection back to the connection pool. This function is threadsafe.95 /// Tries to release a connection back to the connection pool. This function is threadsafe.
90 /// If the connection is marked as closing, it will be closed instead.96 /// 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.
91 pub fn release(pool: *ConnectionPool, allocator: Allocator, connection: *Connection) void {100 pub fn release(pool: *ConnectionPool, allocator: Allocator, connection: *Connection) void {
92 pool.mutex.lock();101 pool.mutex.lock();
93 defer pool.mutex.unlock();102 defer pool.mutex.unlock();
...@@ -195,7 +204,7 @@ pub const Connection = struct {...@@ -195,7 +204,7 @@ pub const Connection = struct {
195204
196 pub fn readvDirectTls(conn: *Connection, buffers: []std.os.iovec) ReadError!usize {205 pub fn readvDirectTls(conn: *Connection, buffers: []std.os.iovec) ReadError!usize {
197 return conn.tls_client.readv(conn.stream, buffers) catch |err| {206 return conn.tls_client.readv(conn.stream, buffers) catch |err| {
198 // TODO: https://github.com/ziglang/zig/issues/2473207 // https://github.com/ziglang/zig/issues/2473
199 if (mem.startsWith(u8, @errorName(err), "TlsAlert")) return error.TlsAlert;208 if (mem.startsWith(u8, @errorName(err), "TlsAlert")) return error.TlsAlert;
200209
201 switch (err) {210 switch (err) {
...@@ -978,7 +987,7 @@ pub const Request = struct {...@@ -978,7 +987,7 @@ pub const Request = struct {
978 }987 }
979};988};
980989
981pub const ProxyInformation = struct {990pub const Proxy = struct {
982 allocator: Allocator,991 allocator: Allocator,
983 headers: http.Headers,992 headers: http.Headers,
984993
...@@ -990,8 +999,12 @@ pub const ProxyInformation = struct {...@@ -990,8 +999,12 @@ pub const ProxyInformation = struct {
990};999};
9911000
992/// Release all associated resources with the client.1001/// Release all associated resources with the client.
993/// TODO: currently leaks all request allocated data1002///
1003/// All pending requests must be de-initialized and all active connections released
1004/// before calling this function.
994pub fn deinit(client: *Client) void {1005pub fn deinit(client: *Client) void {
1006 assert(client.connection_pool.used.first == null); // There are still active requests.
1007
995 client.connection_pool.deinit(client.allocator);1008 client.connection_pool.deinit(client.allocator);
9961009
997 if (client.http_proxy) |*proxy| {1010 if (client.http_proxy) |*proxy| {
...@@ -1013,6 +1026,12 @@ pub fn deinit(client: *Client) void {...@@ -1013,6 +1026,12 @@ pub fn deinit(client: *Client) void {
1013/// Uses the *_proxy environment variable to set any unset proxies for the client.1026/// Uses the *_proxy environment variable to set any unset proxies for the client.
1014/// This function *must not* be called when the client has any active connections.1027/// This function *must not* be called when the client has any active connections.
1015pub fn loadDefaultProxies(client: *Client) !void {1028pub 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
1016 if (client.http_proxy == null) http: {1035 if (client.http_proxy == null) http: {
1017 const content: []const u8 = if (std.process.hasEnvVarConstant("http_proxy"))1036 const content: []const u8 = if (std.process.hasEnvVarConstant("http_proxy"))
1018 try std.process.getEnvVarOwned(client.allocator, "http_proxy")1037 try std.process.getEnvVarOwned(client.allocator, "http_proxy")
...@@ -1203,7 +1222,7 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti...@@ -1203,7 +1222,7 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti
1203/// This function is threadsafe.1222/// This function is threadsafe.
1204pub fn connectTunnel(1223pub fn connectTunnel(
1205 client: *Client,1224 client: *Client,
1206 proxy: *ProxyInformation,1225 proxy: *Proxy,
1207 tunnel_host: []const u8,1226 tunnel_host: []const u8,
1208 tunnel_port: u16,1227 tunnel_port: u16,
1209) !*Connection {1228) !*Connection {
...@@ -1217,7 +1236,7 @@ pub fn connectTunnel(...@@ -1217,7 +1236,7 @@ pub fn connectTunnel(
1217 return node;1236 return node;
12181237
1219 var maybe_valid = false;1238 var maybe_valid = false;
1220 _ = tunnel: {1239 (tunnel: {
1221 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);1240 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);
1222 errdefer {1241 errdefer {
1223 conn.closing = true;1242 conn.closing = true;
...@@ -1241,7 +1260,7 @@ pub fn connectTunnel(...@@ -1241,7 +1260,7 @@ pub fn connectTunnel(
1241 var req = client.open(.CONNECT, uri, proxy.headers, .{1260 var req = client.open(.CONNECT, uri, proxy.headers, .{
1242 .handle_redirects = false,1261 .handle_redirects = false,
1243 .connection = conn,1262 .connection = conn,
1244 .header_strategy = .{ .static = buffer[0..] },1263 .header_strategy = .{ .static = &buffer },
1245 }) catch |err| {1264 }) catch |err| {
1246 std.log.debug("err {}", .{err});1265 std.log.debug("err {}", .{err});
1247 break :tunnel err;1266 break :tunnel err;
...@@ -1269,7 +1288,7 @@ pub fn connectTunnel(...@@ -1269,7 +1288,7 @@ pub fn connectTunnel(
1269 conn.closing = false;1288 conn.closing = false;
12701289
1271 return conn;1290 return conn;
1272 } catch {1291 }) catch {
1273 // something went wrong with the tunnel1292 // something went wrong with the tunnel
1274 proxy.supports_connect = maybe_valid;1293 proxy.supports_connect = maybe_valid;
1275 return error.TunnelNotSupported;1294 return error.TunnelNotSupported;
...@@ -1287,7 +1306,7 @@ pub const ConnectError = ConnectErrorPartial || RequestError;...@@ -1287,7 +1306,7 @@ pub const ConnectError = ConnectErrorPartial || RequestError;
1287/// This function is threadsafe.1306/// This function is threadsafe.
1288pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*Connection {1307pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*Connection {
1289 // pointer required so that `supports_connect` can be updated if a CONNECT fails1308 // 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) {
1291 .plain => if (client.http_proxy) |*proxy_info| proxy_info else null,1310 .plain => if (client.http_proxy) |*proxy_info| proxy_info else null,
1292 .tls => if (client.https_proxy) |*proxy_info| proxy_info else null,1311 .tls => if (client.https_proxy) |*proxy_info| proxy_info else null,
1293 };1312 };
...@@ -1298,12 +1317,12 @@ pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connectio...@@ -1298,12 +1317,12 @@ pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connectio
1298 return client.connectTcp(host, port, protocol);1317 return client.connectTcp(host, port, protocol);
1299 }1318 }
13001319
1301 _ = if (proxy.supports_connect) tunnel: {1320 if (proxy.supports_connect) tunnel: {
1302 return connectTunnel(client, proxy, host, port) catch |err| switch (err) {1321 return connectTunnel(client, proxy, host, port) catch |err| switch (err) {
1303 error.TunnelNotSupported => break :tunnel,1322 error.TunnelNotSupported => break :tunnel,
1304 else => |e| return e,1323 else => |e| return e,
1305 };1324 };
1306 };1325 }
13071326
1308 // fall back to using the proxy as a normal http proxy1327 // fall back to using the proxy as a normal http proxy
1309 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);1328 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);
test/standalone/http.zig-3
...@@ -634,9 +634,6 @@ pub fn main() !void {...@@ -634,9 +634,6 @@ pub fn main() !void {
634 req.transfer_encoding = .chunked;634 req.transfer_encoding = .chunked;
635635
636 try req.send(.{});636 try req.send(.{});
637 try req.wait();
638 try testing.expectEqual(http.Status.@"continue", req.response.status);
639
640 try req.writeAll("Hello, ");637 try req.writeAll("Hello, ");
641 try req.writeAll("World!\n");638 try req.writeAll("World!\n");
642 try req.finish();639 try req.finish();