| 1 | /* |
| 2 | * This file is part of DisOrder. |
| 3 | * Copyright (C) 2005, 2007, 2008 Richard Kettlewell |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 2 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, but |
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| 18 | * USA |
| 19 | */ |
| 20 | #include "test.h" |
| 21 | |
| 22 | static int test_multipart_callback(const char *s, void *u) { |
| 23 | struct vector *parts = u; |
| 24 | |
| 25 | vector_append(parts, (char *)s); |
| 26 | return 0; |
| 27 | } |
| 28 | |
| 29 | void test_mime(void) { |
| 30 | char *t, *n, *v; |
| 31 | struct vector parts[1]; |
| 32 | struct kvp *k; |
| 33 | |
| 34 | fprintf(stderr, "test_mime\n"); |
| 35 | |
| 36 | t = 0; |
| 37 | k = 0; |
| 38 | insist(!mime_content_type("text/plain", &t, &k)); |
| 39 | check_string(t, "text/plain"); |
| 40 | insist(k == 0); |
| 41 | |
| 42 | insist(mime_content_type("TEXT ((broken) comment", &t, &k) < 0); |
| 43 | insist(mime_content_type("TEXT ((broken) comment\\", &t, &k) < 0); |
| 44 | |
| 45 | t = 0; |
| 46 | k = 0; |
| 47 | insist(!mime_content_type("TEXT ((nested)\\ comment) /plain", &t, &k)); |
| 48 | check_string(t, "text/plain"); |
| 49 | insist(k == 0); |
| 50 | |
| 51 | t = 0; |
| 52 | k = 0; |
| 53 | insist(!mime_content_type(" text/plain ; Charset=\"utf-\\8\"", &t, &k)); |
| 54 | check_string(t, "text/plain"); |
| 55 | insist(k != 0); |
| 56 | insist(k->next == 0); |
| 57 | check_string(k->name, "charset"); |
| 58 | check_string(k->value, "utf-8"); |
| 59 | |
| 60 | t = 0; |
| 61 | k = 0; |
| 62 | insist(!mime_content_type("text/plain;charset = ISO-8859-1 ", &t, &k)); |
| 63 | insist(k != 0); |
| 64 | insist(k->next == 0); |
| 65 | check_string(t, "text/plain"); |
| 66 | check_string(k->name, "charset"); |
| 67 | check_string(k->value, "ISO-8859-1"); |
| 68 | |
| 69 | t = n = v = 0; |
| 70 | insist(!mime_rfc2388_content_disposition("form-data; name=\"field1\"", &t, &n, &v)); |
| 71 | check_string(t, "form-data"); |
| 72 | check_string(n, "name"); |
| 73 | check_string(v, "field1"); |
| 74 | |
| 75 | insist(!mime_rfc2388_content_disposition("inline", &t, &n, &v)); |
| 76 | check_string(t, "inline"); |
| 77 | insist(n == 0); |
| 78 | insist(v == 0); |
| 79 | |
| 80 | /* Current versions of the code only understand a single arg to these |
| 81 | * headers. This is a bug at the level they work at but suffices for |
| 82 | * DisOrder's current purposes. */ |
| 83 | |
| 84 | insist(!mime_rfc2388_content_disposition( |
| 85 | "attachment; filename=genome.jpeg;\n" |
| 86 | "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"", |
| 87 | &t, &n, &v)); |
| 88 | check_string(t, "attachment"); |
| 89 | check_string(n, "filename"); |
| 90 | check_string(v, "genome.jpeg"); |
| 91 | |
| 92 | vector_init(parts); |
| 93 | insist(mime_multipart("--outer\r\n" |
| 94 | "Content-Type: text/plain\r\n" |
| 95 | "Content-Disposition: inline\r\n" |
| 96 | "Content-Description: text-part-1\r\n" |
| 97 | "\r\n" |
| 98 | "Some text goes here\r\n" |
| 99 | "\r\n" |
| 100 | "--outer\r\n" |
| 101 | "Content-Type: multipart/mixed; boundary=inner\r\n" |
| 102 | "Content-Disposition: attachment\r\n" |
| 103 | "Content-Description: multipart-2\r\n" |
| 104 | "\r\n" |
| 105 | "--inner\r\n" |
| 106 | "Content-Type: text/plain\r\n" |
| 107 | "Content-Disposition: inline\r\n" |
| 108 | "Content-Description: text-part-2\r\n" |
| 109 | "\r\n" |
| 110 | "Some more text here.\r\n" |
| 111 | "\r\n" |
| 112 | "--inner\r\n" |
| 113 | "Content-Type: image/jpeg\r\n" |
| 114 | "Content-Disposition: attachment\r\n" |
| 115 | "Content-Description: jpeg-1\r\n" |
| 116 | "\r\n" |
| 117 | "<jpeg data>\r\n" |
| 118 | "--inner--\r\n" |
| 119 | "--outer--\r\n", |
| 120 | test_multipart_callback, |
| 121 | "outer", |
| 122 | parts) == 0); |
| 123 | check_integer(parts->nvec, 2); |
| 124 | check_string(parts->vec[0], |
| 125 | "Content-Type: text/plain\r\n" |
| 126 | "Content-Disposition: inline\r\n" |
| 127 | "Content-Description: text-part-1\r\n" |
| 128 | "\r\n" |
| 129 | "Some text goes here\r\n"); |
| 130 | check_string(parts->vec[1], |
| 131 | "Content-Type: multipart/mixed; boundary=inner\r\n" |
| 132 | "Content-Disposition: attachment\r\n" |
| 133 | "Content-Description: multipart-2\r\n" |
| 134 | "\r\n" |
| 135 | "--inner\r\n" |
| 136 | "Content-Type: text/plain\r\n" |
| 137 | "Content-Disposition: inline\r\n" |
| 138 | "Content-Description: text-part-2\r\n" |
| 139 | "\r\n" |
| 140 | "Some more text here.\r\n" |
| 141 | "\r\n" |
| 142 | "--inner\r\n" |
| 143 | "Content-Type: image/jpeg\r\n" |
| 144 | "Content-Disposition: attachment\r\n" |
| 145 | "Content-Description: jpeg-1\r\n" |
| 146 | "\r\n" |
| 147 | "<jpeg data>\r\n" |
| 148 | "--inner--"); |
| 149 | /* No trailing CRLF is _correct_ - see RFC2046 5.1.1 note regarding CRLF |
| 150 | * preceding the boundary delimiter line. An implication of this is that we |
| 151 | * must cope with partial lines at the end of the input when recursively |
| 152 | * decomposing a multipart message. */ |
| 153 | vector_init(parts); |
| 154 | insist(mime_multipart("--inner\r\n" |
| 155 | "Content-Type: text/plain\r\n" |
| 156 | "Content-Disposition: inline\r\n" |
| 157 | "Content-Description: text-part-2\r\n" |
| 158 | "\r\n" |
| 159 | "Some more text here.\r\n" |
| 160 | "\r\n" |
| 161 | "--inner\r\n" |
| 162 | "Content-Type: image/jpeg\r\n" |
| 163 | "Content-Disposition: attachment\r\n" |
| 164 | "Content-Description: jpeg-1\r\n" |
| 165 | "\r\n" |
| 166 | "<jpeg data>\r\n" |
| 167 | "--inner--", |
| 168 | test_multipart_callback, |
| 169 | "inner", |
| 170 | parts) == 0); |
| 171 | check_integer(parts->nvec, 2); |
| 172 | check_string(parts->vec[0], |
| 173 | "Content-Type: text/plain\r\n" |
| 174 | "Content-Disposition: inline\r\n" |
| 175 | "Content-Description: text-part-2\r\n" |
| 176 | "\r\n" |
| 177 | "Some more text here.\r\n"); |
| 178 | check_string(parts->vec[1], |
| 179 | "Content-Type: image/jpeg\r\n" |
| 180 | "Content-Disposition: attachment\r\n" |
| 181 | "Content-Description: jpeg-1\r\n" |
| 182 | "\r\n" |
| 183 | "<jpeg data>"); |
| 184 | |
| 185 | /* XXX mime_parse */ |
| 186 | |
| 187 | check_string(mime_qp(""), ""); |
| 188 | check_string(mime_qp("foobar"), "foobar"); |
| 189 | check_string(mime_qp("foo=20bar"), "foo bar"); |
| 190 | check_string(mime_qp("x \r\ny"), "x\r\ny"); |
| 191 | check_string(mime_qp("x=\r\ny"), "xy"); |
| 192 | check_string(mime_qp("x= \r\ny"), "xy"); |
| 193 | check_string(mime_qp("x =\r\ny"), "x y"); |
| 194 | check_string(mime_qp("x = \r\ny"), "x y"); |
| 195 | |
| 196 | check_string(mime_to_qp(""), ""); |
| 197 | check_string(mime_to_qp("foobar\n"), "foobar\n"); |
| 198 | check_string(mime_to_qp("foobar \n"), "foobar=20\n"); |
| 199 | check_string(mime_to_qp("foobar\t\n"), "foobar=09\n"); |
| 200 | check_string(mime_to_qp("foobar \t \n"), "foobar=20=09=20\n"); |
| 201 | check_string(mime_to_qp(" foo=bar"), " foo=3Dbar\n"); |
| 202 | check_string(mime_to_qp("copyright \xC2\xA9"), "copyright =C2=A9\n"); |
| 203 | check_string(mime_to_qp("foo\nbar\nbaz\n"), "foo\nbar\nbaz\n"); |
| 204 | check_string(mime_to_qp("wibble wobble wibble wobble wibble wobble wibble wobble wibble wobble wibble"), "wibble wobble wibble wobble wibble wobble wibble wobble wibble wobble wibb=\nle\n"); |
| 205 | |
| 206 | /* from RFC2045 */ |
| 207 | check_string(mime_qp("Now's the time =\r\n" |
| 208 | "for all folk to come=\r\n" |
| 209 | " to the aid of their country."), |
| 210 | "Now's the time for all folk to come to the aid of their country."); |
| 211 | |
| 212 | #define check_base64(encoded, decoded) do { \ |
| 213 | check_string(mime_base64(encoded, 0), decoded); \ |
| 214 | check_string(mime_to_base64((const uint8_t *)decoded, \ |
| 215 | (sizeof decoded) - 1), \ |
| 216 | encoded); \ |
| 217 | } while(0) |
| 218 | |
| 219 | |
| 220 | check_base64("", ""); |
| 221 | check_base64("BBBB", "\x04\x10\x41"); |
| 222 | check_base64("////", "\xFF\xFF\xFF"); |
| 223 | check_base64("//BB", "\xFF\xF0\x41"); |
| 224 | check_base64("BBBB//BB////", |
| 225 | "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF"); |
| 226 | check_base64("BBBBBA==", |
| 227 | "\x04\x10\x41" "\x04"); |
| 228 | check_base64("BBBBBBA=", |
| 229 | "\x04\x10\x41" "\x04\x10"); |
| 230 | |
| 231 | /* Check that decoding handles various kinds of rubbish OK */ |
| 232 | check_string(mime_base64("B B B B / / B B / / / /", 0), |
| 233 | "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF"); |
| 234 | check_string(mime_base64("B\r\nBBB.// B-B//~//", 0), |
| 235 | "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF"); |
| 236 | check_string(mime_base64("BBBB BB==", 0), |
| 237 | "\x04\x10\x41" "\x04"); |
| 238 | check_string(mime_base64("BBBB BB = =", 0), |
| 239 | "\x04\x10\x41" "\x04"); |
| 240 | check_string(mime_base64("BBBB BBB=", 0), |
| 241 | "\x04\x10\x41" "\x04\x10"); |
| 242 | check_string(mime_base64("BBBB BBB = ", 0), |
| 243 | "\x04\x10\x41" "\x04\x10"); |
| 244 | check_string(mime_base64("BBBB=", 0), |
| 245 | "\x04\x10\x41"); |
| 246 | check_string(mime_base64("BBBBBB==", 0), |
| 247 | "\x04\x10\x41" "\x04"); |
| 248 | check_string(mime_base64("BBBBBBB=", 0), |
| 249 | "\x04\x10\x41" "\x04\x10"); |
| 250 | /* Not actually valid base64 */ |
| 251 | check_string(mime_base64("BBBBx=", 0), |
| 252 | "\x04\x10\x41"); |
| 253 | } |
| 254 | |
| 255 | /* |
| 256 | Local Variables: |
| 257 | c-basic-offset:2 |
| 258 | comment-column:40 |
| 259 | fill-column:79 |
| 260 | indent-tabs-mode:nil |
| 261 | End: |
| 262 | */ |