mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std.http: introduce options to http client to allow for raw uris
Addresses #17015 by introducing a new startWithOptions. The only option is currently is a flag to use the provided URI as is, without modification when passed to the server. Normally, this is not needed nor desired. However, some REST APIs may have requirements that cannot be satisfied with the default handling.
This commit is contained in:
parent
18f1db134c
commit
fcca3cd1a3
4 changed files with 56 additions and 28 deletions
|
|
@ -216,6 +216,7 @@ pub fn format(
|
||||||
|
|
||||||
const needs_absolute = comptime std.mem.indexOf(u8, fmt, "+") != null;
|
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 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;
|
const needs_fragment = comptime std.mem.indexOf(u8, fmt, "#") != null;
|
||||||
|
|
||||||
if (needs_absolute) {
|
if (needs_absolute) {
|
||||||
|
|
@ -246,18 +247,30 @@ pub fn format(
|
||||||
if (uri.path.len == 0) {
|
if (uri.path.len == 0) {
|
||||||
try writer.writeAll("/");
|
try writer.writeAll("/");
|
||||||
} else {
|
} 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| {
|
if (uri.query) |q| {
|
||||||
try writer.writeAll("?");
|
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 (needs_fragment) {
|
||||||
if (uri.fragment) |f| {
|
if (uri.fragment) |f| {
|
||||||
try writer.writeAll("#");
|
try writer.writeAll("#");
|
||||||
try Uri.writeEscapedQuery(writer, f);
|
if (raw_uri) {
|
||||||
|
try writer.writeAll(f);
|
||||||
|
} else {
|
||||||
|
try Uri.writeEscapedQuery(writer, f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -538,8 +538,13 @@ pub const Request = struct {
|
||||||
|
|
||||||
pub const StartError = Connection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding };
|
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.
|
/// 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;
|
if (!req.method.requestHasBody() and req.transfer_encoding != .none) return error.UnsupportedTransferEncoding;
|
||||||
|
|
||||||
var buffered = std.io.bufferedWriter(req.connection.?.data.writer());
|
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.writeAll(req.uri.host.?);
|
||||||
try w.writeByte(':');
|
try w.writeByte(':');
|
||||||
try w.print("{}", .{req.uri.port.?});
|
try w.print("{}", .{req.uri.port.?});
|
||||||
} else if (req.connection.?.data.proxied) {
|
|
||||||
// proxied connections require the full uri
|
|
||||||
try w.print("{+/}", .{req.uri});
|
|
||||||
} else {
|
} 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.writeByte(' ');
|
||||||
try w.writeAll(@tagName(req.version));
|
try w.writeAll(@tagName(req.version));
|
||||||
try w.writeAll("\r\n");
|
try w.writeAll("\r\n");
|
||||||
|
|
@ -757,7 +771,7 @@ pub const Request = struct {
|
||||||
|
|
||||||
try req.redirect(resolved_url);
|
try req.redirect(resolved_url);
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
} else {
|
} else {
|
||||||
req.response.skip = false;
|
req.response.skip = false;
|
||||||
if (!req.response.parser.done) {
|
if (!req.response.parser.done) {
|
||||||
|
|
@ -1141,6 +1155,7 @@ pub const FetchOptions = struct {
|
||||||
method: http.Method = .GET,
|
method: http.Method = .GET,
|
||||||
headers: http.Headers = http.Headers{ .allocator = std.heap.page_allocator, .owned = false },
|
headers: http.Headers = http.Headers{ .allocator = std.heap.page_allocator, .owned = false },
|
||||||
payload: Payload = .none,
|
payload: Payload = .none,
|
||||||
|
raw_uri: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const FetchResult = struct {
|
pub const FetchResult = struct {
|
||||||
|
|
@ -1188,7 +1203,7 @@ pub fn fetch(client: *Client, allocator: Allocator, options: FetchOptions) !Fetc
|
||||||
.none => {},
|
.none => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{ .raw_uri = options.raw_uri });
|
||||||
|
|
||||||
switch (options.payload) {
|
switch (options.payload) {
|
||||||
.string => |str| try req.writeAll(str),
|
.string => |str| try req.writeAll(str),
|
||||||
|
|
|
||||||
|
|
@ -653,7 +653,7 @@ fn fetchAndUnpack(
|
||||||
var req = try http_client.request(.GET, uri, h, .{});
|
var req = try http_client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
if (req.response.status != .ok) {
|
if (req.response.status != .ok) {
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -265,7 +265,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192 * 1024);
|
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, .{});
|
var req = try client.request(.HEAD, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -315,7 +315,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -340,7 +340,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.HEAD, uri, h, .{});
|
var req = try client.request(.HEAD, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -366,7 +366,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -395,7 +395,7 @@ pub fn main() !void {
|
||||||
|
|
||||||
req.transfer_encoding = .{ .content_length = 14 };
|
req.transfer_encoding = .{ .content_length = 14 };
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.writeAll("Hello, ");
|
try req.writeAll("Hello, ");
|
||||||
try req.writeAll("World!\n");
|
try req.writeAll("World!\n");
|
||||||
try req.finish();
|
try req.finish();
|
||||||
|
|
@ -425,7 +425,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -454,7 +454,7 @@ pub fn main() !void {
|
||||||
|
|
||||||
req.transfer_encoding = .chunked;
|
req.transfer_encoding = .chunked;
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.writeAll("Hello, ");
|
try req.writeAll("Hello, ");
|
||||||
try req.writeAll("World!\n");
|
try req.writeAll("World!\n");
|
||||||
try req.finish();
|
try req.finish();
|
||||||
|
|
@ -482,7 +482,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -506,7 +506,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -530,7 +530,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
const body = try req.reader().readAllAlloc(calloc, 8192);
|
const body = try req.reader().readAllAlloc(calloc, 8192);
|
||||||
|
|
@ -554,7 +554,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
req.wait() catch |err| switch (err) {
|
req.wait() catch |err| switch (err) {
|
||||||
error.TooManyHttpRedirects => {},
|
error.TooManyHttpRedirects => {},
|
||||||
else => return err,
|
else => return err,
|
||||||
|
|
@ -576,7 +576,7 @@ pub fn main() !void {
|
||||||
var req = try client.request(.GET, uri, h, .{});
|
var req = try client.request(.GET, uri, h, .{});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
const result = req.wait();
|
const result = req.wait();
|
||||||
|
|
||||||
try testing.expectError(error.ConnectionRefused, result); // expects not segfault but the regular error
|
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;
|
req.transfer_encoding = .chunked;
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
try testing.expectEqual(http.Status.@"continue", req.response.status);
|
try testing.expectEqual(http.Status.@"continue", req.response.status);
|
||||||
|
|
||||||
|
|
@ -657,7 +657,7 @@ pub fn main() !void {
|
||||||
|
|
||||||
req.transfer_encoding = .chunked;
|
req.transfer_encoding = .chunked;
|
||||||
|
|
||||||
try req.start();
|
try req.start(.{});
|
||||||
try req.wait();
|
try req.wait();
|
||||||
try testing.expectEqual(http.Status.expectation_failed, req.response.status);
|
try testing.expectEqual(http.Status.expectation_failed, req.response.status);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue