diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..56cd390 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +# http://editorconfig.org +root = true +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/lib/index.js b/lib/index.js index 281d6f4..3478948 100644 --- a/lib/index.js +++ b/lib/index.js @@ -24,7 +24,11 @@ var supportedResponseTypes = Object.freeze({ /** Text response (implicit) */ '': true, /** Text response */ - 'text': true + 'text': true, + /** Binary-data response */ + 'arraybuffer': true, + /** JSON response */ + 'json': true }); /** @@ -139,6 +143,14 @@ module.exports = function () { * @type {?String} */ this._responseText = null; + + /** + * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response + * + * @private + * @type {ArrayBuffer | String | Object} + */ + this._response = null; }; /** @alias module:node-http-xhr */ @@ -297,7 +309,17 @@ NodeHttpXHR.prototype = Object.create( throw new Error('Unsupported responseType "' + type + '"'); } - return this._responseText; + switch (type) { + case '': + case 'text': + return this._responseText; + case 'json': + return JSON.parse(this._responseText); + case 'arraybuffer': + return this._response.buffer; + default: + throw new Error('Assertion failed: unsupported response-type: ' + type); + } } }, /** @@ -308,10 +330,19 @@ NodeHttpXHR.prototype = Object.create( * This will be incomplete until the response actually finishes. * * @type {?String} + * @throws when `response` not a String * @readonly */ responseText: { - get: function getResponseText() { return this._responseText; } + get: function getResponseText() { + + // @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText#Exceptions + if (this._responseType !== 'text' && this._responseType !== '') { + throw new Error('InvalidStateError: Response-type is ' + this._responseType); + } + + return this._responseText; + } }, /** * Indicates whether or not cross-site `Access-Control` requests should be @@ -469,13 +500,33 @@ NodeHttpXHR.prototype.send = function (data) { this._resp = resp; this._responseText = ''; - resp.setEncoding('utf8'); + // var contentType = resp.headers['content-type']; + // TODO: adjust responseType from content-type header if applicable + + // from Node API docs: The encoding argument is optional and only applies when chunk is a string. Defaults to 'utf8'. + if (this._responseType === 'text' || this._responseType === '') { + resp.setEncoding('utf8'); + } + resp.on('data', function onData(chunk) { - this._responseText += chunk; + + if (typeof chunk === 'string') { + this._responseText += chunk; + } else if (typeof chunk === 'object') { + if (!(chunk instanceof Buffer)) { + throw new Error('Assertion failed: Response-data should be of `Buffer` type'); + } + if (this._response) { + this._response = Buffer.concat([this._response, chunk]); + } else { + this._response = chunk; + } + } if (this.readyState !== this.LOADING) { this._setReadyState(this.LOADING); } + }.bind(this)); resp.on('end', function onEnd() { diff --git a/test/index.test.js b/test/index.test.js index 942fe75..c19a051 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -413,6 +413,31 @@ function describeXHRProps() { }); describe('#responseType', function () { + + it('supports binary data (arraybuffer responseType)', function (done) { + + var responseData = new Buffer(909); + + var binaryScope = nock('http://example.com') + .get('/music.mp3') + .reply(200, responseData, { + 'Content-Type': 'audio/mpeg' + }); + + req.responseType = 'arraybuffer'; + req.open('GET', 'http://example.com/music.mp3'); + req.send(); + + req.onload = function () { + + assume(req.responseType).equals('arraybuffer'); + assume(req.response).equals(responseData.buffer); + + binaryScope.done(); + done(); + }; + }); + it('intially is `\'\'`', function () { assume(req.responseType).equals(''); });