From a8560e8b2f83a4580c19383176c18d3b68925e1f Mon Sep 17 00:00:00 2001 From: Enrique Jhonatan Mejia Venegas Date: Fri, 14 Aug 2020 16:35:50 -0500 Subject: [PATCH 1/4] companion: add calculated content-length for formdata and body cases --- .../@uppy/companion/src/server/Uploader.js | 88 ++++++++++--------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/packages/@uppy/companion/src/server/Uploader.js b/packages/@uppy/companion/src/server/Uploader.js index d63ea23c7e..3d55442343 100644 --- a/packages/@uppy/companion/src/server/Uploader.js +++ b/packages/@uppy/companion/src/server/Uploader.js @@ -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') @@ -471,54 +472,59 @@ 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('file', file) + form.getLength((error, length) => { + if (error) { + logger.error(error, 'upload.multipart.error') } - ) + reqOptions.headers['content-length'] = length + const req = request[httpMethod](reqOptions, (error, response, body) => this._handleUploadMultipart(error, response, body, bytesUploaded)) + // @ts-ignore + req._form = form + }) } else { + const stats = fs.statSync(this.path) + const fileSizeInBytes = stats.size + reqOptions.headers['content-length'] = fileSizeInBytes reqOptions.body = file + request[httpMethod](reqOptions, (error, response, body) => this._handleUploadMultipart(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 - } + _handleUploadMultipart (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() } /** From 0a4b9508f06ccea1bf7cace482f252015077db38 Mon Sep 17 00:00:00 2001 From: Enrique Mejia Date: Fri, 21 Aug 2020 17:39:32 -0500 Subject: [PATCH 2/4] companion: append fieldname and emit error in form data Co-authored-by: Ifedapo .A. Olarewaju --- packages/@uppy/companion/src/server/Uploader.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/@uppy/companion/src/server/Uploader.js b/packages/@uppy/companion/src/server/Uploader.js index 3d55442343..ecd6235c29 100644 --- a/packages/@uppy/companion/src/server/Uploader.js +++ b/packages/@uppy/companion/src/server/Uploader.js @@ -476,10 +476,15 @@ class Uploader { for (const property in this.options.metadata) { form.append(property, this.options.metadata[property]) } - form.append('file', file) + 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.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._handleUploadMultipart(error, response, body, bytesUploaded)) From 6290edb14bd77a7e370ddc6caaafee8e5fbce777 Mon Sep 17 00:00:00 2001 From: Enrique Mejia Date: Fri, 21 Aug 2020 18:06:38 -0500 Subject: [PATCH 3/4] companion: change _handleUploadMultipart to _onMultipartComplete --- packages/@uppy/companion/src/server/Uploader.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@uppy/companion/src/server/Uploader.js b/packages/@uppy/companion/src/server/Uploader.js index ecd6235c29..83f61b2af4 100644 --- a/packages/@uppy/companion/src/server/Uploader.js +++ b/packages/@uppy/companion/src/server/Uploader.js @@ -487,7 +487,7 @@ class Uploader { return } reqOptions.headers['content-length'] = length - const req = request[httpMethod](reqOptions, (error, response, body) => this._handleUploadMultipart(error, response, body, bytesUploaded)) + const req = request[httpMethod](reqOptions, (error, response, body) => this._onMultipartComplete(error, response, body, bytesUploaded)) // @ts-ignore req._form = form }) @@ -496,11 +496,11 @@ class Uploader { const fileSizeInBytes = stats.size reqOptions.headers['content-length'] = fileSizeInBytes reqOptions.body = file - request[httpMethod](reqOptions, (error, response, body) => this._handleUploadMultipart(error, response, body, bytesUploaded)) + request[httpMethod](reqOptions, (error, response, body) => this._onMultipartComplete(error, response, body, bytesUploaded)) } } - _handleUploadMultipart (error, response, body, bytesUploaded) { + _onMultipartComplete (error, response, body, bytesUploaded) { if (error) { logger.error(error, 'upload.multipart.error') this.emitError(error) From 39d8621c15a8064ca8bc846b6cdea35b23505a7a Mon Sep 17 00:00:00 2001 From: "Ifedapo .A. Olarewaju" Date: Fri, 28 Aug 2020 12:21:58 +0100 Subject: [PATCH 4/4] companion: use async fs.stat --- packages/@uppy/companion/src/server/Uploader.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/@uppy/companion/src/server/Uploader.js b/packages/@uppy/companion/src/server/Uploader.js index 83f61b2af4..bf8a093c25 100644 --- a/packages/@uppy/companion/src/server/Uploader.js +++ b/packages/@uppy/companion/src/server/Uploader.js @@ -492,11 +492,18 @@ class Uploader { req._form = form }) } else { - const stats = fs.statSync(this.path) - const fileSizeInBytes = stats.size - reqOptions.headers['content-length'] = fileSizeInBytes - reqOptions.body = file - request[httpMethod](reqOptions, (error, response, body) => this._onMultipartComplete(error, response, body, bytesUploaded)) + 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)) + }) } }