@mjackson/multipart-parser
Version:
A fast, efficient parser for multipart streams in any JavaScript environment
83 lines (75 loc) • 3.09 kB
text/typescript
import type * as http from 'node:http';
import { Readable } from 'node:stream';
import type { ParseMultipartOptions, MultipartParserOptions, MultipartPart } from './multipart.ts';
import {
MultipartParseError,
parseMultipart as parseMultipartWeb,
parseMultipartStream as parseMultipartStreamWeb,
} from './multipart.ts';
import { getMultipartBoundary } from './multipart-request.ts';
/**
* Parse a `multipart/*` Node.js `Buffer` and yield each part as a `MultipartPart` object.
*
* Note: This is a low-level API that requires manual handling of the content and boundary. If you're
* building a web server, consider using `parseMultipartRequest(request)` instead.
*
* @param message The multipart message as a `Buffer` or an iterable of `Buffer` chunks
* @param options Options for the parser
* @return A generator yielding `MultipartPart` objects
*/
export function* parseMultipart(
message: Buffer | Iterable<Buffer>,
options: ParseMultipartOptions,
): Generator<MultipartPart, void, unknown> {
yield* parseMultipartWeb(message as Uint8Array | Iterable<Uint8Array>, options);
}
/**
* Parse a `multipart/*` Node.js `Readable` stream and yield each part as a `MultipartPart` object.
*
* Note: This is a low-level API that requires manual handling of the stream and boundary. If you're
* building a web server, consider using `parseMultipartRequest(request)` instead.
*
* @param stream A Node.js `Readable` stream containing multipart data
* @param options Options for the parser
* @return An async generator yielding `MultipartPart` objects
*/
export async function* parseMultipartStream(
stream: Readable,
options: ParseMultipartOptions,
): AsyncGenerator<MultipartPart, void, unknown> {
yield* parseMultipartStreamWeb(Readable.toWeb(stream) as ReadableStream, options);
}
/**
* Returns true if the given request is a multipart request.
*
* @param req The Node.js `http.IncomingMessage` object to check
* @return `true` if the request is a multipart request, `false` otherwise
*/
export function isMultipartRequest(req: http.IncomingMessage): boolean {
let contentType = req.headers['content-type'];
return contentType != null && /^multipart\//i.test(contentType);
}
/**
* Parse a multipart Node.js request and yield each part as a `MultipartPart` object.
*
* @param req The Node.js `http.IncomingMessage` object containing multipart data
* @param options Options for the parser
* @return An async generator yielding `MultipartPart` objects
*/
export async function* parseMultipartRequest(
req: http.IncomingMessage,
options?: MultipartParserOptions,
): AsyncGenerator<MultipartPart, void, unknown> {
if (!isMultipartRequest(req)) {
throw new MultipartParseError('Request is not a multipart request');
}
let boundary = getMultipartBoundary(req.headers['content-type']!);
if (!boundary) {
throw new MultipartParseError('Invalid Content-Type header: missing boundary');
}
yield* parseMultipartStream(req, {
boundary,
maxHeaderSize: options?.maxHeaderSize,
maxFileSize: options?.maxFileSize,
});
}