|
@@ -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);
|
|
|
}
|
|
|
}
|
|
|
}
|