Skip to content

Commit 9c35d3c

Browse files
committed
parse multipart with trailing LWSP after boundary delimiter
1 parent 210d457 commit 9c35d3c

File tree

1 file changed

+21
-9
lines changed

1 file changed

+21
-9
lines changed

src/Multipart.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,34 @@ export class Multipart implements Part {
181181
console.warn("Invalid boundary:", new TextDecoder().decode(boundary), "\nMust be 1 to 70 characters long, not end with space, and may only contain: A-Z a-z 0-9 '()+_,-./:=? and space");
182182

183183
const parts: Uint8Array[] = [];
184-
const fullBoundarySequence = new Uint8Array(Multipart.combineArrays([Multipart.DOUBLE_DASH, boundary, Multipart.CRLF]));
185-
const endBoundarySequence = new Uint8Array(Multipart.combineArrays([Multipart.DOUBLE_DASH, boundary, Multipart.DOUBLE_DASH, Multipart.CRLF]));
184+
const fullBoundarySequence = Multipart.combineArrays([Multipart.CRLF, Multipart.DOUBLE_DASH, boundary]);
185+
const endBoundarySequence = Multipart.combineArrays([Multipart.CRLF, Multipart.DOUBLE_DASH, boundary, Multipart.DOUBLE_DASH]);
186+
187+
// add artificial CRLF at the start of the data
188+
const paddedData = Multipart.combineArrays([Multipart.CRLF, data]);
186189

187190
let start = 0;
188191
while (true) {
189-
const boundaryIndex = Multipart.findSequenceIndex(data, fullBoundarySequence, start);
192+
const boundaryIndex = Multipart.findSequenceIndex(paddedData, fullBoundarySequence, start);
190193
if (boundaryIndex === -1) break;
191194

192-
const partStart = boundaryIndex + fullBoundarySequence.length;
193-
const nextBoundaryIndex = Multipart.findSequenceIndex(data, fullBoundarySequence, partStart);
194-
const endBoundaryIndex = Multipart.findSequenceIndex(data, endBoundarySequence, partStart);
195+
let partStart = boundaryIndex + fullBoundarySequence.length;
196+
// ignore linear whitespace after boundary
197+
while (true) {
198+
const byte = paddedData[partStart];
199+
if (byte !== Multipart.SP && byte !== 0x09) break;
200+
++partStart;
201+
}
202+
// account for CRLF after boundary
203+
partStart += 2;
204+
205+
const endBoundaryIndex = Multipart.findSequenceIndex(paddedData, endBoundarySequence, partStart);
206+
if (endBoundaryIndex === -1) break;
207+
const nextBoundaryIndex = Multipart.findSequenceIndex(paddedData, fullBoundarySequence, partStart);
195208

196-
// -2 to ignore the mandatory CRLF at the end of the body
197-
const partEnd = nextBoundaryIndex === -1 ? (endBoundaryIndex === -1 ? data.length : endBoundaryIndex - 2) : nextBoundaryIndex - 2;
209+
const partEnd = nextBoundaryIndex === -1 ? (endBoundaryIndex === -1 ? paddedData.length : endBoundaryIndex) : nextBoundaryIndex;
198210

199-
if (partStart < partEnd) parts.push(data.slice(partStart, partEnd));
211+
if (partStart < partEnd) parts.push(paddedData.slice(partStart, partEnd));
200212
start = partEnd;
201213
}
202214

0 commit comments

Comments
 (0)