1"use strict"; 2 3const 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. 22const 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 asName = fileBaseName.replace(/[\r\n"]/g, encodeURIComponent); 74 const expectedText = [ 75 boundary, 76 'Content-Disposition: form-data; name="filename"', 77 "", 78 fileBaseName, 79 boundary, 80 `Content-Disposition: form-data; name="${asName}"`, 81 "", 82 "filename", 83 boundary, 84 `Content-Disposition: form-data; name="file"; ` + 85 `filename="${asName}"`, 86 "Content-Type: text/plain", 87 "", 88 kTestChars, 89 boundary + "--", 90 ].join("\r\n"); 91 92 assert_true( 93 formDataText.startsWith(expectedText), 94 `Unexpected multipart-shaped form data received:\n${formDataText}\nExpected:\n${expectedText}`, 95 ); 96 }, `Upload ${fileBaseName} (${fileNameSource}) in fetch with FormData`); 97}; 98