api: make request.frame() non-null (#1319)

This commit is contained in:
Dmitry Gozman 2020-03-10 11:39:35 -07:00 committed by GitHub
parent 0ce8efab7b
commit 23cf3be828
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 33 additions and 32 deletions

View File

@ -3405,7 +3405,7 @@ page.on('requestfailed', request => {
``` ```
#### request.frame() #### request.frame()
- returns: <?[Frame]> A [Frame] that initiated this request, or `null` if navigating to error pages. - returns: <[Frame]> A [Frame] that initiated this request.
#### request.fulfill(response) #### request.fulfill(response)
- `response` <[Object]> Response that will fulfill this request - `response` <[Object]> Response that will fulfill this request
@ -3516,7 +3516,7 @@ ResourceType will be one of the following: `document`, `stylesheet`, `image`, `m
- returns: <Promise[?string]> Waits for this response to finish, throws when corresponding request failed. - returns: <Promise[?string]> Waits for this response to finish, throws when corresponding request failed.
#### response.frame() #### response.frame()
- returns: <?[Frame]> A [Frame] that initiated this response, or `null` if navigating to error pages. - returns: <[Frame]> A [Frame] that initiated this response.
#### response.headers() #### response.headers()
- returns: <[Object]> An object with HTTP headers associated with the response. All header names are lower-case. - returns: <[Object]> An object with HTTP headers associated with the response. All header names are lower-case.

View File

@ -42,11 +42,11 @@ export class CRNetworkManager {
this._eventListeners = this.instrumentNetworkEvents(client); this._eventListeners = this.instrumentNetworkEvents(client);
} }
instrumentNetworkEvents(session: CRSession): RegisteredListener[] { instrumentNetworkEvents(session: CRSession, workerFrame?: frames.Frame): RegisteredListener[] {
return [ return [
helper.addEventListener(session, 'Fetch.requestPaused', this._onRequestPaused.bind(this)), helper.addEventListener(session, 'Fetch.requestPaused', this._onRequestPaused.bind(this, workerFrame)),
helper.addEventListener(session, 'Fetch.authRequired', this._onAuthRequired.bind(this)), helper.addEventListener(session, 'Fetch.authRequired', this._onAuthRequired.bind(this)),
helper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this)), helper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this, workerFrame)),
helper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)), helper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)),
helper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)), helper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)),
helper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)), helper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)),
@ -102,20 +102,20 @@ export class CRNetworkManager {
} }
} }
_onRequestWillBeSent(event: Protocol.Network.requestWillBeSentPayload) { _onRequestWillBeSent(workerFrame: frames.Frame | undefined, event: Protocol.Network.requestWillBeSentPayload) {
// Request interception doesn't happen for data URLs with Network Service. // Request interception doesn't happen for data URLs with Network Service.
if (this._protocolRequestInterceptionEnabled && !event.request.url.startsWith('data:')) { if (this._protocolRequestInterceptionEnabled && !event.request.url.startsWith('data:')) {
const requestId = event.requestId; const requestId = event.requestId;
const interceptionId = this._requestIdToInterceptionId.get(requestId); const interceptionId = this._requestIdToInterceptionId.get(requestId);
if (interceptionId) { if (interceptionId) {
this._onRequest(event, interceptionId); this._onRequest(workerFrame, event, interceptionId);
this._requestIdToInterceptionId.delete(requestId); this._requestIdToInterceptionId.delete(requestId);
} else { } else {
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event); this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);
} }
return; return;
} }
this._onRequest(event, null); this._onRequest(workerFrame, event, null);
} }
_onAuthRequired(event: Protocol.Fetch.authRequiredPayload) { _onAuthRequired(event: Protocol.Fetch.authRequiredPayload) {
@ -133,7 +133,7 @@ export class CRNetworkManager {
}).catch(debugError); }).catch(debugError);
} }
_onRequestPaused(event: Protocol.Fetch.requestPausedPayload) { _onRequestPaused(workerFrame: frames.Frame | undefined, event: Protocol.Fetch.requestPausedPayload) {
if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) { if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) {
this._client.send('Fetch.continueRequest', { this._client.send('Fetch.continueRequest', {
requestId: event.requestId requestId: event.requestId
@ -146,14 +146,14 @@ export class CRNetworkManager {
const interceptionId = event.requestId; const interceptionId = event.requestId;
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(requestId); const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(requestId);
if (requestWillBeSentEvent) { if (requestWillBeSentEvent) {
this._onRequest(requestWillBeSentEvent, interceptionId); this._onRequest(workerFrame, requestWillBeSentEvent, interceptionId);
this._requestIdToRequestWillBeSentEvent.delete(requestId); this._requestIdToRequestWillBeSentEvent.delete(requestId);
} else { } else {
this._requestIdToInterceptionId.set(requestId, interceptionId); this._requestIdToInterceptionId.set(requestId, interceptionId);
} }
} }
_onRequest(event: Protocol.Network.requestWillBeSentPayload, interceptionId: string | null) { _onRequest(workerFrame: frames.Frame | undefined, event: Protocol.Network.requestWillBeSentPayload, interceptionId: string | null) {
if (event.request.url.startsWith('data:')) if (event.request.url.startsWith('data:'))
return; return;
let redirectChain: network.Request[] = []; let redirectChain: network.Request[] = [];
@ -165,8 +165,12 @@ export class CRNetworkManager {
redirectChain = request.request._redirectChain; redirectChain = request.request._redirectChain;
} }
} }
// TODO: how can frame be null here? const frame = event.frameId ? this._page._frameManager.frame(event.frameId) : workerFrame;
const frame = event.frameId ? this._page._frameManager.frame(event.frameId) : null; if (!frame) {
if (interceptionId)
this._client.send('Fetch.continueRequest', { requestId: interceptionId }).catch(debugError);
return;
}
const isNavigationRequest = event.requestId === event.loaderId && event.type === 'Document'; const isNavigationRequest = event.requestId === event.loaderId && event.type === 'Document';
const documentId = isNavigationRequest ? event.loaderId : undefined; const documentId = isNavigationRequest ? event.loaderId : undefined;
const request = new InterceptableRequest(this._client, frame, interceptionId, documentId, this._userRequestInterceptionEnabled, event, redirectChain); const request = new InterceptableRequest(this._client, frame, interceptionId, documentId, this._userRequestInterceptionEnabled, event, redirectChain);
@ -244,7 +248,7 @@ class InterceptableRequest implements network.RequestDelegate {
_documentId: string | undefined; _documentId: string | undefined;
private _client: CRSession; private _client: CRSession;
constructor(client: CRSession, frame: frames.Frame | null, interceptionId: string | null, documentId: string | undefined, allowInterception: boolean, event: Protocol.Network.requestWillBeSentPayload, redirectChain: network.Request[]) { constructor(client: CRSession, frame: frames.Frame, interceptionId: string | null, documentId: string | undefined, allowInterception: boolean, event: Protocol.Network.requestWillBeSentPayload, redirectChain: network.Request[]) {
this._client = client; this._client = client;
this._requestId = event.requestId; this._requestId = event.requestId;
this._interceptionId = interceptionId; this._interceptionId = interceptionId;

View File

@ -249,7 +249,8 @@ export class CRPage implements PageDelegate {
this._page._addConsoleMessage(event.type, args, toConsoleMessageLocation(event.stackTrace)); this._page._addConsoleMessage(event.type, args, toConsoleMessageLocation(event.stackTrace));
}); });
session.on('Runtime.exceptionThrown', exception => this._page.emit(Events.Page.PageError, exceptionToError(exception.exceptionDetails))); session.on('Runtime.exceptionThrown', exception => this._page.emit(Events.Page.PageError, exceptionToError(exception.exceptionDetails)));
this._networkManager.instrumentNetworkEvents(session); // TODO: attribute workers to the right frame.
this._networkManager.instrumentNetworkEvents(session, this._page.mainFrame());
} }
_onDetachedFromTarget(event: Protocol.Target.detachedFromTargetPayload) { _onDetachedFromTarget(event: Protocol.Target.detachedFromTargetPayload) {

View File

@ -211,11 +211,8 @@ export class FrameManager {
requestStarted(request: network.Request) { requestStarted(request: network.Request) {
this._inflightRequestStarted(request); this._inflightRequestStarted(request);
const frame = request.frame(); for (const watcher of request.frame()._requestWatchers)
if (frame) { watcher(request);
for (const watcher of frame._requestWatchers)
watcher(request);
}
if (!request._isFavicon) if (!request._isFavicon)
this._page._requestStarted(request); this._page._requestStarted(request);
} }
@ -233,14 +230,13 @@ export class FrameManager {
requestFailed(request: network.Request, canceled: boolean) { requestFailed(request: network.Request, canceled: boolean) {
this._inflightRequestFinished(request); this._inflightRequestFinished(request);
const frame = request.frame(); if (request._documentId) {
if (request._documentId && frame) { const isCurrentDocument = request.frame()._lastDocumentId === request._documentId;
const isCurrentDocument = frame._lastDocumentId === request._documentId;
if (!isCurrentDocument) { if (!isCurrentDocument) {
let errorText = request.failure()!.errorText; let errorText = request.failure()!.errorText;
if (canceled) if (canceled)
errorText += '; maybe frame was detached?'; errorText += '; maybe frame was detached?';
for (const watcher of frame._documentWatchers) for (const watcher of request.frame()._documentWatchers)
watcher(request._documentId, new Error(errorText)); watcher(request._documentId, new Error(errorText));
} }
} }
@ -263,7 +259,7 @@ export class FrameManager {
private _inflightRequestFinished(request: network.Request) { private _inflightRequestFinished(request: network.Request) {
const frame = request.frame(); const frame = request.frame();
if (!frame || request._isFavicon) if (request._isFavicon)
return; return;
if (!frame._inflightRequests.has(request)) if (!frame._inflightRequests.has(request))
return; return;
@ -276,7 +272,7 @@ export class FrameManager {
private _inflightRequestStarted(request: network.Request) { private _inflightRequestStarted(request: network.Request) {
const frame = request.frame(); const frame = request.frame();
if (!frame || request._isFavicon) if (request._isFavicon)
return; return;
frame._inflightRequests.add(request); frame._inflightRequests.add(request);
if (frame._inflightRequests.size === 1) if (frame._inflightRequests.size === 1)

View File

@ -107,14 +107,14 @@ export class Request {
private _method: string; private _method: string;
private _postData: string | undefined; private _postData: string | undefined;
private _headers: Headers; private _headers: Headers;
private _frame: frames.Frame | null; private _frame: frames.Frame;
private _waitForResponsePromise: Promise<Response>; private _waitForResponsePromise: Promise<Response>;
private _waitForResponsePromiseCallback: (value: Response) => void = () => {}; private _waitForResponsePromiseCallback: (value: Response) => void = () => {};
private _waitForFinishedPromise: Promise<Response | null>; private _waitForFinishedPromise: Promise<Response | null>;
private _waitForFinishedPromiseCallback: (value: Response | null) => void = () => {}; private _waitForFinishedPromiseCallback: (value: Response | null) => void = () => {};
private _interceptionHandled = false; private _interceptionHandled = false;
constructor(delegate: RequestDelegate | null, frame: frames.Frame | null, redirectChain: Request[], documentId: string | undefined, constructor(delegate: RequestDelegate | null, frame: frames.Frame, redirectChain: Request[], documentId: string | undefined,
url: string, resourceType: string, method: string, postData: string | undefined, headers: Headers) { url: string, resourceType: string, method: string, postData: string | undefined, headers: Headers) {
assert(!url.startsWith('data:'), 'Data urls should not fire requests'); assert(!url.startsWith('data:'), 'Data urls should not fire requests');
this._delegate = delegate; this._delegate = delegate;
@ -177,7 +177,7 @@ export class Request {
response._finishedPromise.then(() => this._waitForFinishedPromiseCallback(response)); response._finishedPromise.then(() => this._waitForFinishedPromiseCallback(response));
} }
frame(): frames.Frame | null { frame(): frames.Frame {
return this._frame; return this._frame;
} }
@ -309,7 +309,7 @@ export class Response {
return this._request; return this._request;
} }
frame(): frames.Frame | null { frame(): frames.Frame {
return this._request.frame(); return this._request.frame();
} }
} }

View File

@ -46,7 +46,7 @@ export class WKInterceptableRequest implements network.RequestDelegate {
_interceptedCallback: () => void = () => {}; _interceptedCallback: () => void = () => {};
private _interceptedPromise: Promise<unknown>; private _interceptedPromise: Promise<unknown>;
constructor(session: WKSession, allowInterception: boolean, frame: frames.Frame | null, event: Protocol.Network.requestWillBeSentPayload, redirectChain: network.Request[], documentId: string | undefined) { constructor(session: WKSession, allowInterception: boolean, frame: frames.Frame, event: Protocol.Network.requestWillBeSentPayload, redirectChain: network.Request[], documentId: string | undefined) {
this._session = session; this._session = session;
this._requestId = event.requestId; this._requestId = event.requestId;
this.request = new network.Request(allowInterception ? this : null, frame, redirectChain, documentId, event.request.url, this.request = new network.Request(allowInterception ? this : null, frame, redirectChain, documentId, event.request.url,

View File

@ -728,7 +728,7 @@ export class WKPage implements PageDelegate {
redirectChain = request.request._redirectChain; redirectChain = request.request._redirectChain;
} }
} }
const frame = this._page._frameManager.frame(event.frameId); const frame = this._page._frameManager.frame(event.frameId)!;
// TODO(einbinder) this will fail if we are an XHR document request // TODO(einbinder) this will fail if we are an XHR document request
const isNavigationRequest = event.type === 'Document'; const isNavigationRequest = event.type === 'Document';
const documentId = isNavigationRequest ? event.loaderId : undefined; const documentId = isNavigationRequest ? event.loaderId : undefined;