authorgravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2023-04-17 19:37:24-05:00
committergravatar for truemedian@gmail.comNameless <truemedian@gmail.com> 2023-04-18 10:28:53-05:00
loga23c8662b41cf6954d8294ea316fb28a88481a7e
treefb11f4e09ca8262a36a08c850eb055708f53512b
parente65cbff94d2d1d7de6f8615123c62e86f37461af
signaturelock-open Commit is signed but in an unrecognized format.

std.http: pass Method to request directly, parse trailing headers


3 files changed, 31 insertions(+), 13 deletions(-)

lib/std/http/Client.zig+20-12
......@@ -527,7 +527,7 @@ pub const Request = struct {
527527 pub const StartError = BufferedConnection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding };
528528
529529 /// Send the request to the server.
530 pub fn start(req: *Request, uri: Uri) StartError!void {
530 pub fn start(req: *Request) StartError!void {
531531 var buffered = std.io.bufferedWriter(req.connection.data.buffered.writer());
532532 const w = buffered.writer();
533533
......@@ -535,14 +535,14 @@ pub const Request = struct {
535535 try w.writeByte(' ');
536536
537537 if (req.method == .CONNECT) {
538 try w.writeAll(uri.host.?);
538 try w.writeAll(req.uri.host.?);
539539 try w.writeByte(':');
540 try w.print("{}", .{uri.port.?});
540 try w.print("{}", .{req.uri.port.?});
541541 } else if (req.connection.data.proxied) {
542542 // proxied connections require the full uri
543 try w.print("{+/}", .{uri});
543 try w.print("{+/}", .{req.uri});
544544 } else {
545 try w.print("{/}", .{uri});
545 try w.print("{/}", .{req.uri});
546546 }
547547
548548 try w.writeByte(' ');
......@@ -551,7 +551,7 @@ pub const Request = struct {
551551
552552 if (!req.headers.contains("host")) {
553553 try w.writeAll("Host: ");
554 try w.writeAll(uri.host.?);
554 try w.writeAll(req.uri.host.?);
555555 try w.writeAll("\r\n");
556556 }
557557
......@@ -704,8 +704,7 @@ pub const Request = struct {
704704 req.arena.deinit();
705705 req.arena = new_arena;
706706
707 const new_req = try req.client.request(resolved_url, req.headers, .{
708 .method = req.method,
707 const new_req = try req.client.request(req.method, resolved_url, req.headers, .{
709708 .version = req.version,
710709 .max_redirects = req.redirects_left - 1,
711710 .header_strategy = if (req.response.parser.header_bytes_owned) .{
......@@ -738,7 +737,7 @@ pub const Request = struct {
738737 }
739738 }
740739
741 pub const ReadError = TransferReadError || proto.HeadersParser.CheckCompleteHeadError || error{DecompressionFailure};
740 pub const ReadError = TransferReadError || proto.HeadersParser.CheckCompleteHeadError || error{ DecompressionFailure, InvalidTrailers };
742741
743742 pub const Reader = std.io.Reader(*Request, ReadError, read);
744743
......@@ -756,12 +755,22 @@ pub const Request = struct {
756755 };
757756
758757 if (out_index == 0) {
758 const has_trail = !req.response.parser.state.isContent();
759
759760 while (!req.response.parser.state.isContent()) { // read trailing headers
760761 try req.connection.data.buffered.fill();
761762
762763 const nchecked = try req.response.parser.checkCompleteHead(req.client.allocator, req.connection.data.buffered.peek());
763764 req.connection.data.buffered.clear(@intCast(u16, nchecked));
764765 }
766
767 if (has_trail) {
768 req.response.headers = http.Headers{ .allocator = req.client.allocator, .owned = false };
769
770 // The response headers before the trailers are already guaranteed to be valid, so they will always be parsed again and cannot return an error.
771 // This will *only* fail for a malformed trailer.
772 req.response.parse(req.response.parser.header_bytes.items) catch return error.InvalidTrailers;
773 }
765774 }
766775
767776 return out_index;
......@@ -943,7 +952,6 @@ pub const RequestError = ConnectUnproxiedError || ConnectErrorPartial || Request
943952};
944953
945954pub const Options = struct {
946 method: http.Method = .GET,
947955 version: http.Version = .@"HTTP/1.1",
948956
949957 handle_redirects: bool = true,
......@@ -976,7 +984,7 @@ pub const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{
976984
977985/// Form and send a http request to a server.
978986/// This function is threadsafe.
979pub fn request(client: *Client, uri: Uri, headers: http.Headers, options: Options) RequestError!Request {
987pub fn request(client: *Client, method: http.Method, uri: Uri, headers: http.Headers, options: Options) RequestError!Request {
980988 const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUrlScheme;
981989
982990 const port: u16 = uri.port orelse switch (protocol) {
......@@ -1003,7 +1011,7 @@ pub fn request(client: *Client, uri: Uri, headers: http.Headers, options: Option
10031011 .client = client,
10041012 .connection = conn,
10051013 .headers = headers,
1006 .method = options.method,
1014 .method = method,
10071015 .version = options.version,
10081016 .redirects_left = options.max_redirects,
10091017 .handle_redirects = options.handle_redirects,
lib/std/http/Server.zig+10
......@@ -518,12 +518,22 @@ pub const Response = struct {
518518 };
519519
520520 if (out_index == 0) {
521 const has_trail = !res.request.parser.state.isContent();
522
521523 while (!res.request.parser.state.isContent()) { // read trailing headers
522524 try res.connection.fill();
523525
524526 const nchecked = try res.request.parser.checkCompleteHead(res.server.allocator, res.connection.peek());
525527 res.connection.clear(@intCast(u16, nchecked));
526528 }
529
530 if (has_trail) {
531 res.request.headers = http.Headers{ .allocator = res.server.allocator, .owned = false };
532
533 // The response headers before the trailers are already guaranteed to be valid, so they will always be parsed again and cannot return an error.
534 // This will *only* fail for a malformed trailer.
535 res.request.parse(res.request.parser.header_bytes.items) catch return error.InvalidTrailers;
536 }
527537 }
528538
529539 return out_index;
src/Package.zig+1-1
......@@ -482,7 +482,7 @@ fn fetchAndUnpack(
482482 var h = std.http.Headers{ .allocator = gpa };
483483 defer h.deinit();
484484
485 var req = try http_client.request(uri, h, .{ .method = .GET });
485 var req = try http_client.request(.GET, uri, h, .{});
486486 defer req.deinit();
487487
488488 try req.start();