authorgravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2026-03-23 00:29:07+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-23 05:22:46+01:00
log029719cf473f6695a8290aa2873624448a47e0c5
tree8dbdd58e9cdbafd4c22f41ae3cc624abb0f801f5
parent1708da2c710bd5fa84167ed4abc7ec79438c9be4

std.Uri: reject invalid URI schemes according to RFC3986


1 files changed, 22 insertions(+), 12 deletions(-)

lib/std/Uri.zig+22-12
......@@ -374,13 +374,11 @@ pub fn fmt(uri: *const Uri, flags: Format.Flags) std.fmt.Alt(Format, Format.defa
374374/// The return value will contain strings pointing into the original `text`.
375375/// Each component that is provided will be non-`null`.
376376pub fn parse(text: []const u8) ParseError!Uri {
377 const end = for (text, 0..) |byte, i| {
378 if (!isSchemeChar(byte)) break i;
379 } else text.len;
380 // After the scheme, a ':' must appear.
381 if (end >= text.len) return error.InvalidFormat;
382 if (text[end] != ':') return error.UnexpectedCharacter;
383 return parseAfterScheme(text[0..end], text[end + 1 ..]);
377 const scheme, const rest = std.mem.cutScalar(u8, text, ':') orelse
378 return error.InvalidFormat;
379 if (!isValidScheme(scheme))
380 return error.UnexpectedCharacter;
381 return parseAfterScheme(scheme, rest);
384382}
385383
386384pub const ResolveInPlaceError = ParseError || error{NoSpaceLeft};
......@@ -522,11 +520,16 @@ fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Co
522520}
523521
524522/// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
525fn isSchemeChar(c: u8) bool {
526 return switch (c) {
527 'A'...'Z', 'a'...'z', '0'...'9', '+', '-', '.' => true,
528 else => false,
529 };
523fn isValidScheme(scheme: []const u8) bool {
524 if (scheme.len == 0) return false;
525 if (!std.ascii.isAlphabetic(scheme[0])) return false;
526 for (scheme[1..]) |byte| {
527 switch (byte) {
528 'A'...'Z', 'a'...'z', '0'...'9', '+', '-', '.' => continue,
529 else => return false,
530 }
531 }
532 return true;
530533}
531534
532535/// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
......@@ -620,6 +623,13 @@ test "scheme" {
620623 try std.testing.expectEqualStrings("ab+", (try parse("ab+:_")).scheme);
621624 try std.testing.expectEqualStrings("X+++", (try parse("X+++:_")).scheme);
622625 try std.testing.expectEqualStrings("Y+-.", (try parse("Y+-.:_")).scheme);
626
627 try std.testing.expectError(error.InvalidFormat, parse(""));
628 try std.testing.expectError(error.UnexpectedCharacter, parse(":"));
629 try std.testing.expectError(error.UnexpectedCharacter, parse("-:"));
630 try std.testing.expectError(error.UnexpectedCharacter, parse("+hTTp:"));
631 try std.testing.expectError(error.UnexpectedCharacter, parse("$:"));
632 try std.testing.expectError(error.UnexpectedCharacter, parse("h$:"));
623633}
624634
625635test "authority" {