diff --git a/lib/clients/transports/request.js b/lib/clients/transports/request.js index 5f42a41cc..677245b19 100644 --- a/lib/clients/transports/request.js +++ b/lib/clients/transports/request.js @@ -30,6 +30,18 @@ var getRequestTransportArgs = function getReqestTransportArgs(args) { if (has(args.data, 'file')) { transportArgs.formData = args.data; + + // Buffers are sometimes not handled well by the underlying form-data package. Adding extra + // metadata can resolve this. + // see: https://github.com/slackapi/node-slack-sdk/issues/307#issuecomment-289231737 + if (Buffer.isBuffer(transportArgs.formData.file) && has(args.data, 'filename')) { + transportArgs.formData.file = { + value: transportArgs.formData.file, + options: { + filename: args.data.filename + } + }; + } } else { transportArgs.form = args.data; } diff --git a/package.json b/package.json index fc3a4a38a..dd079f206 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "ws": "^1.0.1" }, "devDependencies": { + "busboy": "^0.2.14", "chai": "^3.5.0", "codecov": "^1.0.1", "eslint": "^2.2.0", @@ -44,7 +45,7 @@ "jsdoc-to-markdown": "^1.3.7", "mocha": "^3.4.1", "mocha-lcov-reporter": "^1.0.0", - "nock": "^7.2.2", + "nock": "^9.1.5", "sinon": "^1.17.1" }, "engines": { diff --git a/test/clients/web/client.js b/test/clients/web/client.js index d8d4d9713..730fcf2a6 100644 --- a/test/clients/web/client.js +++ b/test/clients/web/client.js @@ -4,6 +4,7 @@ var path = require('path'); var lodash = require('lodash'); var nock = require('nock'); var sinon = require('sinon'); +var Busboy = require('busboy'); var pkginfo = require('pkginfo')(module, 'version', 'repository'); // eslint-disable-line no-unused-vars var WebAPIClient = require('../../../lib/clients/web/client'); @@ -99,7 +100,6 @@ describe('Web API Client', function () { expect(client.transport.args[0][0].data.body).to.equal('{"test": 10}'); expect(client.transport.args[1][0].data.body).to.equal('{"test": 20}'); expect(client.transport.args.length).to.equal(2); - }); done(); }); @@ -110,7 +110,7 @@ describe('Web API Client', function () { client._makeAPICall('test', { test: 'test' }, null, null); }); - it('should accept overriding of request options', function () { + it('should accept overriding of request options', function (done) { // Add Basic Auth @@ -137,10 +137,63 @@ describe('Web API Client', function () { client._makeAPICall('test', {}, null, function (e, results) { expect(results.test).to.equal('test'); + done(); }); }); + it('should add metadata to raw Buffers for files.upload', function (done) { + var imageBuffer = fs.readFileSync(path.resolve('test', 'fixtures', 'train.jpg')); + var client = new WebAPIClient('test-token', { retryConfig: { retries: 0 } }); + + nock('https://slack.com/api') + .post('/files.upload') + .reply(function (uri, requestBody, cb) { + var busboy = new Busboy({ headers: this.req.headers }); + var fileFound = false; // eslint-disable-line no-unused-vars + var filenameFound = false; // eslint-disable-line no-unused-vars + var errorFound = undefined; + var bodyBuffer; + busboy.on('file', function (fieldname, file, filename) { + fileFound = (fieldname === 'file' && filename === 'train.jpg'); + file.resume(); + }); + busboy.on('field', function (fieldname, val) { + filenameFound = (fieldname === 'filename' && val === 'train.jpg'); + }); + busboy.on('error', function (error) { + errorFound = error; + }); + busboy.on('finish', function () { + if (errorFound) { + cb(errorFound); + } else { + cb(null, [200, '{ "ok": true, "test": "passed" }']); + } + }); + if (requestBody) { + if (lodash.isFunction(Buffer.from)) { + bodyBuffer = Buffer.from(requestBody, 'hex'); + } else { + bodyBuffer = new Buffer(requestBody, 'hex'); + } + busboy.end(bodyBuffer); + } else { + cb(null, [500, '{ "ok": false, "test": "failed" }']); + } + }); + + client._makeAPICall('files.upload', + { filename: 'train.jpg' }, + { file: imageBuffer }, + function (error, results) { + expect(error).to.not.be.an('error'); + expect(results.test).to.equal('passed'); + done(); + } + ); + }); + describe('it should retry failed or rate-limited requests', function () { var attemptAPICall = function (done) { diff --git a/test/fixtures/train.jpg b/test/fixtures/train.jpg new file mode 100644 index 000000000..849941d81 Binary files /dev/null and b/test/fixtures/train.jpg differ