url: search query dynamic and encoded

This commit is contained in:
Pierre Tachoire
2024-05-06 16:32:20 +02:00
parent a9842fd790
commit d0c741f3bb
2 changed files with 77 additions and 8 deletions

View File

@@ -79,19 +79,42 @@ pub const Values = struct {
pub fn deleteValue(self: *Values, k: []const u8, v: []const u8) void {
const list = self.map.getPtr(k) orelse return;
var i: usize = 0;
while (i < list.items.len) {
if (std.mem.eql(u8, v, list.items[i])) {
for (list.items, 0..) |vv, i| {
if (std.mem.eql(u8, v, vv)) {
_ = list.swapRemove(i);
return;
}
i += 1;
}
}
pub fn count(self: *Values) usize {
return self.map.count();
}
// the caller owned the returned string.
pub fn encode(self: *Values, writer: anytype) !void {
var i: usize = 0;
var it = self.map.iterator();
while (it.next()) |entry| {
defer i += 1;
if (i > 0) try writer.writeByte('&');
if (entry.value_ptr.items.len == 0) {
try escape(writer, entry.key_ptr.*);
continue;
}
const start = i;
for (entry.value_ptr.items) |v| {
defer i += 1;
if (start < i) try writer.writeByte('&');
try escape(writer, entry.key_ptr.*);
if (v.len > 0) try writer.writeByte('=');
try escape(writer, v);
}
}
}
};
fn unhex(c: u8) u8 {
@@ -137,6 +160,19 @@ test "unescape" {
alloc.free(v);
}
pub fn escape(writer: anytype, raw: []const u8) !void {
var start: usize = 0;
for (raw, 0..) |char, index| {
if ('a' <= char and char <= 'z' or 'A' <= char and char <= 'Z' or '0' <= char and char <= '9') {
continue;
}
try writer.print("{s}%{X:0>2}", .{ raw[start..index], char });
start = index + 1;
}
try writer.writeAll(raw[start..]);
}
// Parse the given query.
pub fn parseQuery(alloc: std.mem.Allocator, s: []const u8) !Values {
var values = Values.init(alloc);
@@ -213,3 +249,17 @@ test "parse query dup" {
try std.testing.expect(std.mem.eql(u8, values.first("a"), "b"));
try std.testing.expect(values.get("a").len == 2);
}
test "encode query" {
var values = try parseQuery(std.testing.allocator, "a=b&b=c");
defer values.deinit();
try values.append("a", "~");
var buf: std.ArrayListUnmanaged(u8) = .{};
defer buf.deinit(std.testing.allocator);
try values.encode(buf.writer(std.testing.allocator));
try std.testing.expect(std.mem.eql(u8, buf.items, "a=b&a=%7E&b=c"));
}