Skip to content

Commit

Permalink
Catch body errors before next tick happens
Browse files Browse the repository at this point in the history
  • Loading branch information
szmarczak committed Feb 6, 2020
1 parent b4a5402 commit 3dfe11a
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 5 deletions.
30 changes: 25 additions & 5 deletions source/create.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {Readable} from 'stream';
import {Merge} from 'type-fest';
import is from '@sindresorhus/is';
import asPromise, {createRejection} from './as-promise';
Expand Down Expand Up @@ -99,7 +100,29 @@ const aliases: readonly HTTPAlias[] = [
'delete'
];

export const defaultHandler: HandlerFunction = (options, next) => next(options);
export const defaultHandler: HandlerFunction = (options, next) => {
const result = next(options);

if (is.nodeStream(options.body)) {
const errorHandler = (error: Error): void => {
if (options.isStream) {
(result as ProxyStream).destroy(error);
return;
}

(result as CancelableRequest<unknown>).cancel(error.message);
};

options.body.once('error', errorHandler);

// @ts-ignore Each member of the union type '...' has signatures, but none of those signatures are compatible with each other
result.on('request', () => {
(options.body as Readable).off('error', errorHandler);
});
}

return result;
};

const create = (defaults: Defaults): Got => {
// Proxy properties from next handlers
Expand Down Expand Up @@ -167,10 +190,7 @@ const create = (defaults: Defaults): Got => {
}

handlers = handlers.filter(handler => handler !== defaultHandler);

if (handlers.length === 0) {
handlers.push(defaultHandler);
}
handlers.push(defaultHandler);

return create({
options: mergeOptions(...optionsArray) as DefaultOptions,
Expand Down
29 changes: 29 additions & 0 deletions test/post.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {promisify} from 'util';
import stream = require('stream');
import fs = require('fs');
import test from 'ava';
import {Handler} from 'express';
import delay = require('delay');
import getStream = require('get-stream');
import toReadableStream = require('to-readable-stream');
import got from '../source';
import withServer from './helpers/with-server';
Expand Down Expand Up @@ -271,3 +274,29 @@ test('DELETE method sends plain objects as JSON', withServer, async (t, server,
});
t.deepEqual(body, {such: 'wow'});
});

test('catches body errors before calling pipeline() - promise', withServer, async (t, server, got) => {
server.post('/', defaultEndpoint);

await t.throwsAsync(got.post({
body: fs.createReadStream('./file-that-does-not-exist.txt')
}), {
message: /ENOENT: no such file or directory/
});

// Wait for unhandled errors
await delay(100);
});

test('catches body errors before calling pipeline() - stream', withServer, async (t, server, got) => {
server.post('/', defaultEndpoint);

await t.throwsAsync(getStream(got.stream.post({
body: fs.createReadStream('./file-that-does-not-exist.txt')
})), {
message: /ENOENT: no such file or directory/
});

// Wait for unhandled errors
await delay(100);
});

0 comments on commit 3dfe11a

Please sign in to comment.