http: require json bodies to be an object.

This commit is contained in:
Christopher Jeffrey 2017-08-07 15:56:15 -07:00
parent e268e00adb
commit 7de854ce3f
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 52 additions and 16 deletions

View File

@ -329,6 +329,8 @@ HTTPBase.prototype.parseBody = async function parseBody(req, options) {
switch (type) { switch (type) {
case 'json': case 'json':
body = JSON.parse(data); body = JSON.parse(data);
if (!body || typeof body !== 'object' || Array.isArray(body))
throw new Error('JSON body must be an object.');
break; break;
case 'form': case 'form':
body = parsePairs(data, options.keyLimit); body = parsePairs(data, options.keyLimit);

View File

@ -202,16 +202,16 @@ RequestOptions.prototype.isExpected = function isExpected(type) {
return this.expect === type; return this.expect === type;
}; };
RequestOptions.prototype.isOverflow = function isOverflow(length) { RequestOptions.prototype.isOverflow = function isOverflow(hdr) {
if (!length) if (!hdr)
return false; return false;
if (!this.buffer) if (!this.buffer)
return false; return false;
length = parseInt(length, 10); const length = parseInt(hdr, 10);
if (length !== length) if (!isFinite(length))
return true; return true;
return length > this.limit; return length > this.limit;
@ -293,9 +293,10 @@ function Request(options) {
this.total = 0; this.total = 0;
this.decoder = null; this.decoder = null;
this.body = null; this.body = null;
this.buffer = null;
} }
Request.prototype.__proto__ = Stream.prototype; Object.setPrototypeOf(Request.prototype, Stream.prototype);
Request.prototype.startTimeout = function startTimeout() { Request.prototype.startTimeout = function startTimeout() {
if (!this.options.timeout) if (!this.options.timeout)
@ -395,27 +396,58 @@ Request.prototype.finish = function finish(err) {
this.cleanup(); this.cleanup();
if (this.options.buffer && this.body) { if (this.options.buffer) {
assert(this.buffer != null);
switch (this.type) { switch (this.type) {
case 'bin': case 'bin': {
this.body = Buffer.concat(this.body); this.body = Buffer.concat(this.buffer);
this.buffer = null;
break; break;
case 'json': }
case 'json': {
const buffer = this.buffer.trim();
this.buffer = null;
if (buffer.length === 0)
break;
let body;
try { try {
this.body = JSON.parse(this.body); body = JSON.parse(buffer);
} catch (e) { } catch (e) {
this.emit('error', e); this.emit('error', e);
return; return;
} }
if (!body || typeof body !== 'object') {
this.emit('error', new Error('JSON body is a non-object.'));
return;
}
this.body = body;
break; break;
case 'form': }
case 'form': {
const buffer = this.buffer;
this.buffer = null;
try { try {
this.body = qs.parse(this.body); this.body = qs.parse(buffer);
} catch (e) { } catch (e) {
this.emit('error', e); this.emit('error', e);
return; return;
} }
break; break;
}
default: {
this.body = this.buffer;
this.buffer = null;
break;
}
} }
} }
@ -469,9 +501,9 @@ Request.prototype._onResponse = function _onResponse(response) {
if (this.options.buffer) { if (this.options.buffer) {
if (this.type !== 'bin') { if (this.type !== 'bin') {
this.decoder = new StringDecoder('utf8'); this.decoder = new StringDecoder('utf8');
this.body = ''; this.buffer = '';
} else { } else {
this.body = []; this.buffer = [];
} }
} }
}; };
@ -488,11 +520,13 @@ Request.prototype._onData = function _onData(data) {
return; return;
} }
} }
if (this.decoder) { if (this.decoder) {
this.body += this.decoder.write(data); this.buffer += this.decoder.write(data);
return; return;
} }
this.body.push(data);
this.buffer.push(data);
} }
}; };