diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 3c3970a..84be87b 100644 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -10,6 +10,13 @@ var zlib = require('zlib'); var pkg = require('./../../package.json'); var Buffer = require('buffer').Buffer; +// Resolve or reject the Promise based on the status +function settle(resolve, reject, response) { + (response.status >= 200 && response.status < 300 ? + resolve : + reject)(response); +} + /*eslint consistent-return:0*/ module.exports = function httpAdapter(resolve, reject, config) { var data = config.data; @@ -24,13 +31,13 @@ module.exports = function httpAdapter(resolve, reject, config) { headers['User-Agent'] = 'axios/' + pkg.version; } - if (data) { + if (data && !utils.isStream(data)) { if (utils.isArrayBuffer(data)) { data = new Buffer(new Uint8Array(data)); } else if (utils.isString(data)) { data = new Buffer(data, 'utf-8'); } else { - return reject(new Error('Data after transformation must be a string or an ArrayBuffer')); + return reject(new Error('Data after transformation must be a string, an ArrayBuffer, or a Stream')); } // Add Content-Length header if data exists @@ -93,39 +100,37 @@ module.exports = function httpAdapter(resolve, reject, config) { break; } - var responseBuffer = []; - stream.on('data', function handleStreamData(chunk) { - responseBuffer.push(chunk); + var response = { + status: res.statusCode, + statusText: res.statusMessage, + headers: res.headers, + config: config, + request: req + }; - // make sure the content length is not over the maxContentLength if specified - if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) { - reject(new Error('maxContentLength size of ' + config.maxContentLength + ' exceeded')); - } - }); + if (config.responseType === 'stream') { + response.data = stream; + settle(resolve, reject, response); + } else { + var responseBuffer = []; + stream.on('data', function handleStreamData(chunk) { + responseBuffer.push(chunk); - stream.on('end', function handleStreamEnd() { - var d = Buffer.concat(responseBuffer); - if (config.responseType !== 'arraybuffer') { - d = d.toString('utf8'); - } - var response = { - data: transformData( - d, - res.headers, - config.transformResponse - ), - status: res.statusCode, - statusText: res.statusMessage, - headers: res.headers, - config: config, - request: req - }; + // make sure the content length is not over the maxContentLength if specified + if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) { + reject(new Error('maxContentLength size of ' + config.maxContentLength + ' exceeded')); + } + }); - // Resolve or reject the Promise based on the status - (res.statusCode >= 200 && res.statusCode < 300 ? - resolve : - reject)(response); - }); + stream.on('end', function handleStreamEnd() { + var responseData = Buffer.concat(responseBuffer); + if (config.responseType !== 'arraybuffer') { + responseData = responseData.toString('utf8'); + } + response.data = transformData(responseData, res.headers, config.transformResponse); + settle(resolve, reject, response); + }); + } }); // Handle errors @@ -147,5 +152,9 @@ module.exports = function httpAdapter(resolve, reject, config) { } // Send the request - req.end(data); + if (utils.isStream(data)) { + data.pipe(req); + } else { + req.end(data); + } }; diff --git a/lib/defaults.js b/lib/defaults.js index 45910c8..6bbfcbf 100644 --- a/lib/defaults.js +++ b/lib/defaults.js @@ -8,11 +8,8 @@ var DEFAULT_CONTENT_TYPE = { }; module.exports = { - transformRequest: [function transformRequestJSON(data, headers) { - if (utils.isFormData(data)) { - return data; - } - if (utils.isArrayBuffer(data)) { + transformRequest: [function transformRequest(data, headers) { + if (utils.isFormData(data) || utils.isArrayBuffer(data) || utils.isStream(data)) { return data; } if (utils.isArrayBufferView(data)) { @@ -36,7 +33,7 @@ module.exports = { return data; }], - transformResponse: [function transformResponseJSON(data) { + transformResponse: [function transformResponse(data) { /*eslint no-param-reassign:0*/ if (typeof data === 'string') { data = data.replace(PROTECTION_PREFIX, ''); diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index b7f2086..acd0b30 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -2,6 +2,7 @@ var axios = require('../../../index'); var http = require('http'); var url = require('url'); var zlib = require('zlib'); +var fs = require('fs'); var server; module.exports = { @@ -127,7 +128,7 @@ module.exports = { }); }); }, - + testMaxContentLength: function(test) { var str = Array(100000).join('ж'); @@ -145,7 +146,7 @@ module.exports = { error = res; failure = true; }); - + setTimeout(function () { test.equal(success, false, 'request should not succeed'); test.equal(failure, true, 'request should fail'); @@ -153,5 +154,26 @@ module.exports = { test.done(); }, 100); }); + }, + + testStream: function(test) { + server = http.createServer(function (req, res) { + req.pipe(res); + }).listen(4444, function () { + axios.post('http://localhost:4444/', + fs.createReadStream(__filename), { + responseType: 'stream' + }).then(function (res) { + var stream = res.data; + var string = ''; + stream.on('data', function (chunk) { + string += chunk.toString('utf8'); + }); + stream.on('end', function () { + test.equal(string, fs.readFileSync(__filename, 'utf8')); + test.done(); + }); + }); + }); } };