diff options
| -rw-r--r-- | xs_url.h | 103 |
1 files changed, 69 insertions, 34 deletions
| @@ -11,6 +11,39 @@ xs_dict *xs_multipart_form_data(const char *payload, int p_size, const char *hea | |||
| 11 | 11 | ||
| 12 | #ifdef XS_IMPLEMENTATION | 12 | #ifdef XS_IMPLEMENTATION |
| 13 | 13 | ||
| 14 | char *xs_url_dec_in(char *str, int qs) | ||
| 15 | { | ||
| 16 | char *w = str; | ||
| 17 | char *r; | ||
| 18 | |||
| 19 | for (r = str; *r != '\0'; r++) { | ||
| 20 | switch (*r) { | ||
| 21 | case '%': { | ||
| 22 | unsigned hex; | ||
| 23 | if (!r[1] || !r[2]) | ||
| 24 | return NULL; | ||
| 25 | if (sscanf(r + 1, "%2x", &hex) != 1) | ||
| 26 | return NULL; | ||
| 27 | *w++ = hex; | ||
| 28 | r += 2; | ||
| 29 | break; | ||
| 30 | } | ||
| 31 | |||
| 32 | case '+': | ||
| 33 | if (qs) { | ||
| 34 | *w++ = ' '; | ||
| 35 | break; | ||
| 36 | } | ||
| 37 | /* fall-through */ | ||
| 38 | default: | ||
| 39 | *w++ = *r; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | *w++ = '\0'; | ||
| 44 | return str; | ||
| 45 | } | ||
| 46 | |||
| 14 | xs_str *xs_url_dec(const char *str) | 47 | xs_str *xs_url_dec(const char *str) |
| 15 | /* decodes an URL */ | 48 | /* decodes an URL */ |
| 16 | { | 49 | { |
| @@ -76,42 +109,44 @@ xs_dict *xs_url_vars(const char *str) | |||
| 76 | vars = xs_dict_new(); | 109 | vars = xs_dict_new(); |
| 77 | 110 | ||
| 78 | if (xs_is_string(str)) { | 111 | if (xs_is_string(str)) { |
| 79 | /* split by arguments */ | 112 | xs *dup = xs_dup(str); |
| 80 | xs *args = xs_split(str, "&"); | 113 | char *k; |
| 81 | 114 | char *saveptr; | |
| 82 | const xs_val *v; | 115 | for (k = strtok_r(dup, "&", &saveptr); |
| 83 | 116 | k; | |
| 84 | xs_list_foreach(args, v) { | 117 | k = strtok_r(NULL, "&", &saveptr)) { |
| 85 | xs *dv = xs_url_dec(v); | 118 | char *v = strchr(k, '='); |
| 86 | xs *kv = xs_split_n(dv, "=", 1); | 119 | if (!v) |
| 87 | 120 | continue; | |
| 88 | if (xs_list_len(kv) == 2) { | 121 | *v++ = '\0'; |
| 89 | const char *key = xs_list_get(kv, 0); | 122 | k = xs_url_dec_in(k, 1); |
| 90 | const char *pv = xs_dict_get(vars, key); | 123 | v = xs_url_dec_in(v, 1); |
| 91 | 124 | if (!xs_is_string(k) || !xs_is_string(v)) | |
| 92 | if (!xs_is_null(pv)) { | 125 | continue; |
| 93 | /* there is a previous value: convert to a list and append */ | 126 | |
| 94 | xs *vlist = NULL; | 127 | const char *pv = xs_dict_get(vars, k); |
| 95 | if (xs_type(pv) == XSTYPE_LIST) | 128 | if (!xs_is_null(pv)) { |
| 96 | vlist = xs_dup(pv); | 129 | /* there is a previous value: convert to a list and append */ |
| 97 | else { | 130 | xs *vlist = NULL; |
| 98 | vlist = xs_list_new(); | 131 | if (xs_type(pv) == XSTYPE_LIST) |
| 99 | vlist = xs_list_append(vlist, pv); | 132 | vlist = xs_dup(pv); |
| 100 | } | ||
| 101 | |||
| 102 | vlist = xs_list_append(vlist, xs_list_get(kv, 1)); | ||
| 103 | vars = xs_dict_set(vars, key, vlist); | ||
| 104 | } | ||
| 105 | else { | 133 | else { |
| 106 | /* ends with []? force to always be a list */ | 134 | vlist = xs_list_new(); |
| 107 | if (xs_endswith(key, "[]")) { | 135 | vlist = xs_list_append(vlist, pv); |
| 108 | xs *vlist = xs_list_new(); | 136 | } |
| 109 | vlist = xs_list_append(vlist, xs_list_get(kv, 1)); | 137 | |
| 110 | vars = xs_dict_append(vars, key, vlist); | 138 | vlist = xs_list_append(vlist, v); |
| 111 | } | 139 | vars = xs_dict_set(vars, k, vlist); |
| 112 | else | 140 | } |
| 113 | vars = xs_dict_append(vars, key, xs_list_get(kv, 1)); | 141 | else { |
| 142 | /* ends with []? force to always be a list */ | ||
| 143 | if (xs_endswith(k, "[]")) { | ||
| 144 | xs *vlist = xs_list_new(); | ||
| 145 | vlist = xs_list_append(vlist, v); | ||
| 146 | vars = xs_dict_append(vars, k, vlist); | ||
| 114 | } | 147 | } |
| 148 | else | ||
| 149 | vars = xs_dict_append(vars, k, v); | ||
| 115 | } | 150 | } |
| 116 | } | 151 | } |
| 117 | } | 152 | } |