Skip to content

Commit

Permalink
Merge 14459a4 into b45896a
Browse files Browse the repository at this point in the history
  • Loading branch information
djmadeira committed May 22, 2017
2 parents b45896a + 14459a4 commit 459cd91
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 159 deletions.
24 changes: 21 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const Buffer = require('safe-buffer').Buffer;
const isURL = require('isurl');
const isPlainObj = require('is-plain-obj');
const PCancelable = require('p-cancelable');
const pTimeout = require('p-timeout');
const pkg = require('./package');

const getMethodRedirectCodes = new Set([300, 301, 302, 303, 304, 305, 307, 308]);
Expand Down Expand Up @@ -119,7 +120,11 @@ function requestAsEventEmitter(opts) {
}

function asPromise(opts) {
return new PCancelable((onCancel, resolve, reject) => {
const timeoutFn = requestPromise => opts.gotTimeout && opts.gotTimeout.request ?
pTimeout(requestPromise, opts.gotTimeout.request, new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts)) :
requestPromise;

return timeoutFn(new PCancelable((onCancel, resolve, reject) => {
const ee = requestAsEventEmitter(opts);
let cancelOnRequest = false;

Expand Down Expand Up @@ -179,13 +184,20 @@ function asPromise(opts) {
});

ee.on('error', reject);
});
}));
}

function asStream(opts) {
const input = new PassThrough();
const output = new PassThrough();
const proxy = duplexer3(input, output);
let timeout;

if (opts.gotTimeout && opts.gotTimeout.request) {
timeout = setTimeout(() => {
proxy.emit('error', new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts));
}, opts.gotTimeout.request);
}

if (opts.json) {
throw new Error('got can not be used as stream when options.json is used');
Expand Down Expand Up @@ -221,6 +233,8 @@ function asStream(opts) {
});

ee.on('response', res => {
clearTimeout(timeout);

const statusCode = res.statusCode;

res.pipe(output);
Expand Down Expand Up @@ -354,7 +368,11 @@ function normalizeArguments(url, opts) {
}

if (opts.timeout) {
opts.gotTimeout = opts.timeout;
if (typeof opts.timeout === 'number') {
opts.gotTimeout = {request: opts.timeout};
} else {
opts.gotTimeout = opts.timeout;
}
delete opts.timeout;
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"isurl": "^1.0.0-alpha5",
"lowercase-keys": "^1.0.0",
"p-cancelable": "^0.2.0",
"p-timeout": "^1.1.1",
"safe-buffer": "^5.0.1",
"timed-out": "^4.0.0",
"url-parse-lax": "^1.0.0"
Expand Down
4 changes: 2 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ Query string object that will be added to the request URL. This will override th

Type: `number`, `object`

Milliseconds to wait for a server to send response headers before aborting request with `ETIMEDOUT` error.
Milliseconds to wait for the server to end the response before aborting request with `ETIMEDOUT` error.

Option accepts `object` with separate `connect` and `socket` fields for connection and socket inactivity timeouts.
This also accepts an object with separate `connect`, `socket`, and `request` fields for connection, socket, and entire request timeouts.

###### retries

Expand Down
8 changes: 2 additions & 6 deletions test/arguments.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,8 @@ test('overrides querystring from opts', async t => {
});

test('should throw with auth in url', async t => {
try {
await got('https://test:45d3ps453@account.myservice.com/api/token');
t.fail('Exception was not thrown');
} catch (err) {
t.regex(err.message, /Basic authentication must be done with auth option/);
}
const err = await t.throws(got('https://test:45d3ps453@account.myservice.com/api/token'));
t.regex(err.message, /Basic authentication must be done with auth option/);
});

test('should throw when body is set to object', async t => {
Expand Down
48 changes: 18 additions & 30 deletions test/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,30 @@ test.before('setup', async () => {
});

test('properties', async t => {
try {
await got(s.url);
t.fail('Exception was not thrown');
} catch (err) {
t.truthy(err);
t.truthy(err.response);
t.false({}.propertyIsEnumerable.call(err, 'response'));
t.false({}.hasOwnProperty.call(err, 'code'));
t.is(err.message, 'Response code 404 (Not Found)');
t.is(err.host, `${s.host}:${s.port}`);
t.is(err.method, 'GET');
t.is(err.protocol, 'http:');
t.is(err.url, err.response.requestUrl);
t.is(err.headers.connection, 'close');
}
const err = await t.throws(got(s.url));
t.truthy(err);
t.truthy(err.response);
t.false({}.propertyIsEnumerable.call(err, 'response'));
t.false({}.hasOwnProperty.call(err, 'code'));
t.is(err.message, 'Response code 404 (Not Found)');
t.is(err.host, `${s.host}:${s.port}`);
t.is(err.method, 'GET');
t.is(err.protocol, 'http:');
t.is(err.url, err.response.requestUrl);
t.is(err.headers.connection, 'close');
});

test('dns message', async t => {
try {
await got('.com', {retries: 0});
t.fail('Exception was not thrown');
} catch (err) {
t.truthy(err);
t.regex(err.message, /getaddrinfo ENOTFOUND/);
t.is(err.host, '.com');
t.is(err.method, 'GET');
}
const err = await t.throws(got('.com', {retries: 0}));
t.truthy(err);
t.regex(err.message, /getaddrinfo ENOTFOUND/);
t.is(err.host, '.com');
t.is(err.method, 'GET');
});

test('options.body error message', async t => {
try {
await got(s.url, {body: () => {}});
t.fail('Exception was not thrown');
} catch (err) {
t.regex(err.message, /options.body must be a ReadableStream, string, Buffer or plain Object/);
}
const err = await t.throws(got(s.url, {body: () => {}}));
t.regex(err.message, /options.body must be a ReadableStream, string, Buffer or plain Object/);
});

test.after('cleanup', async () => {
Expand Down
12 changes: 4 additions & 8 deletions test/gzip.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,10 @@ test('decompress content - stream', async t => {
});

test('handles gzip error', async t => {
try {
await got(`${s.url}/corrupted`);
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.message, 'incorrect header check');
t.is(err.path, '/corrupted');
t.is(err.name, 'ReadError');
}
const err = await t.throws(got(`${s.url}/corrupted`));
t.is(err.message, 'incorrect header check');
t.is(err.path, '/corrupted');
t.is(err.name, 'ReadError');
});

test('preserve headers property', async t => {
Expand Down
18 changes: 5 additions & 13 deletions test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,11 @@ test.before('setup', async () => {
test('promise mode', async t => {
t.is((await got.get(s.url)).body, 'ok');

try {
await got.get(`${s.url}/404`);
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.response.body, 'not found');
}

try {
await got.get('.com', {retries: 0});
t.fail('Exception was not thrown');
} catch (err) {
t.truthy(err);
}
const err = await t.throws(got.get(`${s.url}/404`));
t.is(err.response.body, 'not found');

const err2 = await t.throws(got.get('.com', {retries: 0}));
t.truthy(err2);
});

test.after('cleanup', async () => {
Expand Down
34 changes: 3 additions & 31 deletions test/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,9 @@ test('requestUrl response', async t => {
});

test('error with code', async t => {
try {
await got(`${s.url}/404`);
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.statusCode, 404);
t.is(err.response.body, 'not');
}
const err = await t.throws(got(`${s.url}/404`));
t.is(err.statusCode, 404);
t.is(err.response.body, 'not');
});

test('status code 304 doesn\'t throw', async t => {
Expand All @@ -77,30 +73,6 @@ test('buffer on encoding === null', async t => {
t.truthy(Buffer.isBuffer(data));
});

test('timeout option', async t => {
try {
await got(`${s.url}/404`, {
timeout: 1,
retries: 0
});
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.code, 'ETIMEDOUT');
}
});

test('timeout option as object', async t => {
try {
await got(`${s.url}/404`, {
timeout: {connect: 1},
retries: 0
});
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.code, 'ETIMEDOUT');
}
});

test('query option', async t => {
t.is((await got(s.url, {query: {recent: true}})).body, 'recent');
t.is((await got(s.url, {query: 'recent=true'})).body, 'recent');
Expand Down
32 changes: 10 additions & 22 deletions test/json-parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,34 +47,22 @@ test('not parses responses without a body', async t => {
});

test('wraps parsing errors', async t => {
try {
await got(`${s.url}/invalid`, {json: true});
t.fail('Exception was not thrown');
} catch (err) {
t.regex(err.message, /Unexpected token/);
t.true(err.message.indexOf(err.hostname) !== -1, err.message);
t.is(err.path, '/invalid');
}
const err = await t.throws(got(`${s.url}/invalid`, {json: true}));
t.regex(err.message, /Unexpected token/);
t.true(err.message.indexOf(err.hostname) !== -1, err.message);
t.is(err.path, '/invalid');
});

test('parses non-200 responses', async t => {
try {
await got(`${s.url}/non200`, {json: true});
t.fail('Exception was not thrown');
} catch (err) {
t.deepEqual(err.response.body, {data: 'dog'});
}
const err = await t.throws(got(`${s.url}/non200`, {json: true}));
t.deepEqual(err.response.body, {data: 'dog'});
});

test('ignores errors on invalid non-200 responses', async t => {
try {
await got(`${s.url}/non200-invalid`, {json: true});
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.message, 'Response code 500 (Internal Server Error)');
t.is(err.response.body, 'Internal error');
t.is(err.path, '/non200-invalid');
}
const err = await t.throws(got(`${s.url}/non200-invalid`, {json: true}));
t.is(err.message, 'Response code 500 (Internal Server Error)');
t.is(err.response.body, 'Internal error');
t.is(err.path, '/non200-invalid');
});

test('should have statusCode in err', async t => {
Expand Down
22 changes: 7 additions & 15 deletions test/redirects.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,9 @@ test('relative redirect works', async t => {
});

test('throws on endless redirect', async t => {
try {
await got(`${http.url}/endless`);
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.message, 'Redirected 10 times. Aborting.');
t.deepEqual(err.redirectUrls, Array(10).fill(`${http.url}/endless`));
}
const err = await t.throws(got(`${http.url}/endless`));
t.is(err.message, 'Redirected 10 times. Aborting.');
t.deepEqual(err.redirectUrls, Array(10).fill(`${http.url}/endless`));
});

test('query in options are not breaking redirects', async t => {
Expand All @@ -161,14 +157,10 @@ test('hostname+path in options are not breaking redirects', async t => {
});

test('redirect only GET and HEAD requests', async t => {
try {
await got(`${http.url}/relative`, {body: 'wow'});
t.fail('Exception was not thrown');
} catch (err) {
t.is(err.message, 'Response code 302 (Found)');
t.is(err.path, '/relative');
t.is(err.statusCode, 302);
}
const err = await t.throws(got(`${http.url}/relative`, {body: 'wow'}));
t.is(err.message, 'Response code 302 (Found)');
t.is(err.path, '/relative');
t.is(err.statusCode, 302);
});

test('redirect on 303 response even with post, put, delete', async t => {
Expand Down
48 changes: 19 additions & 29 deletions test/retry.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,12 @@ test('works on timeout error', async t => {
});

test('can be disabled with option', async t => {
try {
await got(`${s.url}/try-me`, {
timeout: {connect: 500, socket: 500},
retries: 0
});
t.fail();
} catch (err) {
t.truthy(err);
t.is(trys, 1);
}
const err = await t.throws(got(`${s.url}/try-me`, {
timeout: {connect: 500, socket: 500},
retries: 0
}));
t.truthy(err);
t.is(trys, 1);
});

test('function gets iter count', async t => {
Expand All @@ -57,28 +53,22 @@ test('function gets iter count', async t => {
});

test('falsy value prevents retries', async t => {
try {
await got(`${s.url}/long`, {
timeout: {connect: 100, socket: 100},
retries: () => 0
});
} catch (err) {
t.truthy(err);
}
const err = await t.throws(got(`${s.url}/long`, {
timeout: {connect: 100, socket: 100},
retries: () => 0
}));
t.truthy(err);
});

test('falsy value prevents retries #2', async t => {
try {
await got(`${s.url}/long`, {
timeout: {connect: 100, socket: 100},
retries: (iter, err) => {
t.truthy(err);
return false;
}
});
} catch (err) {
t.truthy(err);
}
const err = await t.throws(got(`${s.url}/long`, {
timeout: {connect: 100, socket: 100},
retries: (iter, err) => {
t.truthy(err);
return false;
}
}));
t.truthy(err);
});

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

0 comments on commit 459cd91

Please sign in to comment.