diff --git a/CHANGELOG.md b/CHANGELOG.md index a02a15bb986..fe3efac0b66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,3 @@ - Replaces underlying terminal coloring library. +- Make storage emulator multipart parsing handle quotes in boundary header #3953 - Make storage emulator content type case insensitive #3953 diff --git a/src/emulator/storage/multipart.ts b/src/emulator/storage/multipart.ts index 955f62b57fb..aae53d1d76d 100644 --- a/src/emulator/storage/multipart.ts +++ b/src/emulator/storage/multipart.ts @@ -51,7 +51,9 @@ function splitBufferByDelimiter(buffer: Buffer, delimiter: string, maxResults = * @param body multipart request body as a Buffer */ function parseMultipartRequestBody(boundaryId: string, body: Buffer): MultipartRequestBody { - const boundaryString = `--${boundaryId}`; + // strip additional surrounding single and double quotes, cloud sdks have additional quote here + const cleanBoundaryId = boundaryId.replace(/^["'](.+(?=["']$))["']$/, "$1"); + const boundaryString = `--${cleanBoundaryId}`; const bodyParts = splitBufferByDelimiter(body, boundaryString).map((buf) => { // Remove the \r\n and the beginning of each part left from the boundary line. return Buffer.from(buf.slice(2)); diff --git a/src/test/emulators/storage/multipart.spec.ts b/src/test/emulators/storage/multipart.spec.ts index 44d3e96132c..dd5c63695ed 100644 --- a/src/test/emulators/storage/multipart.spec.ts +++ b/src/test/emulators/storage/multipart.spec.ts @@ -78,6 +78,28 @@ hello there! ); }); + it("parses an upload object multipart request with additional quotes in the boundary value", () => { + const contentTypeHeaderWithDoubleQuotes = `multipart/related; boundary="b1d5b2e3-1845-4338-9400-6ac07ce53c1e"`; + + let { metadataRaw, dataRaw } = parseObjectUploadMultipartRequest( + contentTypeHeaderWithDoubleQuotes, + BODY + ); + + expect(metadataRaw).to.equal('{"contentType":"text/plain"}'); + expect(dataRaw.toString()).to.equal("hello there!\n"); + + const contentTypeHeaderWithSingleQuotes = `multipart/related; boundary='b1d5b2e3-1845-4338-9400-6ac07ce53c1e'`; + + ({ metadataRaw, dataRaw } = parseObjectUploadMultipartRequest( + contentTypeHeaderWithSingleQuotes, + BODY + )); + + expect(metadataRaw).to.equal('{"contentType":"text/plain"}'); + expect(dataRaw.toString()).to.equal("hello there!\n"); + }); + it("fails to parse when body has wrong number of parts", () => { const invalidBody = Buffer.from(`--b1d5b2e3-1845-4338-9400-6ac07ce53c1e\r Content-Type: application/json\r