| "use strict"; |
| |
| const kTestChars = "ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ"; |
| |
| // formDataPostFileUploadTest - verifies multipart upload structure and |
| // numeric character reference replacement for filenames, field names, |
| // and field values using FormData and fetch(). |
| // |
| // Uses /fetch/api/resources/echo-content.py to echo the upload |
| // POST (unlike in send-file-form-helper.js, here we expect all |
| // multipart/form-data request bodies to be UTF-8, so we don't need to |
| // escape controls and non-ASCII bytes). |
| // |
| // Fields in the parameter object: |
| // |
| // - fileNameSource: purely explanatory and gives a clue about which |
| // character encoding is the source for the non-7-bit-ASCII parts of |
| // the fileBaseName, or Unicode if no smaller-than-Unicode source |
| // contains all the characters. Used in the test name. |
| // - fileBaseName: the not-necessarily-just-7-bit-ASCII file basename |
| // used for the constructed test file. Used in the test name. |
| const formDataPostFileUploadTest = ({ |
| fileNameSource, |
| fileBaseName, |
| }) => { |
| promise_test(async (testCase) => { |
| const formData = new FormData(); |
| let file = new Blob([kTestChars], { type: "text/plain" }); |
| try { |
| // Switch to File in browsers that allow this |
| file = new File([file], fileBaseName, { type: file.type }); |
| } catch (ignoredException) { |
| } |
| |
| // Used to verify that the browser agrees with the test about |
| // field value replacement and encoding independently of file system |
| // idiosyncracies. |
| formData.append("filename", fileBaseName); |
| |
| // Same, but with name and value reversed to ensure field names |
| // get the same treatment. |
| formData.append(fileBaseName, "filename"); |
| |
| formData.append("file", file, fileBaseName); |
| |
| const formDataText = await (await fetch( |
| `/fetch/api/resources/echo-content.py`, |
| { |
| method: "POST", |
| body: formData, |
| }, |
| )).text(); |
| const formDataLines = formDataText.split("\r\n"); |
| if (formDataLines.length && !formDataLines[formDataLines.length - 1]) { |
| --formDataLines.length; |
| } |
| assert_greater_than( |
| formDataLines.length, |
| 2, |
| `${fileBaseName}: multipart form data must have at least 3 lines: ${ |
| JSON.stringify(formDataText) |
| }`, |
| ); |
| const boundary = formDataLines[0]; |
| assert_equals( |
| formDataLines[formDataLines.length - 1], |
| boundary + "--", |
| `${fileBaseName}: multipart form data must end with ${boundary}--: ${ |
| JSON.stringify(formDataText) |
| }`, |
| ); |
| |
| const asValue = fileBaseName.replace(/\r\n?|\n/g, "\r\n"); |
| const asName = asValue.replace(/[\r\n"]/g, encodeURIComponent); |
| const asFilename = fileBaseName.replace(/[\r\n"]/g, encodeURIComponent); |
| const expectedText = [ |
| boundary, |
| 'Content-Disposition: form-data; name="filename"', |
| "", |
| asValue, |
| boundary, |
| `Content-Disposition: form-data; name="${asName}"`, |
| "", |
| "filename", |
| boundary, |
| `Content-Disposition: form-data; name="file"; ` + |
| `filename="${asFilename}"`, |
| "Content-Type: text/plain", |
| "", |
| kTestChars, |
| boundary + "--", |
| ].join("\r\n"); |
| |
| assert_true( |
| formDataText.startsWith(expectedText), |
| `Unexpected multipart-shaped form data received:\n${formDataText}\nExpected:\n${expectedText}`, |
| ); |
| }, `Upload ${fileBaseName} (${fileNameSource}) in fetch with FormData`); |
| }; |