fix(chromium): race between loadingFailed and requestPaused (#10289)
This commit is contained in:
parent
119a2e8f1b
commit
6a46711347
|
|
@ -56,7 +56,7 @@ export class CRNetworkManager {
|
||||||
eventsHelper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)),
|
eventsHelper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)),
|
||||||
eventsHelper.addEventListener(session, 'Network.responseReceivedExtraInfo', this._onResponseReceivedExtraInfo.bind(this)),
|
eventsHelper.addEventListener(session, 'Network.responseReceivedExtraInfo', this._onResponseReceivedExtraInfo.bind(this)),
|
||||||
eventsHelper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)),
|
eventsHelper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)),
|
||||||
eventsHelper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)),
|
eventsHelper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this, workerFrame)),
|
||||||
eventsHelper.addEventListener(session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)),
|
eventsHelper.addEventListener(session, 'Network.webSocketCreated', e => this._page._frameManager.onWebSocketCreated(e.requestId, e.url)),
|
||||||
eventsHelper.addEventListener(session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId)),
|
eventsHelper.addEventListener(session, 'Network.webSocketWillSendHandshakeRequest', e => this._page._frameManager.onWebSocketRequest(e.requestId)),
|
||||||
eventsHelper.addEventListener(session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText)),
|
eventsHelper.addEventListener(session, 'Network.webSocketHandshakeResponseReceived', e => this._page._frameManager.onWebSocketResponse(e.requestId, e.response.status, e.response.statusText)),
|
||||||
|
|
@ -368,12 +368,25 @@ export class CRNetworkManager {
|
||||||
this._page._frameManager.reportRequestFinished(request.request, response);
|
this._page._frameManager.reportRequestFinished(request.request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onLoadingFailed(event: Protocol.Network.loadingFailedPayload) {
|
_onLoadingFailed(workerFrame: frames.Frame | undefined, event: Protocol.Network.loadingFailedPayload) {
|
||||||
this._responseExtraInfoTracker.loadingFailed(event);
|
this._responseExtraInfoTracker.loadingFailed(event);
|
||||||
|
|
||||||
let request = this._requestIdToRequest.get(event.requestId);
|
let request = this._requestIdToRequest.get(event.requestId);
|
||||||
if (!request)
|
if (!request)
|
||||||
request = this._maybeAdoptMainRequest(event.requestId);
|
request = this._maybeAdoptMainRequest(event.requestId);
|
||||||
|
|
||||||
|
if (!request) {
|
||||||
|
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(event.requestId);
|
||||||
|
if (requestWillBeSentEvent) {
|
||||||
|
// This is a case where request has failed before we had a chance to intercept it.
|
||||||
|
// We stop waiting for Fetch.requestPaused (it might never come), and dispatch request event
|
||||||
|
// right away, followed by requestfailed event.
|
||||||
|
this._requestIdToRequestWillBeSentEvent.delete(event.requestId);
|
||||||
|
this._onRequest(workerFrame, requestWillBeSentEvent, null);
|
||||||
|
request = this._requestIdToRequest.get(event.requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For certain requestIds we never receive requestWillBeSent event.
|
// For certain requestIds we never receive requestWillBeSent event.
|
||||||
// @see https://crbug.com/750469
|
// @see https://crbug.com/750469
|
||||||
if (!request)
|
if (!request)
|
||||||
|
|
|
||||||
|
|
@ -69,3 +69,56 @@ it('should return response body when Cross-Origin-Opener-Policy is set', async (
|
||||||
expect(response.request().failure()).toBeNull();
|
expect(response.request().failure()).toBeNull();
|
||||||
expect(await response.text()).toBe('Hello there!');
|
expect(await response.text()).toBe('Hello there!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fire requestfailed when intercepting race', async ({ page, server, browserName }) => {
|
||||||
|
const promsie = new Promise<void>(resolve => {
|
||||||
|
let counter = 0;
|
||||||
|
const failures = new Set();
|
||||||
|
const alive = new Set();
|
||||||
|
page.on('request', request => {
|
||||||
|
expect(alive.has(request)).toBe(false);
|
||||||
|
expect(failures.has(request)).toBe(false);
|
||||||
|
alive.add(request);
|
||||||
|
});
|
||||||
|
page.on('requestfailed', request => {
|
||||||
|
expect(failures.has(request)).toBe(false);
|
||||||
|
expect(alive.has(request)).toBe(true);
|
||||||
|
alive.delete(request);
|
||||||
|
failures.add(request);
|
||||||
|
if (++counter === 10)
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stall requests to make sure we don't get requestfinished.
|
||||||
|
await page.route('**', route => {});
|
||||||
|
|
||||||
|
const runFunc = {
|
||||||
|
chromium: 'abortAll()', // Fast in chromium to expose the race.
|
||||||
|
webkit: 'setTimeout(abortAll, 0)', // Async in webkit to let it issue requests.
|
||||||
|
firefox: 'setTimeout(abortAll, 1000)', // Slow in firefox to give it enough time to issue requests.
|
||||||
|
}[browserName];
|
||||||
|
|
||||||
|
await page.setContent(`
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<iframe src="${server.EMPTY_PAGE}"></iframe>
|
||||||
|
<script>
|
||||||
|
function abortAll() {
|
||||||
|
const frames = document.querySelectorAll("iframe");
|
||||||
|
for (const frame of frames)
|
||||||
|
frame.src = "about:blank";
|
||||||
|
}
|
||||||
|
${runFunc}
|
||||||
|
</script>
|
||||||
|
`);
|
||||||
|
|
||||||
|
await promsie;
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue