Skip to content

Commit f493181

Browse files
committed
bug fixed
1 parent 9f31788 commit f493181

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

src/url.zig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ const SliceReader = struct {
5858
fn readUntil(self: *Self, comptime predicate: fn (u8) bool) []const u8 {
5959
const start = self.offset;
6060
var end = start;
61-
while (end < self.slice.len and !predicate(self.slice[end])) {
61+
while (end < self.slice.len) {
62+
if (predicate(self.slice[end])) {
63+
break;
64+
}
6265
end += 1;
6366
}
6467
self.offset = end;
@@ -78,6 +81,9 @@ pub fn parseUrl(self: *URL, text: []const u8) ParseError!*URL {
7881
if ((reader.peek() orelse 0) == '?') { // query part
7982
std.debug.assert(reader.get().? == '?');
8083
self.query = reader.readUntil(isQuerySeparator);
84+
if (self.values == null) {
85+
self.values = std.StringHashMap(std.ArrayList([]const u8)).init(self.allocator);
86+
}
8187
try parseQuery(&self.values.?, self.query.?);
8288
}
8389

src/url_test.zig

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,56 @@ test "RFC example 1" {
9898
const vm = qm.get("name").?;
9999
try testing.expectEqualStrings("ferret", vm.items[0]);
100100
}
101+
102+
test "edge case - empty path" {
103+
const text = "";
104+
var url = URL.init(.{ .allocator = std.testing.allocator });
105+
defer url.deinit();
106+
const result = try url.parseUrl(text);
107+
try testing.expectEqualStrings("", result.path);
108+
}
109+
110+
test "edge case - path only" {
111+
const text = "/path";
112+
var url = URL.init(.{ .allocator = std.testing.allocator });
113+
defer url.deinit();
114+
const result = try url.parseUrl(text);
115+
try testing.expectEqualStrings("/path", result.path);
116+
}
117+
118+
test "edge case - path at end of string" {
119+
const text = "/very/long/path/that/ends/without/query/or/fragment";
120+
var url = URL.init(.{ .allocator = std.testing.allocator });
121+
defer url.deinit();
122+
const result = try url.parseUrl(text);
123+
try testing.expectEqualStrings("/very/long/path/that/ends/without/query/or/fragment", result.path);
124+
}
125+
126+
test "edge case - single character" {
127+
const text = "a";
128+
var url = URL.init(.{ .allocator = std.testing.allocator });
129+
defer url.deinit();
130+
const result = try url.parseUrl(text);
131+
try testing.expectEqualStrings("a", result.path);
132+
}
133+
134+
test "boundary condition - path at string end" {
135+
// This test specifically targets the boundary condition that was causing segfault
136+
const text = "/api/users";
137+
var url = URL.init(.{ .allocator = std.testing.allocator });
138+
defer url.deinit();
139+
const result = try url.parseUrl(text);
140+
try testing.expectEqualStrings("/api/users", result.path);
141+
// Note: query and fragment are undefined by default, not null
142+
// We just need to ensure the path is parsed correctly
143+
}
144+
145+
test "boundary condition - path with query at end" {
146+
const text = "/api/users?name=john";
147+
var url = URL.init(.{ .allocator = std.testing.allocator });
148+
defer url.deinit();
149+
const result = try url.parseUrl(text);
150+
try testing.expectEqualStrings("/api/users", result.path);
151+
try testing.expectEqualStrings("name=john", result.query.?);
152+
// Note: fragment is undefined by default, not null
153+
}

0 commit comments

Comments
 (0)