diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index 1a2993f174..b27a3d7012 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -216,6 +216,7 @@ pub fn format( const needs_absolute = comptime std.mem.indexOf(u8, fmt, "+") != null; const needs_path = comptime std.mem.indexOf(u8, fmt, "/") != null or fmt.len == 0; + const raw_uri = comptime std.mem.indexOf(u8, fmt, "r") != null; const needs_fragment = comptime std.mem.indexOf(u8, fmt, "#") != null; if (needs_absolute) { @@ -246,18 +247,30 @@ pub fn format( if (uri.path.len == 0) { try writer.writeAll("/"); } else { - try Uri.writeEscapedPath(writer, uri.path); + if (raw_uri) { + try writer.writeAll(uri.path); + } else { + try Uri.writeEscapedPath(writer, uri.path); + } } if (uri.query) |q| { try writer.writeAll("?"); - try Uri.writeEscapedQuery(writer, q); + if (raw_uri) { + try writer.writeAll(q); + } else { + try Uri.writeEscapedQuery(writer, q); + } } if (needs_fragment) { if (uri.fragment) |f| { try writer.writeAll("#"); - try Uri.writeEscapedQuery(writer, f); + if (raw_uri) { + try writer.writeAll(f); + } else { + try Uri.writeEscapedQuery(writer, f); + } } } } diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig index bfb96f2cfc..9e475df51b 100644 --- a/lib/std/http/Client.zig +++ b/lib/std/http/Client.zig @@ -538,8 +538,13 @@ pub const Request = struct { pub const StartError = Connection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding }; + pub const StartOptions = struct { + /// Specifies that the uri should be used as is + raw_uri: bool = false, + }; + /// Send the request to the server. - pub fn start(req: *Request) StartError!void { + pub fn start(req: *Request, options: StartOptions) StartError!void { if (!req.method.requestHasBody() and req.transfer_encoding != .none) return error.UnsupportedTransferEncoding; var buffered = std.io.bufferedWriter(req.connection.?.data.writer()); @@ -552,13 +557,22 @@ pub const Request = struct { try w.writeAll(req.uri.host.?); try w.writeByte(':'); try w.print("{}", .{req.uri.port.?}); - } else if (req.connection.?.data.proxied) { - // proxied connections require the full uri - try w.print("{+/}", .{req.uri}); } else { - try w.print("{/}", .{req.uri}); + if (req.connection.?.data.proxied) { + // proxied connections require the full uri + if (options.raw_uri) { + try w.print("{+/r}", .{req.uri}); + } else { + try w.print("{+/}", .{req.uri}); + } + } else { + if (options.raw_uri) { + try w.print("{/r}", .{req.uri}); + } else { + try w.print("{/}", .{req.uri}); + } + } } - try w.writeByte(' '); try w.writeAll(@tagName(req.version)); try w.writeAll("\r\n"); @@ -757,7 +771,7 @@ pub const Request = struct { try req.redirect(resolved_url); - try req.start(); + try req.start(.{}); } else { req.response.skip = false; if (!req.response.parser.done) { @@ -1141,6 +1155,7 @@ pub const FetchOptions = struct { method: http.Method = .GET, headers: http.Headers = http.Headers{ .allocator = std.heap.page_allocator, .owned = false }, payload: Payload = .none, + raw_uri: bool = false, }; pub const FetchResult = struct { @@ -1188,7 +1203,7 @@ pub fn fetch(client: *Client, allocator: Allocator, options: FetchOptions) !Fetc .none => {}, } - try req.start(); + try req.start(.{ .raw_uri = options.raw_uri }); switch (options.payload) { .string => |str| try req.writeAll(str), diff --git a/src/Package.zig b/src/Package.zig index 03c4c72ab0..d170baeae5 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -653,7 +653,7 @@ fn fetchAndUnpack( var req = try http_client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); if (req.response.status != .ok) { diff --git a/test/standalone/http.zig b/test/standalone/http.zig index f0dc0e6b2a..00fd4397b0 100644 --- a/test/standalone/http.zig +++ b/test/standalone/http.zig @@ -240,7 +240,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -265,7 +265,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192 * 1024); @@ -289,7 +289,7 @@ pub fn main() !void { var req = try client.request(.HEAD, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -315,7 +315,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -340,7 +340,7 @@ pub fn main() !void { var req = try client.request(.HEAD, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -366,7 +366,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -395,7 +395,7 @@ pub fn main() !void { req.transfer_encoding = .{ .content_length = 14 }; - try req.start(); + try req.start(.{}); try req.writeAll("Hello, "); try req.writeAll("World!\n"); try req.finish(); @@ -425,7 +425,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -454,7 +454,7 @@ pub fn main() !void { req.transfer_encoding = .chunked; - try req.start(); + try req.start(.{}); try req.writeAll("Hello, "); try req.writeAll("World!\n"); try req.finish(); @@ -482,7 +482,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -506,7 +506,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -530,7 +530,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); try req.wait(); const body = try req.reader().readAllAlloc(calloc, 8192); @@ -554,7 +554,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); req.wait() catch |err| switch (err) { error.TooManyHttpRedirects => {}, else => return err, @@ -576,7 +576,7 @@ pub fn main() !void { var req = try client.request(.GET, uri, h, .{}); defer req.deinit(); - try req.start(); + try req.start(.{}); const result = req.wait(); try testing.expectError(error.ConnectionRefused, result); // expects not segfault but the regular error @@ -623,7 +623,7 @@ pub fn main() !void { req.transfer_encoding = .chunked; - try req.start(); + try req.start(.{}); try req.wait(); try testing.expectEqual(http.Status.@"continue", req.response.status); @@ -657,7 +657,7 @@ pub fn main() !void { req.transfer_encoding = .chunked; - try req.start(); + try req.start(.{}); try req.wait(); try testing.expectEqual(http.Status.expectation_failed, req.response.status); }