diff --git a/shell/browser/net/node_stream_loader.cc b/shell/browser/net/node_stream_loader.cc index 4669d21cde19..613e75824d93 100644 --- a/shell/browser/net/node_stream_loader.cc +++ b/shell/browser/net/node_stream_loader.cc @@ -42,6 +42,12 @@ NodeStreamLoader::~NodeStreamLoader() { node::MakeCallback(isolate_, emitter_.Get(isolate_), "removeListener", node::arraysize(args), args, {0, 0}); } + + // Destroy the stream if not already ended + if (!ended_) { + node::MakeCallback(isolate_, emitter_.Get(isolate_), "destroy", 0, nullptr, + {0, 0}); + } } void NodeStreamLoader::Start(network::mojom::URLResponseHeadPtr head) { diff --git a/spec-main/api-protocol-spec.ts b/spec-main/api-protocol-spec.ts index fa1fcbb5db60..1202d3d2742e 100644 --- a/spec-main/api-protocol-spec.ts +++ b/spec-main/api-protocol-spec.ts @@ -440,6 +440,30 @@ describe('protocol module', () => { ajax(protocolName + '://fake-host'); await hasEndedPromise; }); + + it('destroys response streams when aborted before completion', async () => { + const events = new EventEmitter(); + registerStreamProtocol(protocolName, (request, callback) => { + const responseStream = new stream.PassThrough(); + responseStream.push('data\r\n'); + responseStream.on('close', () => { + events.emit('close'); + }); + callback({ + statusCode: 200, + headers: { 'Content-Type': 'text/plain' }, + data: responseStream + }); + events.emit('respond'); + }); + + const hasRespondedPromise = emittedOnce(events, 'respond'); + const hasClosedPromise = emittedOnce(events, 'close'); + ajax(protocolName + '://fake-host'); + await hasRespondedPromise; + await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'jquery.html')); + await hasClosedPromise; + }); }); describe('protocol.isProtocolRegistered', () => {