@@ -41,6 +41,17 @@ pub const Values = struct {
4141 try self .map .put (self .alloc , kk , list );
4242 }
4343
44+ // append by taking the ownership of the key and the value
45+ fn appendOwned (self : * Values , k : []const u8 , v : []const u8 ) ! void {
46+ if (self .map .getPtr (k )) | list | {
47+ return try list .append (self .alloc , v );
48+ }
49+
50+ var list = List {};
51+ try list .append (self .alloc , v );
52+ try self .map .put (self .alloc , k , list );
53+ }
54+
4455 pub fn get (self : * Values , k : []const u8 ) [][]const u8 {
4556 if (self .map .get (k )) | list | {
4657 return list .items ;
@@ -83,6 +94,49 @@ pub const Values = struct {
8394 }
8495};
8596
97+ fn unhex (c : u8 ) u8 {
98+ if ('0' <= c and c <= '9' ) return c - '0' ;
99+ if ('a' <= c and c <= 'f' ) return c - 'a' + 10 ;
100+ if ('A' <= c and c <= 'F' ) return c - 'A' + 10 ;
101+ return 0 ;
102+ }
103+
104+ // unescape decodes a percent encoded string.
105+ // The caller owned the returned string.
106+ pub fn unescape (alloc : std.mem.Allocator , s : []const u8 ) ! []const u8 {
107+ var buf : std .ArrayListUnmanaged (u8 ) = .{};
108+ defer buf .deinit (alloc );
109+
110+ var i : usize = 0 ;
111+ while (i < s .len ) {
112+ defer i += 1 ;
113+
114+ switch (s [i ]) {
115+ '%' = > {
116+ if (i + 2 > s .len ) return error .EscapeError ;
117+ if (! std .ascii .isHex (s [i + 1 ])) return error .EscapeError ;
118+ if (! std .ascii .isHex (s [i + 2 ])) return error .EscapeError ;
119+
120+ try buf .append (alloc , unhex (s [i + 1 ]) << 4 | unhex (s [i + 2 ]));
121+ i += 2 ;
122+ },
123+ '+' = > try buf .append (alloc , ' ' ), // TODO should we decode or keep as it?
124+ else = > try buf .append (alloc , s [i ]),
125+ }
126+ }
127+
128+ return try buf .toOwnedSlice (alloc );
129+ }
130+
131+ test "unescape" {
132+ var v : []const u8 = undefined ;
133+ const alloc = std .testing .allocator ;
134+
135+ v = try unescape (alloc , "%7E" );
136+ try std .testing .expect (std .mem .eql (u8 , "~" , v ));
137+ alloc .free (v );
138+ }
139+
86140// Parse the given query.
87141pub fn parseQuery (alloc : std.mem.Allocator , s : []const u8 ) ! Values {
88142 var values = Values .init (alloc );
@@ -103,9 +157,11 @@ pub fn parseQuery(alloc: std.mem.Allocator, s: []const u8) !Values {
103157 _ = rr .skip ();
104158 const v = rr .tail ();
105159
106- // TODO decode k and v
160+ // decode k and v
161+ const kk = try unescape (alloc , k );
162+ const vv = try unescape (alloc , v );
107163
108- try values .append ( k , v );
164+ try values .appendOwned ( kk , vv );
109165
110166 if (! r .skip ()) break ;
111167 }
0 commit comments