chiark / gitweb /
Fix mime_content_type() to not be so lazy; now it copes with arbitrary
authorrjk@greenend.org.uk <>
Sun, 6 Jan 2008 12:39:13 +0000 (12:39 +0000)
committerrjk@greenend.org.uk <>
Sun, 6 Jan 2008 12:39:13 +0000 (12:39 +0000)
parameters rather than just one that has to be the right one.  This
gets the web interface working on Opera (for Mac).

lib/mime.c
lib/mime.h
lib/test.c
server/cgi.c

index 87766472f52ab59f1a6683f1a534ea513d50adac..90372c932a0d46a8cbce4a3cfa8b6b38d074b134 100644 (file)
@@ -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 <a href="http://tools.ietf.org/html/rfc2045#section-5">RFC 2045 s5</a>.
  */
 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(&parametername);
     ++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, &parametervalue, tspecial))) return -1;
     if(!(s = skipwhite(s, 1))) return -1;
     dynstr_terminate(&parametername);
-    *parameternamep = parametername.vec;
-  } else
-    *parametervaluep = *parameternamep = 0;
+    kvp_set(&parameters, parametername.vec, parametervalue);
+  }
   dynstr_terminate(&type);
   *typep = type.vec;
+  *parametersp = parameters;
   return 0;
 }
 
index b863f4abb6695f8d9cdeaed4ec3ec74edcea3533..d9c28ac90bf3abc51cd775bf56b6d96647ba3adb 100644 (file)
 #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,
index 27651ec1cedf84e9b6db03c779f4209e87f21b11..a10571342947db4e17593ae681f3bf612da6a9ed 100644 (file)
@@ -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));
index 5abf145f0bffc0569082f22223345d382f6134d3..095611ab81dee8269e19b89228827616e6f1a6c5 100644 (file)
@@ -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);