From e95c656d9aac7bea3c9b265ab08114888cd9717c Mon Sep 17 00:00:00 2001 From: skdishansachin Date: Sat, 4 Jul 2026 08:11:51 +0000 Subject: [PATCH] Uri: use findLast for @ delimiter in authority parsing --- lib/std/Uri.zig | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index 831c4fb282719881b8e436cfb4ffe074f79f14b7..416a5cf16150e421759290f2c73c56bf163774f4 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -191,7 +191,11 @@ pub fn parseAfterScheme(scheme: []const u8, text: []const u8) ParseError!Uri { } var start_of_host: usize = 0; - if (std.mem.find(u8, authority, "@")) |index| { + // Use findLast to handle unencoded @ in userinfo gracefully, + // e.g. scheme://user:p@ssword@hostname. This deviates from RFC3986 + // (which requires @ to be percent-encoded as %40 in userinfo) but + // is more robust against URIs in the wild. + if (std.mem.findLast(u8, authority, "@")) |index| { start_of_host = index + 1; const user_info = authority[0..index]; @@ -621,6 +625,23 @@ test "authority" { try std.testing.expectEqual(@as(u16, 1234), (try parse("scheme://user:password@hostname:1234")).port.?); try std.testing.expectEqualStrings("user", (try parse("scheme://user:password@hostname:1234")).user.?.percent_encoded); try std.testing.expectEqualStrings("password", (try parse("scheme://user:password@hostname:1234")).password.?.percent_encoded); + + try std.testing.expectEqualStrings("user", (try parse("scheme://user:p@ssword@hostname:1234")).user.?.percent_encoded); + try std.testing.expectEqualStrings("p@ssword", (try parse("scheme://user:p@ssword@hostname:1234")).password.?.percent_encoded); + try std.testing.expectEqualStrings("hostname", (try parse("scheme://user:p@ssword@hostname:1234")).host.?.percent_encoded); + + try std.testing.expectEqualStrings("user", (try parse("scheme://user:p@@@word@hostname:1234")).user.?.percent_encoded); + try std.testing.expectEqualStrings("p@@@word", (try parse("scheme://user:p@@@word@hostname:1234")).password.?.percent_encoded); + try std.testing.expectEqualStrings("hostname", (try parse("scheme://user:p@@@word@hostname:1234")).host.?.percent_encoded); + + try std.testing.expectEqualStrings("user@name", (try parse("scheme://user@name@hostname")).user.?.percent_encoded); + try std.testing.expectEqual(@as(?Component, null), (try parse("scheme://user@name@hostname")).password); + try std.testing.expectEqualStrings("hostname", (try parse("scheme://user@name@hostname")).host.?.percent_encoded); + + try std.testing.expectEqualStrings("user@name", (try parse("scheme://user@name@hostname:1234")).user.?.percent_encoded); + try std.testing.expectEqual(@as(?Component, null), (try parse("scheme://user@name@hostname:1234")).password); + try std.testing.expectEqualStrings("hostname", (try parse("scheme://user@name@hostname:1234")).host.?.percent_encoded); + try std.testing.expectEqual(@as(u16, 1234), (try parse("scheme://user@name@hostname:1234")).port.?); } test "authority.password" { -- 2.54.0