From 9bce81d175de1bc9aa90a4fbf24e3121ea294fa6 Mon Sep 17 00:00:00 2001 Message-Id: <9bce81d175de1bc9aa90a4fbf24e3121ea294fa6.1715359746.git.mdw@distorted.org.uk> From: Mark Wooding Date: Sun, 6 Jan 2008 12:39:13 +0000 Subject: [PATCH] Fix mime_content_type() to not be so lazy; now it copes with arbitrary parameters rather than just one that has to be the right one. This gets the web interface working on Opera (for Mac). Organization: Straylight/Edgeware From: rjk@greenend.org.uk <> --- lib/mime.c | 19 ++++++++++--------- lib/mime.h | 9 +++------ lib/test.c | 43 +++++++++++++++++++++++++------------------ server/cgi.c | 14 +++++++------- 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/lib/mime.c b/lib/mime.c index 8776647..90372c9 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -35,6 +35,7 @@ #include "hex.h" #include "log.h" #include "base64.h" +#include "kvp.h" /** @brief Match whitespace characters */ static int whitespace(int c) { @@ -208,17 +209,17 @@ static const char *parsetoken(const char *s, char **valuep, /** @brief Parse a MIME content-type field * @param s Start of field * @param typep Where to store type - * @param parameternamep Where to store parameter name - * @param parametervaluep Wher to store parameter value + * @param parametersp Where to store parameter list * @return 0 on success, non-0 on error * * See RFC 2045 s5. */ int mime_content_type(const char *s, char **typep, - char **parameternamep, - char **parametervaluep) { + struct kvp **parametersp) { struct dynstr type, parametername; + struct kvp *parameters = 0; + char *parametervalue; dynstr_init(&type); if(!(s = skipwhite(s, 1))) return -1; @@ -233,7 +234,7 @@ int mime_content_type(const char *s, dynstr_append(&type, tolower((unsigned char)*s++)); if(!(s = skipwhite(s, 1))) return -1; - if(*s == ';') { + while(*s == ';') { dynstr_init(¶metername); ++s; if(!(s = skipwhite(s, 1))) return -1; @@ -243,14 +244,14 @@ int mime_content_type(const char *s, if(!(s = skipwhite(s, 1))) return -1; if(*s++ != '=') return -1; if(!(s = skipwhite(s, 1))) return -1; - if(!(s = parseword(s, parametervaluep, tspecial))) return -1; + if(!(s = parseword(s, ¶metervalue, tspecial))) return -1; if(!(s = skipwhite(s, 1))) return -1; dynstr_terminate(¶metername); - *parameternamep = parametername.vec; - } else - *parametervaluep = *parameternamep = 0; + kvp_set(¶meters, parametername.vec, parametervalue); + } dynstr_terminate(&type); *typep = type.vec; + *parametersp = parameters; return 0; } diff --git a/lib/mime.h b/lib/mime.h index b863f4a..d9c28ac 100644 --- a/lib/mime.h +++ b/lib/mime.h @@ -24,14 +24,11 @@ #ifndef MIME_H #define MIME_H +struct kvp; + int mime_content_type(const char *s, char **typep, - char **parameternamep, - char **parametervaluep); -/* Parse a content-type value. returns 0 on success, -1 on error. - * paramaternamep and parametervaluep are only set if present. - * type and parametername are forced to lower case. - */ + struct kvp **parametersp); const char *mime_parse(const char *s, int (*callback)(const char *name, const char *value, diff --git a/lib/test.c b/lib/test.c index 27651ec..a105713 100644 --- a/lib/test.c +++ b/lib/test.c @@ -297,35 +297,42 @@ static int test_multipart_callback(const char *s, void *u) { static void test_mime(void) { char *t, *n, *v; struct vector parts[1]; + struct kvp *k; fprintf(stderr, "test_mime\n"); - t = n = v = 0; - insist(!mime_content_type("text/plain", &t, &n, &v)); + t = 0; + k = 0; + insist(!mime_content_type("text/plain", &t, &k)); check_string(t, "text/plain"); - insist(n == 0); - insist(v == 0); + insist(k == 0); - insist(mime_content_type("TEXT ((broken) comment", &t, &n, &v) < 0); - insist(mime_content_type("TEXT ((broken) comment\\", &t, &n, &v) < 0); + insist(mime_content_type("TEXT ((broken) comment", &t, &k) < 0); + insist(mime_content_type("TEXT ((broken) comment\\", &t, &k) < 0); - t = n = v = 0; - insist(!mime_content_type("TEXT ((nested)\\ comment) /plain", &t, &n, &v)); + t = 0; + k = 0; + insist(!mime_content_type("TEXT ((nested)\\ comment) /plain", &t, &k)); check_string(t, "text/plain"); - insist(n == 0); - insist(v == 0); + insist(k == 0); - t = n = v = 0; - insist(!mime_content_type(" text/plain ; Charset=\"utf-\\8\"", &t, &n, &v)); + t = 0; + k = 0; + insist(!mime_content_type(" text/plain ; Charset=\"utf-\\8\"", &t, &k)); check_string(t, "text/plain"); - check_string(n, "charset"); - check_string(v, "utf-8"); + insist(k != 0); + insist(k->next == 0); + check_string(k->name, "charset"); + check_string(k->value, "utf-8"); - t = n = v = 0; - insist(!mime_content_type("text/plain;charset = ISO-8859-1 ", &t, &n, &v)); + t = 0; + k = 0; + insist(!mime_content_type("text/plain;charset = ISO-8859-1 ", &t, &k)); + insist(k != 0); + insist(k->next == 0); check_string(t, "text/plain"); - check_string(n, "charset"); - check_string(v, "ISO-8859-1"); + check_string(k->name, "charset"); + check_string(k->value, "ISO-8859-1"); t = n = v = 0; insist(!mime_rfc2388_content_disposition("form-data; name=\"field1\"", &t, &n, &v)); diff --git a/server/cgi.c b/server/cgi.c index 5abf145..095611a 100644 --- a/server/cgi.c +++ b/server/cgi.c @@ -152,13 +152,14 @@ static void cgi_parse_multipart(const char *boundary) { } static void cgi_parse_post(void) { - const char *ct; - char *q, *type, *pname, *pvalue; + const char *ct, *boundary; + char *q, *type; size_t n; + struct kvp *k; if(!(ct = getenv("CONTENT_TYPE"))) ct = "application/x-www-form-urlencoded"; - if(mime_content_type(ct, &type, &pname, &pvalue)) + if(mime_content_type(ct, &type, &k)) fatal(0, "invalid content type '%s'", ct); if(!strcmp(type, "application/x-www-form-urlencoded")) { cgi_input(&q, &n); @@ -166,10 +167,9 @@ static void cgi_parse_post(void) { return; } if(!strcmp(type, "multipart/form-data")) { - if(!pname || strcmp(pname, "boundary")) - fatal(0, "expected a boundary parameter, found %s", - pname ? pname : "nothing"); - cgi_parse_multipart(pvalue); + if(!(boundary = kvp_get(k, "boundary"))) + fatal(0, "no boundary parameter found"); + cgi_parse_multipart(boundary); return; } fatal(0, "unrecognized content type '%s'", type); -- [mdw]