From 121f51ac44276ce2744e91bc589e9dc78d3ffd3b Mon Sep 17 00:00:00 2001 Message-Id: <121f51ac44276ce2744e91bc589e9dc78d3ffd3b.1714815087.git.mdw@distorted.org.uk> From: Mark Wooding Date: Thu, 10 Jan 2008 20:40:31 +0000 Subject: [PATCH] MIME parsing test. Organization: Straylight/Edgeware From: Richard Kettlewell --- lib/mime.c | 132 +++++++++++++++++++++++++++++++++++---------------- lib/t-mime.c | 58 ++++++++++++++++++++++ 2 files changed, 150 insertions(+), 40 deletions(-) diff --git a/lib/mime.c b/lib/mime.c index 90372c9..0e7d097 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -134,12 +134,14 @@ static const char *skipwhite(const char *s, int rfc822_comments) { case '(': ++depth; break; case ')': --depth; break; case '\\': - if(!*s) return 0; + if(!*s) + return 0; ++s; break; } } - if(depth) return 0; + if(depth) + return 0; break; default: return s; @@ -175,13 +177,15 @@ static const char *parseword(const char *s, char **valuep, while((c = *s++) != '"') { switch(c) { case '\\': - if(!(c = *s++)) return 0; + if(!(c = *s++)) + return 0; default: dynstr_append(value, c); break; } } - if(!c) return 0; + if(!c) + return 0; } else { if(!iswordchar((unsigned char)*s, special)) return NULL; @@ -202,7 +206,8 @@ static const char *parseword(const char *s, char **valuep, */ static const char *parsetoken(const char *s, char **valuep, int (*special)(int)) { - if(*s == '"') return 0; + if(*s == '"') + return 0; return parseword(s, valuep, special); } @@ -222,30 +227,43 @@ int mime_content_type(const char *s, char *parametervalue; dynstr_init(&type); - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&type, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; - if(*s++ != '/') return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(*s++ != '/') + return -1; dynstr_append(&type, '/'); - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&type, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; while(*s == ';') { dynstr_init(¶metername); ++s; - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(¶metername, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; - if(*s++ != '=') return -1; - if(!(s = skipwhite(s, 1))) return -1; - if(!(s = parseword(s, ¶metervalue, tspecial))) return -1; - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(*s++ != '=') + return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!(s = parseword(s, ¶metervalue, tspecial))) + return -1; + if(!(s = skipwhite(s, 1))) + return -1; dynstr_terminate(¶metername); kvp_set(¶meters, parametername.vec, parametervalue); } @@ -278,12 +296,25 @@ const char *mime_parse(const char *s, dynstr_init(&value); while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&name, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return 0; - if(*s != ':') return 0; + if(!(s = skipwhite(s, 1))) + return 0; + if(*s != ':') + return 0; ++s; - while(*s && !(*s == '\n' && !(s[1] == ' ' || s[1] == '\t'))) - dynstr_append(&value, *s++); - if(*s) ++s; + while(*s && !(*s == '\n' && !(s[1] == ' ' || s[1] == '\t'))) { + const int c = *s++; + /* Strip leading whitespace */ + if(value.nvec || !(c == ' ' || c == '\t' || c == '\n' || c == '\r')) + dynstr_append(&value, c); + } + /* Strip trailing whitespace */ + while(value.nvec > 0 && (value.vec[value.nvec - 1] == ' ' + || value.vec[value.nvec - 1] == '\t' + || value.vec[value.nvec - 1] == '\n' + || value.vec[value.nvec - 1] == '\r')) + --value.nvec; + if(*s) + ++s; dynstr_terminate(&name); dynstr_terminate(&value); if(!strcmp(name.vec, "content-transfer-encoding")) { @@ -291,12 +322,20 @@ const char *mime_parse(const char *s, for(p = cte; *p; p++) *p = tolower((unsigned char)*p); } - if(callback(name.vec, value.vec, u)) return 0; + if(callback(name.vec, value.vec, u)) + return 0; } - if(*s) s += 2; + if(*s) + s += 2; if(cte) { - if(!strcmp(cte, "base64")) return mime_base64(s, 0); - if(!strcmp(cte, "quoted-printable")) return mime_qp(s); + if(!strcmp(cte, "base64")) + return mime_base64(s, 0); + if(!strcmp(cte, "quoted-printable")) + return mime_qp(s); + if(!strcmp(cte, "7bit") || !strcmp(cte, "8bit")) + return s; + error(0, "unknown content-transfer-encoding '%s'", cte); + return 0; } return s; } @@ -378,24 +417,34 @@ int mime_rfc2388_content_disposition(const char *s, struct dynstr disposition, parametername; dynstr_init(&disposition); - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(&disposition, tolower((unsigned char)*s++)); - if(!(s = skipwhite(s, 1))) return -1; + if(!(s = skipwhite(s, 1))) + return -1; if(*s == ';') { dynstr_init(¶metername); ++s; - if(!(s = skipwhite(s, 1))) return -1; - if(!*s) return -1; + if(!(s = skipwhite(s, 1))) + return -1; + if(!*s) + return -1; while(*s && !tspecial(*s) && !whitespace(*s)) dynstr_append(¶metername, tolower((unsigned 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 = skipwhite(s, 1))) return -1; + 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 = skipwhite(s, 1))) + return -1; dynstr_terminate(¶metername); *parameternamep = parametername.vec; } else @@ -474,11 +523,14 @@ int parse_cookie(const char *s, s = skipwhite(s, 0); continue; } - if(!(s = parsetoken(s, &n, http_separator))) return -1; + if(!(s = parsetoken(s, &n, http_separator))) + return -1; s = skipwhite(s, 0); - if(*s++ != '=') return -1; + if(*s++ != '=') + return -1; s = skipwhite(s, 0); - if(!(s = parseword(s, &v, http_separator))) return -1; + if(!(s = parseword(s, &v, http_separator))) + return -1; if(n[0] == '$') { /* Some bit of meta-information */ if(!strcmp(n, "$Version")) diff --git a/lib/t-mime.c b/lib/t-mime.c index 882d186..05ae8b5 100644 --- a/lib/t-mime.c +++ b/lib/t-mime.c @@ -26,10 +26,20 @@ static int test_multipart_callback(const char *s, void *u) { return 0; } +static int header_callback(const char *name, const char *value, + void *u) { + hash *const h = u; + + hash_add(h, name, &value, HASH_INSERT); + return 0; +} + void test_mime(void) { char *t, *n, *v; struct vector parts[1]; struct kvp *k; + const char *s; + hash *h; fprintf(stderr, "test_mime\n"); @@ -250,6 +260,54 @@ void test_mime(void) { /* Not actually valid base64 */ check_string(mime_base64("BBBBx=", 0), "\x04\x10\x41"); + + h = hash_new(sizeof (char *)); + s = mime_parse("From: sender@example.com\r\n" + "To: rcpt@example.com\r\n" + "Subject: test #1\r\n" + "\r\n" + "body\r\n", + header_callback, h); + insist(s != 0); + check_string(*(char **)hash_find(h, "from"), "sender@example.com"); + check_string(*(char **)hash_find(h, "to"), "rcpt@example.com"); + check_string(*(char **)hash_find(h, "subject"), "test #1"); + check_string(s, "body\r\n"); + + h = hash_new(sizeof (char *)); + s = mime_parse("FROM: sender@example.com\r\n" + "TO: rcpt@example.com\r\n" + "SUBJECT: test #1\r\n" + "CONTENT-TRANSFER-ENCODING: 7bit\r\n" + "\r\n" + "body\r\n", + header_callback, h); + insist(s != 0); + check_string(*(char **)hash_find(h, "from"), "sender@example.com"); + check_string(*(char **)hash_find(h, "to"), "rcpt@example.com"); + check_string(*(char **)hash_find(h, "subject"), "test #1"); + check_string(*(char **)hash_find(h, "content-transfer-encoding"), "7bit"); + check_string(s, "body\r\n"); + + h = hash_new(sizeof (char *)); + s = mime_parse("From: sender@example.com\r\n" + "To: \r\n" + " rcpt@example.com\r\n" + "Subject: test #1\r\n" + "MIME-Version: 1.0\r\n" + "Content-Type: text/plain\r\n" + "Content-Transfer-Encoding: BASE64\r\n" + "\r\n" + "d2liYmxlDQo=\r\n", + header_callback, h); + insist(s != 0); + check_string(*(char **)hash_find(h, "from"), "sender@example.com"); + check_string(*(char **)hash_find(h, "to"), "rcpt@example.com"); + check_string(*(char **)hash_find(h, "subject"), "test #1"); + check_string(*(char **)hash_find(h, "mime-version"), "1.0"); + check_string(*(char **)hash_find(h, "content-type"), "text/plain"); + check_string(*(char **)hash_find(h, "content-transfer-encoding"), "BASE64"); + check_string(s, "wibble\r\n"); } /* -- [mdw]