Initial Save
This commit is contained in:
318
node_modules/@apollographql/graphql-upload-8-fork/lib/processRequest.js
generated
vendored
Normal file
318
node_modules/@apollographql/graphql-upload-8-fork/lib/processRequest.js
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
'use strict'
|
||||
|
||||
exports.__esModule = true
|
||||
exports.processRequest = void 0
|
||||
|
||||
var _util = _interopRequireDefault(require('util'))
|
||||
|
||||
var _busboy = _interopRequireDefault(require('busboy'))
|
||||
|
||||
var _fsCapacitor = require('fs-capacitor')
|
||||
|
||||
var _httpErrors = _interopRequireDefault(require('http-errors'))
|
||||
|
||||
var _objectPath = _interopRequireDefault(require('object-path'))
|
||||
|
||||
var _constants = require('./constants')
|
||||
|
||||
var _ignoreStream = require('./ignoreStream')
|
||||
|
||||
var _isEnumerableObject = require('./isEnumerableObject')
|
||||
|
||||
// istanbul ignore next
|
||||
function _interopRequireDefault(obj) {
|
||||
return obj && obj.__esModule ? obj : { default: obj }
|
||||
}
|
||||
|
||||
class Upload {
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = file => {
|
||||
this.file = file
|
||||
resolve(file)
|
||||
}
|
||||
|
||||
this.reject = reject
|
||||
})
|
||||
this.promise.catch(() => {})
|
||||
}
|
||||
}
|
||||
|
||||
const processRequest = (
|
||||
request,
|
||||
response,
|
||||
{ maxFieldSize = 1000000, maxFileSize = Infinity, maxFiles = Infinity } = {}
|
||||
) =>
|
||||
new Promise((resolve, reject) => {
|
||||
let released
|
||||
let exitError
|
||||
let currentStream
|
||||
let operations
|
||||
let operationsPath
|
||||
let map
|
||||
const parser = new _busboy.default({
|
||||
headers: request.headers,
|
||||
limits: {
|
||||
fieldSize: maxFieldSize,
|
||||
fields: 2,
|
||||
fileSize: maxFileSize,
|
||||
files: maxFiles
|
||||
}
|
||||
})
|
||||
|
||||
const exit = error => {
|
||||
if (exitError) return
|
||||
exitError = error
|
||||
reject(exitError)
|
||||
parser.destroy()
|
||||
if (currentStream) currentStream.destroy(exitError)
|
||||
if (map)
|
||||
for (const upload of map.values())
|
||||
if (!upload.file) upload.reject(exitError)
|
||||
request.unpipe(parser)
|
||||
setImmediate(() => {
|
||||
request.resume()
|
||||
})
|
||||
}
|
||||
|
||||
const release = () => {
|
||||
// istanbul ignore next
|
||||
if (released) return
|
||||
released = true
|
||||
if (map)
|
||||
for (const upload of map.values())
|
||||
if (upload.file) upload.file.capacitor.destroy()
|
||||
}
|
||||
|
||||
const abort = () => {
|
||||
exit(
|
||||
(0, _httpErrors.default)(
|
||||
499,
|
||||
'Request disconnected during file upload stream parsing.'
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
parser.on(
|
||||
'field',
|
||||
(fieldName, value, fieldNameTruncated, valueTruncated) => {
|
||||
if (exitError) return
|
||||
if (valueTruncated)
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
413,
|
||||
`The ‘${fieldName}’ multipart field value exceeds the ${maxFieldSize} byte size limit.`
|
||||
)
|
||||
)
|
||||
|
||||
switch (fieldName) {
|
||||
case 'operations':
|
||||
try {
|
||||
operations = JSON.parse(value)
|
||||
} catch (error) {
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Invalid JSON in the ‘operations’ multipart field (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
!(0, _isEnumerableObject.isEnumerableObject)(operations) &&
|
||||
!Array.isArray(operations)
|
||||
)
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Invalid type for the ‘operations’ multipart field (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
operationsPath = (0, _objectPath.default)(operations)
|
||||
break
|
||||
|
||||
case 'map': {
|
||||
if (!operations)
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Misordered multipart fields; ‘map’ should follow ‘operations’ (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
let parsedMap
|
||||
|
||||
try {
|
||||
parsedMap = JSON.parse(value)
|
||||
} catch (error) {
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Invalid JSON in the ‘map’ multipart field (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (!(0, _isEnumerableObject.isEnumerableObject)(parsedMap))
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Invalid type for the ‘map’ multipart field (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
const mapEntries = Object.entries(parsedMap)
|
||||
if (mapEntries.length > maxFiles)
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
413,
|
||||
`${maxFiles} max file uploads exceeded.`
|
||||
)
|
||||
)
|
||||
map = new Map()
|
||||
|
||||
for (const [fieldName, paths] of mapEntries) {
|
||||
if (!Array.isArray(paths))
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Invalid type for the ‘map’ multipart field entry key ‘${fieldName}’ array (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
map.set(fieldName, new Upload())
|
||||
|
||||
for (const [index, path] of paths.entries()) {
|
||||
if (typeof path !== 'string')
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Invalid type for the ‘map’ multipart field entry key ‘${fieldName}’ array index ‘${index}’ value (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
|
||||
try {
|
||||
operationsPath.set(path, map.get(fieldName).promise)
|
||||
} catch (error) {
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Invalid object path for the ‘map’ multipart field entry key ‘${fieldName}’ array index ‘${index}’ value ‘${path}’ (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve(operations)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
parser.on('file', (fieldName, stream, filename, encoding, mimetype) => {
|
||||
if (exitError) {
|
||||
;(0, _ignoreStream.ignoreStream)(stream)
|
||||
return
|
||||
}
|
||||
|
||||
if (!map) {
|
||||
;(0, _ignoreStream.ignoreStream)(stream)
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Misordered multipart fields; files should follow ‘map’ (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
currentStream = stream
|
||||
stream.on('end', () => {
|
||||
currentStream = null
|
||||
})
|
||||
const upload = map.get(fieldName)
|
||||
|
||||
if (!upload) {
|
||||
;(0, _ignoreStream.ignoreStream)(stream)
|
||||
return
|
||||
}
|
||||
|
||||
const capacitor = new _fsCapacitor.WriteStream()
|
||||
capacitor.on('error', () => {
|
||||
stream.unpipe()
|
||||
stream.resume()
|
||||
})
|
||||
stream.on('limit', () => {
|
||||
stream.unpipe()
|
||||
capacitor.destroy(
|
||||
(0, _httpErrors.default)(
|
||||
413,
|
||||
`File truncated as it exceeds the ${maxFileSize} byte size limit.`
|
||||
)
|
||||
)
|
||||
})
|
||||
stream.on('error', error => {
|
||||
stream.unpipe() // istanbul ignore next
|
||||
|
||||
capacitor.destroy(exitError || error)
|
||||
})
|
||||
stream.pipe(capacitor)
|
||||
const file = {
|
||||
filename,
|
||||
mimetype,
|
||||
encoding,
|
||||
|
||||
createReadStream() {
|
||||
const error = capacitor.error || (released ? exitError : null)
|
||||
if (error) throw error
|
||||
return capacitor.createReadStream()
|
||||
}
|
||||
}
|
||||
let capacitorStream
|
||||
Object.defineProperty(file, 'stream', {
|
||||
get: _util.default.deprecate(function() {
|
||||
if (!capacitorStream) capacitorStream = this.createReadStream()
|
||||
return capacitorStream
|
||||
}, 'File upload property ‘stream’ is deprecated. Use ‘createReadStream()’ instead.')
|
||||
})
|
||||
Object.defineProperty(file, 'capacitor', {
|
||||
value: capacitor
|
||||
})
|
||||
upload.resolve(file)
|
||||
})
|
||||
parser.once('filesLimit', () =>
|
||||
exit(
|
||||
(0, _httpErrors.default)(413, `${maxFiles} max file uploads exceeded.`)
|
||||
)
|
||||
)
|
||||
parser.once('finish', () => {
|
||||
request.unpipe(parser)
|
||||
request.resume()
|
||||
if (!operations)
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Missing multipart field ‘operations’ (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
if (!map)
|
||||
return exit(
|
||||
(0, _httpErrors.default)(
|
||||
400,
|
||||
`Missing multipart field ‘map’ (${_constants.SPEC_URL}).`
|
||||
)
|
||||
)
|
||||
|
||||
for (const upload of map.values())
|
||||
if (!upload.file)
|
||||
upload.reject(
|
||||
(0, _httpErrors.default)(400, 'File missing in the request.')
|
||||
)
|
||||
})
|
||||
parser.once('error', exit)
|
||||
response.once('finish', release)
|
||||
response.once('close', release)
|
||||
request.once('close', abort)
|
||||
request.once('end', () => {
|
||||
request.removeListener('close', abort)
|
||||
})
|
||||
request.pipe(parser)
|
||||
})
|
||||
|
||||
exports.processRequest = processRequest
|
||||
Reference in New Issue
Block a user