commit 0155ccfa5280b8e95aca8f085bd3114213d506a6
parent de8fd8305396abd1e7e7208f443be4a4891219cd
Author: Santtu Lakkala <inz@inz.fi>
Date: Thu, 6 Feb 2025 00:47:23 +0200
Rewrite query string decoding
Diffstat:
M | xs_url.h | | | 103 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
1 file changed, 69 insertions(+), 34 deletions(-)
diff --git a/xs_url.h b/xs_url.h
@@ -11,6 +11,39 @@ xs_dict *xs_multipart_form_data(const char *payload, int p_size, const char *hea
#ifdef XS_IMPLEMENTATION
+char *xs_url_dec_in(char *str, int qs)
+{
+ char *w = str;
+ char *r;
+
+ for (r = str; *r != '\0'; r++) {
+ switch (*r) {
+ case '%': {
+ unsigned hex;
+ if (!r[1] || !r[2])
+ return NULL;
+ if (sscanf(r + 1, "%2x", &hex) != 1)
+ return NULL;
+ *w++ = hex;
+ r += 2;
+ break;
+ }
+
+ case '+':
+ if (qs) {
+ *w++ = ' ';
+ break;
+ }
+ /* fall-through */
+ default:
+ *w++ = *r;
+ }
+ }
+
+ *w++ = '\0';
+ return str;
+}
+
xs_str *xs_url_dec(const char *str)
/* decodes an URL */
{
@@ -76,42 +109,44 @@ xs_dict *xs_url_vars(const char *str)
vars = xs_dict_new();
if (xs_is_string(str)) {
- /* split by arguments */
- xs *args = xs_split(str, "&");
-
- const xs_val *v;
-
- xs_list_foreach(args, v) {
- xs *dv = xs_url_dec(v);
- xs *kv = xs_split_n(dv, "=", 1);
-
- if (xs_list_len(kv) == 2) {
- const char *key = xs_list_get(kv, 0);
- const char *pv = xs_dict_get(vars, key);
-
- if (!xs_is_null(pv)) {
- /* there is a previous value: convert to a list and append */
- xs *vlist = NULL;
- if (xs_type(pv) == XSTYPE_LIST)
- vlist = xs_dup(pv);
- else {
- vlist = xs_list_new();
- vlist = xs_list_append(vlist, pv);
- }
-
- vlist = xs_list_append(vlist, xs_list_get(kv, 1));
- vars = xs_dict_set(vars, key, vlist);
- }
+ xs *dup = xs_dup(str);
+ char *k;
+ char *saveptr;
+ for (k = strtok_r(dup, "&", &saveptr);
+ k;
+ k = strtok_r(NULL, "&", &saveptr)) {
+ char *v = strchr(k, '=');
+ if (!v)
+ continue;
+ *v++ = '\0';
+ k = xs_url_dec_in(k, 1);
+ v = xs_url_dec_in(v, 1);
+ if (!xs_is_string(k) || !xs_is_string(v))
+ continue;
+
+ const char *pv = xs_dict_get(vars, k);
+ if (!xs_is_null(pv)) {
+ /* there is a previous value: convert to a list and append */
+ xs *vlist = NULL;
+ if (xs_type(pv) == XSTYPE_LIST)
+ vlist = xs_dup(pv);
else {
- /* ends with []? force to always be a list */
- if (xs_endswith(key, "[]")) {
- xs *vlist = xs_list_new();
- vlist = xs_list_append(vlist, xs_list_get(kv, 1));
- vars = xs_dict_append(vars, key, vlist);
- }
- else
- vars = xs_dict_append(vars, key, xs_list_get(kv, 1));
+ vlist = xs_list_new();
+ vlist = xs_list_append(vlist, pv);
+ }
+
+ vlist = xs_list_append(vlist, v);
+ vars = xs_dict_set(vars, k, vlist);
+ }
+ else {
+ /* ends with []? force to always be a list */
+ if (xs_endswith(k, "[]")) {
+ xs *vlist = xs_list_new();
+ vlist = xs_list_append(vlist, v);
+ vars = xs_dict_append(vars, k, vlist);
}
+ else
+ vars = xs_dict_append(vars, k, v);
}
}
}