UNPKG

52.5 kBSource Map (JSON)View Raw
1{"version":3,"sources":["../src/bodyparser_middleware.ts","../src/debug.ts","../src/parsers/form.ts","../src/parsers/json.ts","../src/multipart/main.ts","../src/form_fields.ts","../src/multipart/part_handler.ts","../src/multipart/stream_file.ts","../src/bindings/request.ts","../src/parsers/text.ts"],"sourcesContent":["/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { tmpdir } from 'node:os'\nimport { Exception } from '@poppinss/utils'\nimport { join, isAbsolute } from 'node:path'\nimport { createId } from '@paralleldrive/cuid2'\nimport type { HttpContext } from '@adonisjs/http-server'\nimport type { NextFn } from '@adonisjs/http-server/types'\n\nimport debug from './debug.js'\nimport { parseForm } from './parsers/form.js'\nimport { parseJSON } from './parsers/json.js'\nimport { Multipart } from './multipart/main.js'\nimport type { BodyParserConfig } from './types.js'\nimport { streamFile } from './multipart/stream_file.js'\n\n/**\n * Bindings to extend request\n */\nimport './bindings/request.js'\nimport { parseText } from './parsers/text.js'\n\n/**\n * BodyParser middleware parses the incoming request body and set it as\n * request body to be read later in the request lifecycle.\n */\nexport class BodyParserMiddleware {\n /**\n * Bodyparser config\n */\n #config: BodyParserConfig\n\n constructor(config: BodyParserConfig) {\n this.#config = config\n debug('using config %O', this.#config)\n }\n\n /**\n * Returns config for a given type\n */\n #getConfigFor<K extends keyof BodyParserConfig>(type: K): BodyParserConfig[K] {\n const config = this.#config[type]\n return config\n }\n\n /**\n * Ensures that types exists and have length\n */\n #ensureTypes(types: string[]): boolean {\n return !!(types && types.length)\n }\n\n /**\n * Returns a boolean telling if request `content-type` header\n * matches the expected types or not\n */\n #isType(request: HttpContext['request'], types: string[]): boolean {\n return !!(this.#ensureTypes(types) && request.is(types))\n }\n\n /**\n * Returns a proper Adonis style exception for popular error codes\n * returned by https://github.com/stream-utils/raw-body#readme.\n */\n #getExceptionFor(error: { type: string; status: number; message: string }) {\n switch (error.type) {\n case 'encoding.unsupported':\n return new Exception(error.message, {\n status: error.status,\n code: 'E_ENCODING_UNSUPPORTED',\n })\n case 'entity.too.large':\n return new Exception(error.message, {\n status: error.status,\n code: 'E_REQUEST_ENTITY_TOO_LARGE',\n })\n case 'request.aborted':\n return new Exception(error.message, { status: error.status, code: 'E_REQUEST_ABORTED' })\n default:\n return error\n }\n }\n\n /**\n * Returns the tmp path for storing the files temporarly\n */\n #getTmpPath(config: BodyParserConfig['multipart']) {\n if (typeof config.tmpFileName === 'function') {\n const tmpPath = config.tmpFileName()\n return isAbsolute(tmpPath) ? tmpPath : join(tmpdir(), tmpPath)\n }\n\n return join(tmpdir(), createId())\n }\n\n /**\n * Handle HTTP request body by parsing it as per the user\n * config\n */\n async handle(ctx: HttpContext, next: NextFn) {\n /**\n * Initiating the `__raw_files` property as an object\n */\n ctx.request['__raw_files'] = {}\n const requestUrl = ctx.request.url()\n const requestMethod = ctx.request.method()\n\n /**\n * Only process for whitelisted nodes\n */\n if (!this.#config.allowedMethods.includes(requestMethod)) {\n debug('skipping HTTP request \"%s:%s\"', requestMethod, requestUrl)\n return next()\n }\n\n /**\n * Return early when request body is empty. Many clients set the `Content-length = 0`\n * when request doesn't have any body, which is not handled by the below method.\n *\n * The main point of `hasBody` is to early return requests with empty body created by\n * clients with missing headers.\n */\n if (!ctx.request.hasBody()) {\n debug('skipping as request has no body \"%s:%s\"', requestMethod, requestUrl)\n return next()\n }\n\n /**\n * Handle multipart form\n */\n const multipartConfig = this.#getConfigFor('multipart')\n\n if (this.#isType(ctx.request, multipartConfig.types)) {\n debug('detected multipart request \"%s:%s\"', requestMethod, requestUrl)\n\n ctx.request.multipart = new Multipart(ctx, {\n maxFields: multipartConfig.maxFields,\n limit: multipartConfig.limit,\n fieldsLimit: multipartConfig.fieldsLimit,\n convertEmptyStringsToNull: multipartConfig.convertEmptyStringsToNull,\n })\n\n /**\n * Skip parsing when `autoProcess` is disabled\n */\n if (multipartConfig.autoProcess === false) {\n debug('skipping auto processing of multipart request \"%s:%s\"', requestMethod, requestUrl)\n return next()\n }\n\n /**\n * Skip parsing when the current route matches one of the defined\n * processManually route patterns.\n */\n if (ctx.route && multipartConfig.processManually.includes(ctx.route.pattern)) {\n debug('skipping auto processing of multipart request \"%s:%s\"', requestMethod, requestUrl)\n return next()\n }\n\n /**\n * Skip parsing when the current route matches one of the \"autoProcess\"\n * patterns\n */\n if (\n ctx.route &&\n Array.isArray(multipartConfig.autoProcess) &&\n !multipartConfig.autoProcess.includes(ctx.route.pattern)\n ) {\n debug('skipping auto processing of multipart request \"%s:%s\"', requestMethod, requestUrl)\n return next()\n }\n\n /**\n * Make sure we are not running any validations on the uploaded files. They are\n * deferred for the end user when they will access file using `request.file`\n * method.\n */\n debug('auto processing multipart request \"%s:%s\"', requestMethod, requestUrl)\n ctx.request.multipart.onFile('*', { deferValidations: true }, async (part, reporter) => {\n /**\n * We need to abort the main request when we are unable to process any\n * file. Otherwise the error will endup on the file object, which\n * is incorrect.\n */\n try {\n const tmpPath = this.#getTmpPath(multipartConfig)\n await streamFile(part, tmpPath, reporter)\n return { tmpPath }\n } catch (error) {\n ctx.request.multipart.abort(error)\n }\n })\n\n try {\n await ctx.request.multipart.process()\n return next()\n } catch (error) {\n throw error\n }\n }\n\n /**\n * Handle url-encoded form data\n */\n const formConfig = this.#getConfigFor('form')\n if (this.#isType(ctx.request, formConfig.types)) {\n debug('detected urlencoded request \"%s:%s\"', requestMethod, requestUrl)\n\n try {\n const { parsed, raw } = await parseForm(ctx.request.request, formConfig)\n ctx.request.setInitialBody(parsed)\n ctx.request.updateRawBody(raw)\n return next()\n } catch (error) {\n throw this.#getExceptionFor(error)\n }\n }\n\n /**\n * Handle content with JSON types\n */\n const jsonConfig = this.#getConfigFor('json')\n if (this.#isType(ctx.request, jsonConfig.types)) {\n debug('detected JSON request \"%s:%s\"', requestMethod, requestUrl)\n\n try {\n const { parsed, raw } = await parseJSON(ctx.request.request, jsonConfig)\n ctx.request.setInitialBody(parsed)\n ctx.request.updateRawBody(raw)\n return next()\n } catch (error) {\n throw this.#getExceptionFor(error)\n }\n }\n\n /**\n * Handles raw request body\n */\n const rawConfig = this.#getConfigFor('raw')\n if (this.#isType(ctx.request, rawConfig.types)) {\n debug('parsing raw body \"%s:%s\"', requestMethod, requestUrl)\n\n try {\n ctx.request.setInitialBody({})\n ctx.request.updateRawBody(await parseText(ctx.request.request, rawConfig))\n return next()\n } catch (error) {\n throw this.#getExceptionFor(error)\n }\n }\n\n await next()\n }\n}\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { debuglog } from 'node:util'\n\nexport default debuglog('adonisjs:bodyparser')\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport raw from 'raw-body'\nimport inflate from 'inflation'\nimport qs, { IParseOptions } from 'qs'\nimport type { IncomingMessage } from 'node:http'\nimport { BodyParserFormConfig } from '../types.js'\n\n/**\n * Parse x-www-form-urlencoded request body\n */\nexport async function parseForm(req: IncomingMessage, options: Partial<BodyParserFormConfig>) {\n /**\n * Shallow clone options\n */\n const normalizedOptions = Object.assign(\n {\n encoding: 'utf8',\n limit: '56kb',\n length: 0,\n },\n options\n )\n\n /**\n * Shallow clone query string options\n */\n const queryStringOptions: IParseOptions = Object.assign({}, normalizedOptions.queryString)\n\n /**\n * Mimicing behavior of\n * https://github.com/poppinss/co-body/blob/master/lib/form.js#L30\n */\n if (queryStringOptions.allowDots === undefined) {\n queryStringOptions.allowDots = true\n }\n\n /**\n * Mimicing behavior of\n * https://github.com/poppinss/co-body/blob/master/lib/form.js#L35\n */\n const contentLength = req.headers['content-length']\n const encoding = req.headers['content-encoding'] || 'identity'\n if (contentLength && encoding === 'identity') {\n normalizedOptions.length = ~~contentLength\n }\n\n /**\n * Convert empty strings to null\n */\n if (normalizedOptions.convertEmptyStringsToNull) {\n queryStringOptions.decoder = function (str, defaultDecoder, charset, type) {\n const value = defaultDecoder(str, defaultDecoder, charset)\n if (type === 'value' && value === '') {\n return null\n }\n return value\n }\n }\n\n const requestBody = await raw(inflate(req), normalizedOptions)\n const parsed = qs.parse(requestBody, queryStringOptions)\n return { parsed, raw: requestBody }\n}\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport raw from 'raw-body'\nimport inflate from 'inflation'\nimport json from '@poppinss/utils/json'\nimport { Exception } from '@poppinss/utils'\nimport type { IncomingMessage } from 'node:http'\nimport { BodyParserJSONConfig } from '../types.js'\n\n/**\n * Allowed whitespace is defined in RFC 7159\n * http://www.rfc-editor.org/rfc/rfc7159.txt\n */\n// eslint-disable-next-line no-control-regex\nconst strictJSONReg = /^[\\x20\\x09\\x0a\\x0d]*(\\[|\\{)/\n\n/**\n * JSON reviver to convert empty strings to null\n */\nfunction convertEmptyStringsToNull(key: string, value: any) {\n if (key === '') {\n return value\n }\n\n if (value === '') {\n return null\n }\n\n return value\n}\n\n/**\n * Parses JSON request body\n */\nexport async function parseJSON(req: IncomingMessage, options: Partial<BodyParserJSONConfig>) {\n /**\n * Shallow clone options\n */\n const normalizedOptions = Object.assign(\n {\n encoding: 'utf8',\n limit: '1mb',\n length: 0,\n },\n options\n )\n\n /**\n * Mimicing behavior of\n * https://github.com/poppinss/co-body/blob/master/lib/json.js#L47\n */\n const contentLength = req.headers['content-length']\n const encoding = req.headers['content-encoding'] || 'identity'\n if (contentLength && encoding === 'identity') {\n normalizedOptions.length = ~~contentLength\n }\n\n const strict = normalizedOptions.strict !== false\n const reviver = normalizedOptions.convertEmptyStringsToNull\n ? convertEmptyStringsToNull\n : undefined\n\n const requestBody = await raw(inflate(req), normalizedOptions)\n\n /**\n * Do not parse body when request body is empty\n */\n if (!requestBody) {\n return strict\n ? {\n parsed: {},\n raw: requestBody,\n }\n : {\n parsed: requestBody,\n raw: requestBody,\n }\n }\n\n /**\n * Test JSON body to ensure it is valid JSON in strict mode\n */\n if (strict && !strictJSONReg.test(requestBody)) {\n throw new Exception('Invalid JSON, only supports object and array', { status: 422 })\n }\n\n try {\n return {\n parsed: json.safeParse(requestBody, reviver),\n raw: requestBody,\n }\n } catch (error) {\n error.status = 400\n error.body = requestBody\n throw error\n }\n}\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n// @ts-expect-error\nimport multiparty from '@poppinss/multiparty'\n\nimport bytes from 'bytes'\nimport { Exception } from '@poppinss/utils'\nimport type { HttpContext } from '@adonisjs/http-server'\n\nimport debug from '../debug.js'\nimport { FormFields } from '../form_fields.js'\nimport { PartHandler } from './part_handler.js'\nimport type {\n MultipartStream,\n FileValidationOptions,\n PartHandler as PartHandlerType,\n} from '../types.js'\n\n/**\n * Multipart class offers a low level API to interact the incoming\n * HTTP request data as a stream. This makes it super easy to\n * write files to s3 without saving them to the disk first.\n */\nexport class Multipart {\n #ctx: HttpContext\n #config: Partial<{\n limit: string | number\n fieldsLimit: string | number\n maxFields: number\n convertEmptyStringsToNull: boolean\n }>\n\n /**\n * The registered handlers to handle the file uploads\n */\n #handlers: {\n [key: string]: {\n handler: PartHandlerType\n options: Partial<FileValidationOptions & { deferValidations: boolean }>\n }\n } = {}\n\n /**\n * Collected fields from the multipart stream\n */\n #fields: FormFields\n\n /**\n * Collected files from the multipart stream. Files are only collected\n * when there is an attached listener for a given file.\n */\n #files: FormFields\n\n /**\n * We track the finishing of `this.onFile` async handlers\n * to make sure that `process` promise resolves for all\n * handlers to finish.\n */\n #pendingHandlers = 0\n\n /**\n * The reference to underlying multiparty form\n */\n #form: multiparty.Form\n\n /**\n * Total size limit of the multipart stream. If it goes beyond\n * the limit, then an exception will be raised.\n */\n #upperLimit?: number\n\n /**\n * Total size in bytes for all the fields (not the files)\n */\n #maxFieldsSize?: number\n\n /**\n * A track of total number of file bytes processed so far\n */\n #processedBytes: number = 0\n\n /**\n * The current state of the multipart form handler\n */\n state: 'idle' | 'processing' | 'error' | 'success' = 'idle'\n\n constructor(\n ctx: HttpContext,\n config: Partial<{\n limit: string | number\n fieldsLimit: string | number\n maxFields: number\n convertEmptyStringsToNull: boolean\n }> = {}\n ) {\n this.#ctx = ctx\n this.#config = config\n this.#fields = new FormFields({\n convertEmptyStringsToNull: this.#config.convertEmptyStringsToNull === true,\n })\n this.#files = new FormFields({\n convertEmptyStringsToNull: this.#config.convertEmptyStringsToNull === true,\n })\n }\n\n /**\n * Returns a boolean telling whether all streams have been\n * consumed along with all handlers execution\n */\n #isClosed(): boolean {\n return this.#form['flushing'] <= 0 && this.#pendingHandlers <= 0\n }\n\n /**\n * Removes array like expression from the part name to\n * find the handler\n */\n #getHandlerName(name: string): string {\n return name.replace(/\\[\\d*\\]/, '')\n }\n\n /**\n * Validates and returns an error when upper limit is defined and\n * processed bytes is over the upper limit\n */\n #validateProcessedBytes(chunkLength: number) {\n if (!this.#upperLimit) {\n return\n }\n\n this.#processedBytes += chunkLength\n if (this.#processedBytes > this.#upperLimit) {\n return new Exception('request entity too large', {\n code: 'E_REQUEST_ENTITY_TOO_LARGE',\n status: 413,\n })\n }\n }\n\n /**\n * Handles a given part by invoking it's handler or\n * by resuming the part, if there is no defined\n * handler\n */\n async #handlePart(part: MultipartStream) {\n /**\n * Skip parts with empty name or empty filenames. The empty\n * filenames takes place when user doesn't upload a file\n * and empty name is more of a bad client scanerio.\n */\n if (!part.name || !part.filename) {\n part.resume()\n return\n }\n\n const name = this.#getHandlerName(part.name)\n\n /**\n * Skip, if their is no handler to consume the part.\n */\n const handler = this.#handlers[name] || this.#handlers['*']\n if (!handler) {\n debug('skipping multipart part as there are no handlers \"%s\"', name)\n part.resume()\n return\n }\n\n debug('processing multipart part \"%s\"', name)\n this.#pendingHandlers++\n\n /**\n * Instantiate the part handler\n */\n const partHandler = new PartHandler(part, handler.options)\n partHandler.begin()\n\n /**\n * Track the file instance created by the part handler. The end user\n * must be able to access these files.\n */\n this.#files.add(partHandler.file.fieldName, partHandler.file)\n part.file = partHandler.file\n\n try {\n const response = await handler.handler(part, async (line) => {\n if (this.state !== 'processing') {\n return\n }\n\n const lineLength = line.length\n\n /**\n * Keeping an eye on total bytes processed so far and shortcircuit\n * request when more than expected bytes have been received.\n */\n const error = this.#validateProcessedBytes(lineLength)\n if (error) {\n part.emit('error', error)\n this.abort(error)\n return\n }\n\n try {\n await partHandler.reportProgress(line, lineLength)\n } catch (err) {\n this.#ctx.logger.fatal(\n 'Unhandled multipart stream error. Make sure to handle \"error\" events for all manually processed streams'\n )\n }\n })\n\n /**\n * Stream consumed successfully\n */\n await partHandler.reportSuccess(response || {})\n } catch (error) {\n /**\n * The stream handler reported an exception\n */\n await partHandler.reportError(error)\n }\n\n this.#pendingHandlers--\n }\n\n /**\n * Record the fields inside multipart contract\n */\n #handleField(key: string, value: string) {\n if (!key) {\n return\n }\n\n this.#fields.add(key, value)\n }\n\n /**\n * Processes the user config and computes the `upperLimit` value from\n * it.\n */\n #processConfig(config?: Partial<{ limit: string | number; maxFields: number }>) {\n this.#config = Object.assign(this.#config, config)\n\n /**\n * Getting bytes from the `config.fieldsLimit` option, which can\n * also be a string.\n */\n this.#maxFieldsSize =\n typeof this.#config!.fieldsLimit === 'string'\n ? bytes(this.#config.fieldsLimit)\n : this.#config!.fieldsLimit\n\n /**\n * Getting bytes from the `config.limit` option, which can\n * also be a string\n */\n this.#upperLimit =\n typeof this.#config!.limit === 'string' ? bytes(this.#config!.limit) : this.#config!.limit\n }\n\n /**\n * Mark the process as finished\n */\n #finish(newState: 'error' | 'success') {\n if (this.state === 'idle' || this.state === 'processing') {\n this.state = newState\n ;(this.#ctx.request as any)['__raw_files'] = this.#files.get()\n this.#ctx.request.setInitialBody(this.#fields.get())\n }\n }\n\n /**\n * Attach handler for a given file. To handle all files, you\n * can attach a wildcard handler.\n *\n * @example\n * ```ts\n * multipart.onFile('package', {}, async (stream) => {\n * })\n *\n * multipart.onFile('*', {}, async (stream) => {\n * })\n * ```\n */\n onFile(\n name: string,\n options: Partial<FileValidationOptions & { deferValidations: boolean }>,\n handler: PartHandlerType\n ): this {\n this.#handlers[name] = { handler, options }\n return this\n }\n\n /**\n * Abort request by emitting error\n */\n abort(error: any): void {\n this.#form.emit('error', error)\n }\n\n /**\n * Process the request by going all the file and field\n * streams.\n */\n process(config?: Partial<{ limit: string | number; maxFields: number }>): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.state !== 'idle') {\n reject(\n new Exception('multipart stream has already been consumed', {\n code: 'E_RUNTIME_EXCEPTION',\n })\n )\n return\n }\n\n this.state = 'processing'\n this.#processConfig(config)\n\n this.#form = new multiparty.Form({\n maxFields: this.#config!.maxFields,\n maxFieldsSize: this.#maxFieldsSize,\n })\n\n debug('processing multipart body')\n\n /**\n * Raise error when form encounters an\n * error\n */\n this.#form.on('error', (error: Error) => {\n this.#finish('error')\n\n process.nextTick(() => {\n if (this.#ctx.request.request.readable) {\n this.#ctx.request.request.resume()\n }\n\n if (error.message.match(/stream ended unexpectedly/)) {\n reject(\n new Exception('Invalid multipart request', {\n status: 400,\n code: 'E_INVALID_MULTIPART_REQUEST',\n })\n )\n } else if (error.message.match(/maxFields [0-9]+ exceeded/)) {\n reject(\n new Exception('Fields length limit exceeded', {\n status: 413,\n code: 'E_REQUEST_ENTITY_TOO_LARGE',\n })\n )\n } else if (error.message.match(/maxFieldsSize [0-9]+ exceeded/)) {\n reject(\n new Exception('Fields size in bytes exceeded', {\n status: 413,\n code: 'E_REQUEST_ENTITY_TOO_LARGE',\n })\n )\n } else {\n reject(error)\n }\n })\n })\n\n /**\n * Process each part at a time and also resolve the\n * promise when all parts are consumed and processed\n * by their handlers\n */\n this.#form.on('part', async (part: MultipartStream) => {\n await this.#handlePart(part)\n\n /**\n * When a stream finishes before the handler, the close `event`\n * will not resolve the current Promise. So in that case, we\n * check and resolve from here\n */\n if (this.#isClosed()) {\n this.#finish('success')\n resolve()\n }\n })\n\n /**\n * Listen for fields\n */\n this.#form.on('field', (key: string, value: any) => {\n try {\n this.#handleField(key, value)\n } catch (error) {\n this.abort(error)\n }\n })\n\n /**\n * Resolve promise on close, when all internal\n * file handlers are done processing files\n */\n this.#form.on('close', () => {\n if (this.#isClosed()) {\n this.#finish('success')\n resolve()\n }\n })\n\n this.#form.parse(this.#ctx.request.request)\n })\n }\n}\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport lodash from '@poppinss/utils/lodash'\n\n/**\n * A jar of form fields to store form data by handling\n * array gracefully\n */\nexport class FormFields {\n #fields: any = {}\n #config: { convertEmptyStringsToNull: boolean }\n\n constructor(config: { convertEmptyStringsToNull: boolean }) {\n this.#config = config\n }\n\n /**\n * Add a new key/value pair. The keys with array like\n * expressions are handled properly.\n *\n * @example\n * ```\n * formfields.add('username', 'virk')\n *\n * // array\n * formfields.add('username[]', 'virk')\n * formfields.add('username[]', 'nikk')\n *\n * // Indexed keys are orderd properly\n * formfields.add('username[1]', 'virk')\n * formfields.add('username[0]', 'nikk')\n * ```\n */\n add(key: string, value: any): void {\n let isArray = false\n\n /**\n * Convert empty strings to null\n */\n if (this.#config.convertEmptyStringsToNull && value === '') {\n value = null\n }\n\n /**\n * Drop `[]` without indexes, since lodash `_.set` and\n * `_.get` methods needs the index or plain key.\n */\n key = key.replace(/\\[]$/, () => {\n isArray = true\n return ''\n })\n\n /**\n * Check to see if value exists or set it (if missing)\n */\n const existingValue = lodash.get(this.#fields, key)\n\n if (!existingValue) {\n lodash.set(this.#fields, key, isArray ? [value] : value)\n return\n }\n\n /**\n * Mutate existing value if it's an array\n */\n if (Array.isArray(existingValue)) {\n existingValue.push(value)\n return\n }\n\n /**\n * Set new value + existing value\n */\n lodash.set(this.#fields, key, [existingValue, value])\n }\n\n /**\n * Returns the copy of form fields\n */\n get() {\n return this.#fields\n }\n}\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { extname } from 'node:path'\nimport { Exception } from '@poppinss/utils'\n\nimport { MultipartFile } from './file.js'\nimport type { MultipartStream, FileValidationOptions } from '../types.js'\nimport { computeFileTypeFromName, getFileType, supportMagicFileTypes } from '../helpers.js'\n\n/**\n * Part handler handles the progress of a stream and also internally validates\n * it's size and extension.\n *\n * This class offloads the task of validating a file stream, regardless of how\n * the stream is consumed. For example:\n *\n * In classic scanerio, we will process the file stream and write files to the\n * tmp directory and in more advanced cases, the end user can handle the\n * stream by themselves and report each chunk to this class.\n */\nexport class PartHandler {\n #part: MultipartStream\n #options: Partial<FileValidationOptions & { deferValidations: boolean }>\n\n /**\n * The stream buffer reported by the stream consumer. We hold the buffer until are\n * able to detect the file extension and then buff memory is released\n */\n #buff?: Buffer\n\n /**\n * A boolean to know, if we have emitted the error event after one or\n * more validation errors. We need this flag, since the race conditions\n * between `data` and `error` events will trigger multiple `error`\n * emit.\n */\n #emittedValidationError = false\n\n /**\n * A boolean to know if we can use the magic number to detect the file type. This is how it\n * works.\n *\n * - We begin by extracting the file extension from the file name\n * - If the file has no extension, we try to inspect the buffer\n * - If the extension is something we support via magic numbers, then we ignore the extension\n * \t and inspect the buffer\n * - Otherwise, we have no other option than to trust the extension\n *\n * Think of this as using the optimal way for validating the file type\n */\n get #canFileTypeBeDetected() {\n const fileExtension = extname(this.#part.filename).replace(/^\\./, '') as any\n\n return fileExtension ? supportMagicFileTypes.has(fileExtension) : true\n }\n\n /**\n * Creating a new file object for each part inside the multipart\n * form data\n */\n file: MultipartFile\n\n constructor(\n part: MultipartStream,\n options: Partial<FileValidationOptions & { deferValidations: boolean }>\n ) {\n this.#part = part\n this.#options = options\n this.file = new MultipartFile(\n {\n clientName: part.filename,\n fieldName: part.name,\n headers: part.headers,\n },\n {\n size: options.size,\n extnames: options.extnames,\n }\n )\n }\n\n /**\n * Detects the file type and extension and also validates it when validations\n * are not deferred.\n */\n async #detectFileTypeAndExtension() {\n if (!this.#buff) {\n return\n }\n\n const fileType = this.#canFileTypeBeDetected\n ? await getFileType(this.#buff)\n : computeFileTypeFromName(this.file.clientName, this.file.headers)\n\n if (fileType) {\n this.file.extname = fileType.ext\n this.file.type = fileType.type\n this.file.subtype = fileType.subtype\n }\n }\n\n /**\n * Skip the stream or end it forcefully. This is invoked when the\n * streaming consumer reports an error\n */\n #skipEndStream() {\n this.#part.emit('close')\n }\n\n /**\n * Finish the process of listening for any more events and mark the\n * file state as consumed.\n */\n #finish() {\n this.file.state = 'consumed'\n if (!this.#options.deferValidations) {\n this.file.validate()\n }\n }\n\n /**\n * Start the process the updating the file state\n * to streaming mode.\n */\n begin() {\n this.file.state = 'streaming'\n }\n\n /**\n * Handles the file upload progress by validating the file size and\n * extension.\n */\n async reportProgress(line: Buffer, bufferLength: number) {\n /**\n * Do not consume stream data when file state is not `streaming`. Stream\n * events race conditions may emit the `data` event after the `error`\n * event in some cases, so we have to restrict it here.\n */\n if (this.file.state !== 'streaming') {\n return\n }\n\n /**\n * Detect the file type and extension when extname is null, otherwise\n * empty out the buffer. We only need the buffer to find the\n * file extension from it's content.\n */\n if (this.file.extname === undefined) {\n this.#buff = this.#buff ? Buffer.concat([this.#buff, line]) : line\n await this.#detectFileTypeAndExtension()\n } else {\n this.#buff = undefined\n }\n\n /**\n * The length of stream buffer\n */\n this.file.size = this.file.size + bufferLength\n\n /**\n * Validate the file on every chunk, unless validations have been deferred.\n */\n if (this.#options.deferValidations) {\n return\n }\n\n /**\n * Attempt to validate the file after every chunk and report error\n * when it has one or more failures. After this the consumer must\n * call `reportError`.\n */\n this.file.validate()\n if (!this.file.isValid && !this.#emittedValidationError) {\n this.#emittedValidationError = true\n this.#part.emit(\n 'error',\n new Exception('one or more validations failed', {\n code: 'E_STREAM_VALIDATION_FAILURE',\n status: 400,\n })\n )\n }\n }\n\n /**\n * Report errors encountered while processing the stream. These can be errors\n * apart from the one reported by this class. For example: The `s3` failure\n * due to some bad credentails.\n */\n async reportError(error: any) {\n if (this.file.state !== 'streaming') {\n return\n }\n\n this.#skipEndStream()\n this.#finish()\n\n if (error.code === 'E_STREAM_VALIDATION_FAILURE') {\n return\n }\n\n /**\n * Push to the array of file errors\n */\n this.file.errors.push({\n fieldName: this.file.fieldName,\n clientName: this.file.clientName,\n type: 'fatal',\n message: error.message,\n })\n }\n\n /**\n * Report success data about the file.\n */\n async reportSuccess(data?: { filePath?: string; tmpPath?: string } & { [key: string]: any }) {\n if (this.file.state !== 'streaming') {\n return\n }\n\n /**\n * Re-attempt to detect the file extension after we are done\n * consuming the stream\n */\n if (this.file.extname === undefined) {\n await this.#detectFileTypeAndExtension()\n }\n\n if (data) {\n const { filePath, tmpPath, ...meta } = data\n if (filePath) {\n this.file.filePath = filePath\n }\n\n if (tmpPath) {\n this.file.tmpPath = tmpPath\n }\n\n this.file.meta = meta || {}\n }\n\n this.#finish()\n }\n}\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport { Readable } from 'node:stream'\nimport { unlink } from 'node:fs/promises'\nimport { createWriteStream } from 'node:fs'\nimport { pipeline } from 'node:stream/promises'\n\n/**\n * Writes readable stream to the given location by properly cleaning up readable\n * and writable streams in case of any errors. Also an optional data listener\n * can listen for the `data` event.\n */\nexport async function streamFile(\n readStream: Readable,\n location: string,\n dataListener?: (line: Buffer) => void\n): Promise<void> {\n if (typeof dataListener === 'function') {\n readStream.pause()\n readStream.on('data', dataListener)\n }\n\n const writeStream = createWriteStream(location)\n try {\n await pipeline(readStream, writeStream)\n } catch (error) {\n unlink(writeStream.path).catch(() => {})\n throw error\n }\n}\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport lodash from '@poppinss/utils/lodash'\nimport { Request } from '@adonisjs/http-server'\nimport { RuntimeException } from '@poppinss/utils'\n\nimport debug from '../debug.js'\nimport { MultipartFile } from '../multipart/file.js'\nimport type { FileValidationOptions } from '../types.js'\n\n/**\n * Updates the validation options on the file instance\n */\nfunction setFileOptions(file: MultipartFile, options?: Partial<FileValidationOptions>) {\n if (file.sizeLimit === undefined && options && options.size) {\n file.sizeLimit = options.size\n }\n\n if (file.allowedExtensions === undefined && options && options.extnames) {\n file.allowedExtensions = options.extnames\n }\n}\n\n/**\n * A boolean to know if file is an instance of multipart\n * file class\n */\nfunction isInstanceOfFile(file: any): file is MultipartFile {\n return file && file instanceof MultipartFile\n}\n\ndebug('extending request class with \"file\", \"files\" and \"allFiles\" macros')\n\n/**\n * Serialize files alongside rest of the request files\n */\nRequest.macro('toJSON', function (this: Request) {\n return {\n ...this.serialize(),\n files: this['__raw_files'] || {},\n }\n})\n\n/**\n * Fetch a single file\n */\nRequest.macro(\n 'file',\n function getFile(this: Request, key: string, options?: Partial<FileValidationOptions>) {\n let file: unknown = lodash.get(this.allFiles(), key)\n file = Array.isArray(file) ? file[0] : file\n\n if (!isInstanceOfFile(file)) {\n return null\n }\n\n setFileOptions(file, options)\n file.validate()\n return file\n }\n)\n\n/**\n * Fetch an array of files\n */\nRequest.macro(\n 'files',\n function getFiles(this: Request, key: string, options?: Partial<FileValidationOptions>) {\n let files: unknown[] = lodash.get(this.allFiles(), key)\n files = Array.isArray(files) ? files : files ? [files] : []\n\n return files.filter(isInstanceOfFile).map((file) => {\n setFileOptions(file, options)\n file.validate()\n return file\n })\n }\n)\n\n/**\n * Fetch all files\n */\nRequest.macro('allFiles', function allFiles(this: Request) {\n if (!this.__raw_files) {\n throw new RuntimeException(\n 'Cannot read files. Make sure the bodyparser middleware is registered'\n )\n }\n\n return this['__raw_files']\n})\n","/*\n * @adonisjs/bodyparser\n *\n * (c) AdonisJS\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport raw from 'raw-body'\nimport inflate from 'inflation'\nimport type { IncomingMessage } from 'node:http'\nimport { BodyParserRawConfig } from '../types.js'\n\n/**\n * Inflates request body\n */\nexport function parseText(req: IncomingMessage, options: Partial<BodyParserRawConfig>) {\n /**\n * Shallow clone options\n */\n const normalizedOptions = Object.assign(\n {\n encoding: 'utf8',\n limit: '1mb',\n length: 0,\n },\n options\n )\n\n /**\n * Mimicing behavior of\n * https://github.com/poppinss/co-body/blob/master/lib/text.js#L30\n */\n const contentLength = req.headers['content-length']\n const encoding = req.headers['content-encoding'] || 'identity'\n if (contentLength && encoding === 'identity') {\n normalizedOptions.length = ~~contentLength\n }\n\n return raw(inflate(req), normalizedOptions)\n}\n"],"mappings":"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","names":["Exception","raw","inflate","Exception","Exception","Exception","Exception","lodash","lodash","raw","inflate","Exception","raw"]}
\No newline at end of file