| ... | ... | @@ -54,7 +54,7 @@ pub const ConnectionPool = struct { |
| 54 | 54 | |
| 55 | 55 | /// Finds and acquires a connection from the connection pool matching the criteria. This function is threadsafe. |
| 56 | 56 | /// If no connection is found, null is returned. |
| 57 | | pub fn findConnection(pool: *ConnectionPool, criteria: Criteria) ?*Node { |
| 57 | pub fn findConnection(pool: *ConnectionPool, criteria: Criteria) ?*Connection { |
| 58 | 58 | pool.mutex.lock(); |
| 59 | 59 | defer pool.mutex.unlock(); |
| 60 | 60 | |
| ... | ... | @@ -65,7 +65,7 @@ pub const ConnectionPool = struct { |
| 65 | 65 | if (!std.ascii.eqlIgnoreCase(node.data.host, criteria.host)) continue; |
| 66 | 66 | |
| 67 | 67 | pool.acquireUnsafe(node); |
| 68 | | return node; |
| 68 | return &node.data; |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | 71 | return null; |
| ... | ... | @@ -89,10 +89,12 @@ pub const ConnectionPool = struct { |
| 89 | 89 | |
| 90 | 90 | /// Tries to release a connection back to the connection pool. This function is threadsafe. |
| 91 | 91 | /// If the connection is marked as closing, it will be closed instead. |
| 92 | | pub fn release(pool: *ConnectionPool, allocator: Allocator, node: *Node) void { |
| 92 | pub fn release(pool: *ConnectionPool, allocator: Allocator, connection: *Connection) void { |
| 93 | 93 | pool.mutex.lock(); |
| 94 | 94 | defer pool.mutex.unlock(); |
| 95 | 95 | |
| 96 | const node = @fieldParentPtr(Node, "data", connection); |
| 97 | |
| 96 | 98 | pool.used.remove(node); |
| 97 | 99 | |
| 98 | 100 | if (node.data.closing or pool.free_size == 0) { |
| ... | ... | @@ -151,6 +153,8 @@ pub const ConnectionPool = struct { |
| 151 | 153 | /// An interface to either a plain or TLS connection. |
| 152 | 154 | pub const Connection = struct { |
| 153 | 155 | pub const buffer_size = std.crypto.tls.max_ciphertext_record_len; |
| 156 | const BufferSize = std.math.IntFittingRange(0, buffer_size); |
| 157 | |
| 154 | 158 | pub const Protocol = enum { plain, tls }; |
| 155 | 159 | |
| 156 | 160 | stream: net.Stream, |
| ... | ... | @@ -164,14 +168,16 @@ pub const Connection = struct { |
| 164 | 168 | proxied: bool = false, |
| 165 | 169 | closing: bool = false, |
| 166 | 170 | |
| 167 | | read_start: u16 = 0, |
| 168 | | read_end: u16 = 0, |
| 171 | read_start: BufferSize = 0, |
| 172 | read_end: BufferSize = 0, |
| 173 | write_end: BufferSize = 0, |
| 169 | 174 | read_buf: [buffer_size]u8 = undefined, |
| 175 | write_buf: [buffer_size]u8 = undefined, |
| 170 | 176 | |
| 171 | | pub fn rawReadAtLeast(conn: *Connection, buffer: []u8, len: usize) ReadError!usize { |
| 177 | pub fn readvDirect(conn: *Connection, buffers: []std.os.iovec) ReadError!usize { |
| 172 | 178 | return switch (conn.protocol) { |
| 173 | | .plain => conn.stream.readAtLeast(buffer, len), |
| 174 | | .tls => conn.tls_client.readAtLeast(conn.stream, buffer, len), |
| 179 | .plain => conn.stream.readv(buffers), |
| 180 | .tls => conn.tls_client.readv(conn.stream, buffers), |
| 175 | 181 | } catch |err| { |
| 176 | 182 | // TODO: https://github.com/ziglang/zig/issues/2473 |
| 177 | 183 | if (mem.startsWith(u8, @errorName(err), "TlsAlert")) return error.TlsAlert; |
| ... | ... | @@ -188,58 +194,52 @@ pub const Connection = struct { |
| 188 | 194 | pub fn fill(conn: *Connection) ReadError!void { |
| 189 | 195 | if (conn.read_end != conn.read_start) return; |
| 190 | 196 | |
| 191 | | const nread = try conn.rawReadAtLeast(conn.read_buf[0..], 1); |
| 197 | var iovecs = [1]std.os.iovec{ |
| 198 | .{ .iov_base = &conn.read_buf, .iov_len = conn.read_buf.len }, |
| 199 | }; |
| 200 | const nread = try conn.readvDirect(&iovecs); |
| 192 | 201 | if (nread == 0) return error.EndOfStream; |
| 193 | 202 | conn.read_start = 0; |
| 194 | | conn.read_end = @as(u16, @intCast(nread)); |
| 203 | conn.read_end = @intCast(nread); |
| 195 | 204 | } |
| 196 | 205 | |
| 197 | 206 | pub fn peek(conn: *Connection) []const u8 { |
| 198 | 207 | return conn.read_buf[conn.read_start..conn.read_end]; |
| 199 | 208 | } |
| 200 | 209 | |
| 201 | | pub fn drop(conn: *Connection, num: u16) void { |
| 210 | pub fn drop(conn: *Connection, num: BufferSize) void { |
| 202 | 211 | conn.read_start += num; |
| 203 | 212 | } |
| 204 | 213 | |
| 205 | | pub fn readAtLeast(conn: *Connection, buffer: []u8, len: usize) ReadError!usize { |
| 206 | | assert(len <= buffer.len); |
| 207 | | |
| 208 | | var out_index: u16 = 0; |
| 209 | | while (out_index < len) { |
| 210 | | const available_read = conn.read_end - conn.read_start; |
| 211 | | const available_buffer = buffer.len - out_index; |
| 212 | | |
| 213 | | if (available_read > available_buffer) { // partially read buffered data |
| 214 | | @memcpy(buffer[out_index..], conn.read_buf[conn.read_start..conn.read_end][0..available_buffer]); |
| 215 | | out_index += @as(u16, @intCast(available_buffer)); |
| 216 | | conn.read_start += @as(u16, @intCast(available_buffer)); |
| 214 | pub fn read(conn: *Connection, buffer: []u8) ReadError!usize { |
| 215 | const available_read = conn.read_end - conn.read_start; |
| 216 | const available_buffer = buffer.len; |
| 217 | 217 | |
| 218 | | break; |
| 219 | | } else if (available_read > 0) { // fully read buffered data |
| 220 | | @memcpy(buffer[out_index..][0..available_read], conn.read_buf[conn.read_start..conn.read_end]); |
| 221 | | out_index += available_read; |
| 222 | | conn.read_start += available_read; |
| 218 | if (available_read > available_buffer) { // partially read buffered data |
| 219 | @memcpy(buffer[0..available_buffer], conn.read_buf[conn.read_start..conn.read_end][0..available_buffer]); |
| 220 | conn.read_start += @intCast(available_buffer); |
| 223 | 221 | |
| 224 | | if (out_index >= len) break; |
| 225 | | } |
| 222 | return available_buffer; |
| 223 | } else if (available_read > 0) { // fully read buffered data |
| 224 | @memcpy(buffer[0..available_read], conn.read_buf[conn.read_start..conn.read_end]); |
| 225 | conn.read_start += available_read; |
| 226 | 226 | |
| 227 | | const leftover_buffer = available_buffer - available_read; |
| 228 | | const leftover_len = len - out_index; |
| 227 | return available_read; |
| 228 | } |
| 229 | 229 | |
| 230 | | if (leftover_buffer > conn.read_buf.len) { |
| 231 | | // skip the buffer if the output is large enough |
| 232 | | return conn.rawReadAtLeast(buffer[out_index..], leftover_len); |
| 233 | | } |
| 230 | var iovecs = [2]std.os.iovec{ |
| 231 | .{ .iov_base = buffer.ptr, .iov_len = buffer.len }, |
| 232 | .{ .iov_base = &conn.read_buf, .iov_len = conn.read_buf.len }, |
| 233 | }; |
| 234 | const nread = try conn.readvDirect(&iovecs); |
| 234 | 235 | |
| 235 | | try conn.fill(); |
| 236 | if (nread > buffer.len) { |
| 237 | conn.read_start = 0; |
| 238 | conn.read_end = @intCast(nread - buffer.len); |
| 239 | return buffer.len; |
| 236 | 240 | } |
| 237 | 241 | |
| 238 | | return out_index; |
| 239 | | } |
| 240 | | |
| 241 | | pub fn read(conn: *Connection, buffer: []u8) ReadError!usize { |
| 242 | | return conn.readAtLeast(buffer, 1); |
| 242 | return nread; |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | 245 | pub const ReadError = error{ |
| ... | ... | @@ -257,7 +257,7 @@ pub const Connection = struct { |
| 257 | 257 | return Reader{ .context = conn }; |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | | pub fn writeAll(conn: *Connection, buffer: []const u8) !void { |
| 260 | pub fn writeAllDirect(conn: *Connection, buffer: []const u8) WriteError!void { |
| 261 | 261 | return switch (conn.protocol) { |
| 262 | 262 | .plain => conn.stream.writeAll(buffer), |
| 263 | 263 | .tls => conn.tls_client.writeAll(conn.stream, buffer), |
| ... | ... | @@ -267,14 +267,27 @@ pub const Connection = struct { |
| 267 | 267 | }; |
| 268 | 268 | } |
| 269 | 269 | |
| 270 | | pub fn write(conn: *Connection, buffer: []const u8) !usize { |
| 271 | | return switch (conn.protocol) { |
| 272 | | .plain => conn.stream.write(buffer), |
| 273 | | .tls => conn.tls_client.write(conn.stream, buffer), |
| 274 | | } catch |err| switch (err) { |
| 275 | | error.BrokenPipe, error.ConnectionResetByPeer => return error.ConnectionResetByPeer, |
| 276 | | else => return error.UnexpectedWriteFailure, |
| 277 | | }; |
| 270 | pub fn write(conn: *Connection, buffer: []const u8) WriteError!usize { |
| 271 | if (conn.write_end + buffer.len > conn.write_buf.len) { |
| 272 | try conn.flush(); |
| 273 | |
| 274 | if (buffer.len > conn.write_buf.len) { |
| 275 | try conn.writeAllDirect(buffer); |
| 276 | return buffer.len; |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | @memcpy(conn.write_buf[conn.write_end..][0..buffer.len], buffer); |
| 281 | conn.write_end += @intCast(buffer.len); |
| 282 | |
| 283 | return buffer.len; |
| 284 | } |
| 285 | |
| 286 | pub fn flush(conn: *Connection) WriteError!void { |
| 287 | if (conn.write_end == 0) return; |
| 288 | |
| 289 | try conn.writeAllDirect(conn.write_buf[0..conn.write_end]); |
| 290 | conn.write_end = 0; |
| 278 | 291 | } |
| 279 | 292 | |
| 280 | 293 | pub const WriteError = error{ |
| ... | ... | @@ -455,7 +468,7 @@ pub const Request = struct { |
| 455 | 468 | uri: Uri, |
| 456 | 469 | client: *Client, |
| 457 | 470 | /// is null when this connection is released |
| 458 | | connection: ?*ConnectionPool.Node, |
| 471 | connection: ?*Connection, |
| 459 | 472 | |
| 460 | 473 | method: http.Method, |
| 461 | 474 | version: http.Version = .@"HTTP/1.1", |
| ... | ... | @@ -489,7 +502,7 @@ pub const Request = struct { |
| 489 | 502 | if (req.connection) |connection| { |
| 490 | 503 | if (!req.response.parser.done) { |
| 491 | 504 | // If the response wasn't fully read, then we need to close the connection. |
| 492 | | connection.data.closing = true; |
| 505 | connection.closing = true; |
| 493 | 506 | } |
| 494 | 507 | req.client.connection_pool.release(req.client.allocator, connection); |
| 495 | 508 | } |
| ... | ... | @@ -548,8 +561,7 @@ pub const Request = struct { |
| 548 | 561 | pub fn start(req: *Request, options: StartOptions) StartError!void { |
| 549 | 562 | if (!req.method.requestHasBody() and req.transfer_encoding != .none) return error.UnsupportedTransferEncoding; |
| 550 | 563 | |
| 551 | | var buffered = std.io.bufferedWriter(req.connection.?.data.writer()); |
| 552 | | const w = buffered.writer(); |
| 564 | const w = req.connection.?.writer(); |
| 553 | 565 | |
| 554 | 566 | try req.method.write(w); |
| 555 | 567 | try w.writeByte(' '); |
| ... | ... | @@ -558,9 +570,9 @@ pub const Request = struct { |
| 558 | 570 | try req.uri.writeToStream(.{ .authority = true }, w); |
| 559 | 571 | } else { |
| 560 | 572 | try req.uri.writeToStream(.{ |
| 561 | | .scheme = req.connection.?.data.proxied, |
| 562 | | .authentication = req.connection.?.data.proxied, |
| 563 | | .authority = req.connection.?.data.proxied, |
| 573 | .scheme = req.connection.?.proxied, |
| 574 | .authentication = req.connection.?.proxied, |
| 575 | .authority = req.connection.?.proxied, |
| 564 | 576 | .path = true, |
| 565 | 577 | .query = true, |
| 566 | 578 | .raw = options.raw_uri, |
| ... | ... | @@ -629,8 +641,8 @@ pub const Request = struct { |
| 629 | 641 | try w.writeAll("\r\n"); |
| 630 | 642 | } |
| 631 | 643 | |
| 632 | | if (req.connection.?.data.proxied) { |
| 633 | | const proxy_headers: ?http.Headers = switch (req.connection.?.data.protocol) { |
| 644 | if (req.connection.?.proxied) { |
| 645 | const proxy_headers: ?http.Headers = switch (req.connection.?.protocol) { |
| 634 | 646 | .plain => if (req.client.http_proxy) |proxy| proxy.headers else null, |
| 635 | 647 | .tls => if (req.client.https_proxy) |proxy| proxy.headers else null, |
| 636 | 648 | }; |
| ... | ... | @@ -649,7 +661,7 @@ pub const Request = struct { |
| 649 | 661 | |
| 650 | 662 | try w.writeAll("\r\n"); |
| 651 | 663 | |
| 652 | | try buffered.flush(); |
| 664 | try req.connection.?.flush(); |
| 653 | 665 | } |
| 654 | 666 | |
| 655 | 667 | const TransferReadError = Connection.ReadError || proto.HeadersParser.ReadError; |
| ... | ... | @@ -665,7 +677,7 @@ pub const Request = struct { |
| 665 | 677 | |
| 666 | 678 | var index: usize = 0; |
| 667 | 679 | while (index == 0) { |
| 668 | | const amt = try req.response.parser.read(&req.connection.?.data, buf[index..], req.response.skip); |
| 680 | const amt = try req.response.parser.read(req.connection.?, buf[index..], req.response.skip); |
| 669 | 681 | if (amt == 0 and req.response.parser.done) break; |
| 670 | 682 | index += amt; |
| 671 | 683 | } |
| ... | ... | @@ -683,10 +695,10 @@ pub const Request = struct { |
| 683 | 695 | pub fn wait(req: *Request) WaitError!void { |
| 684 | 696 | while (true) { // handle redirects |
| 685 | 697 | while (true) { // read headers |
| 686 | | try req.connection.?.data.fill(); |
| 698 | try req.connection.?.fill(); |
| 687 | 699 | |
| 688 | | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.?.data.peek()); |
| 689 | | req.connection.?.data.drop(@as(u16, @intCast(nchecked))); |
| 700 | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.?.peek()); |
| 701 | req.connection.?.drop(@intCast(nchecked)); |
| 690 | 702 | |
| 691 | 703 | if (req.response.parser.state.isContent()) break; |
| 692 | 704 | } |
| ... | ... | @@ -701,7 +713,7 @@ pub const Request = struct { |
| 701 | 713 | |
| 702 | 714 | // we're switching protocols, so this connection is no longer doing http |
| 703 | 715 | if (req.response.status == .switching_protocols or (req.method == .CONNECT and req.response.status == .ok)) { |
| 704 | | req.connection.?.data.closing = false; |
| 716 | req.connection.?.closing = false; |
| 705 | 717 | req.response.parser.done = true; |
| 706 | 718 | } |
| 707 | 719 | |
| ... | ... | @@ -712,9 +724,9 @@ pub const Request = struct { |
| 712 | 724 | const res_connection = req.response.headers.getFirstValue("connection"); |
| 713 | 725 | const res_keepalive = res_connection != null and !std.ascii.eqlIgnoreCase("close", res_connection.?); |
| 714 | 726 | if (res_keepalive and (req_keepalive or req_connection == null)) { |
| 715 | | req.connection.?.data.closing = false; |
| 727 | req.connection.?.closing = false; |
| 716 | 728 | } else { |
| 717 | | req.connection.?.data.closing = true; |
| 729 | req.connection.?.closing = true; |
| 718 | 730 | } |
| 719 | 731 | |
| 720 | 732 | if (req.response.transfer_encoding) |te| { |
| ... | ... | @@ -827,10 +839,10 @@ pub const Request = struct { |
| 827 | 839 | const has_trail = !req.response.parser.state.isContent(); |
| 828 | 840 | |
| 829 | 841 | while (!req.response.parser.state.isContent()) { // read trailing headers |
| 830 | | try req.connection.?.data.fill(); |
| 842 | try req.connection.?.fill(); |
| 831 | 843 | |
| 832 | | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.?.data.peek()); |
| 833 | | req.connection.?.data.drop(@as(u16, @intCast(nchecked))); |
| 844 | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.?.peek()); |
| 845 | req.connection.?.drop(@intCast(nchecked)); |
| 834 | 846 | } |
| 835 | 847 | |
| 836 | 848 | if (has_trail) { |
| ... | ... | @@ -868,16 +880,16 @@ pub const Request = struct { |
| 868 | 880 | pub fn write(req: *Request, bytes: []const u8) WriteError!usize { |
| 869 | 881 | switch (req.transfer_encoding) { |
| 870 | 882 | .chunked => { |
| 871 | | try req.connection.?.data.writer().print("{x}\r\n", .{bytes.len}); |
| 872 | | try req.connection.?.data.writeAll(bytes); |
| 873 | | try req.connection.?.data.writeAll("\r\n"); |
| 883 | try req.connection.?.writer().print("{x}\r\n", .{bytes.len}); |
| 884 | try req.connection.?.writer().writeAll(bytes); |
| 885 | try req.connection.?.writer().writeAll("\r\n"); |
| 874 | 886 | |
| 875 | 887 | return bytes.len; |
| 876 | 888 | }, |
| 877 | 889 | .content_length => |*len| { |
| 878 | 890 | if (len.* < bytes.len) return error.MessageTooLong; |
| 879 | 891 | |
| 880 | | const amt = try req.connection.?.data.write(bytes); |
| 892 | const amt = try req.connection.?.write(bytes); |
| 881 | 893 | len.* -= amt; |
| 882 | 894 | return amt; |
| 883 | 895 | }, |
| ... | ... | @@ -897,10 +909,12 @@ pub const Request = struct { |
| 897 | 909 | /// Finish the body of a request. This notifies the server that you have no more data to send. |
| 898 | 910 | pub fn finish(req: *Request) FinishError!void { |
| 899 | 911 | switch (req.transfer_encoding) { |
| 900 | | .chunked => try req.connection.?.data.writeAll("0\r\n\r\n"), |
| 912 | .chunked => try req.connection.?.writer().writeAll("0\r\n\r\n"), |
| 901 | 913 | .content_length => |len| if (len != 0) return error.MessageNotCompleted, |
| 902 | 914 | .none => {}, |
| 903 | 915 | } |
| 916 | |
| 917 | try req.connection.?.flush(); |
| 904 | 918 | } |
| 905 | 919 | }; |
| 906 | 920 | |
| ... | ... | @@ -1024,7 +1038,7 @@ pub const ConnectTcpError = Allocator.Error || error{ ConnectionRefused, Network |
| 1024 | 1038 | |
| 1025 | 1039 | /// Connect to `host:port` using the specified protocol. This will reuse a connection if one is already open. |
| 1026 | 1040 | /// This function is threadsafe. |
| 1027 | | pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectTcpError!*ConnectionPool.Node { |
| 1041 | pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectTcpError!*Connection { |
| 1028 | 1042 | if (client.connection_pool.findConnection(.{ |
| 1029 | 1043 | .host = host, |
| 1030 | 1044 | .port = port, |
| ... | ... | @@ -1074,12 +1088,12 @@ pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connec |
| 1074 | 1088 | |
| 1075 | 1089 | client.connection_pool.addUsed(conn); |
| 1076 | 1090 | |
| 1077 | | return conn; |
| 1091 | return &conn.data; |
| 1078 | 1092 | } |
| 1079 | 1093 | |
| 1080 | 1094 | pub const ConnectUnixError = Allocator.Error || std.os.SocketError || error{ NameTooLong, Unsupported } || std.os.ConnectError; |
| 1081 | 1095 | |
| 1082 | | pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*ConnectionPool.Node { |
| 1096 | pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connection { |
| 1083 | 1097 | if (!net.has_unix_sockets) return error.Unsupported; |
| 1084 | 1098 | |
| 1085 | 1099 | if (client.connection_pool.findConnection(.{ |
| ... | ... | @@ -1108,7 +1122,7 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti |
| 1108 | 1122 | |
| 1109 | 1123 | client.connection_pool.addUsed(conn); |
| 1110 | 1124 | |
| 1111 | | return conn; |
| 1125 | return &conn.data; |
| 1112 | 1126 | } |
| 1113 | 1127 | |
| 1114 | 1128 | pub fn connectTunnel( |
| ... | ... | @@ -1116,7 +1130,7 @@ pub fn connectTunnel( |
| 1116 | 1130 | proxy: *ProxyInformation, |
| 1117 | 1131 | tunnel_host: []const u8, |
| 1118 | 1132 | tunnel_port: u16, |
| 1119 | | ) !*ConnectionPool.Node { |
| 1133 | ) !*Connection { |
| 1120 | 1134 | if (!proxy.supports_connect) return error.TunnelNotSupported; |
| 1121 | 1135 | |
| 1122 | 1136 | if (client.connection_pool.findConnection(.{ |
| ... | ... | @@ -1130,7 +1144,7 @@ pub fn connectTunnel( |
| 1130 | 1144 | _ = tunnel: { |
| 1131 | 1145 | const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol); |
| 1132 | 1146 | errdefer { |
| 1133 | | conn.data.closing = true; |
| 1147 | conn.closing = true; |
| 1134 | 1148 | client.connection_pool.release(client.allocator, conn); |
| 1135 | 1149 | } |
| 1136 | 1150 | |
| ... | ... | @@ -1171,12 +1185,12 @@ pub fn connectTunnel( |
| 1171 | 1185 | // this connection is now a tunnel, so we can't use it for anything else, it will only be released when the client is de-initialized. |
| 1172 | 1186 | req.connection = null; |
| 1173 | 1187 | |
| 1174 | | client.allocator.free(conn.data.host); |
| 1175 | | conn.data.host = try client.allocator.dupe(u8, tunnel_host); |
| 1176 | | errdefer client.allocator.free(conn.data.host); |
| 1188 | client.allocator.free(conn.host); |
| 1189 | conn.host = try client.allocator.dupe(u8, tunnel_host); |
| 1190 | errdefer client.allocator.free(conn.host); |
| 1177 | 1191 | |
| 1178 | | conn.data.port = tunnel_port; |
| 1179 | | conn.data.closing = false; |
| 1192 | conn.port = tunnel_port; |
| 1193 | conn.closing = false; |
| 1180 | 1194 | |
| 1181 | 1195 | return conn; |
| 1182 | 1196 | } catch { |
| ... | ... | @@ -1190,7 +1204,7 @@ pub fn connectTunnel( |
| 1190 | 1204 | const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUrlScheme, ConnectionRefused }; |
| 1191 | 1205 | pub const ConnectError = ConnectErrorPartial || RequestError; |
| 1192 | 1206 | |
| 1193 | | pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*ConnectionPool.Node { |
| 1207 | pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*Connection { |
| 1194 | 1208 | // pointer required so that `supports_connect` can be updated if a CONNECT fails |
| 1195 | 1209 | const potential_proxy: ?*ProxyInformation = switch (protocol) { |
| 1196 | 1210 | .plain => if (client.http_proxy) |*proxy_info| proxy_info else null, |
| ... | ... | @@ -1213,11 +1227,11 @@ pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connectio |
| 1213 | 1227 | // fall back to using the proxy as a normal http proxy |
| 1214 | 1228 | const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol); |
| 1215 | 1229 | errdefer { |
| 1216 | | conn.data.closing = true; |
| 1230 | conn.closing = true; |
| 1217 | 1231 | client.connection_pool.release(conn); |
| 1218 | 1232 | } |
| 1219 | 1233 | |
| 1220 | | conn.data.proxied = true; |
| 1234 | conn.proxied = true; |
| 1221 | 1235 | return conn; |
| 1222 | 1236 | } |
| 1223 | 1237 | |
| ... | ... | @@ -1240,7 +1254,7 @@ pub const RequestOptions = struct { |
| 1240 | 1254 | header_strategy: StorageStrategy = .{ .dynamic = 16 * 1024 }, |
| 1241 | 1255 | |
| 1242 | 1256 | /// Must be an already acquired connection. |
| 1243 | | connection: ?*ConnectionPool.Node = null, |
| 1257 | connection: ?*Connection = null, |
| 1244 | 1258 | |
| 1245 | 1259 | pub const StorageStrategy = union(enum) { |
| 1246 | 1260 | /// In this case, the client's Allocator will be used to store the |