diff --git a/lib/http/request.js b/lib/http/request.js index e17fbc3c..4deb85e3 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -192,13 +192,28 @@ RequestOptions.prototype.fromOptions = function fromOptions(options) { } }; -RequestOptions.prototype.expected = function expected(type) { +RequestOptions.prototype.isExpected = function isExpected(type) { if (!this.expect) return true; return this.expect === type; }; +RequestOptions.prototype.isOverflow = function isOverflow(length) { + if (!length) + return false; + + if (!this.buffer) + return false; + + length = parseInt(length, 10); + + if (length !== length) + return true; + + return length > this.limit; +}; + RequestOptions.prototype.getBackend = function getBackend() { ensureRequires(this.ssl); return this.ssl ? https : http; @@ -299,10 +314,6 @@ Request.prototype.cleanup = function cleanup() { this.response.removeListener('data', this.onData); this.response.removeListener('error', this.onEnd); this.response.removeListener('end', this.onEnd); - if (this.response.socket) { - this.response.socket.removeListener('error', this.onEnd); - this.response.socket.removeListener('end', this.onEnd); - } } }; @@ -400,8 +411,9 @@ Request.prototype.finish = function finish(err) { }; Request.prototype._onResponse = function _onResponse(response) { - var location = response.headers['location']; var type = response.headers['content-type']; + var length = response.headers['content-length']; + var location = response.headers['location']; if (location) { if (++this.redirects > this.options.maxRedirects) { @@ -417,16 +429,25 @@ Request.prototype._onResponse = function _onResponse(response) { type = parseType(type); - if (!this.options.expected(type)) { + if (!this.options.isExpected(type)) { this.finish(new Error('Wrong content-type for response.')); return; } + if (this.options.isOverflow(length)) { + this.finish(new Error('Response exceeded limit.')); + return; + } + this.response = response; this.statusCode = response.statusCode; this.headers = response.headers; this.type = type; + this.response.on('data', this.onData); + this.response.on('error', this.onEnd); + this.response.on('end', this.onEnd); + this.emit('headers', response.headers); this.emit('type', this.type); this.emit('response', response); @@ -439,31 +460,26 @@ Request.prototype._onResponse = function _onResponse(response) { this.body = []; } } - - this.response.on('data', this.onData); - this.response.on('error', this.onEnd); - this.response.on('end', this.onEnd); }; Request.prototype._onData = function _onData(data) { this.total += data.length; - if (this.options.limit) { - if (this.total > this.options.limit) { - this.finish(new Error('Response exceeded limit.')); - return; - } - } + this.emit('data', data); if (this.options.buffer) { + if (this.options.limit) { + if (this.total > this.options.limit) { + this.finish(new Error('Response exceeded limit.')); + return; + } + } if (this.decoder) { this.body += this.decoder.write(data); return; } this.body.push(data); } - - this.emit('data', data); }; Request.prototype._onEnd = function _onEnd(err) { @@ -539,19 +555,32 @@ request.promise = function promise(options) { */ function parseType(type) { - if (/\/json/i.test(type)) - return 'json'; + type = type || ''; + type = type.split(';')[0]; + type = type.toLowerCase(); + type = type.trim(); - if (/form-urlencoded/i.test(type)) - return 'form'; - - if (/\/x?html/i.test(type)) - return 'html'; - - if (/text\/plain/i.test(type)) - return 'text'; - - return 'binary'; + switch (type) { + case 'text/x-json': + case 'application/json': + return 'json'; + case 'application/x-www-form-urlencoded': + return 'form'; + case 'text/html': + case 'application/xhtml+xml': + return 'html'; + case 'text/javascript': + case 'application/javascript': + return 'js'; + case 'text/css': + return 'css'; + case 'text/plain': + return 'text'; + case 'application/octet-stream': + return 'binary'; + default: + return 'binary'; + } } function getType(type) { @@ -562,6 +591,10 @@ function getType(type) { return 'application/x-www-form-urlencoded; charset=utf-8'; case 'html': return 'text/html; charset=utf-8'; + case 'js': + return 'application/javascript; charset=utf-8'; + case 'css': + return 'text/css; charset=utf-8'; case 'text': return 'text/plain; charset=utf-8'; case 'binary':