From 0d79e465e6f01e51c5ddf26b40096e608b506d9b Mon Sep 17 00:00:00 2001 From: default Date: Sun, 16 Oct 2022 11:08:50 +0200 Subject: [PATCH] Use multipart/form-data for posts (on the way to supporting uploads). --- html.c | 7 ++-- xs_httpd.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++- xs_version.h | 2 +- 3 files changed, 111 insertions(+), 6 deletions(-) diff --git a/html.c b/html.c index 5673062..f4ecb8a 100644 --- a/html.c +++ b/html.c @@ -191,12 +191,12 @@ d_char *html_top_controls(snac *snac, d_char *s) "
\n" "
\n" - "
\n" + "\n" "\n" "\n" - "\n" - " %s

" + "

\n" + "

\n" "

\n" "

\n" @@ -244,7 +244,6 @@ d_char *html_top_controls(snac *snac, d_char *s) xs *s1 = xs_fmt(_tmpl, snac->actor, L("Post"), - L("Image to attach (URL)"), L("More options..."), diff --git a/xs_httpd.h b/xs_httpd.h index 68f60c4..ea56263 100644 --- a/xs_httpd.h +++ b/xs_httpd.h @@ -69,6 +69,109 @@ d_char *xs_url_vars(char *str) } +d_char *_xs_multipart_form_data(char *payload, int p_size, char *header) +/* parses a multipart/form-data payload */ +{ + d_char *p_vars = xs_dict_new(); + xs *boundary = NULL; + int offset = 0; + int bsz; + char *p; + + /* build the boundary string */ + { + xs *l1 = xs_split(header, "="); + + if (xs_list_len(l1) != 2) + return NULL; + + boundary = xs_fmt("--%s", xs_list_get(l1, 1)); + } + + bsz = strlen(boundary); + + /* iterate searching the boundaries */ + while ((p = memmem(payload + offset, p_size - offset, boundary, bsz)) != NULL) { + xs *s1 = NULL; + xs *l1 = NULL; + char *vn = NULL; + char *fn = NULL; + char *q; + int po, ps; + + /* final boundary? */ + p += bsz; + + if (p[0] == '-' && p[1] == '-') + break; + + /* skip the \r\n */ + p += 2; + + /* now on a Content-Disposition... line; get it */ + q = strchr(p, '\r'); + s1 = xs_realloc(NULL, q - p + 1); + memcpy(s1, p, q - p); + s1[q - p] = '\0'; + + /* move on (over a \r\n) */ + p = q; + + /* split by " like a primitive man */ + l1 = xs_split(s1, "\""); + + /* get the variable name */ + vn = xs_list_get(l1, 1); + + /* is it an attached file? */ + if (xs_list_len(l1) >= 4 && strcmp(xs_list_get(l1, 2), "; filename=") == 0) { + /* get the file name */ + fn = xs_list_get(l1, 3); + } + + /* find the start of the part content */ + if ((p = memmem(p, p_size - offset, "\r\n\r\n", 4)) == NULL) + break; + + p += 4; + + /* find the next boundary */ + if ((q = memmem(p, p_size - offset, boundary, bsz)) == NULL) + break; + + po = p - payload; + ps = q - p - 2; /* - 2 because the final \r\n */ + + /* is it a filename? */ + if (fn != NULL) { + /* p_var value is a list */ + xs *l1 = xs_list_new(); + xs *vpo = xs_number_new(po); + xs *vps = xs_number_new(ps); + + l1 = xs_list_append(l1, fn); + l1 = xs_list_append(l1, vpo); + l1 = xs_list_append(l1, vps); + + p_vars = xs_dict_append(p_vars, vn, l1); + } + else { + /* regular variable; just copy */ + xs *vc = xs_realloc(NULL, ps + 1); + memcpy(vc, payload + po, ps); + vc[ps] = '\0'; + + p_vars = xs_dict_append(p_vars, vn, vc); + } + + /* move on */ + offset = q - payload; + } + + return p_vars; +} + + d_char *xs_httpd_request(FILE *f, d_char **payload, int *p_size) /* processes an httpd connection */ { @@ -131,13 +234,16 @@ d_char *xs_httpd_request(FILE *f, d_char **payload, int *p_size) *payload = xs_read(f, p_size); } - /* is the payload form urlencoded variables? */ v = xs_dict_get(req, "content-type"); if (v && strcmp(v, "application/x-www-form-urlencoded") == 0) { xs *upl = xs_url_dec(*payload); p_vars = xs_url_vars(upl); } + else + if (v && xs_startswith(v, "multipart/form-data")) { + p_vars = _xs_multipart_form_data(*payload, *p_size, v); + } else p_vars = xs_dict_new(); diff --git a/xs_version.h b/xs_version.h index ca721ea..ad735a7 100644 --- a/xs_version.h +++ b/xs_version.h @@ -1 +1 @@ -/* b6512569814e4b409191a24193abe54d00427df2 */ +/* 639f769029cee785f4e854b66c695bbf84f016b9 */