(buffer, contentType)
| 388 | } |
| 389 | |
| 390 | function parseMultipart(buffer, contentType) { |
| 391 | const match = /boundary=(?:"([^"]+)"|([^;]+))/i.exec(contentType || ""); |
| 392 | if (!match) throw new Error("Missing multipart boundary"); |
| 393 | const boundary = Buffer.from(`--${match[1] || match[2]}`); |
| 394 | const parts = []; |
| 395 | let offset = 0; |
| 396 | |
| 397 | while (true) { |
| 398 | const start = buffer.indexOf(boundary, offset); |
| 399 | if (start === -1) break; |
| 400 | let partStart = start + boundary.length; |
| 401 | if (buffer.slice(partStart, partStart + 2).toString() === "--") break; |
| 402 | if (buffer.slice(partStart, partStart + 2).toString() === "\r\n") partStart += 2; |
| 403 | const headerEnd = buffer.indexOf(Buffer.from("\r\n\r\n"), partStart); |
| 404 | if (headerEnd === -1) break; |
| 405 | const headers = buffer.slice(partStart, headerEnd).toString("utf8"); |
| 406 | let dataStart = headerEnd + 4; |
| 407 | let next = buffer.indexOf(boundary, dataStart); |
| 408 | if (next === -1) break; |
| 409 | let dataEnd = next - 2; |
| 410 | if (dataEnd < dataStart) dataEnd = next; |
| 411 | |
| 412 | const disposition = /content-disposition:[^\r\n]+/i.exec(headers)?.[0] || ""; |
| 413 | const name = /name="([^"]+)"/i.exec(disposition)?.[1]; |
| 414 | const filename = /filename="([^"]*)"/i.exec(disposition)?.[1]; |
| 415 | parts.push({ name, filename, data: buffer.slice(dataStart, dataEnd) }); |
| 416 | offset = next; |
| 417 | } |
| 418 | |
| 419 | return parts; |
| 420 | } |
| 421 | |
| 422 | async function saveMultipartVideos(req) { |
| 423 | const body = await readBody(req); |
no outgoing calls
no test coverage detected