aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Uri.zig
diff options
context:
space:
mode:
authorNameless <truemedian@gmail.com>2023-04-14 12:38:13 -0500
committerNameless <truemedian@gmail.com>2023-04-17 19:14:48 -0500
commit96533b1289f210b415e12d4cf5bbac466279c2e5 (patch)
tree1f566443a986b4a8b0d05edfb585023e9616b70b /lib/std/Uri.zig
parent2c492064fbc882fa31256209d201ade1bb20cb92 (diff)
downloadzig-96533b1289f210b415e12d4cf5bbac466279c2e5.tar.gz
zig-96533b1289f210b415e12d4cf5bbac466279c2e5.zip
std.http: very basic http client proxy
Diffstat (limited to 'lib/std/Uri.zig')
-rw-r--r--lib/std/Uri.zig76
1 files changed, 76 insertions, 0 deletions
diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig
index eb6311a19b..b010ce8662 100644
--- a/lib/std/Uri.zig
+++ b/lib/std/Uri.zig
@@ -27,6 +27,18 @@ pub fn escapeQuery(allocator: std.mem.Allocator, input: []const u8) error{OutOfM
return escapeStringWithFn(allocator, input, isQueryChar);
}
+pub fn writeEscapedString(writer: anytype, input: []const u8) !void {
+ return writeEscapedStringWithFn(writer, input, isUnreserved);
+}
+
+pub fn writeEscapedPath(writer: anytype, input: []const u8) !void {
+ return writeEscapedStringWithFn(writer, input, isPathChar);
+}
+
+pub fn writeEscapedQuery(writer: anytype, input: []const u8) !void {
+ return writeEscapedStringWithFn(writer, input, isQueryChar);
+}
+
pub fn escapeStringWithFn(allocator: std.mem.Allocator, input: []const u8, comptime keepUnescaped: fn (c: u8) bool) std.mem.Allocator.Error![]const u8 {
var outsize: usize = 0;
for (input) |c| {
@@ -52,6 +64,16 @@ pub fn escapeStringWithFn(allocator: std.mem.Allocator, input: []const u8, compt
return output;
}
+pub fn writeEscapedStringWithFn(writer: anytype, input: []const u8, comptime keepUnescaped: fn (c: u8) bool) @TypeOf(writer).Error!void {
+ for (input) |c| {
+ if (keepUnescaped(c)) {
+ try writer.writeByte(c);
+ } else {
+ try writer.print("%{X:0>2}", .{c});
+ }
+ }
+}
+
/// Parses a URI string and unescapes all %XX where XX is a valid hex number. Otherwise, verbatim copies
/// them to the output.
pub fn unescapeString(allocator: std.mem.Allocator, input: []const u8) error{OutOfMemory}![]const u8 {
@@ -184,6 +206,60 @@ pub fn parseWithoutScheme(text: []const u8) ParseError!Uri {
return uri;
}
+pub fn format(
+ uri: Uri,
+ comptime fmt: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+) @TypeOf(writer).Error!void {
+ _ = options;
+
+ const needs_absolute = comptime std.mem.indexOf(u8, fmt, "+") != null;
+ const needs_path = comptime std.mem.indexOf(u8, fmt, "/") != null or fmt.len == 0;
+
+ if (needs_absolute) {
+ try writer.writeAll(uri.scheme);
+ try writer.writeAll(":");
+ if (uri.host) |host| {
+ try writer.writeAll("//");
+
+ if (uri.user) |user| {
+ try writer.writeAll(user);
+ if (uri.password) |password| {
+ try writer.writeAll(":");
+ try writer.writeAll(password);
+ }
+ try writer.writeAll("@");
+ }
+
+ try writer.writeAll(host);
+
+ if (uri.port) |port| {
+ try writer.writeAll(":");
+ try std.fmt.formatInt(port, 10, .lower, .{}, writer);
+ }
+ }
+ }
+
+ if (needs_path) {
+ if (uri.path.len == 0) {
+ try writer.writeAll("/");
+ } else {
+ try Uri.writeEscapedPath(writer, uri.path);
+ }
+
+ if (uri.query) |q| {
+ try writer.writeAll("?");
+ try Uri.writeEscapedQuery(writer, q);
+ }
+
+ if (uri.fragment) |f| {
+ try writer.writeAll("#");
+ try Uri.writeEscapedQuery(writer, f);
+ }
+ }
+}
+
/// Parses the URI or returns an error.
/// The return value will contain unescaped strings pointing into the
/// original `text`. Each component that is provided, will be non-`null`.