Skip to content

Commit 43b51ba

Browse files
wwwoutersindresorhus
authored andcommitted
Prevent uncaught exception in some cases (#459)
1 parent 13d6b68 commit 43b51ba

4 files changed

Lines changed: 100 additions & 77 deletions

File tree

index.js

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -142,59 +142,12 @@ function requestAsEventEmitter(opts) {
142142
return;
143143
}
144144

145-
const downloadBodySize = Number(res.headers['content-length']) || null;
146-
let downloaded = 0;
147-
148145
setImmediate(() => {
149-
const progressStream = new Transform({
150-
transform(chunk, encoding, callback) {
151-
downloaded += chunk.length;
152-
153-
const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
154-
155-
// Let flush() be responsible for emitting the last event
156-
if (percent < 1) {
157-
ee.emit('downloadProgress', {
158-
percent,
159-
transferred: downloaded,
160-
total: downloadBodySize
161-
});
162-
}
163-
164-
callback(null, chunk);
165-
},
166-
167-
flush(callback) {
168-
ee.emit('downloadProgress', {
169-
percent: 1,
170-
transferred: downloaded,
171-
total: downloadBodySize
172-
});
173-
174-
callback();
175-
}
176-
});
177-
178-
mimicResponse(res, progressStream);
179-
progressStream.redirectUrls = redirects;
180-
181-
const response = opts.decompress === true &&
182-
is.function(decompressResponse) &&
183-
opts.method !== 'HEAD' ? decompressResponse(progressStream) : progressStream;
184-
185-
if (!opts.decompress && ['gzip', 'deflate'].indexOf(res.headers['content-encoding']) !== -1) {
186-
opts.encoding = null;
146+
try {
147+
getResponse(res, opts, ee, redirects);
148+
} catch (e) {
149+
ee.emit('error', e);
187150
}
188-
189-
ee.emit('response', response);
190-
191-
ee.emit('downloadProgress', {
192-
percent: 0,
193-
transferred: 0,
194-
total: downloadBodySize
195-
});
196-
197-
res.pipe(progressStream);
198151
});
199152
});
200153

@@ -297,6 +250,61 @@ function requestAsEventEmitter(opts) {
297250
return ee;
298251
}
299252

253+
function getResponse(res, opts, ee, redirects) {
254+
const downloadBodySize = Number(res.headers['content-length']) || null;
255+
let downloaded = 0;
256+
257+
const progressStream = new Transform({
258+
transform(chunk, encoding, callback) {
259+
downloaded += chunk.length;
260+
261+
const percent = downloadBodySize ? downloaded / downloadBodySize : 0;
262+
263+
// Let flush() be responsible for emitting the last event
264+
if (percent < 1) {
265+
ee.emit('downloadProgress', {
266+
percent,
267+
transferred: downloaded,
268+
total: downloadBodySize
269+
});
270+
}
271+
272+
callback(null, chunk);
273+
},
274+
275+
flush(callback) {
276+
ee.emit('downloadProgress', {
277+
percent: 1,
278+
transferred: downloaded,
279+
total: downloadBodySize
280+
});
281+
282+
callback();
283+
}
284+
});
285+
286+
mimicResponse(res, progressStream);
287+
progressStream.redirectUrls = redirects;
288+
289+
const response = opts.decompress === true &&
290+
is.function(decompressResponse) &&
291+
opts.method !== 'HEAD' ? decompressResponse(progressStream) : progressStream;
292+
293+
if (!opts.decompress && ['gzip', 'deflate'].indexOf(res.headers['content-encoding']) !== -1) {
294+
opts.encoding = null;
295+
}
296+
297+
ee.emit('response', response);
298+
299+
ee.emit('downloadProgress', {
300+
percent: 0,
301+
transferred: 0,
302+
total: downloadBodySize
303+
});
304+
305+
res.pipe(progressStream);
306+
}
307+
300308
function asPromise(opts) {
301309
const timeoutFn = requestPromise => opts.gotTimeout && opts.gotTimeout.request ?
302310
pTimeout(requestPromise, opts.gotTimeout.request, new got.RequestError({message: 'Request timed out', code: 'ETIMEDOUT'}, opts)) :

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"nyc": "^11.0.2",
7878
"p-event": "^1.3.0",
7979
"pem": "^1.4.4",
80+
"proxyquire": "^1.8.0",
8081
"sinon": "^4.0.0",
8182
"slow-stream": "0.0.4",
8283
"tempfile": "^2.0.0",

test/error.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import http from 'http';
22
import test from 'ava';
33
import sinon from 'sinon';
4+
import proxyquire from 'proxyquire';
45
import got from '..';
56
import {createServer} from './helpers/server';
67

@@ -52,7 +53,7 @@ test('dns message', async t => {
5253
});
5354

5455
test('options.body error message', async t => {
55-
const err = await t.throws(got(s.url, {body: () => {}}));
56+
const err = await t.throws(got(s.url, {body: () => { }}));
5657
t.regex(err.message, /The `body` option must be a stream\.Readable, string, Buffer or plain Object/);
5758
});
5859

@@ -78,6 +79,17 @@ test.serial('http.request error', async t => {
7879
stub.restore();
7980
});
8081

82+
test.serial('catch error in mimicResponse', async t => {
83+
const proxiedGot = proxyquire('..', {
84+
'mimic-response'() {
85+
throw new Error('Error in mimic-response');
86+
}
87+
});
88+
89+
const err = await t.throws(proxiedGot(s.url));
90+
t.is(err.message, 'Error in mimic-response');
91+
});
92+
8193
test.after('cleanup', async () => {
8294
await s.close();
8395
});

test/unix-socket.js

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,37 @@ const socketPath = tempy.file({extension: 'socket'});
88

99
let s;
1010

11-
test.before('setup', async () => {
12-
s = await createServer();
11+
if (process.platform !== 'win32') {
12+
test.before('setup', async () => {
13+
s = await createServer();
1314

14-
s.on('/', (req, res) => {
15-
res.end('ok');
16-
});
15+
s.on('/', (req, res) => {
16+
res.end('ok');
17+
});
1718

18-
s.on('/foo:bar', (req, res) => {
19-
res.end('ok');
20-
});
19+
s.on('/foo:bar', (req, res) => {
20+
res.end('ok');
21+
});
2122

22-
await s.listen(socketPath);
23-
});
23+
await s.listen(socketPath);
24+
});
2425

25-
test('works', async t => {
26-
const url = format('http://unix:%s:%s', socketPath, '/');
27-
t.is((await got(url)).body, 'ok');
28-
});
26+
test('works', async t => {
27+
const url = format('http://unix:%s:%s', socketPath, '/');
28+
t.is((await got(url)).body, 'ok');
29+
});
2930

30-
test('protocol-less works', async t => {
31-
const url = format('unix:%s:%s', socketPath, '/');
32-
t.is((await got(url)).body, 'ok');
33-
});
31+
test('protocol-less works', async t => {
32+
const url = format('unix:%s:%s', socketPath, '/');
33+
t.is((await got(url)).body, 'ok');
34+
});
3435

35-
test('address with : works', async t => {
36-
const url = format('unix:%s:%s', socketPath, '/foo:bar');
37-
t.is((await got(url)).body, 'ok');
38-
});
36+
test('address with : works', async t => {
37+
const url = format('unix:%s:%s', socketPath, '/foo:bar');
38+
t.is((await got(url)).body, 'ok');
39+
});
3940

40-
test.after('cleanup', async () => {
41-
await s.close();
42-
});
41+
test.after('cleanup', async () => {
42+
await s.close();
43+
});
44+
}

0 commit comments

Comments
 (0)