Skip to content

Commit

Permalink
Loosen unnecessary restrictions on the body option (#521)
Browse files Browse the repository at this point in the history
Fixes #381
  • Loading branch information
szmarczak authored and sindresorhus committed Jul 14, 2018
1 parent 107756f commit 7a49ce7
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 17 deletions.
13 changes: 7 additions & 6 deletions source/normalize-arguments.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,26 @@ module.exports = (url, options, defaults) => {
options.method = (options.method || 'GET').toUpperCase();
} else {
const {headers} = options;
const isObject = is.object(body) && !Buffer.isBuffer(body) && !is.nodeStream(body);
if (!is.nodeStream(body) && !is.string(body) && !is.buffer(body) && !(options.form || options.json)) {
throw new TypeError('The `body` option must be a stream.Readable, string or Buffer');
}

if (options.json && !(is.plainObject(body) || is.array(body))) {
throw new TypeError('The `body` option must be a plain Object or Array when the `json` option is used');
if (options.json && !(isObject || is.array(body))) {
throw new TypeError('The `body` option must be an Object or Array when the `json` option is used');
}

if (options.form && !is.plainObject(body)) {
throw new TypeError('The `body` option must be a plain Object when the `form` option is used');
if (options.form && !isObject) {
throw new TypeError('The `body` option must be an Object when the `form` option is used');
}

if (isFormData(body)) {
// Special case for https://github.com/form-data/form-data
headers['content-type'] = headers['content-type'] || `multipart/form-data; boundary=${body.getBoundary()}`;
} else if (options.form && is.plainObject(body)) {
} else if (options.form) {
headers['content-type'] = headers['content-type'] || 'application/x-www-form-urlencoded';
options.body = (new URLSearchParamsGlobal(body)).toString();
} else if (options.json && (is.plainObject(body) || is.array(body))) {
} else if (options.json) {
headers['content-type'] = headers['content-type'] || 'application/json';
options.body = JSON.stringify(body);
}
Expand Down
38 changes: 27 additions & 11 deletions test/error.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import http from 'http';
import test from 'ava';
import sinon from 'sinon';
import getStream from 'get-stream';
import proxyquire from 'proxyquire';
import got from '../source';
import {createServer} from './helpers/server';
Expand All @@ -26,6 +27,11 @@ test.before('setup', async () => {
res.end('body');
});

s.on('/body', async (req, res) => {
const body = await getStream(req);
res.end(body);
});

await s.listen(s.port);
});

Expand Down Expand Up @@ -53,18 +59,31 @@ test('dns message', async t => {
});

test('options.body error message', async t => {
const err = await t.throws(got(s.url, {body: {}}));
t.regex(err.message, /The `body` option must be a stream\.Readable, string or Buffer/);
await t.throws(got(s.url, {body: {}}), {
message: 'The `body` option must be a stream.Readable, string or Buffer'
});
});

test('options.body json error message', async t => {
const err = await t.throws(got(s.url, {body: Buffer.from('test'), json: true}));
t.regex(err.message, /The `body` option must be a plain Object or Array when the `json` option is used/);
await t.throws(got(s.url, {body: Buffer.from('test'), json: true}), {
message: 'The `body` option must be an Object or Array when the `json` option is used'
});
});

test('options.body form error message', async t => {
const err = await t.throws(got(s.url, {body: Buffer.from('test'), form: true}));
t.regex(err.message, /The `body` option must be a plain Object when the `form` option is used/);
await t.throws(got(s.url, {body: Buffer.from('test'), form: true}), {
message: 'The `body` option must be an Object when the `form` option is used'
});
});

test('no plain object restriction on body', async t => {
function CustomObject() {
this.a = 123;
}

const {body} = await got(`${s.url}/body`, {body: new CustomObject(), json: true});

t.deepEqual(body, {a: 123});
});

test('default status message', async t => {
Expand All @@ -83,9 +102,7 @@ test.serial('http.request error', async t => {
const stub = sinon.stub(http, 'request').callsFake(() => {
throw new TypeError('The header content contains invalid characters');
});
const err = await t.throws(got(s.url));
t.true(err instanceof got.RequestError);
t.is(err.message, 'The header content contains invalid characters');
await t.throws(got(s.url), {instanceOf: got.RequestError, message: 'The header content contains invalid characters'});
stub.restore();
});

Expand All @@ -99,8 +116,7 @@ test.serial('catch error in mimicResponse', async t => {
'mimic-response': mimicResponse
});

const err = await t.throws(proxiedGot(s.url));
t.is(err.message, 'Error in mimic-response');
await t.throws(proxiedGot(s.url), {message: 'Error in mimic-response'});
});

test.after('cleanup', async () => {
Expand Down

0 comments on commit 7a49ce7

Please # to comment.