diff options
author | Marcos Casagrande <marcos@denode.com> | 2023-10-05 19:28:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-05 19:28:44 +0200 |
commit | 176bf9ba5ffe1c925e7d6a395d0e946880afdcda (patch) | |
tree | b3a9f3746e093802c8ad86c635afee436aa24758 | |
parent | 1619932a651a189d590bd579f334faac3c6b4397 (diff) |
fix(ext/formdata): support multiple headers in FormData (#20801)
Fixes https://github.com/denoland/deno/issues/20793
-rw-r--r-- | cli/tests/unit/body_test.ts | 32 | ||||
-rw-r--r-- | ext/fetch/21_formdata.js | 31 |
2 files changed, 47 insertions, 16 deletions
diff --git a/cli/tests/unit/body_test.ts b/cli/tests/unit/body_test.ts index 8aebfadd3..7dd026dc5 100644 --- a/cli/tests/unit/body_test.ts +++ b/cli/tests/unit/body_test.ts @@ -155,3 +155,35 @@ Deno.test(async function bodyArrayBufferMultipleParts() { const body = buildBody(stream); assertEquals((await body.arrayBuffer()).byteLength, size); }); + +// https://github.com/denoland/deno/issues/20793 +Deno.test( + { permissions: { net: true } }, + async function bodyMultipartFormDataMultipleHeaders() { + const boundary = "----formdata-polyfill-0.970665446687947"; + const payload = [ + "------formdata-polyfill-0.970665446687947", + 'Content-Disposition: form-data; name="x"; filename="blob"', + "Content-Length: 1", + "Content-Type: application/octet-stream", + "last-modified: Wed, 04 Oct 2023 20:28:45 GMT", + "", + "y", + "------formdata-polyfill-0.970665446687947--", + ].join("\r\n"); + + const body = buildBody( + new TextEncoder().encode(payload), + new Headers({ + "Content-Type": `multipart/form-data; boundary=${boundary}`, + }), + ); + + const formData = await body.formData(); + const file = formData.get("x"); + assert(file instanceof File); + const text = await file.text(); + assertEquals(text, "y"); + assertEquals(file.size, 1); + }, +); diff --git a/ext/fetch/21_formdata.js b/ext/fetch/21_formdata.js index 1f0f00088..d905ec7c4 100644 --- a/ext/fetch/21_formdata.js +++ b/ext/fetch/21_formdata.js @@ -448,25 +448,24 @@ class MultipartParser { const prevByte = this.body[i - 1]; const isNewLine = byte === LF && prevByte === CR; - if (state === 1 || state === 2 || state == 3) { + if (state === 1) { headerText += StringFromCharCode(byte); } + if (state === 0 && isNewLine) { state = 1; - } else if (state === 1 && isNewLine) { - state = 2; - const headersDone = this.body[i + 1] === CR && - this.body[i + 2] === LF; - - if (headersDone) { - state = 3; + } else if ( + state === 1 + ) { + if ( + isNewLine && this.body[i + 1] === CR && + this.body[i + 2] === LF + ) { + // end of the headers section + state = 2; + fileStart = i + 3; // After \r\n } - } else if (state === 2 && isNewLine) { - state = 3; - } else if (state === 3 && isNewLine) { - state = 4; - fileStart = i + 1; - } else if (state === 4) { + } else if (state === 2) { if (this.boundaryChars[boundaryIndex] !== byte) { boundaryIndex = 0; } else { @@ -487,7 +486,7 @@ class MultipartParser { const latin1Filename = MapPrototypeGet(disposition, "filename"); const latin1Name = MapPrototypeGet(disposition, "name"); - state = 5; + state = 3; // Reset boundaryIndex = 0; headerText = ""; @@ -510,7 +509,7 @@ class MultipartParser { formData.append(name, core.decode(content)); } } - } else if (state === 5 && isNewLine) { + } else if (state === 3 && isNewLine) { state = 1; } } |