diff options
| author | 2022-10-16 11:08:50 +0200 | |
|---|---|---|
| committer | 2022-10-16 11:08:50 +0200 | |
| commit | 0d79e465e6f01e51c5ddf26b40096e608b506d9b (patch) | |
| tree | 7bb1c46372139afb8795a30a6a8e41897689fa08 /xs_httpd.h | |
| parent | Replace %host% in greeting.html. (diff) | |
| download | snac2-0d79e465e6f01e51c5ddf26b40096e608b506d9b.tar.gz snac2-0d79e465e6f01e51c5ddf26b40096e608b506d9b.tar.xz snac2-0d79e465e6f01e51c5ddf26b40096e608b506d9b.zip | |
Use multipart/form-data for posts (on the way to supporting uploads).
Diffstat (limited to 'xs_httpd.h')
| -rw-r--r-- | xs_httpd.h | 108 |
1 files changed, 107 insertions, 1 deletions
| @@ -69,6 +69,109 @@ d_char *xs_url_vars(char *str) | |||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | 71 | ||
| 72 | d_char *_xs_multipart_form_data(char *payload, int p_size, char *header) | ||
| 73 | /* parses a multipart/form-data payload */ | ||
| 74 | { | ||
| 75 | d_char *p_vars = xs_dict_new(); | ||
| 76 | xs *boundary = NULL; | ||
| 77 | int offset = 0; | ||
| 78 | int bsz; | ||
| 79 | char *p; | ||
| 80 | |||
| 81 | /* build the boundary string */ | ||
| 82 | { | ||
| 83 | xs *l1 = xs_split(header, "="); | ||
| 84 | |||
| 85 | if (xs_list_len(l1) != 2) | ||
| 86 | return NULL; | ||
| 87 | |||
| 88 | boundary = xs_fmt("--%s", xs_list_get(l1, 1)); | ||
| 89 | } | ||
| 90 | |||
| 91 | bsz = strlen(boundary); | ||
| 92 | |||
| 93 | /* iterate searching the boundaries */ | ||
| 94 | while ((p = memmem(payload + offset, p_size - offset, boundary, bsz)) != NULL) { | ||
| 95 | xs *s1 = NULL; | ||
| 96 | xs *l1 = NULL; | ||
| 97 | char *vn = NULL; | ||
| 98 | char *fn = NULL; | ||
| 99 | char *q; | ||
| 100 | int po, ps; | ||
| 101 | |||
| 102 | /* final boundary? */ | ||
| 103 | p += bsz; | ||
| 104 | |||
| 105 | if (p[0] == '-' && p[1] == '-') | ||
| 106 | break; | ||
| 107 | |||
| 108 | /* skip the \r\n */ | ||
| 109 | p += 2; | ||
| 110 | |||
| 111 | /* now on a Content-Disposition... line; get it */ | ||
| 112 | q = strchr(p, '\r'); | ||
| 113 | s1 = xs_realloc(NULL, q - p + 1); | ||
| 114 | memcpy(s1, p, q - p); | ||
| 115 | s1[q - p] = '\0'; | ||
| 116 | |||
| 117 | /* move on (over a \r\n) */ | ||
| 118 | p = q; | ||
| 119 | |||
| 120 | /* split by " like a primitive man */ | ||
| 121 | l1 = xs_split(s1, "\""); | ||
| 122 | |||
| 123 | /* get the variable name */ | ||
| 124 | vn = xs_list_get(l1, 1); | ||
| 125 | |||
| 126 | /* is it an attached file? */ | ||
| 127 | if (xs_list_len(l1) >= 4 && strcmp(xs_list_get(l1, 2), "; filename=") == 0) { | ||
| 128 | /* get the file name */ | ||
| 129 | fn = xs_list_get(l1, 3); | ||
| 130 | } | ||
| 131 | |||
| 132 | /* find the start of the part content */ | ||
| 133 | if ((p = memmem(p, p_size - offset, "\r\n\r\n", 4)) == NULL) | ||
| 134 | break; | ||
| 135 | |||
| 136 | p += 4; | ||
| 137 | |||
| 138 | /* find the next boundary */ | ||
| 139 | if ((q = memmem(p, p_size - offset, boundary, bsz)) == NULL) | ||
| 140 | break; | ||
| 141 | |||
| 142 | po = p - payload; | ||
| 143 | ps = q - p - 2; /* - 2 because the final \r\n */ | ||
| 144 | |||
| 145 | /* is it a filename? */ | ||
| 146 | if (fn != NULL) { | ||
| 147 | /* p_var value is a list */ | ||
| 148 | xs *l1 = xs_list_new(); | ||
| 149 | xs *vpo = xs_number_new(po); | ||
| 150 | xs *vps = xs_number_new(ps); | ||
| 151 | |||
| 152 | l1 = xs_list_append(l1, fn); | ||
| 153 | l1 = xs_list_append(l1, vpo); | ||
| 154 | l1 = xs_list_append(l1, vps); | ||
| 155 | |||
| 156 | p_vars = xs_dict_append(p_vars, vn, l1); | ||
| 157 | } | ||
| 158 | else { | ||
| 159 | /* regular variable; just copy */ | ||
| 160 | xs *vc = xs_realloc(NULL, ps + 1); | ||
| 161 | memcpy(vc, payload + po, ps); | ||
| 162 | vc[ps] = '\0'; | ||
| 163 | |||
| 164 | p_vars = xs_dict_append(p_vars, vn, vc); | ||
| 165 | } | ||
| 166 | |||
| 167 | /* move on */ | ||
| 168 | offset = q - payload; | ||
| 169 | } | ||
| 170 | |||
| 171 | return p_vars; | ||
| 172 | } | ||
| 173 | |||
| 174 | |||
| 72 | d_char *xs_httpd_request(FILE *f, d_char **payload, int *p_size) | 175 | d_char *xs_httpd_request(FILE *f, d_char **payload, int *p_size) |
| 73 | /* processes an httpd connection */ | 176 | /* processes an httpd connection */ |
| 74 | { | 177 | { |
| @@ -131,7 +234,6 @@ d_char *xs_httpd_request(FILE *f, d_char **payload, int *p_size) | |||
| 131 | *payload = xs_read(f, p_size); | 234 | *payload = xs_read(f, p_size); |
| 132 | } | 235 | } |
| 133 | 236 | ||
| 134 | /* is the payload form urlencoded variables? */ | ||
| 135 | v = xs_dict_get(req, "content-type"); | 237 | v = xs_dict_get(req, "content-type"); |
| 136 | 238 | ||
| 137 | if (v && strcmp(v, "application/x-www-form-urlencoded") == 0) { | 239 | if (v && strcmp(v, "application/x-www-form-urlencoded") == 0) { |
| @@ -139,6 +241,10 @@ d_char *xs_httpd_request(FILE *f, d_char **payload, int *p_size) | |||
| 139 | p_vars = xs_url_vars(upl); | 241 | p_vars = xs_url_vars(upl); |
| 140 | } | 242 | } |
| 141 | else | 243 | else |
| 244 | if (v && xs_startswith(v, "multipart/form-data")) { | ||
| 245 | p_vars = _xs_multipart_form_data(*payload, *p_size, v); | ||
| 246 | } | ||
| 247 | else | ||
| 142 | p_vars = xs_dict_new(); | 248 | p_vars = xs_dict_new(); |
| 143 | 249 | ||
| 144 | req = xs_dict_append(req, "q_vars", q_vars); | 250 | req = xs_dict_append(req, "q_vars", q_vars); |