| ... | ... | @@ -489,13 +489,21 @@ pub const Response = struct { |
| 489 | 489 | status: http.Status, |
| 490 | 490 | reason: []const u8, |
| 491 | 491 | |
| 492 | /// If present, the number of bytes in the response body. |
| 492 | 493 | content_length: ?u64 = null, |
| 494 | |
| 495 | /// If present, the transfer encoding of the response body, otherwise none. |
| 493 | 496 | transfer_encoding: http.TransferEncoding = .none, |
| 497 | |
| 498 | /// If present, the compression of the response body, otherwise identity (no compression). |
| 494 | 499 | transfer_compression: http.ContentEncoding = .identity, |
| 495 | 500 | |
| 501 | /// The headers received from the server. |
| 496 | 502 | headers: http.Headers, |
| 497 | 503 | parser: proto.HeadersParser, |
| 498 | 504 | compression: Compression = .none, |
| 505 | |
| 506 | /// Whether the response body should be skipped. Any data read from the response body will be discarded. |
| 499 | 507 | skip: bool = false, |
| 500 | 508 | }; |
| 501 | 509 | |
| ... | ... | @@ -511,6 +519,8 @@ pub const Request = struct { |
| 511 | 519 | method: http.Method, |
| 512 | 520 | version: http.Version = .@"HTTP/1.1", |
| 513 | 521 | headers: http.Headers, |
| 522 | |
| 523 | /// The transfer encoding of the request body. |
| 514 | 524 | transfer_encoding: RequestTransfer = .none, |
| 515 | 525 | |
| 516 | 526 | redirects_left: u32, |
| ... | ... | @@ -595,7 +605,7 @@ pub const Request = struct { |
| 595 | 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 | 609 | pub fn start(req: *Request, options: StartOptions) StartError!void { |
| 600 | 610 | if (!req.method.requestHasBody() and req.transfer_encoding != .none) return error.UnsupportedTransferEncoding; |
| 601 | 611 | |
| ... | ... | @@ -730,6 +740,8 @@ pub const Request = struct { |
| 730 | 740 | /// |
| 731 | 741 | /// If `handle_redirects` is true and the request has no payload, then this function will automatically follow |
| 732 | 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 | 745 | pub fn wait(req: *Request) WaitError!void { |
| 734 | 746 | while (true) { // handle redirects |
| 735 | 747 | while (true) { // read headers |
| ... | ... | @@ -865,7 +877,7 @@ pub const Request = struct { |
| 865 | 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 | 881 | pub fn read(req: *Request, buffer: []u8) ReadError!usize { |
| 870 | 882 | const out_index = switch (req.response.compression) { |
| 871 | 883 | .deflate => |*deflate| deflate.read(buffer) catch return error.DecompressionFailure, |
| ... | ... | @@ -896,7 +908,7 @@ pub const Request = struct { |
| 896 | 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 | 912 | pub fn readAll(req: *Request, buffer: []u8) !usize { |
| 901 | 913 | var index: usize = 0; |
| 902 | 914 | while (index < buffer.len) { |
| ... | ... | @@ -915,7 +927,8 @@ pub const Request = struct { |
| 915 | 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 | 932 | pub fn write(req: *Request, bytes: []const u8) WriteError!usize { |
| 920 | 933 | switch (req.transfer_encoding) { |
| 921 | 934 | .chunked => { |
| ... | ... | @@ -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 | 954 | pub fn writeAll(req: *Request, bytes: []const u8) WriteError!void { |
| 940 | 955 | var index: usize = 0; |
| 941 | 956 | while (index < bytes.len) { |
| ... | ... | @@ -946,6 +961,7 @@ pub const Request = struct { |
| 946 | 961 | pub const FinishError = WriteError || error{MessageNotCompleted}; |
| 947 | 962 | |
| 948 | 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 | 965 | pub fn finish(req: *Request) FinishError!void { |
| 950 | 966 | switch (req.transfer_encoding) { |
| 951 | 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 | 1150 | |
| 1135 | 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 | 1155 | pub fn connectUnix(client: *Client, path: []const u8) ConnectUnixError!*Connection { |
| 1138 | 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 | 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 | 1189 | pub fn connectTunnel( |
| 1170 | 1190 | client: *Client, |
| 1171 | 1191 | proxy: *ProxyInformation, |
| ... | ... | @@ -1245,6 +1265,11 @@ pub fn connectTunnel( |
| 1245 | 1265 | const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUrlScheme, ConnectionRefused }; |
| 1246 | 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 | 1273 | pub fn connect(client: *Client, host: []const u8, port: u16, protocol: Connection.Protocol) ConnectError!*Connection { |
| 1249 | 1274 | // pointer required so that `supports_connect` can be updated if a CONNECT fails |
| 1250 | 1275 | const potential_proxy: ?*ProxyInformation = switch (protocol) { |
| ... | ... | @@ -1318,7 +1343,7 @@ pub const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{ |
| 1318 | 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 | 1348 | /// `uri` must remain alive during the entire request. |
| 1324 | 1349 | /// `headers` is cloned and may be freed after this function returns. |
| ... | ... | @@ -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 | 1451 | pub fn fetch(client: *Client, allocator: Allocator, options: FetchOptions) !FetchResult { |
| 1424 | 1452 | const has_transfer_encoding = options.headers.contains("transfer-encoding"); |
| 1425 | 1453 | const has_content_length = options.headers.contains("content-length"); |