aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Uri.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-04-18 19:56:24 -0700
committerGitHub <noreply@github.com>2023-04-18 19:56:24 -0700
commit0eebc258809beac9779af48216b01c5c20cbbfea (patch)
treea912eef3d99d3e2371484fd60f6b32a7e11d509b /lib/std/Uri.zig
parent77fdd76c16196441dce0f38ccea2eae01436c4be (diff)
parenta23c8662b41cf6954d8294ea316fb28a88481a7e (diff)
downloadzig-0eebc258809beac9779af48216b01c5c20cbbfea.tar.gz
zig-0eebc258809beac9779af48216b01c5c20cbbfea.zip
Merge pull request #15299 from truemedian/std-http
std.http: curated error sets and custom Headers
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`.