Skip to content

Commit

Permalink
Add read timeout (#1518)
Browse files Browse the repository at this point in the history
  • Loading branch information
szmarczak committed Feb 26, 2021
1 parent 51d88a0 commit e943672
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 10 deletions.
5 changes: 4 additions & 1 deletion readme.md
Expand Up @@ -518,7 +518,10 @@ This also accepts an `object` with the following fields to constrain the duratio
- `socket` starts when the socket is connected. See [request.setTimeout](https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback).
- `response` starts when the request has been written to the socket and ends when the response headers are received.
- `send` starts when the socket is connected and ends with the request has been written to the socket.
- `request` starts when the request is initiated and ends when the response's end event fires.
- `request` starts when the request is initiated and ends when the response's `end` event fires.
- ~~`read` starts when the `response` event is emitted and ends when the response's `end` event fires.~~

**Note:** The `read` timeout is blocked by https://github.com/nodejs/node/issues/35923

###### retry

Expand Down
24 changes: 15 additions & 9 deletions source/core/utils/timed-out.ts
Expand Up @@ -13,11 +13,12 @@ interface TimedOutOptions {

export interface Delays {
lookup?: number;
socket?: number;
connect?: number;
secureConnect?: number;
socket?: number;
response?: number;
send?: number;
response?: number;
read?: number;
request?: number;
}

Expand Down Expand Up @@ -89,14 +90,12 @@ export default (request: ClientRequest, delays: Delays, options: TimedOutOptions
}
});

request.once('close', cancelTimeouts);

once(request, 'response', (response: IncomingMessage): void => {
once(response, 'end', cancelTimeouts);
});

if (typeof delays.request !== 'undefined') {
addTimeout(delays.request, timeoutHandler, 'request');
const cancelTimeout = addTimeout(delays.request, timeoutHandler, 'request');

once(request, 'response', (response: IncomingMessage): void => {
once(response, 'end', cancelTimeout);
});
}

if (typeof delays.socket !== 'undefined') {
Expand Down Expand Up @@ -168,6 +167,13 @@ export default (request: ClientRequest, delays: Delays, options: TimedOutOptions
});
}

if (typeof delays.read !== 'undefined') {
once(request, 'response', (response: IncomingMessage): void => {
const cancelTimeout = addTimeout(delays.read!, timeoutHandler, 'read');
once(response, 'end', cancelTimeout);
});
}

return cancelTimeouts;
};

Expand Down
31 changes: 31 additions & 0 deletions test/timeout.ts
Expand Up @@ -642,6 +642,37 @@ test.serial('no unhandled `Premature close` error', withServer, async (t, server
await delay(20);
});

// TODO: use fakeTimers here
test.serial('`read` timeout - promise', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.write('o');
});

await t.throwsAsync(got({
timeout: {
read: 10
},
retry: 0
}), {message: 'Timeout awaiting \'read\' for 10ms'});
});

// TODO: use fakeTimers here
test.serial.failing('`read` timeout - stream', withServer, async (t, server, got) => {
t.timeout(100);

server.get('/', (_request, response) => {
response.end('ok');
});

const stream = got.stream({
timeout: {
read: 10
}
});

await t.throwsAsync(pEvent(stream, 'end'), {message: 'Timeout awaiting \'read\' for 10ms'});
});

// TODO: use fakeTimers here
test.serial('cancelling the request removes timeouts', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
Expand Down

0 comments on commit e943672

Please sign in to comment.