send-file-formdata-helper.js (3466B)
1 "use strict"; 2 3 const kTestChars = "ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ"; 4 5 // formDataPostFileUploadTest - verifies multipart upload structure and 6 // numeric character reference replacement for filenames, field names, 7 // and field values using FormData and fetch(). 8 // 9 // Uses /fetch/api/resources/echo-content.py to echo the upload 10 // POST (unlike in send-file-form-helper.js, here we expect all 11 // multipart/form-data request bodies to be UTF-8, so we don't need to 12 // escape controls and non-ASCII bytes). 13 // 14 // Fields in the parameter object: 15 // 16 // - fileNameSource: purely explanatory and gives a clue about which 17 // character encoding is the source for the non-7-bit-ASCII parts of 18 // the fileBaseName, or Unicode if no smaller-than-Unicode source 19 // contains all the characters. Used in the test name. 20 // - fileBaseName: the not-necessarily-just-7-bit-ASCII file basename 21 // used for the constructed test file. Used in the test name. 22 const formDataPostFileUploadTest = ({ 23 fileNameSource, 24 fileBaseName, 25 }) => { 26 promise_test(async (testCase) => { 27 const formData = new FormData(); 28 let file = new Blob([kTestChars], { type: "text/plain" }); 29 try { 30 // Switch to File in browsers that allow this 31 file = new File([file], fileBaseName, { type: file.type }); 32 } catch (ignoredException) { 33 } 34 35 // Used to verify that the browser agrees with the test about 36 // field value replacement and encoding independently of file system 37 // idiosyncracies. 38 formData.append("filename", fileBaseName); 39 40 // Same, but with name and value reversed to ensure field names 41 // get the same treatment. 42 formData.append(fileBaseName, "filename"); 43 44 formData.append("file", file, fileBaseName); 45 46 const formDataText = await (await fetch( 47 `/fetch/api/resources/echo-content.py`, 48 { 49 method: "POST", 50 body: formData, 51 }, 52 )).text(); 53 const formDataLines = formDataText.split("\r\n"); 54 if (formDataLines.length && !formDataLines[formDataLines.length - 1]) { 55 --formDataLines.length; 56 } 57 assert_greater_than( 58 formDataLines.length, 59 2, 60 `${fileBaseName}: multipart form data must have at least 3 lines: ${ 61 JSON.stringify(formDataText) 62 }`, 63 ); 64 const boundary = formDataLines[0]; 65 assert_equals( 66 formDataLines[formDataLines.length - 1], 67 boundary + "--", 68 `${fileBaseName}: multipart form data must end with ${boundary}--: ${ 69 JSON.stringify(formDataText) 70 }`, 71 ); 72 73 const asValue = fileBaseName.replace(/\r\n?|\n/g, "\r\n"); 74 const asName = asValue.replace(/[\r\n"]/g, encodeURIComponent); 75 const asFilename = fileBaseName.replace(/[\r\n"]/g, encodeURIComponent); 76 const expectedText = [ 77 boundary, 78 'Content-Disposition: form-data; name="filename"', 79 "", 80 asValue, 81 boundary, 82 `Content-Disposition: form-data; name="${asName}"`, 83 "", 84 "filename", 85 boundary, 86 `Content-Disposition: form-data; name="file"; ` + 87 `filename="${asFilename}"`, 88 "Content-Type: text/plain", 89 "", 90 kTestChars, 91 boundary + "--", 92 ].join("\r\n"); 93 94 assert_true( 95 formDataText.startsWith(expectedText), 96 `Unexpected multipart-shaped form data received:\n${formDataText}\nExpected:\n${expectedText}`, 97 ); 98 }, `Upload ${fileBaseName} (${fileNameSource}) in fetch with FormData`); 99 };