snac2

Fork of https://codeberg.org/grunfink/snac2
git clone https://git.inz.fi/snac2
Log | Files | Refs | README | LICENSE

commit 164a9b987fd3b349cc65c44daf819efc36e60e0d
parent de8fd8305396abd1e7e7208f443be4a4891219cd
Author: grunfink <grunfink@noreply.codeberg.org>
Date:   Thu,  6 Feb 2025 07:45:16 +0000

Merge pull request 'Rewrite query string decoding' (#299) from inz/snac2:qs-parse into master

Reviewed-on: https://codeberg.org/grunfink/snac2/pulls/299

Diffstat:
Mxs_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); } } }