test_formdataparsing.js (8634B)
1 var boundary = "1234567891011121314151617"; 2 3 // fn(body) should create a Body subclass with content body treated as 4 // FormData and return it. 5 function testFormDataParsing(fn) { 6 function makeTest(shouldPass, input, testFn) { 7 var obj = fn(input); 8 return obj.formData().then( 9 function (fd) { 10 ok(shouldPass, "Expected test to be valid FormData for " + input); 11 if (testFn) { 12 return testFn(fd); 13 } 14 return undefined; 15 }, 16 function (e) { 17 if (shouldPass) { 18 ok(false, "Expected test to pass for " + input); 19 } else { 20 ok(e.name == "TypeError", "Error should be a TypeError."); 21 } 22 } 23 ); 24 } 25 26 // [shouldPass?, input, testFn] 27 var tests = [ 28 [ 29 true, 30 31 boundary + 32 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 33 boundary + 34 "-", 35 36 function (fd) { 37 is(fd.get("greeting"), '"hello"'); 38 }, 39 ], 40 [ 41 false, 42 43 // Invalid disposition. 44 boundary + 45 '\r\nContent-Disposition: form-datafoobar; name="greeting"\r\n\r\n"hello"\r\n' + 46 boundary + 47 "-", 48 ], 49 [ 50 true, 51 52 "--" + 53 boundary + 54 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 55 boundary + 56 "-", 57 58 function (fd) { 59 is(fd.get("greeting"), '"hello"'); 60 }, 61 ], 62 [false, boundary + "\r\n\r\n" + boundary + "-"], 63 [ 64 false, 65 // No valid ending. 66 boundary + "\r\n\r\n" + boundary, 67 ], 68 [ 69 false, 70 71 // One '-' prefix is not allowed. 2 or none. 72 "-" + 73 boundary + 74 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 75 boundary + 76 "-", 77 ], 78 [ 79 false, 80 81 "invalid" + 82 boundary + 83 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 84 boundary + 85 "-", 86 ], 87 [ 88 false, 89 90 boundary + 91 "suffix" + 92 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 93 boundary + 94 "-", 95 ], 96 [ 97 false, 98 99 boundary + 100 "suffix" + 101 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 102 boundary + 103 "-", 104 ], 105 [ 106 false, 107 108 // Partial boundary 109 boundary.substr(3) + 110 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 111 boundary + 112 "-", 113 ], 114 [ 115 false, 116 117 boundary + 118 // Missing '\n' at beginning. 119 '\rContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 120 boundary + 121 "-", 122 ], 123 [ 124 false, 125 126 boundary + 127 // No form-data. 128 '\r\nContent-Disposition: mixed; name="greeting"\r\n\r\n"hello"\r\n' + 129 boundary + 130 "-", 131 ], 132 [ 133 false, 134 135 boundary + 136 // No headers. 137 '\r\n\r\n"hello"\r\n' + 138 boundary + 139 "-", 140 ], 141 [ 142 false, 143 144 boundary + 145 // No content-disposition. 146 '\r\nContent-Dispositypo: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 147 boundary + 148 "-", 149 ], 150 [ 151 false, 152 153 boundary + 154 // No name. 155 '\r\nContent-Disposition: form-data;\r\n\r\n"hello"\r\n' + 156 boundary + 157 "-", 158 ], 159 [ 160 false, 161 162 boundary + 163 // Missing empty line between headers and body. 164 '\r\nContent-Disposition: form-data; name="greeting"\r\n"hello"\r\n' + 165 boundary + 166 "-", 167 ], 168 [ 169 false, 170 171 // Empty entry followed by valid entry. 172 boundary + 173 "\r\n\r\n" + 174 boundary + 175 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n"hello"\r\n' + 176 boundary + 177 "-", 178 ], 179 [ 180 false, 181 182 boundary + 183 // Header followed by empty line, but empty body not followed by 184 // newline. 185 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n' + 186 boundary + 187 "-", 188 ], 189 [ 190 true, 191 192 boundary + 193 // Empty body followed by newline. 194 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n\r\n' + 195 boundary + 196 "-", 197 198 function (fd) { 199 is(fd.get("greeting"), "", "Empty value is allowed."); 200 }, 201 ], 202 [ 203 false, 204 boundary + 205 // Value is boundary itself. 206 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n' + 207 boundary + 208 "\r\n" + 209 boundary + 210 "-", 211 ], 212 [ 213 false, 214 boundary + 215 // Variant of above with no valid ending boundary. 216 '\r\nContent-Disposition: form-data; name="greeting"\r\n\r\n' + 217 boundary, 218 ], 219 [ 220 true, 221 boundary + 222 // Unquoted filename with empty body. 223 '\r\nContent-Disposition: form-data; name="file"; filename=file1.txt\r\n\r\n\r\n' + 224 boundary + 225 "-", 226 227 function (fd) { 228 var f = fd.get("file"); 229 ok( 230 f instanceof File, 231 "Entry with filename attribute should be read as File." 232 ); 233 is(f.name, "file1.txt", "Filename should match."); 234 is(f.type, "text/plain", "Default content-type should be text/plain."); 235 return readAsText(f).then(function (text) { 236 is(text, "", "File should be empty."); 237 }); 238 }, 239 ], 240 [ 241 true, 242 boundary + 243 // Quoted filename with empty body. 244 '\r\nContent-Disposition: form-data; name="file"; filename="file1.txt"\r\n\r\n\r\n' + 245 boundary + 246 "-", 247 248 function (fd) { 249 var f = fd.get("file"); 250 ok( 251 f instanceof File, 252 "Entry with filename attribute should be read as File." 253 ); 254 is(f.name, "file1.txt", "Filename should match."); 255 is(f.type, "text/plain", "Default content-type should be text/plain."); 256 return readAsText(f).then(function (text) { 257 is(text, "", "File should be empty."); 258 }); 259 }, 260 ], 261 [ 262 false, 263 boundary + 264 // Invalid filename 265 '\r\nContent-Disposition: form-data; name="file"; filename="[\n@;xt"\r\n\r\n\r\n' + 266 boundary + 267 "-", 268 ], 269 [ 270 true, 271 boundary + 272 '\r\nContent-Disposition: form-data; name="file"; filename="[@;xt"\r\n\r\n\r\n' + 273 boundary + 274 "-", 275 276 function (fd) { 277 var f = fd.get("file"); 278 ok( 279 f instanceof File, 280 "Entry with filename attribute should be read as File." 281 ); 282 is(f.name, "[@", "Filename should match."); 283 }, 284 ], 285 [ 286 true, 287 boundary + 288 '\r\nContent-Disposition: form-data; name="file"; filename="file with spaces"\r\n\r\n\r\n' + 289 boundary + 290 "-", 291 292 function (fd) { 293 var f = fd.get("file"); 294 ok( 295 f instanceof File, 296 "Entry with filename attribute should be read as File." 297 ); 298 is(f.name, "file with spaces", "Filename should match."); 299 }, 300 ], 301 [ 302 true, 303 boundary + 304 "\r\n" + 305 'Content-Disposition: form-data; name="file"; filename="xml.txt"\r\n' + 306 "content-type : application/xml\r\n" + 307 "\r\n" + 308 "<body>foobar\r\n\r\n</body>\r\n" + 309 boundary + 310 "-", 311 312 function (fd) { 313 var f = fd.get("file"); 314 ok( 315 f instanceof File, 316 "Entry with filename attribute should be read as File." 317 ); 318 is(f.name, "xml.txt", "Filename should match."); 319 is( 320 f.type, 321 "application/xml", 322 "content-type should be application/xml." 323 ); 324 return readAsText(f).then(function (text) { 325 is( 326 text, 327 "<body>foobar\r\n\r\n</body>", 328 "File should have correct text." 329 ); 330 }); 331 }, 332 ], 333 ]; 334 335 var promises = []; 336 for (var i = 0; i < tests.length; ++i) { 337 var test = tests[i]; 338 promises.push(makeTest(test[0], test[1], test[2])); 339 } 340 341 return Promise.all(promises); 342 } 343 344 function makeRequest(body) { 345 var req = new Request("", { 346 method: "post", 347 body, 348 headers: { 349 "Content-Type": "multipart/form-data; boundary=" + boundary, 350 }, 351 }); 352 return req; 353 } 354 355 function makeResponse(body) { 356 var res = new Response(body, { 357 headers: { 358 "Content-Type": "multipart/form-data; boundary=" + boundary, 359 }, 360 }); 361 return res; 362 } 363 364 function runTest() { 365 return Promise.all([ 366 testFormDataParsing(makeRequest), 367 testFormDataParsing(makeResponse), 368 ]); 369 }