| author | |
| committer | |
| log | 50e2a5f673d880515caf3497bfb6eb0114149de1 |
| tree | 81e3aa0e6078f86f4669c3f2189dd54431938da2 |
| parent | 06d0c58305a04d28da9a2caf510fc906e38a54ef |
This is a state machine that already has a `state` field. No need to
additionally store "done" - it just makes things unnecessarily
complicated and buggy.4 files changed, 152 insertions(+), 85 deletions(-)
lib/std/http/Client.zig+12-10| ... | @@ -610,7 +610,7 @@ pub const Request = struct { | ... | @@ -610,7 +610,7 @@ pub const Request = struct { |
| 610 | req.response.headers.deinit(); | 610 | req.response.headers.deinit(); |
| 611 | 611 | ||
| 612 | if (req.connection) |connection| { | 612 | if (req.connection) |connection| { |
| 613 | if (!req.response.parser.done) { | 613 | if (req.response.parser.state != .complete) { |
| 614 | // If the response wasn't fully read, then we need to close the connection. | 614 | // If the response wasn't fully read, then we need to close the connection. |
| 615 | connection.closing = true; | 615 | connection.closing = true; |
| 616 | } | 616 | } |
| ... | @@ -624,7 +624,7 @@ pub const Request = struct { | ... | @@ -624,7 +624,7 @@ pub const Request = struct { |
| 624 | // This function must deallocate all resources associated with the request, or keep those which will be used | 624 | // This function must deallocate all resources associated with the request, or keep those which will be used |
| 625 | // This needs to be kept in sync with deinit and request | 625 | // This needs to be kept in sync with deinit and request |
| 626 | fn redirect(req: *Request, uri: Uri) !void { | 626 | fn redirect(req: *Request, uri: Uri) !void { |
| 627 | assert(req.response.parser.done); | 627 | assert(req.response.parser.state == .complete); |
| 628 | 628 | ||
| 629 | switch (req.response.compression) { | 629 | switch (req.response.compression) { |
| 630 | .none => {}, | 630 | .none => {}, |
| ... | @@ -794,12 +794,12 @@ pub const Request = struct { | ... | @@ -794,12 +794,12 @@ pub const Request = struct { |
| 794 | } | 794 | } |
| 795 | 795 | ||
| 796 | fn transferRead(req: *Request, buf: []u8) TransferReadError!usize { | 796 | fn transferRead(req: *Request, buf: []u8) TransferReadError!usize { |
| 797 | if (req.response.parser.done) return 0; | 797 | if (req.response.parser.state == .complete) return 0; |
| 798 | 798 | ||
| 799 | var index: usize = 0; | 799 | var index: usize = 0; |
| 800 | while (index == 0) { | 800 | while (index == 0) { |
| 801 | const amt = try req.response.parser.read(req.connection.?, buf[index..], req.response.skip); | 801 | const amt = try req.response.parser.read(req.connection.?, buf[index..], req.response.skip); |
| 802 | if (amt == 0 and req.response.parser.done) break; | 802 | if (amt == 0 and req.response.parser.state == .complete) break; |
| 803 | index += amt; | 803 | index += amt; |
| 804 | } | 804 | } |
| 805 | 805 | ||
| ... | @@ -840,7 +840,7 @@ pub const Request = struct { | ... | @@ -840,7 +840,7 @@ pub const Request = struct { |
| 840 | try req.response.parse(req.response.parser.get(), false); | 840 | try req.response.parse(req.response.parser.get(), false); |
| 841 | 841 | ||
| 842 | if (req.response.status == .@"continue") { | 842 | if (req.response.status == .@"continue") { |
| 843 | req.response.parser.done = true; // we're done parsing the continue response, reset to prepare for the real response | 843 | req.response.parser.state = .complete; // we're done parsing the continue response, reset to prepare for the real response |
| 844 | req.response.parser.reset(); | 844 | req.response.parser.reset(); |
| 845 | 845 | ||
| 846 | if (req.handle_continue) | 846 | if (req.handle_continue) |
| ... | @@ -852,7 +852,7 @@ pub const Request = struct { | ... | @@ -852,7 +852,7 @@ pub const Request = struct { |
| 852 | // we're switching protocols, so this connection is no longer doing http | 852 | // we're switching protocols, so this connection is no longer doing http |
| 853 | if (req.method == .CONNECT and req.response.status.class() == .success) { | 853 | if (req.method == .CONNECT and req.response.status.class() == .success) { |
| 854 | req.connection.?.closing = false; | 854 | req.connection.?.closing = false; |
| 855 | req.response.parser.done = true; | 855 | req.response.parser.state = .complete; |
| 856 | 856 | ||
| 857 | return; // the connection is not HTTP past this point, return to the caller | 857 | return; // the connection is not HTTP past this point, return to the caller |
| 858 | } | 858 | } |
| ... | @@ -872,8 +872,10 @@ pub const Request = struct { | ... | @@ -872,8 +872,10 @@ pub const Request = struct { |
| 872 | // Any response to a HEAD request and any response with a 1xx (Informational), 204 (No Content), or 304 (Not Modified) | 872 | // Any response to a HEAD request and any response with a 1xx (Informational), 204 (No Content), or 304 (Not Modified) |
| 873 | // status code is always terminated by the first empty line after the header fields, regardless of the header fields | 873 | // status code is always terminated by the first empty line after the header fields, regardless of the header fields |
| 874 | // present in the message | 874 | // present in the message |
| 875 | if (req.method == .HEAD or req.response.status.class() == .informational or req.response.status == .no_content or req.response.status == .not_modified) { | 875 | if (req.method == .HEAD or req.response.status.class() == .informational or |
| 876 | req.response.parser.done = true; | 876 | req.response.status == .no_content or req.response.status == .not_modified) |
| 877 | { | ||
| 878 | req.response.parser.state = .complete; | ||
| 877 | 879 | ||
| 878 | return; // the response is empty, no further setup or redirection is necessary | 880 | return; // the response is empty, no further setup or redirection is necessary |
| 879 | } | 881 | } |
| ... | @@ -889,7 +891,7 @@ pub const Request = struct { | ... | @@ -889,7 +891,7 @@ pub const Request = struct { |
| 889 | } else if (req.response.content_length) |cl| { | 891 | } else if (req.response.content_length) |cl| { |
| 890 | req.response.parser.next_chunk_length = cl; | 892 | req.response.parser.next_chunk_length = cl; |
| 891 | 893 | ||
| 892 | if (cl == 0) req.response.parser.done = true; | 894 | if (cl == 0) req.response.parser.state = .complete; |
| 893 | } else { | 895 | } else { |
| 894 | // read until the connection is closed | 896 | // read until the connection is closed |
| 895 | req.response.parser.next_chunk_length = std.math.maxInt(u64); | 897 | req.response.parser.next_chunk_length = std.math.maxInt(u64); |
| ... | @@ -947,7 +949,7 @@ pub const Request = struct { | ... | @@ -947,7 +949,7 @@ pub const Request = struct { |
| 947 | try req.send(.{}); | 949 | try req.send(.{}); |
| 948 | } else { | 950 | } else { |
| 949 | req.response.skip = false; | 951 | req.response.skip = false; |
| 950 | if (!req.response.parser.done) { | 952 | if (req.response.parser.state != .complete) { |
| 951 | switch (req.response.transfer_compression) { | 953 | switch (req.response.transfer_compression) { |
| 952 | .identity => req.response.compression = .none, | 954 | .identity => req.response.compression = .none, |
| 953 | .compress, .@"x-compress" => return error.CompressionNotSupported, | 955 | .compress, .@"x-compress" => return error.CompressionNotSupported, |
lib/std/http/Server.zig+6-6| ... | @@ -395,7 +395,7 @@ pub const Response = struct { | ... | @@ -395,7 +395,7 @@ pub const Response = struct { |
| 395 | return .reset; | 395 | return .reset; |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | if (!res.request.parser.done) { | 398 | if (res.request.parser.state != .complete) { |
| 399 | // If the response wasn't fully read, then we need to close the connection. | 399 | // If the response wasn't fully read, then we need to close the connection. |
| 400 | res.connection.closing = true; | 400 | res.connection.closing = true; |
| 401 | return .closing; | 401 | return .closing; |
| ... | @@ -534,12 +534,12 @@ pub const Response = struct { | ... | @@ -534,12 +534,12 @@ pub const Response = struct { |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | fn transferRead(res: *Response, buf: []u8) TransferReadError!usize { | 536 | fn transferRead(res: *Response, buf: []u8) TransferReadError!usize { |
| 537 | if (res.request.parser.done) return 0; | 537 | if (res.request.parser.state == .complete) return 0; |
| 538 | 538 | ||
| 539 | var index: usize = 0; | 539 | var index: usize = 0; |
| 540 | while (index == 0) { | 540 | while (index == 0) { |
| 541 | const amt = try res.request.parser.read(&res.connection, buf[index..], false); | 541 | const amt = try res.request.parser.read(&res.connection, buf[index..], false); |
| 542 | if (amt == 0 and res.request.parser.done) break; | 542 | if (amt == 0 and res.request.parser.state == .complete) break; |
| 543 | index += amt; | 543 | index += amt; |
| 544 | } | 544 | } |
| 545 | 545 | ||
| ... | @@ -596,12 +596,12 @@ pub const Response = struct { | ... | @@ -596,12 +596,12 @@ pub const Response = struct { |
| 596 | } else if (res.request.content_length) |cl| { | 596 | } else if (res.request.content_length) |cl| { |
| 597 | res.request.parser.next_chunk_length = cl; | 597 | res.request.parser.next_chunk_length = cl; |
| 598 | 598 | ||
| 599 | if (cl == 0) res.request.parser.done = true; | 599 | if (cl == 0) res.request.parser.state = .complete; |
| 600 | } else { | 600 | } else { |
| 601 | res.request.parser.done = true; | 601 | res.request.parser.state = .complete; |
| 602 | } | 602 | } |
| 603 | 603 | ||
| 604 | if (!res.request.parser.done) { | 604 | if (res.request.parser.state != .complete) { |
| 605 | switch (res.request.transfer_compression) { | 605 | switch (res.request.transfer_compression) { |
| 606 | .identity => res.request.compression = .none, | 606 | .identity => res.request.compression = .none, |
| 607 | .compress, .@"x-compress" => return error.CompressionNotSupported, | 607 | .compress, .@"x-compress" => return error.CompressionNotSupported, |
lib/std/http/protocol.zig+58-50| ... | @@ -14,7 +14,7 @@ pub const State = enum { | ... | @@ -14,7 +14,7 @@ pub const State = enum { |
| 14 | seen_r, | 14 | seen_r, |
| 15 | seen_rn, | 15 | seen_rn, |
| 16 | seen_rnr, | 16 | seen_rnr, |
| 17 | finished, | 17 | headers_end, |
| 18 | /// Begin transfer-encoding: chunked parsing states. | 18 | /// Begin transfer-encoding: chunked parsing states. |
| 19 | chunk_head_size, | 19 | chunk_head_size, |
| 20 | chunk_head_ext, | 20 | chunk_head_ext, |
| ... | @@ -22,46 +22,61 @@ pub const State = enum { | ... | @@ -22,46 +22,61 @@ pub const State = enum { |
| 22 | chunk_data, | 22 | chunk_data, |
| 23 | chunk_data_suffix, | 23 | chunk_data_suffix, |
| 24 | chunk_data_suffix_r, | 24 | chunk_data_suffix_r, |
| 25 | /// When the parser has finished parsing a complete message. A message is | ||
| 26 | /// only complete after the entire body has been read and any trailing | ||
| 27 | /// headers have been parsed. | ||
| 28 | complete, | ||
| 25 | 29 | ||
| 26 | /// Returns true if the parser is in a content state (ie. not waiting for more headers). | 30 | /// Returns true if the parser is in a content state (ie. not waiting for more headers). |
| 27 | pub fn isContent(self: State) bool { | 31 | pub fn isContent(self: State) bool { |
| 28 | return switch (self) { | 32 | return switch (self) { |
| 29 | .invalid, .start, .seen_n, .seen_r, .seen_rn, .seen_rnr => false, | 33 | .invalid, |
| 30 | .finished, .chunk_head_size, .chunk_head_ext, .chunk_head_r, .chunk_data, .chunk_data_suffix, .chunk_data_suffix_r => true, | 34 | .start, |
| 35 | .seen_n, | ||
| 36 | .seen_r, | ||
| 37 | .seen_rn, | ||
| 38 | .seen_rnr, | ||
| 39 | => false, | ||
| 40 | |||
| 41 | .headers_end, | ||
| 42 | .chunk_head_size, | ||
| 43 | .chunk_head_ext, | ||
| 44 | .chunk_head_r, | ||
| 45 | .chunk_data, | ||
| 46 | .chunk_data_suffix, | ||
| 47 | .chunk_data_suffix_r, | ||
| 48 | .complete, | ||
| 49 | => true, | ||
| 31 | }; | 50 | }; |
| 32 | } | 51 | } |
| 33 | }; | 52 | }; |
| 34 | 53 | ||
| 35 | pub const HeadersParser = struct { | 54 | pub const HeadersParser = struct { |
| 36 | state: State = .start, | 55 | state: State, |
| 37 | /// A fixed buffer of len `max_header_bytes`. | 56 | /// A fixed buffer of len `max_header_bytes`. |
| 38 | /// Pointers into this buffer are not stable until after a message is complete. | 57 | /// Pointers into this buffer are not stable until after a message is complete. |
| 39 | header_bytes_buffer: []u8, | 58 | header_bytes_buffer: []u8, |
| 40 | header_bytes_len: u32, | 59 | header_bytes_len: u32, |
| 41 | next_chunk_length: u64, | 60 | next_chunk_length: u64, |
| 42 | /// Whether this parser is done parsing a complete message. | ||
| 43 | /// A message is only done when the entire payload has been read. | ||
| 44 | done: bool, | ||
| 45 | 61 | ||
| 46 | /// Initializes the parser with a provided buffer `buf`. | 62 | /// Initializes the parser with a provided buffer `buf`. |
| 47 | pub fn init(buf: []u8) HeadersParser { | 63 | pub fn init(buf: []u8) HeadersParser { |
| 48 | return .{ | 64 | return .{ |
| 65 | .state = .start, | ||
| 49 | .header_bytes_buffer = buf, | 66 | .header_bytes_buffer = buf, |
| 50 | .header_bytes_len = 0, | 67 | .header_bytes_len = 0, |
| 51 | .done = false, | ||
| 52 | .next_chunk_length = 0, | 68 | .next_chunk_length = 0, |
| 53 | }; | 69 | }; |
| 54 | } | 70 | } |
| 55 | 71 | ||
| 56 | /// Reinitialize the parser. | 72 | /// Reinitialize the parser. |
| 57 | /// Asserts the parser is in the "done" state. | 73 | /// Asserts the parser is in the `complete` state. |
| 58 | pub fn reset(hp: *HeadersParser) void { | 74 | pub fn reset(hp: *HeadersParser) void { |
| 59 | assert(hp.done); | 75 | assert(hp.state == .complete); |
| 60 | hp.* = .{ | 76 | hp.* = .{ |
| 61 | .state = .start, | 77 | .state = .start, |
| 62 | .header_bytes_buffer = hp.header_bytes_buffer, | 78 | .header_bytes_buffer = hp.header_bytes_buffer, |
| 63 | .header_bytes_len = 0, | 79 | .header_bytes_len = 0, |
| 64 | .done = false, | ||
| 65 | .next_chunk_length = 0, | 80 | .next_chunk_length = 0, |
| 66 | }; | 81 | }; |
| 67 | } | 82 | } |
| ... | @@ -86,7 +101,8 @@ pub const HeadersParser = struct { | ... | @@ -86,7 +101,8 @@ pub const HeadersParser = struct { |
| 86 | while (true) { | 101 | while (true) { |
| 87 | switch (r.state) { | 102 | switch (r.state) { |
| 88 | .invalid => unreachable, | 103 | .invalid => unreachable, |
| 89 | .finished => return index, | 104 | .complete => unreachable, |
| 105 | .headers_end => return index, | ||
| 90 | .start => switch (len - index) { | 106 | .start => switch (len - index) { |
| 91 | 0 => return index, | 107 | 0 => return index, |
| 92 | 1 => { | 108 | 1 => { |
| ... | @@ -110,7 +126,7 @@ pub const HeadersParser = struct { | ... | @@ -110,7 +126,7 @@ pub const HeadersParser = struct { |
| 110 | 126 | ||
| 111 | switch (b16) { | 127 | switch (b16) { |
| 112 | int16("\r\n") => r.state = .seen_rn, | 128 | int16("\r\n") => r.state = .seen_rn, |
| 113 | int16("\n\n") => r.state = .finished, | 129 | int16("\n\n") => r.state = .headers_end, |
| 114 | else => {}, | 130 | else => {}, |
| 115 | } | 131 | } |
| 116 | 132 | ||
| ... | @@ -129,7 +145,7 @@ pub const HeadersParser = struct { | ... | @@ -129,7 +145,7 @@ pub const HeadersParser = struct { |
| 129 | 145 | ||
| 130 | switch (b16) { | 146 | switch (b16) { |
| 131 | int16("\r\n") => r.state = .seen_rn, | 147 | int16("\r\n") => r.state = .seen_rn, |
| 132 | int16("\n\n") => r.state = .finished, | 148 | int16("\n\n") => r.state = .headers_end, |
| 133 | else => {}, | 149 | else => {}, |
| 134 | } | 150 | } |
| 135 | 151 | ||
| ... | @@ -154,7 +170,7 @@ pub const HeadersParser = struct { | ... | @@ -154,7 +170,7 @@ pub const HeadersParser = struct { |
| 154 | 170 | ||
| 155 | switch (b16) { | 171 | switch (b16) { |
| 156 | int16("\r\n") => r.state = .seen_rn, | 172 | int16("\r\n") => r.state = .seen_rn, |
| 157 | int16("\n\n") => r.state = .finished, | 173 | int16("\n\n") => r.state = .headers_end, |
| 158 | else => {}, | 174 | else => {}, |
| 159 | } | 175 | } |
| 160 | 176 | ||
| ... | @@ -164,7 +180,7 @@ pub const HeadersParser = struct { | ... | @@ -164,7 +180,7 @@ pub const HeadersParser = struct { |
| 164 | } | 180 | } |
| 165 | 181 | ||
| 166 | switch (b32) { | 182 | switch (b32) { |
| 167 | int32("\r\n\r\n") => r.state = .finished, | 183 | int32("\r\n\r\n") => r.state = .headers_end, |
| 168 | else => {}, | 184 | else => {}, |
| 169 | } | 185 | } |
| 170 | 186 | ||
| ... | @@ -212,7 +228,7 @@ pub const HeadersParser = struct { | ... | @@ -212,7 +228,7 @@ pub const HeadersParser = struct { |
| 212 | 228 | ||
| 213 | switch (b16) { | 229 | switch (b16) { |
| 214 | int16("\r\n") => r.state = .seen_rn, | 230 | int16("\r\n") => r.state = .seen_rn, |
| 215 | int16("\n\n") => r.state = .finished, | 231 | int16("\n\n") => r.state = .headers_end, |
| 216 | else => {}, | 232 | else => {}, |
| 217 | } | 233 | } |
| 218 | }, | 234 | }, |
| ... | @@ -229,7 +245,7 @@ pub const HeadersParser = struct { | ... | @@ -229,7 +245,7 @@ pub const HeadersParser = struct { |
| 229 | 245 | ||
| 230 | switch (b16) { | 246 | switch (b16) { |
| 231 | int16("\r\n") => r.state = .seen_rn, | 247 | int16("\r\n") => r.state = .seen_rn, |
| 232 | int16("\n\n") => r.state = .finished, | 248 | int16("\n\n") => r.state = .headers_end, |
| 233 | else => {}, | 249 | else => {}, |
| 234 | } | 250 | } |
| 235 | 251 | ||
| ... | @@ -246,10 +262,10 @@ pub const HeadersParser = struct { | ... | @@ -246,10 +262,10 @@ pub const HeadersParser = struct { |
| 246 | const b16 = intShift(u16, b32); | 262 | const b16 = intShift(u16, b32); |
| 247 | 263 | ||
| 248 | if (b32 == int32("\r\n\r\n")) { | 264 | if (b32 == int32("\r\n\r\n")) { |
| 249 | r.state = .finished; | 265 | r.state = .headers_end; |
| 250 | return index + i + 4; | 266 | return index + i + 4; |
| 251 | } else if (b16 == int16("\n\n")) { | 267 | } else if (b16 == int16("\n\n")) { |
| 252 | r.state = .finished; | 268 | r.state = .headers_end; |
| 253 | return index + i + 2; | 269 | return index + i + 2; |
| 254 | } | 270 | } |
| 255 | } | 271 | } |
| ... | @@ -266,7 +282,7 @@ pub const HeadersParser = struct { | ... | @@ -266,7 +282,7 @@ pub const HeadersParser = struct { |
| 266 | 282 | ||
| 267 | switch (b16) { | 283 | switch (b16) { |
| 268 | int16("\r\n") => r.state = .seen_rn, | 284 | int16("\r\n") => r.state = .seen_rn, |
| 269 | int16("\n\n") => r.state = .finished, | 285 | int16("\n\n") => r.state = .headers_end, |
| 270 | else => {}, | 286 | else => {}, |
| 271 | } | 287 | } |
| 272 | 288 | ||
| ... | @@ -286,7 +302,7 @@ pub const HeadersParser = struct { | ... | @@ -286,7 +302,7 @@ pub const HeadersParser = struct { |
| 286 | 0 => return index, | 302 | 0 => return index, |
| 287 | else => { | 303 | else => { |
| 288 | switch (bytes[index]) { | 304 | switch (bytes[index]) { |
| 289 | '\n' => r.state = .finished, | 305 | '\n' => r.state = .headers_end, |
| 290 | else => r.state = .start, | 306 | else => r.state = .start, |
| 291 | } | 307 | } |
| 292 | 308 | ||
| ... | @@ -318,7 +334,7 @@ pub const HeadersParser = struct { | ... | @@ -318,7 +334,7 @@ pub const HeadersParser = struct { |
| 318 | switch (b16) { | 334 | switch (b16) { |
| 319 | int16("\r\n") => r.state = .seen_rn, | 335 | int16("\r\n") => r.state = .seen_rn, |
| 320 | int16("\n\r") => r.state = .seen_rnr, | 336 | int16("\n\r") => r.state = .seen_rnr, |
| 321 | int16("\n\n") => r.state = .finished, | 337 | int16("\n\n") => r.state = .headers_end, |
| 322 | else => {}, | 338 | else => {}, |
| 323 | } | 339 | } |
| 324 | 340 | ||
| ... | @@ -337,12 +353,12 @@ pub const HeadersParser = struct { | ... | @@ -337,12 +353,12 @@ pub const HeadersParser = struct { |
| 337 | 353 | ||
| 338 | switch (b16) { | 354 | switch (b16) { |
| 339 | int16("\r\n") => r.state = .seen_rn, | 355 | int16("\r\n") => r.state = .seen_rn, |
| 340 | int16("\n\n") => r.state = .finished, | 356 | int16("\n\n") => r.state = .headers_end, |
| 341 | else => {}, | 357 | else => {}, |
| 342 | } | 358 | } |
| 343 | 359 | ||
| 344 | switch (b24) { | 360 | switch (b24) { |
| 345 | int24("\n\r\n") => r.state = .finished, | 361 | int24("\n\r\n") => r.state = .headers_end, |
| 346 | else => {}, | 362 | else => {}, |
| 347 | } | 363 | } |
| 348 | 364 | ||
| ... | @@ -372,8 +388,8 @@ pub const HeadersParser = struct { | ... | @@ -372,8 +388,8 @@ pub const HeadersParser = struct { |
| 372 | } | 388 | } |
| 373 | 389 | ||
| 374 | switch (b16) { | 390 | switch (b16) { |
| 375 | int16("\r\n") => r.state = .finished, | 391 | int16("\r\n") => r.state = .headers_end, |
| 376 | int16("\n\n") => r.state = .finished, | 392 | int16("\n\n") => r.state = .headers_end, |
| 377 | else => {}, | 393 | else => {}, |
| 378 | } | 394 | } |
| 379 | 395 | ||
| ... | @@ -385,7 +401,7 @@ pub const HeadersParser = struct { | ... | @@ -385,7 +401,7 @@ pub const HeadersParser = struct { |
| 385 | 0 => return index, | 401 | 0 => return index, |
| 386 | else => { | 402 | else => { |
| 387 | switch (bytes[index]) { | 403 | switch (bytes[index]) { |
| 388 | '\n' => r.state = .finished, | 404 | '\n' => r.state = .headers_end, |
| 389 | else => r.state = .start, | 405 | else => r.state = .start, |
| 390 | } | 406 | } |
| 391 | 407 | ||
| ... | @@ -486,13 +502,6 @@ pub const HeadersParser = struct { | ... | @@ -486,13 +502,6 @@ pub const HeadersParser = struct { |
| 486 | return len; | 502 | return len; |
| 487 | } | 503 | } |
| 488 | 504 | ||
| 489 | /// Returns whether or not the parser has finished parsing a complete | ||
| 490 | /// message. A message is only complete after the entire body has been read | ||
| 491 | /// and any trailing headers have been parsed. | ||
| 492 | pub fn isComplete(r: *HeadersParser) bool { | ||
| 493 | return r.done and r.state == .finished; | ||
| 494 | } | ||
| 495 | |||
| 496 | pub const CheckCompleteHeadError = error{HttpHeadersOversize}; | 505 | pub const CheckCompleteHeadError = error{HttpHeadersOversize}; |
| 497 | 506 | ||
| 498 | /// Pushes `in` into the parser. Returns the number of bytes consumed by | 507 | /// Pushes `in` into the parser. Returns the number of bytes consumed by |
| ... | @@ -523,13 +532,12 @@ pub const HeadersParser = struct { | ... | @@ -523,13 +532,12 @@ pub const HeadersParser = struct { |
| 523 | /// See `std.http.Client.Connection for an example of `conn`. | 532 | /// See `std.http.Client.Connection for an example of `conn`. |
| 524 | pub fn read(r: *HeadersParser, conn: anytype, buffer: []u8, skip: bool) !usize { | 533 | pub fn read(r: *HeadersParser, conn: anytype, buffer: []u8, skip: bool) !usize { |
| 525 | assert(r.state.isContent()); | 534 | assert(r.state.isContent()); |
| 526 | if (r.done) return 0; | ||
| 527 | |||
| 528 | var out_index: usize = 0; | 535 | var out_index: usize = 0; |
| 529 | while (true) { | 536 | while (true) { |
| 530 | switch (r.state) { | 537 | switch (r.state) { |
| 538 | .complete => return out_index, | ||
| 531 | .invalid, .start, .seen_n, .seen_r, .seen_rn, .seen_rnr => unreachable, | 539 | .invalid, .start, .seen_n, .seen_r, .seen_rn, .seen_rnr => unreachable, |
| 532 | .finished => { | 540 | .headers_end => { |
| 533 | const data_avail = r.next_chunk_length; | 541 | const data_avail = r.next_chunk_length; |
| 534 | 542 | ||
| 535 | if (skip) { | 543 | if (skip) { |
| ... | @@ -539,7 +547,8 @@ pub const HeadersParser = struct { | ... | @@ -539,7 +547,8 @@ pub const HeadersParser = struct { |
| 539 | conn.drop(@intCast(nread)); | 547 | conn.drop(@intCast(nread)); |
| 540 | r.next_chunk_length -= nread; | 548 | r.next_chunk_length -= nread; |
| 541 | 549 | ||
| 542 | if (r.next_chunk_length == 0 or nread == 0) r.done = true; | 550 | if (r.next_chunk_length == 0 or nread == 0) |
| 551 | r.state = .complete; | ||
| 543 | 552 | ||
| 544 | return out_index; | 553 | return out_index; |
| 545 | } else if (out_index < buffer.len) { | 554 | } else if (out_index < buffer.len) { |
| ... | @@ -549,7 +558,8 @@ pub const HeadersParser = struct { | ... | @@ -549,7 +558,8 @@ pub const HeadersParser = struct { |
| 549 | const nread = try conn.read(buffer[0..can_read]); | 558 | const nread = try conn.read(buffer[0..can_read]); |
| 550 | r.next_chunk_length -= nread; | 559 | r.next_chunk_length -= nread; |
| 551 | 560 | ||
| 552 | if (r.next_chunk_length == 0 or nread == 0) r.done = true; | 561 | if (r.next_chunk_length == 0 or nread == 0) |
| 562 | r.state = .complete; | ||
| 553 | 563 | ||
| 554 | return nread; | 564 | return nread; |
| 555 | } else { | 565 | } else { |
| ... | @@ -566,14 +576,12 @@ pub const HeadersParser = struct { | ... | @@ -566,14 +576,12 @@ pub const HeadersParser = struct { |
| 566 | .invalid => return error.HttpChunkInvalid, | 576 | .invalid => return error.HttpChunkInvalid, |
| 567 | .chunk_data => if (r.next_chunk_length == 0) { | 577 | .chunk_data => if (r.next_chunk_length == 0) { |
| 568 | if (std.mem.eql(u8, conn.peek(), "\r\n")) { | 578 | if (std.mem.eql(u8, conn.peek(), "\r\n")) { |
| 569 | r.state = .finished; | 579 | r.state = .complete; |
| 570 | r.done = true; | ||
| 571 | } else { | 580 | } else { |
| 572 | // The trailer section is formatted identically to the header section. | 581 | // The trailer section is formatted identically |
| 582 | // to the header section. | ||
| 573 | r.state = .seen_rn; | 583 | r.state = .seen_rn; |
| 574 | } | 584 | } |
| 575 | r.done = true; | ||
| 576 | |||
| 577 | return out_index; | 585 | return out_index; |
| 578 | }, | 586 | }, |
| 579 | else => return out_index, | 587 | else => return out_index, |
| ... | @@ -611,21 +619,21 @@ pub const HeadersParser = struct { | ... | @@ -611,21 +619,21 @@ pub const HeadersParser = struct { |
| 611 | }; | 619 | }; |
| 612 | 620 | ||
| 613 | inline fn int16(array: *const [2]u8) u16 { | 621 | inline fn int16(array: *const [2]u8) u16 { |
| 614 | return @as(u16, @bitCast(array.*)); | 622 | return @bitCast(array.*); |
| 615 | } | 623 | } |
| 616 | 624 | ||
| 617 | inline fn int24(array: *const [3]u8) u24 { | 625 | inline fn int24(array: *const [3]u8) u24 { |
| 618 | return @as(u24, @bitCast(array.*)); | 626 | return @bitCast(array.*); |
| 619 | } | 627 | } |
| 620 | 628 | ||
| 621 | inline fn int32(array: *const [4]u8) u32 { | 629 | inline fn int32(array: *const [4]u8) u32 { |
| 622 | return @as(u32, @bitCast(array.*)); | 630 | return @bitCast(array.*); |
| 623 | } | 631 | } |
| 624 | 632 | ||
| 625 | inline fn intShift(comptime T: type, x: anytype) T { | 633 | inline fn intShift(comptime T: type, x: anytype) T { |
| 626 | switch (@import("builtin").cpu.arch.endian()) { | 634 | switch (@import("builtin").cpu.arch.endian()) { |
| 627 | .little => return @as(T, @truncate(x >> (@bitSizeOf(@TypeOf(x)) - @bitSizeOf(T)))), | 635 | .little => return @truncate(x >> (@bitSizeOf(@TypeOf(x)) - @bitSizeOf(T))), |
| 628 | .big => return @as(T, @truncate(x)), | 636 | .big => return @truncate(x), |
| 629 | } | 637 | } |
| 630 | } | 638 | } |
| 631 | 639 |
test/standalone/http.zig+76-19| ... | @@ -165,10 +165,11 @@ fn handleRequest(res: *Server.Response) !void { | ... | @@ -165,10 +165,11 @@ fn handleRequest(res: *Server.Response) !void { |
| 165 | var handle_new_requests = true; | 165 | var handle_new_requests = true; |
| 166 | 166 | ||
| 167 | fn runServer(srv: *Server) !void { | 167 | fn runServer(srv: *Server) !void { |
| 168 | var client_header_buffer: [1024]u8 = undefined; | ||
| 168 | outer: while (handle_new_requests) { | 169 | outer: while (handle_new_requests) { |
| 169 | var res = try srv.accept(.{ | 170 | var res = try srv.accept(.{ |
| 170 | .allocator = salloc, | 171 | .allocator = salloc, |
| 171 | .header_strategy = .{ .dynamic = max_header_size }, | 172 | .client_header_buffer = &client_header_buffer, |
| 172 | }); | 173 | }); |
| 173 | defer res.deinit(); | 174 | defer res.deinit(); |
| 174 | 175 | ||
| ... | @@ -244,7 +245,10 @@ pub fn main() !void { | ... | @@ -244,7 +245,10 @@ pub fn main() !void { |
| 244 | const uri = try std.Uri.parse(location); | 245 | const uri = try std.Uri.parse(location); |
| 245 | 246 | ||
| 246 | log.info("{s}", .{location}); | 247 | log.info("{s}", .{location}); |
| 247 | var req = try client.open(.GET, uri, h, .{}); | 248 | var server_header_buffer: [1024]u8 = undefined; |
| 249 | var req = try client.open(.GET, uri, h, .{ | ||
| 250 | .server_header_buffer = &server_header_buffer, | ||
| 251 | }); | ||
| 248 | defer req.deinit(); | 252 | defer req.deinit(); |
| 249 | 253 | ||
| 250 | try req.send(.{}); | 254 | try req.send(.{}); |
| ... | @@ -269,7 +273,10 @@ pub fn main() !void { | ... | @@ -269,7 +273,10 @@ pub fn main() !void { |
| 269 | const uri = try std.Uri.parse(location); | 273 | const uri = try std.Uri.parse(location); |
| 270 | 274 | ||
| 271 | log.info("{s}", .{location}); | 275 | log.info("{s}", .{location}); |
| 272 | var req = try client.open(.GET, uri, h, .{}); | 276 | var server_header_buffer: [1024]u8 = undefined; |
| 277 | var req = try client.open(.GET, uri, h, .{ | ||
| 278 | .server_header_buffer = &server_header_buffer, | ||
| 279 | }); | ||
| 273 | defer req.deinit(); | 280 | defer req.deinit(); |
| 274 | 281 | ||
| 275 | try req.send(.{}); | 282 | try req.send(.{}); |
| ... | @@ -293,7 +300,10 @@ pub fn main() !void { | ... | @@ -293,7 +300,10 @@ pub fn main() !void { |
| 293 | const uri = try std.Uri.parse(location); | 300 | const uri = try std.Uri.parse(location); |
| 294 | 301 | ||
| 295 | log.info("{s}", .{location}); | 302 | log.info("{s}", .{location}); |
| 296 | var req = try client.open(.HEAD, uri, h, .{}); | 303 | var server_header_buffer: [1024]u8 = undefined; |
| 304 | var req = try client.open(.HEAD, uri, h, .{ | ||
| 305 | .server_header_buffer = &server_header_buffer, | ||
| 306 | }); | ||
| 297 | defer req.deinit(); | 307 | defer req.deinit(); |
| 298 | 308 | ||
| 299 | try req.send(.{}); | 309 | try req.send(.{}); |
| ... | @@ -319,7 +329,10 @@ pub fn main() !void { | ... | @@ -319,7 +329,10 @@ pub fn main() !void { |
| 319 | const uri = try std.Uri.parse(location); | 329 | const uri = try std.Uri.parse(location); |
| 320 | 330 | ||
| 321 | log.info("{s}", .{location}); | 331 | log.info("{s}", .{location}); |
| 322 | var req = try client.open(.GET, uri, h, .{}); | 332 | var server_header_buffer: [1024]u8 = undefined; |
| 333 | var req = try client.open(.GET, uri, h, .{ | ||
| 334 | .server_header_buffer = &server_header_buffer, | ||
| 335 | }); | ||
| 323 | defer req.deinit(); | 336 | defer req.deinit(); |
| 324 | 337 | ||
| 325 | try req.send(.{}); | 338 | try req.send(.{}); |
| ... | @@ -344,7 +357,10 @@ pub fn main() !void { | ... | @@ -344,7 +357,10 @@ pub fn main() !void { |
| 344 | const uri = try std.Uri.parse(location); | 357 | const uri = try std.Uri.parse(location); |
| 345 | 358 | ||
| 346 | log.info("{s}", .{location}); | 359 | log.info("{s}", .{location}); |
| 347 | var req = try client.open(.HEAD, uri, h, .{}); | 360 | var server_header_buffer: [1024]u8 = undefined; |
| 361 | var req = try client.open(.HEAD, uri, h, .{ | ||
| 362 | .server_header_buffer = &server_header_buffer, | ||
| 363 | }); | ||
| 348 | defer req.deinit(); | 364 | defer req.deinit(); |
| 349 | 365 | ||
| 350 | try req.send(.{}); | 366 | try req.send(.{}); |
| ... | @@ -370,7 +386,10 @@ pub fn main() !void { | ... | @@ -370,7 +386,10 @@ pub fn main() !void { |
| 370 | const uri = try std.Uri.parse(location); | 386 | const uri = try std.Uri.parse(location); |
| 371 | 387 | ||
| 372 | log.info("{s}", .{location}); | 388 | log.info("{s}", .{location}); |
| 373 | var req = try client.open(.GET, uri, h, .{}); | 389 | var server_header_buffer: [1024]u8 = undefined; |
| 390 | var req = try client.open(.GET, uri, h, .{ | ||
| 391 | .server_header_buffer = &server_header_buffer, | ||
| 392 | }); | ||
| 374 | defer req.deinit(); | 393 | defer req.deinit(); |
| 375 | 394 | ||
| 376 | try req.send(.{}); | 395 | try req.send(.{}); |
| ... | @@ -397,7 +416,10 @@ pub fn main() !void { | ... | @@ -397,7 +416,10 @@ pub fn main() !void { |
| 397 | const uri = try std.Uri.parse(location); | 416 | const uri = try std.Uri.parse(location); |
| 398 | 417 | ||
| 399 | log.info("{s}", .{location}); | 418 | log.info("{s}", .{location}); |
| 400 | var req = try client.open(.POST, uri, h, .{}); | 419 | var server_header_buffer: [1024]u8 = undefined; |
| 420 | var req = try client.open(.POST, uri, h, .{ | ||
| 421 | .server_header_buffer = &server_header_buffer, | ||
| 422 | }); | ||
| 401 | defer req.deinit(); | 423 | defer req.deinit(); |
| 402 | 424 | ||
| 403 | req.transfer_encoding = .{ .content_length = 14 }; | 425 | req.transfer_encoding = .{ .content_length = 14 }; |
| ... | @@ -429,7 +451,10 @@ pub fn main() !void { | ... | @@ -429,7 +451,10 @@ pub fn main() !void { |
| 429 | const uri = try std.Uri.parse(location); | 451 | const uri = try std.Uri.parse(location); |
| 430 | 452 | ||
| 431 | log.info("{s}", .{location}); | 453 | log.info("{s}", .{location}); |
| 432 | var req = try client.open(.GET, uri, h, .{}); | 454 | var server_header_buffer: [1024]u8 = undefined; |
| 455 | var req = try client.open(.GET, uri, h, .{ | ||
| 456 | .server_header_buffer = &server_header_buffer, | ||
| 457 | }); | ||
| 433 | defer req.deinit(); | 458 | defer req.deinit(); |
| 434 | 459 | ||
| 435 | try req.send(.{}); | 460 | try req.send(.{}); |
| ... | @@ -456,7 +481,10 @@ pub fn main() !void { | ... | @@ -456,7 +481,10 @@ pub fn main() !void { |
| 456 | const uri = try std.Uri.parse(location); | 481 | const uri = try std.Uri.parse(location); |
| 457 | 482 | ||
| 458 | log.info("{s}", .{location}); | 483 | log.info("{s}", .{location}); |
| 459 | var req = try client.open(.POST, uri, h, .{}); | 484 | var server_header_buffer: [1024]u8 = undefined; |
| 485 | var req = try client.open(.POST, uri, h, .{ | ||
| 486 | .server_header_buffer = &server_header_buffer, | ||
| 487 | }); | ||
| 460 | defer req.deinit(); | 488 | defer req.deinit(); |
| 461 | 489 | ||
| 462 | req.transfer_encoding = .chunked; | 490 | req.transfer_encoding = .chunked; |
| ... | @@ -486,7 +514,10 @@ pub fn main() !void { | ... | @@ -486,7 +514,10 @@ pub fn main() !void { |
| 486 | const uri = try std.Uri.parse(location); | 514 | const uri = try std.Uri.parse(location); |
| 487 | 515 | ||
| 488 | log.info("{s}", .{location}); | 516 | log.info("{s}", .{location}); |
| 489 | var req = try client.open(.GET, uri, h, .{}); | 517 | var server_header_buffer: [1024]u8 = undefined; |
| 518 | var req = try client.open(.GET, uri, h, .{ | ||
| 519 | .server_header_buffer = &server_header_buffer, | ||
| 520 | }); | ||
| 490 | defer req.deinit(); | 521 | defer req.deinit(); |
| 491 | 522 | ||
| 492 | try req.send(.{}); | 523 | try req.send(.{}); |
| ... | @@ -510,7 +541,10 @@ pub fn main() !void { | ... | @@ -510,7 +541,10 @@ pub fn main() !void { |
| 510 | const uri = try std.Uri.parse(location); | 541 | const uri = try std.Uri.parse(location); |
| 511 | 542 | ||
| 512 | log.info("{s}", .{location}); | 543 | log.info("{s}", .{location}); |
| 513 | var req = try client.open(.GET, uri, h, .{}); | 544 | var server_header_buffer: [1024]u8 = undefined; |
| 545 | var req = try client.open(.GET, uri, h, .{ | ||
| 546 | .server_header_buffer = &server_header_buffer, | ||
| 547 | }); | ||
| 514 | defer req.deinit(); | 548 | defer req.deinit(); |
| 515 | 549 | ||
| 516 | try req.send(.{}); | 550 | try req.send(.{}); |
| ... | @@ -534,7 +568,10 @@ pub fn main() !void { | ... | @@ -534,7 +568,10 @@ pub fn main() !void { |
| 534 | const uri = try std.Uri.parse(location); | 568 | const uri = try std.Uri.parse(location); |
| 535 | 569 | ||
| 536 | log.info("{s}", .{location}); | 570 | log.info("{s}", .{location}); |
| 537 | var req = try client.open(.GET, uri, h, .{}); | 571 | var server_header_buffer: [1024]u8 = undefined; |
| 572 | var req = try client.open(.GET, uri, h, .{ | ||
| 573 | .server_header_buffer = &server_header_buffer, | ||
| 574 | }); | ||
| 538 | defer req.deinit(); | 575 | defer req.deinit(); |
| 539 | 576 | ||
| 540 | try req.send(.{}); | 577 | try req.send(.{}); |
| ... | @@ -558,7 +595,10 @@ pub fn main() !void { | ... | @@ -558,7 +595,10 @@ pub fn main() !void { |
| 558 | const uri = try std.Uri.parse(location); | 595 | const uri = try std.Uri.parse(location); |
| 559 | 596 | ||
| 560 | log.info("{s}", .{location}); | 597 | log.info("{s}", .{location}); |
| 561 | var req = try client.open(.GET, uri, h, .{}); | 598 | var server_header_buffer: [1024]u8 = undefined; |
| 599 | var req = try client.open(.GET, uri, h, .{ | ||
| 600 | .server_header_buffer = &server_header_buffer, | ||
| 601 | }); | ||
| 562 | defer req.deinit(); | 602 | defer req.deinit(); |
| 563 | 603 | ||
| 564 | try req.send(.{}); | 604 | try req.send(.{}); |
| ... | @@ -580,7 +620,10 @@ pub fn main() !void { | ... | @@ -580,7 +620,10 @@ pub fn main() !void { |
| 580 | const uri = try std.Uri.parse(location); | 620 | const uri = try std.Uri.parse(location); |
| 581 | 621 | ||
| 582 | log.info("{s}", .{location}); | 622 | log.info("{s}", .{location}); |
| 583 | var req = try client.open(.GET, uri, h, .{}); | 623 | var server_header_buffer: [1024]u8 = undefined; |
| 624 | var req = try client.open(.GET, uri, h, .{ | ||
| 625 | .server_header_buffer = &server_header_buffer, | ||
| 626 | }); | ||
| 584 | defer req.deinit(); | 627 | defer req.deinit(); |
| 585 | 628 | ||
| 586 | try req.send(.{}); | 629 | try req.send(.{}); |
| ... | @@ -628,7 +671,10 @@ pub fn main() !void { | ... | @@ -628,7 +671,10 @@ pub fn main() !void { |
| 628 | const uri = try std.Uri.parse(location); | 671 | const uri = try std.Uri.parse(location); |
| 629 | 672 | ||
| 630 | log.info("{s}", .{location}); | 673 | log.info("{s}", .{location}); |
| 631 | var req = try client.open(.POST, uri, h, .{}); | 674 | var server_header_buffer: [1024]u8 = undefined; |
| 675 | var req = try client.open(.POST, uri, h, .{ | ||
| 676 | .server_header_buffer = &server_header_buffer, | ||
| 677 | }); | ||
| 632 | defer req.deinit(); | 678 | defer req.deinit(); |
| 633 | 679 | ||
| 634 | req.transfer_encoding = .chunked; | 680 | req.transfer_encoding = .chunked; |
| ... | @@ -659,7 +705,10 @@ pub fn main() !void { | ... | @@ -659,7 +705,10 @@ pub fn main() !void { |
| 659 | const uri = try std.Uri.parse(location); | 705 | const uri = try std.Uri.parse(location); |
| 660 | 706 | ||
| 661 | log.info("{s}", .{location}); | 707 | log.info("{s}", .{location}); |
| 662 | var req = try client.open(.POST, uri, h, .{}); | 708 | var server_header_buffer: [1024]u8 = undefined; |
| 709 | var req = try client.open(.POST, uri, h, .{ | ||
| 710 | .server_header_buffer = &server_header_buffer, | ||
| 711 | }); | ||
| 663 | defer req.deinit(); | 712 | defer req.deinit(); |
| 664 | 713 | ||
| 665 | req.transfer_encoding = .chunked; | 714 | req.transfer_encoding = .chunked; |
| ... | @@ -678,9 +727,17 @@ pub fn main() !void { | ... | @@ -678,9 +727,17 @@ pub fn main() !void { |
| 678 | var requests = try calloc.alloc(http.Client.Request, total_connections); | 727 | var requests = try calloc.alloc(http.Client.Request, total_connections); |
| 679 | defer calloc.free(requests); | 728 | defer calloc.free(requests); |
| 680 | 729 | ||
| 730 | var header_bufs = std.ArrayList([]u8).init(calloc); | ||
| 731 | defer header_bufs.deinit(); | ||
| 732 | defer for (header_bufs.items) |item| calloc.free(item); | ||
| 733 | |||
| 681 | for (0..total_connections) |i| { | 734 | for (0..total_connections) |i| { |
| 682 | var req = try client.open(.GET, uri, .{ .allocator = calloc }, .{}); | 735 | const headers_buf = try calloc.alloc(u8, 1024); |
| 683 | req.response.parser.done = true; | 736 | try header_bufs.append(headers_buf); |
| 737 | var req = try client.open(.GET, uri, .{ .allocator = calloc }, .{ | ||
| 738 | .server_header_buffer = headers_buf, | ||
| 739 | }); | ||
| 740 | req.response.parser.state = .complete; | ||
| 684 | req.connection.?.closing = false; | 741 | req.connection.?.closing = false; |
| 685 | requests[i] = req; | 742 | requests[i] = req; |
| 686 | } | 743 | } |