| ... | @@ -489,13 +489,21 @@ pub const Response = struct { | ... | @@ -489,13 +489,21 @@ pub const Response = struct { |
| 489 | status: http.Status, | 489 | status: http.Status, |
| 490 | reason: []const u8, | 490 | reason: []const u8, |
| 491 | | 491 | |
| | 492 | /// If present, the number of bytes in the response body. |
| 492 | content_length: ?u64 = null, | 493 | content_length: ?u64 = null, |
| | 494 | |
| | 495 | /// If present, the transfer encoding of the response body, otherwise none. |
| 493 | transfer_encoding: http.TransferEncoding = .none, | 496 | transfer_encoding: http.TransferEncoding = .none, |
| | 497 | |
| | 498 | /// If present, the compression of the response body, otherwise identity (no compression). |
| 494 | transfer_compression: http.ContentEncoding = .identity, | 499 | transfer_compression: http.ContentEncoding = .identity, |
| 495 | | 500 | |
| | 501 | /// The headers received from the server. |
| 496 | headers: http.Headers, | 502 | headers: http.Headers, |
| 497 | parser: proto.HeadersParser, | 503 | parser: proto.HeadersParser, |
| 498 | compression: Compression = .none, | 504 | compression: Compression = .none, |
| | 505 | |
| | 506 | /// Whether the response body should be skipped. Any data read from the response body will be discarded. |
| 499 | skip: bool = false, | 507 | skip: bool = false, |
| 500 | }; | 508 | }; |
| 501 | | 509 | |
| ... | @@ -511,6 +519,8 @@ pub const Request = struct { | ... | @@ -511,6 +519,8 @@ pub const Request = struct { |
| 511 | method: http.Method, | 519 | method: http.Method, |
| 512 | version: http.Version = .@"HTTP/1.1", | 520 | version: http.Version = .@"HTTP/1.1", |
| 513 | headers: http.Headers, | 521 | headers: http.Headers, |
| | 522 | |
| | 523 | /// The transfer encoding of the request body. |
| 514 | transfer_encoding: RequestTransfer = .none, | 524 | transfer_encoding: RequestTransfer = .none, |
| 515 | | 525 | |
| 516 | redirects_left: u32, | 526 | redirects_left: u32, |
| ... | @@ -595,7 +605,7 @@ pub const Request = struct { | ... | @@ -595,7 +605,7 @@ pub const Request = struct { |
| 595 | raw_uri: bool = false, | 605 | raw_uri: bool = false, |
| 596 | }; | 606 | }; |
| 597 | | 607 | |
| 598 | /// Send the request to the server. | 608 | /// Send the HTTP request to the server. |
| 599 | pub fn start(req: *Request, options: StartOptions) StartError!void { | 609 | pub fn start(req: *Request, options: StartOptions) StartError!void { |
| 600 | if (!req.method.requestHasBody() and req.transfer_encoding != .none) return error.UnsupportedTransferEncoding; | 610 | if (!req.method.requestHasBody() and req.transfer_encoding != .none) return error.UnsupportedTransferEncoding; |
| 601 | | 611 | |
| ... | @@ -730,6 +740,8 @@ pub const Request = struct { | ... | @@ -730,6 +740,8 @@ pub const Request = struct { |
| 730 | /// | 740 | /// |
| 731 | /// If `handle_redirects` is true and the request has no payload, then this function will automatically follow | 741 | /// If `handle_redirects` is true and the request has no payload, then this function will automatically follow |
| 732 | /// redirects. If a request payload is present, then this function will error with error.RedirectRequiresResend. | 742 | /// redirects. If a request payload is present, then this function will error with error.RedirectRequiresResend. |
| | 743 | /// |
| | 744 | /// Must be called after `start` and, if any data was written to the request body, then also after `finish`. |
| 733 | pub fn wait(req: *Request) WaitError!void { | 745 | pub fn wait(req: *Request) WaitError!void { |
| 734 | while (true) { // handle redirects | 746 | while (true) { // handle redirects |
| 735 | while (true) { // read headers | 747 | while (true) { // read headers |
| ... | @@ -865,7 +877,7 @@ pub const Request = struct { | ... | @@ -865,7 +877,7 @@ pub const Request = struct { |
| 865 | return .{ .context = req }; | 877 | return .{ .context = req }; |
| 866 | } | 878 | } |
| 867 | | 879 | |
| 868 | /// Reads data from the response body. Must be called after `do`. | 880 | /// Reads data from the response body. Must be called after `wait`. |
| 869 | pub fn read(req: *Request, buffer: []u8) ReadError!usize { | 881 | pub fn read(req: *Request, buffer: []u8) ReadError!usize { |
| 870 | const out_index = switch (req.response.compression) { | 882 | const out_index = switch (req.response.compression) { |
| 871 | .deflate => |*deflate| deflate.read(buffer) catch return error.DecompressionFailure, | 883 | .deflate => |*deflate| deflate.read(buffer) catch return error.DecompressionFailure, |
| ... | @@ -896,7 +908,7 @@ pub const Request = struct { | ... | @@ -896,7 +908,7 @@ pub const Request = struct { |
| 896 | return out_index; | 908 | return out_index; |
| 897 | } | 909 | } |
| 898 | | 910 | |
| 899 | /// Reads data from the response body. Must be called after `do`. | 911 | /// Reads data from the response body. Must be called after `wait`. |
| 900 | pub fn readAll(req: *Request, buffer: []u8) !usize { | 912 | pub fn readAll(req: *Request, buffer: []u8) !usize { |
| 901 | var index: usize = 0; | 913 | var index: usize = 0; |
| 902 | while (index < buffer.len) { | 914 | while (index < buffer.len) { |
| ... | @@ -915,7 +927,8 @@ pub const Request = struct { | ... | @@ -915,7 +927,8 @@ pub const Request = struct { |
| 915 | return .{ .context = req }; | 927 | return .{ .context = req }; |
| 916 | } | 928 | } |
| 917 | | 929 | |
| 918 | /// Write `bytes` to the server. The `transfer_encoding` request header determines how data will be sent. | 930 | /// Write `bytes` to the server. The `transfer_encoding` field determines how data will be sent. |
| | 931 | /// Must be called after `start` and before `finish`. |
| 919 | pub fn write(req: *Request, bytes: []const u8) WriteError!usize { | 932 | pub fn write(req: *Request, bytes: []const u8) WriteError!usize { |
| 920 | switch (req.transfer_encoding) { | 933 | switch (req.transfer_encoding) { |
| 921 | .chunked => { | 934 | .chunked => { |
| ... | @@ -936,6 +949,8 @@ pub const Request = struct { | ... | @@ -936,6 +949,8 @@ pub const Request = struct { |
| 936 | } | 949 | } |
| 937 | } | 950 | } |
| 938 | | 951 | |
| | 952 | /// Write `bytes` to the server. The `transfer_encoding` field determines how data will be sent. |
| | 953 | /// Must be called after `start` and before `finish`. |
| 939 | pub fn writeAll(req: *Request, bytes: []const u8) WriteError!void { | 954 | pub fn writeAll(req: *Request, bytes: []const u8) WriteError!void { |
| 940 | var index: usize = 0; | 955 | var index: usize = 0; |
| 941 | while (index < bytes.len) { | 956 | while (index < bytes.len) { |
| ... | @@ -946,6 +961,7 @@ pub const Request = struct { | ... | @@ -946,6 +961,7 @@ pub const Request = struct { |
| 946 | pub const FinishError = WriteError || error{MessageNotCompleted}; | 961 | pub const FinishError = WriteError || error{MessageNotCompleted}; |
| 947 | | 962 | |
| 948 | /// Finish the body of a request. This notifies the server that you have no more data to send. | 963 | /// Finish the body of a request. This notifies the server that you have no more data to send. |
| | 964 | /// Must be called after `start`. |
| 949 | pub fn finish(req: *Request) FinishError!void { | 965 | pub fn finish(req: *Request) FinishError!void { |
| 950 | switch (req.transfer_encoding) { | 966 | switch (req.transfer_encoding) { |
| 951 | .chunked => try req.connection.?.writer().writeAll("0\r\n\r\n"), | 967 | .chunked => try req.connection.?.writer().writeAll("0\r\n\r\n"), |
| ... | @@ -1134,6 +1150,8 @@ pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connec | ... | @@ -1134,6 +1150,8 @@ pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connec |
| 1134 | | 1150 | |
| 1135 | pub const ConnectUnixError = Allocator.Error || std.os.SocketError || error{ NameTooLong, Unsupported } || std.os.ConnectError; | 1151 | pub const ConnectUnixError = Allocator.Error || std.os.SocketError || error{ NameTooLong, Unsupported } || std.os.ConnectError; |
| 1136 | | 1152 | |
| | 1153 | /// Connect to `path` as a unix domain socket. This will reuse a connection if one is already open. |
| | 1154 | /// This function is threadsafe. |
| 1137 | pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connection { | 1155 | pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connection { |
| 1138 | if (!net.has_unix_sockets) return error.Unsupported; | 1156 | if (!net.has_unix_sockets) return error.Unsupported; |
| 1139 | | 1157 | |
| ... | @@ -1166,6 +1184,8 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti | ... | @@ -1166,6 +1184,8 @@ pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connecti |
| 1166 | return &conn.data; | 1184 | return &conn.data; |
| 1167 | } | 1185 | } |
| 1168 | | 1186 | |
| | 1187 | /// Connect to `tunnel_host:tunnel_port` using the specified proxy with HTTP CONNECT. This will reuse a connection if one is already open. |
| | 1188 | /// This function is threadsafe. |
| 1169 | pub fn connectTunnel( | 1189 | pub fn connectTunnel( |
| 1170 | client: *Client, | 1190 | client: *Client, |
| 1171 | proxy: *ProxyInformation, | 1191 | proxy: *ProxyInformation, |
| ... | @@ -1245,6 +1265,11 @@ pub fn connectTunnel( | ... | @@ -1245,6 +1265,11 @@ pub fn connectTunnel( |
| 1245 | const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUrlScheme, ConnectionRefused }; | 1265 | const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUrlScheme, ConnectionRefused }; |
| 1246 | pub const ConnectError = ConnectErrorPartial || RequestError; | 1266 | pub const ConnectError = ConnectErrorPartial || RequestError; |
| 1247 | | 1267 | |
| | 1268 | /// Connect to `host:port` using the specified protocol. This will reuse a connection if one is already open. |
| | 1269 | /// |
| | 1270 | /// If a proxy is configured for the client, then the proxy will be used to connect to the host. |
| | 1271 | /// |
| | 1272 | /// This function is threadsafe. |
| 1248 | pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*Connection { | 1273 | pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*Connection { |
| 1249 | // pointer required so that `supports_connect` can be updated if a CONNECT fails | 1274 | // pointer required so that `supports_connect` can be updated if a CONNECT fails |
| 1250 | const potential_proxy: ?*ProxyInformation = switch (protocol) { | 1275 | const potential_proxy: ?*ProxyInformation = switch (protocol) { |
| ... | @@ -1318,7 +1343,7 @@ pub const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{ | ... | @@ -1318,7 +1343,7 @@ pub const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{ |
| 1318 | .{ "wss", .tls }, | 1343 | .{ "wss", .tls }, |
| 1319 | }); | 1344 | }); |
| 1320 | | 1345 | |
| 1321 | /// Form and send a http request to a server. | 1346 | /// Open a connection to the host specified by `uri` and prepare to send a HTTP request. |
| 1322 | /// | 1347 | /// |
| 1323 | /// `uri` must remain alive during the entire request. | 1348 | /// `uri` must remain alive during the entire request. |
| 1324 | /// `headers` is cloned and may be freed after this function returns. | 1349 | /// `headers` is cloned and may be freed after this function returns. |
| ... | @@ -1420,6 +1445,9 @@ pub const FetchResult = struct { | ... | @@ -1420,6 +1445,9 @@ pub const FetchResult = struct { |
| 1420 | } | 1445 | } |
| 1421 | }; | 1446 | }; |
| 1422 | | 1447 | |
| | 1448 | /// Perform a one-shot HTTP request with the provided options. |
| | 1449 | /// |
| | 1450 | /// This function is threadsafe. |
| 1423 | pub fn fetch(client: *Client, allocator: Allocator, options: FetchOptions) !FetchResult { | 1451 | pub fn fetch(client: *Client, allocator: Allocator, options: FetchOptions) !FetchResult { |
| 1424 | const has_transfer_encoding = options.headers.contains("transfer-encoding"); | 1452 | const has_transfer_encoding = options.headers.contains("transfer-encoding"); |
| 1425 | const has_content_length = options.headers.contains("content-length"); | 1453 | const has_content_length = options.headers.contains("content-length"); |