1'use strict'
2
3const WritableStream = require('node:stream').Writable
4const { inherits } = require('node:util')
5const Dicer = require('../deps/dicer/lib/Dicer')
6
7const MultipartParser = require('./types/multipart')
8const UrlencodedParser = require('./types/urlencoded')
9const parseParams = require('./utils/parseParams')
10
11function Busboy (opts) {
12  if (!(this instanceof Busboy)) { return new Busboy(opts) }
13
14  if (typeof opts !== 'object') {
15    throw new TypeError('Busboy expected an options-Object.')
16  }
17  if (typeof opts.headers !== 'object') {
18    throw new TypeError('Busboy expected an options-Object with headers-attribute.')
19  }
20  if (typeof opts.headers['content-type'] !== 'string') {
21    throw new TypeError('Missing Content-Type-header.')
22  }
23
24  const {
25    headers,
26    ...streamOptions
27  } = opts
28
29  this.opts = {
30    autoDestroy: false,
31    ...streamOptions
32  }
33  WritableStream.call(this, this.opts)
34
35  this._done = false
36  this._parser = this.getParserByHeaders(headers)
37  this._finished = false
38}
39inherits(Busboy, WritableStream)
40
41Busboy.prototype.emit = function (ev) {
42  if (ev === 'finish') {
43    if (!this._done) {
44      this._parser?.end()
45      return
46    } else if (this._finished) {
47      return
48    }
49    this._finished = true
50  }
51  WritableStream.prototype.emit.apply(this, arguments)
52}
53
54Busboy.prototype.getParserByHeaders = function (headers) {
55  const parsed = parseParams(headers['content-type'])
56
57  const cfg = {
58    defCharset: this.opts.defCharset,
59    fileHwm: this.opts.fileHwm,
60    headers,
61    highWaterMark: this.opts.highWaterMark,
62    isPartAFile: this.opts.isPartAFile,
63    limits: this.opts.limits,
64    parsedConType: parsed,
65    preservePath: this.opts.preservePath
66  }
67
68  if (MultipartParser.detect.test(parsed[0])) {
69    return new MultipartParser(this, cfg)
70  }
71  if (UrlencodedParser.detect.test(parsed[0])) {
72    return new UrlencodedParser(this, cfg)
73  }
74  throw new Error('Unsupported Content-Type.')
75}
76
77Busboy.prototype._write = function (chunk, encoding, cb) {
78  this._parser.write(chunk, cb)
79}
80
81module.exports = Busboy
82module.exports.default = Busboy
83module.exports.Busboy = Busboy
84
85module.exports.Dicer = Dicer
86