MCPcopy Create free account
hub / github.com/nodejs/node / multipartFormDataParser

Function multipartFormDataParser

deps/undici/src/lib/web/fetch/formdata-parser.js:64–201  ·  view source on GitHub ↗

* @see https://andreubotella.github.io/multipart-form-data/#multipart-form-data-parser * @param {Buffer} input * @param {ReturnType } mimeType

(input, mimeType)

Source from the content-addressed store, hash-verified

62 * @param {ReturnType<import('./data-url')['parseMIMEType']>} mimeType
63 */
64function multipartFormDataParser (input, mimeType) {
65 // 1. Assert: mimeType’s essence is "multipart/form-data".
66 assert(mimeType !== 'failure' && mimeType.essence === 'multipart/form-data')
67
68 const boundaryString = mimeType.parameters.get('boundary')
69
70 // 2. If mimeType’s parameters["boundary"] does not exist, return failure.
71 // Otherwise, let boundary be the result of UTF-8 decoding mimeType’s
72 // parameters["boundary"].
73 if (boundaryString === undefined) {
74 throw parsingError('missing boundary in content-type header')
75 }
76
77 const boundary = Buffer.from(`--${boundaryString}`, 'utf8')
78
79 // 3. Let entry list be an empty entry list.
80 const entryList = []
81
82 // 4. Let position be a pointer to a byte in input, initially pointing at
83 // the first byte.
84 const position = { position: 0 }
85
86 // Note: Per RFC 2046 Section 5.1.1, we must ignore anything before the
87 // first boundary delimiter line (preamble). Search for the first boundary.
88 const firstBoundaryIndex = input.indexOf(boundary)
89
90 if (firstBoundaryIndex === -1) {
91 throw parsingError('no boundary found in multipart body')
92 }
93
94 // Start parsing from the first boundary, ignoring any preamble
95 position.position = firstBoundaryIndex
96
97 // 5. While true:
98 while (true) {
99 // 5.1. If position points to a sequence of bytes starting with 0x2D 0x2D
100 // (`--`) followed by boundary, advance position by 2 + the length of
101 // boundary. Otherwise, return failure.
102 // Note: boundary is padded with 2 dashes already, no need to add 2.
103 if (input.subarray(position.position, position.position + boundary.length).equals(boundary)) {
104 position.position += boundary.length
105 } else {
106 throw parsingError('expected a value starting with -- and the boundary')
107 }
108
109 // 5.2. If position points to the sequence of bytes 0x2D 0x2D 0x0D 0x0A
110 // (`--` followed by CR LF) followed by the end of input, return entry list.
111 // Note: Per RFC 2046 Section 5.1.1, we must ignore anything after the
112 // final boundary delimiter (epilogue). Check for -- or --CRLF and return
113 // regardless of what follows.
114 if (bufferStartsWith(input, dd, position)) {
115 // Found closing boundary delimiter (--), ignore any epilogue
116 return entryList
117 }
118
119 // 5.3. If position does not point to a sequence of bytes starting with 0x0D
120 // 0x0A (CR LF), return failure.
121 if (input[position.position] !== 0x0d || input[position.position + 1] !== 0x0a) {

Callers 1

formDataFunction · 0.70

Calls 14

USVStringMethod · 0.80
parsingErrorFunction · 0.70
bufferStartsWithFunction · 0.70
isAsciiStringFunction · 0.70
makeEntryFunction · 0.70
getMethod · 0.65
decodeMethod · 0.65
assertFunction · 0.50
fromMethod · 0.45
indexOfMethod · 0.45
equalsMethod · 0.45

Tested by

no test coverage detected