Skip to content

Commit

Permalink
companion: add calculated content-length for multipart uploads (trans…
Browse files Browse the repository at this point in the history
…loadit#2466)

* companion: add calculated content-length for formdata and body cases

* companion: append fieldname and emit error in form data

Co-authored-by: Ifedapo .A. Olarewaju <[email protected]>

* companion: change _handleUploadMultipart to _onMultipartComplete

* companion: use async fs.stat

Co-authored-by: Enrique Jhonatan Mejia Venegas <[email protected]>
Co-authored-by: Ifedapo .A. Olarewaju <[email protected]>
  • Loading branch information
3 people authored Aug 28, 2020
1 parent 868927d commit d51d742
Showing 1 changed file with 60 additions and 42 deletions.
102 changes: 60 additions & 42 deletions src/server/Uploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const uuid = require('uuid')
const isObject = require('isobject')
const validator = require('validator')
const request = require('request')
const FormData = require('form-data')
const emitter = require('./emitter')
const serializeError = require('serialize-error')
const { jsonStringify, hasMatch } = require('./helpers/utils')
Expand Down Expand Up @@ -471,54 +472,71 @@ class Uploader {
const headers = headerSanitize(this.options.headers)
const reqOptions = { url: this.options.endpoint, headers, encoding: null }
if (this.options.useFormData) {
reqOptions.formData = Object.assign(
{},
this.options.metadata,
{
[this.options.fieldname]: {
value: file,
options: {
filename: this.uploadFileName,
contentType: this.options.metadata.type
}
}
const form = new FormData()
for (const property in this.options.metadata) {
form.append(property, this.options.metadata[property])
}
form.append(this.options.fieldname, file, {
filename: this.uploadFileName,
contentType: this.options.metadata.type
})
form.getLength((error, length) => {
if (error) {
logger.error(error, 'upload.multipart.size.error')
this.emitError(error)
return
}
)
reqOptions.headers['content-length'] = length
const req = request[httpMethod](reqOptions, (error, response, body) => this._onMultipartComplete(error, response, body, bytesUploaded))
// @ts-ignore
req._form = form
})
} else {
reqOptions.body = file
fs.stat(this.path, (err, stats) => {
if (err) {
logger.error(err, 'upload.multipart.size.error')
this.emitError(err)
return
}

const fileSizeInBytes = stats.size
reqOptions.headers['content-length'] = fileSizeInBytes
reqOptions.body = file
request[httpMethod](reqOptions, (error, response, body) => this._onMultipartComplete(error, response, body, bytesUploaded))
})
}
}

request[httpMethod](reqOptions, (error, response, body) => {
if (error) {
logger.error(error, 'upload.multipart.error')
this.emitError(error)
return
}
const headers = response.headers
// remove browser forbidden headers
delete headers['set-cookie']
delete headers['set-cookie2']

const respObj = {
responseText: body.toString(),
status: response.statusCode,
statusText: response.statusMessage,
headers
}
_onMultipartComplete (error, response, body, bytesUploaded) {
if (error) {
logger.error(error, 'upload.multipart.error')
this.emitError(error)
return
}
const headers = response.headers
// remove browser forbidden headers
delete headers['set-cookie']
delete headers['set-cookie2']

const respObj = {
responseText: body.toString(),
status: response.statusCode,
statusText: response.statusMessage,
headers
}

if (response.statusCode >= 400) {
logger.error(`upload failed with status: ${response.statusCode}`, 'upload.multipart.error')
this.emitError(new Error(response.statusMessage), respObj)
} else if (bytesUploaded !== this.bytesWritten && bytesUploaded !== this.options.size) {
const errMsg = `uploaded only ${bytesUploaded} of ${this.bytesWritten} with status: ${response.statusCode}`
logger.error(errMsg, 'upload.multipart.mismatch.error')
this.emitError(new Error(errMsg))
} else {
this.emitSuccess(null, { response: respObj })
}
if (response.statusCode >= 400) {
logger.error(`upload failed with status: ${response.statusCode}`, 'upload.multipart.error')
this.emitError(new Error(response.statusMessage), respObj)
} else if (bytesUploaded !== this.bytesWritten && bytesUploaded !== this.options.size) {
const errMsg = `uploaded only ${bytesUploaded} of ${this.bytesWritten} with status: ${response.statusCode}`
logger.error(errMsg, 'upload.multipart.mismatch.error')
this.emitError(new Error(errMsg))
} else {
this.emitSuccess(null, { response: respObj })
}

this.cleanUp()
})
this.cleanUp()
}

/**
Expand Down

0 comments on commit d51d742

Please sign in to comment.