1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-22 15:06:54 -05:00

fix(fetch): implement newline normalization and escapes in the multipart/form-data serializer (#10832)

This commit is contained in:
Andreu Botella 2021-06-03 20:48:09 +02:00 committed by GitHub
parent 55e962b688
commit 03184aeabb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 13 deletions

View file

@ -323,11 +323,13 @@
filename, filename,
type, type,
) { ) {
const escapedField = this.#headerEscape(field);
const escapedFilename = this.#headerEscape(filename, true);
/** @type {[string, string][]} */ /** @type {[string, string][]} */
const headers = [ const headers = [
[ [
"Content-Disposition", "Content-Disposition",
`form-data; name="${field}"; filename="${filename}"`, `form-data; name="${escapedField}"; filename="${escapedFilename}"`,
], ],
["Content-Type", type || "application/octet-stream"], ["Content-Type", type || "application/octet-stream"],
]; ];
@ -340,7 +342,10 @@
*/ */
#writeFieldHeaders(field) { #writeFieldHeaders(field) {
/** @type {[string, string][]} */ /** @type {[string, string][]} */
const headers = [["Content-Disposition", `form-data; name="${field}"`]]; const headers = [[
"Content-Disposition",
`form-data; name="${this.#headerEscape(field)}"`,
]];
return this.#writeHeaders(headers); return this.#writeHeaders(headers);
} }
@ -351,7 +356,7 @@
*/ */
#writeField(field, value) { #writeField(field, value) {
this.#writeFieldHeaders(field); this.#writeFieldHeaders(field);
this.chunks.push(encoder.encode(value)); this.chunks.push(encoder.encode(this.#normalizeNewlines(value)));
} }
/** /**
@ -363,6 +368,32 @@
this.#writeFileHeaders(field, value.name, value.type); this.#writeFileHeaders(field, value.name, value.type);
this.chunks.push(value[_byteSequence]); this.chunks.push(value[_byteSequence]);
} }
/**
* @param {string} string
* @returns {string}
*/
#normalizeNewlines(string) {
return string.replace(/\r(?!\n)|(?<!\r)\n/g, "\r\n");
}
/**
* Performs the percent-escaping and the normalization required for field
* names and filenames in Content-Disposition headers.
* @param {string} name
* @param {boolean} isFilename Whether we are encoding a filename. This
* skips the newline normalization that takes place for field names.
* @returns {string}
*/
#headerEscape(name, isFilename = false) {
if (!isFilename) {
name = this.#normalizeNewlines(name);
}
return name
.replaceAll("\n", "%0A")
.replaceAll("\r", "%0D")
.replaceAll('"', "%22");
}
} }
/** /**

View file

@ -990,16 +990,8 @@
}, },
"file": { "file": {
"File-constructor.any.html": true, "File-constructor.any.html": true,
"send-file-formdata-controls.any.html": [ "send-file-formdata-controls.any.html": true,
"Upload file-for-upload-in-form-LF-[\n].txt (ASCII) in fetch with FormData", "send-file-formdata-punctuation.any.html": true,
"Upload file-for-upload-in-form-LF-CR-[\n\r].txt (ASCII) in fetch with FormData",
"Upload file-for-upload-in-form-CR-[\r].txt (ASCII) in fetch with FormData",
"Upload file-for-upload-in-form-CR-LF-[\r\n].txt (ASCII) in fetch with FormData"
],
"send-file-formdata-punctuation.any.html": [
"Upload file-for-upload-in-form-QUOTATION-MARK-[\"].txt (ASCII) in fetch with FormData",
"Upload \"file-for-upload-in-form-double-quoted.txt\" (ASCII) in fetch with FormData"
],
"send-file-formdata-utf-8.any.html": true, "send-file-formdata-utf-8.any.html": true,
"send-file-formdata.any.html": true "send-file-formdata.any.html": true
}, },