Skip to content

Commit 359cb3a

Browse files
authored
fix(oopif): adopt main requests into oopifs (#2284)
Main request for an OOPIF starts in the parent session, and the oopif session is create only after the response has been received. Therefore, we should adopt the request after oopif session is created.
1 parent 2bd427a commit 359cb3a

File tree

3 files changed

+69
-8
lines changed

3 files changed

+69
-8
lines changed

src/chromium/crNetworkManager.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { logError } from '../logger';
2828
export class CRNetworkManager {
2929
private _client: CRSession;
3030
private _page: Page;
31+
private _parentManager: CRNetworkManager | null;
3132
private _requestIdToRequest = new Map<string, InterceptableRequest>();
3233
private _requestIdToRequestWillBeSentEvent = new Map<string, Protocol.Network.requestWillBeSentPayload>();
3334
private _credentials: {username: string, password: string} | null = null;
@@ -37,9 +38,10 @@ export class CRNetworkManager {
3738
private _requestIdToRequestPausedEvent = new Map<string, Protocol.Fetch.requestPausedPayload>();
3839
private _eventListeners: RegisteredListener[];
3940

40-
constructor(client: CRSession, page: Page) {
41+
constructor(client: CRSession, page: Page, parentManager: CRNetworkManager | null) {
4142
this._client = client;
4243
this._page = page;
44+
this._parentManager = parentManager;
4345
this._eventListeners = this.instrumentNetworkEvents(client);
4446
}
4547

@@ -235,7 +237,9 @@ export class CRNetworkManager {
235237
}
236238

237239
_onLoadingFinished(event: Protocol.Network.loadingFinishedPayload) {
238-
const request = this._requestIdToRequest.get(event.requestId);
240+
let request = this._requestIdToRequest.get(event.requestId);
241+
if (!request)
242+
request = this._maybeAdoptMainRequest(event.requestId);
239243
// For certain requestIds we never receive requestWillBeSent event.
240244
// @see https://crbug.com/750469
241245
if (!request)
@@ -253,7 +257,9 @@ export class CRNetworkManager {
253257
}
254258

255259
_onLoadingFailed(event: Protocol.Network.loadingFailedPayload) {
256-
const request = this._requestIdToRequest.get(event.requestId);
260+
let request = this._requestIdToRequest.get(event.requestId);
261+
if (!request)
262+
request = this._maybeAdoptMainRequest(event.requestId);
257263
// For certain requestIds we never receive requestWillBeSent event.
258264
// @see https://crbug.com/750469
259265
if (!request)
@@ -267,6 +273,23 @@ export class CRNetworkManager {
267273
request.request._setFailureText(event.errorText);
268274
this._page._frameManager.requestFailed(request.request, !!event.canceled);
269275
}
276+
277+
private _maybeAdoptMainRequest(requestId: Protocol.Network.RequestId): InterceptableRequest | undefined {
278+
// OOPIF has a main request that starts in the parent session but finishes in the child session.
279+
if (!this._parentManager)
280+
return;
281+
const request = this._parentManager._requestIdToRequest.get(requestId);
282+
// Main requests have matching loaderId and requestId.
283+
if (!request || request._documentId !== requestId)
284+
return;
285+
this._requestIdToRequest.set(requestId, request);
286+
this._parentManager._requestIdToRequest.delete(requestId);
287+
if (request._interceptionId && this._parentManager._attemptedAuthentications.has(request._interceptionId)) {
288+
this._parentManager._attemptedAuthentications.delete(request._interceptionId);
289+
this._attemptedAuthentications.add(request._interceptionId);
290+
}
291+
return request;
292+
}
270293
}
271294

272295
class InterceptableRequest implements network.RouteDelegate {

src/chromium/crPage.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class CRPage implements PageDelegate {
6565
this._coverage = new CRCoverage(client, browserContext);
6666
this._browserContext = browserContext;
6767
this._page = new Page(this, browserContext);
68-
this._mainFrameSession = new FrameSession(this, client, targetId);
68+
this._mainFrameSession = new FrameSession(this, client, targetId, null);
6969
this._sessions.set(targetId, this._mainFrameSession);
7070
client.once(CRSessionEvents.Disconnected, () => this._page._didDisconnect());
7171
this._pagePromise = this._mainFrameSession._initialize(hasUIWindow).then(() => this._initializedPage = this._page).catch(e => e);
@@ -75,7 +75,7 @@ export class CRPage implements PageDelegate {
7575
await Promise.all(Array.from(this._sessions.values()).map(frame => cb(frame)));
7676
}
7777

78-
private _sessionForFrame(frame: frames.Frame): FrameSession {
78+
_sessionForFrame(frame: frames.Frame): FrameSession {
7979
// Frame id equals target id.
8080
while (!this._sessions.has(frame._id)) {
8181
const parent = frame.parentFrame();
@@ -95,8 +95,9 @@ export class CRPage implements PageDelegate {
9595
// Frame id equals target id.
9696
const frame = this._page._frameManager.frame(targetId);
9797
assert(frame);
98+
const parentSession = this._sessionForFrame(frame);
9899
this._page._frameManager.removeChildFramesRecursively(frame);
99-
const frameSession = new FrameSession(this, session, targetId);
100+
const frameSession = new FrameSession(this, session, targetId, parentSession);
100101
this._sessions.set(targetId, frameSession);
101102
frameSession._initialize(false).catch(e => e);
102103
}
@@ -330,12 +331,12 @@ class FrameSession {
330331
private _firstNonInitialNavigationCommittedReject = (e: Error) => {};
331332
private _windowId: number | undefined;
332333

333-
constructor(crPage: CRPage, client: CRSession, targetId: string) {
334+
constructor(crPage: CRPage, client: CRSession, targetId: string, parentSession: FrameSession | null) {
334335
this._client = client;
335336
this._crPage = crPage;
336337
this._page = crPage._page;
337338
this._targetId = targetId;
338-
this._networkManager = new CRNetworkManager(client, this._page);
339+
this._networkManager = new CRNetworkManager(client, this._page, parentSession ? parentSession._networkManager : null);
339340
this._firstNonInitialNavigationCommittedPromise = new Promise((f, r) => {
340341
this._firstNonInitialNavigationCommittedFulfill = f;
341342
this._firstNonInitialNavigationCommittedReject = r;

test/chromium/oopif.spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,43 @@ describe('OOPIF', function() {
151151
await page.goto(server.PREFIX + '/dynamic-oopif.html');
152152
expect(await countOOPIFs(browser)).toBe(1);
153153
});
154+
it('should report main requests', async function({browser, page, server, context}) {
155+
const requestFrames = [];
156+
page.on('request', r => requestFrames.push(r.frame()));
157+
const finishedFrames = [];
158+
page.on('requestfinished', r => finishedFrames.push(r.frame()));
159+
160+
await page.goto(server.PREFIX + '/empty.html');
161+
const main = page.mainFrame();
162+
163+
await main.evaluate(url => {
164+
const iframe = document.createElement('iframe');
165+
iframe.src = url;
166+
document.body.appendChild(iframe);
167+
return new Promise(f => iframe.onload = f);
168+
}, server.CROSS_PROCESS_PREFIX + '/empty.html');
169+
expect(page.frames().length).toBe(2);
170+
const child = main.childFrames()[0];
171+
await child.waitForLoadState('domcontentloaded');
172+
173+
await child.evaluate(url => {
174+
const iframe = document.createElement('iframe');
175+
iframe.src = url;
176+
document.body.appendChild(iframe);
177+
return new Promise(f => iframe.onload = f);
178+
}, server.PREFIX + '/empty.html');
179+
expect(page.frames().length).toBe(3);
180+
const grandChild = child.childFrames()[0];
181+
await grandChild.waitForLoadState('domcontentloaded');
182+
183+
expect(await countOOPIFs(browser)).toBe(2);
184+
expect(requestFrames[0]).toBe(main);
185+
expect(finishedFrames[0]).toBe(main);
186+
expect(requestFrames[1]).toBe(child);
187+
expect(finishedFrames[1]).toBe(child);
188+
expect(requestFrames[2]).toBe(grandChild);
189+
expect(finishedFrames[2]).toBe(grandChild);
190+
});
154191
// @see https://github.com/microsoft/playwright/issues/1240
155192
it('should click a button when it overlays oopif', async function({browser, page, server, context}) {
156193
await page.goto(server.PREFIX + '/button-overlay-oopif.html');

0 commit comments

Comments
 (0)