| ... | ... | @@ -451,7 +451,8 @@ pub const Response = struct { |
| 451 | 451 | pub const Request = struct { |
| 452 | 452 | uri: Uri, |
| 453 | 453 | client: *Client, |
| 454 | | connection: *ConnectionPool.Node, |
| 454 | /// is null when this connection is released |
| 455 | connection: ?*ConnectionPool.Node, |
| 455 | 456 | |
| 456 | 457 | method: http.Method, |
| 457 | 458 | version: http.Version = .@"HTTP/1.1", |
| ... | ... | @@ -481,13 +482,14 @@ pub const Request = struct { |
| 481 | 482 | req.response.parser.header_bytes.deinit(req.client.allocator); |
| 482 | 483 | } |
| 483 | 484 | |
| 484 | | if (!req.response.parser.done) { |
| 485 | | // If the response wasn't fully read, then we need to close the connection. |
| 486 | | req.connection.data.closing = true; |
| 485 | if (req.connection) |connection| { |
| 486 | if (!req.response.parser.done) { |
| 487 | // If the response wasn't fully read, then we need to close the connection. |
| 488 | connection.data.closing = true; |
| 489 | } |
| 490 | req.client.connection_pool.release(req.client, connection); |
| 487 | 491 | } |
| 488 | 492 | |
| 489 | | req.client.connection_pool.release(req.client, req.connection); |
| 490 | | |
| 491 | 493 | req.arena.deinit(); |
| 492 | 494 | req.* = undefined; |
| 493 | 495 | } |
| ... | ... | @@ -504,7 +506,8 @@ pub const Request = struct { |
| 504 | 506 | .zstd => |*zstd| zstd.deinit(), |
| 505 | 507 | } |
| 506 | 508 | |
| 507 | | req.client.connection_pool.release(req.client, req.connection); |
| 509 | req.client.connection_pool.release(req.client, req.connection.?); |
| 510 | req.connection = null; |
| 508 | 511 | |
| 509 | 512 | const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUrlScheme; |
| 510 | 513 | |
| ... | ... | @@ -534,7 +537,7 @@ pub const Request = struct { |
| 534 | 537 | |
| 535 | 538 | /// Send the request to the server. |
| 536 | 539 | pub fn start(req: *Request) StartError!void { |
| 537 | | var buffered = std.io.bufferedWriter(req.connection.data.writer()); |
| 540 | var buffered = std.io.bufferedWriter(req.connection.?.data.writer()); |
| 538 | 541 | const w = buffered.writer(); |
| 539 | 542 | |
| 540 | 543 | try w.writeAll(@tagName(req.method)); |
| ... | ... | @@ -544,7 +547,7 @@ pub const Request = struct { |
| 544 | 547 | try w.writeAll(req.uri.host.?); |
| 545 | 548 | try w.writeByte(':'); |
| 546 | 549 | try w.print("{}", .{req.uri.port.?}); |
| 547 | | } else if (req.connection.data.proxied) { |
| 550 | } else if (req.connection.?.data.proxied) { |
| 548 | 551 | // proxied connections require the full uri |
| 549 | 552 | try w.print("{+/}", .{req.uri}); |
| 550 | 553 | } else { |
| ... | ... | @@ -625,7 +628,7 @@ pub const Request = struct { |
| 625 | 628 | |
| 626 | 629 | var index: usize = 0; |
| 627 | 630 | while (index == 0) { |
| 628 | | const amt = try req.response.parser.read(&req.connection.data, buf[index..], req.response.skip); |
| 631 | const amt = try req.response.parser.read(&req.connection.?.data, buf[index..], req.response.skip); |
| 629 | 632 | if (amt == 0 and req.response.parser.done) break; |
| 630 | 633 | index += amt; |
| 631 | 634 | } |
| ... | ... | @@ -643,10 +646,10 @@ pub const Request = struct { |
| 643 | 646 | pub fn wait(req: *Request) WaitError!void { |
| 644 | 647 | while (true) { // handle redirects |
| 645 | 648 | while (true) { // read headers |
| 646 | | try req.connection.data.fill(); |
| 649 | try req.connection.?.data.fill(); |
| 647 | 650 | |
| 648 | | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.data.peek()); |
| 649 | | req.connection.data.drop(@intCast(u16, nchecked)); |
| 651 | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.?.data.peek()); |
| 652 | req.connection.?.data.drop(@intCast(u16, nchecked)); |
| 650 | 653 | |
| 651 | 654 | if (req.response.parser.state.isContent()) break; |
| 652 | 655 | } |
| ... | ... | @@ -654,12 +657,12 @@ pub const Request = struct { |
| 654 | 657 | try req.response.parse(req.response.parser.header_bytes.items, false); |
| 655 | 658 | |
| 656 | 659 | if (req.response.status == .switching_protocols) { |
| 657 | | req.connection.data.closing = false; |
| 660 | req.connection.?.data.closing = false; |
| 658 | 661 | req.response.parser.done = true; |
| 659 | 662 | } |
| 660 | 663 | |
| 661 | 664 | if (req.method == .CONNECT and req.response.status == .ok) { |
| 662 | | req.connection.data.closing = false; |
| 665 | req.connection.?.data.closing = false; |
| 663 | 666 | req.response.parser.done = true; |
| 664 | 667 | } |
| 665 | 668 | |
| ... | ... | @@ -670,9 +673,9 @@ pub const Request = struct { |
| 670 | 673 | const res_connection = req.response.headers.getFirstValue("connection"); |
| 671 | 674 | const res_keepalive = res_connection != null and !std.ascii.eqlIgnoreCase("close", res_connection.?); |
| 672 | 675 | if (res_keepalive and (req_keepalive or req_connection == null)) { |
| 673 | | req.connection.data.closing = false; |
| 676 | req.connection.?.data.closing = false; |
| 674 | 677 | } else { |
| 675 | | req.connection.data.closing = true; |
| 678 | req.connection.?.data.closing = true; |
| 676 | 679 | } |
| 677 | 680 | |
| 678 | 681 | if (req.response.transfer_encoding) |te| { |
| ... | ... | @@ -762,10 +765,10 @@ pub const Request = struct { |
| 762 | 765 | const has_trail = !req.response.parser.state.isContent(); |
| 763 | 766 | |
| 764 | 767 | while (!req.response.parser.state.isContent()) { // read trailing headers |
| 765 | | try req.connection.data.fill(); |
| 768 | try req.connection.?.data.fill(); |
| 766 | 769 | |
| 767 | | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.data.peek()); |
| 768 | | req.connection.data.drop(@intCast(u16, nchecked)); |
| 770 | const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.?.data.peek()); |
| 771 | req.connection.?.data.drop(@intCast(u16, nchecked)); |
| 769 | 772 | } |
| 770 | 773 | |
| 771 | 774 | if (has_trail) { |
| ... | ... | @@ -803,16 +806,16 @@ pub const Request = struct { |
| 803 | 806 | pub fn write(req: *Request, bytes: []const u8) WriteError!usize { |
| 804 | 807 | switch (req.transfer_encoding) { |
| 805 | 808 | .chunked => { |
| 806 | | try req.connection.data.writer().print("{x}\r\n", .{bytes.len}); |
| 807 | | try req.connection.data.writeAll(bytes); |
| 808 | | try req.connection.data.writeAll("\r\n"); |
| 809 | try req.connection.?.data.writer().print("{x}\r\n", .{bytes.len}); |
| 810 | try req.connection.?.data.writeAll(bytes); |
| 811 | try req.connection.?.data.writeAll("\r\n"); |
| 809 | 812 | |
| 810 | 813 | return bytes.len; |
| 811 | 814 | }, |
| 812 | 815 | .content_length => |*len| { |
| 813 | 816 | if (len.* < bytes.len) return error.MessageTooLong; |
| 814 | 817 | |
| 815 | | const amt = try req.connection.data.write(bytes); |
| 818 | const amt = try req.connection.?.data.write(bytes); |
| 816 | 819 | len.* -= amt; |
| 817 | 820 | return amt; |
| 818 | 821 | }, |
| ... | ... | @@ -832,7 +835,7 @@ pub const Request = struct { |
| 832 | 835 | /// Finish the body of a request. This notifies the server that you have no more data to send. |
| 833 | 836 | pub fn finish(req: *Request) FinishError!void { |
| 834 | 837 | switch (req.transfer_encoding) { |
| 835 | | .chunked => try req.connection.data.writeAll("0\r\n\r\n"), |
| 838 | .chunked => try req.connection.?.data.writeAll("0\r\n\r\n"), |
| 836 | 839 | .content_length => |len| if (len != 0) return error.MessageNotCompleted, |
| 837 | 840 | .none => {}, |
| 838 | 841 | } |