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