fix: allow ClientRequest responses to be throttled (#25531)

* fix: allow net streams to be throttled [WIP]

* fix: handle resume throttling within IncomingMessage [WIP]

* fix: fix urlLoader typing, add throttle test

* fix: fix lint and increase test timeout for Linux

* fix: increase test chunk limit to 20 and timeout to 2000

Co-authored-by: Jeremy Rose <nornagon@nornagon.net>
This commit is contained in:
Keeley Hammond 2020-10-05 17:47:41 -07:00 committed by GitHub
parent 53ee708fe8
commit 6356cd4018
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 8 deletions

View file

@ -38,12 +38,14 @@ class IncomingMessage extends Readable {
_shouldPush: boolean;
_data: (Buffer | null)[];
_responseHead: NodeJS.ResponseHead;
_resume: (() => void) | null;
constructor (responseHead: NodeJS.ResponseHead) {
super();
this._shouldPush = false;
this._data = [];
this._responseHead = responseHead;
this._resume = null;
}
get statusCode () {
@ -103,7 +105,9 @@ class IncomingMessage extends Readable {
throw new Error('HTTP trailers are not supported');
}
_storeInternalData (chunk: Buffer | null) {
_storeInternalData (chunk: Buffer | null, resume: (() => void) | null) {
// save the network callback for use in _pushInternalData
this._resume = resume;
this._data.push(chunk);
this._pushInternalData();
}
@ -113,6 +117,12 @@ class IncomingMessage extends Readable {
const chunk = this._data.shift();
this._shouldPush = this.push(chunk);
}
if (this._shouldPush && this._resume) {
this._resume();
// Reset the callback, so that a new one is used for each
// batch of throttled data
this._resume = null;
}
}
_read () {
@ -404,11 +414,11 @@ export class ClientRequest extends Writable implements Electron.ClientRequest {
const response = this._response = new IncomingMessage(responseHead);
this.emit('response', response);
});
this._urlLoader.on('data', (event, data) => {
this._response!._storeInternalData(Buffer.from(data));
this._urlLoader.on('data', (event, data, resume) => {
this._response!._storeInternalData(Buffer.from(data), resume);
});
this._urlLoader.on('complete', () => {
if (this._response) { this._response._storeInternalData(null); }
if (this._response) { this._response._storeInternalData(null, null); }
});
this._urlLoader.on('error', (event, netErrorString) => {
const error = new Error(netErrorString);