fix(requestinterception): fix font loading issue (#7060)
See https://github.com/puppeteer/puppeteer/pull/6996#issuecomment-811546501 and https://github.com/puppeteer/puppeteer/pull/6996#issuecomment-813797393 for context. Issue: #7038
This commit is contained in:
parent
8126101980
commit
c9978d20d5
@ -69,11 +69,47 @@ export class NetworkManager extends EventEmitter {
|
||||
_client: CDPSession;
|
||||
_ignoreHTTPSErrors: boolean;
|
||||
_frameManager: FrameManager;
|
||||
_requestIdToRequest = new Map<string, HTTPRequest>();
|
||||
|
||||
/*
|
||||
* There are four possible orders of events:
|
||||
* A. `_onRequestWillBeSent`
|
||||
* B. `_onRequestWillBeSent`, `_onRequestPaused`
|
||||
* C. `_onRequestPaused`, `_onRequestWillBeSent`
|
||||
* D. `_onRequestPaused`, `_onRequestWillBeSent`, `_onRequestPaused`
|
||||
* (see crbug.com/1196004)
|
||||
*
|
||||
* For `_onRequest` we need the event from `_onRequestWillBeSent` and
|
||||
* optionally the `interceptionId` from `_onRequestPaused`.
|
||||
*
|
||||
* If request interception is disabled, call `_onRequest` once per call to
|
||||
* `_onRequestWillBeSent`.
|
||||
* If request interception is enabled, call `_onRequest` once per call to
|
||||
* `_onRequestPaused` (once per `interceptionId`).
|
||||
*
|
||||
* Events are stored to allow for subsequent events to call `_onRequest`.
|
||||
*
|
||||
* Note that (chains of) redirect requests have the same `requestId` (!) as
|
||||
* the original request. We have to anticipate series of events like these:
|
||||
* A. `_onRequestWillBeSent`,
|
||||
* `_onRequestWillBeSent`, ...
|
||||
* B. `_onRequestWillBeSent`, `_onRequestPaused`,
|
||||
* `_onRequestWillBeSent`, `_onRequestPaused`, ...
|
||||
* C. `_onRequestWillBeSent`, `_onRequestPaused`,
|
||||
* `_onRequestPaused`, `_onRequestWillBeSent`, ...
|
||||
* D. `_onRequestPaused`, `_onRequestWillBeSent`,
|
||||
* `_onRequestPaused`, `_onRequestWillBeSent`, `_onRequestPaused`, ...
|
||||
* (see crbug.com/1196004)
|
||||
*/
|
||||
_requestIdToRequestWillBeSentEvent = new Map<
|
||||
string,
|
||||
Protocol.Network.RequestWillBeSentEvent
|
||||
>();
|
||||
_requestIdToRequestPausedEvent = new Map<
|
||||
string,
|
||||
Protocol.Fetch.RequestPausedEvent
|
||||
>();
|
||||
_requestIdToRequest = new Map<string, HTTPRequest>();
|
||||
|
||||
_extraHTTPHeaders: Record<string, string> = {};
|
||||
_credentials?: Credentials = null;
|
||||
_attemptedAuthentications = new Set<string>();
|
||||
@ -81,7 +117,6 @@ export class NetworkManager extends EventEmitter {
|
||||
_userRequestInterceptionCacheSafe = false;
|
||||
_protocolRequestInterceptionEnabled = false;
|
||||
_userCacheDisabled = false;
|
||||
_requestIdToInterceptionId = new Map<string, string>();
|
||||
_emulatedNetworkConditions: InternalNetworkConditions = {
|
||||
offline: false,
|
||||
upload: -1,
|
||||
@ -222,12 +257,17 @@ export class NetworkManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
_cacheDisabled(): boolean {
|
||||
return (
|
||||
this._userCacheDisabled ||
|
||||
(this._userRequestInterceptionEnabled &&
|
||||
!this._userRequestInterceptionCacheSafe)
|
||||
);
|
||||
}
|
||||
|
||||
async _updateProtocolCacheDisabled(): Promise<void> {
|
||||
await this._client.send('Network.setCacheDisabled', {
|
||||
cacheDisabled:
|
||||
this._userCacheDisabled ||
|
||||
(this._userRequestInterceptionEnabled &&
|
||||
!this._userRequestInterceptionCacheSafe),
|
||||
cacheDisabled: this._cacheDisabled(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -238,13 +278,18 @@ export class NetworkManager extends EventEmitter {
|
||||
!event.request.url.startsWith('data:')
|
||||
) {
|
||||
const requestId = event.requestId;
|
||||
const interceptionId = this._requestIdToInterceptionId.get(requestId);
|
||||
if (interceptionId) {
|
||||
const requestPausedEvent = this._requestIdToRequestPausedEvent.get(
|
||||
requestId
|
||||
);
|
||||
|
||||
this._requestIdToRequestWillBeSentEvent.set(requestId, event);
|
||||
|
||||
if (requestPausedEvent) {
|
||||
const interceptionId = requestPausedEvent.requestId;
|
||||
this._onRequest(event, interceptionId);
|
||||
this._requestIdToInterceptionId.delete(requestId);
|
||||
} else {
|
||||
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);
|
||||
this._requestIdToRequestPausedEvent.delete(requestId);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
this._onRequest(event, null);
|
||||
@ -288,14 +333,30 @@ export class NetworkManager extends EventEmitter {
|
||||
|
||||
const requestId = event.networkId;
|
||||
const interceptionId = event.requestId;
|
||||
if (requestId && this._requestIdToRequestWillBeSentEvent.has(requestId)) {
|
||||
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(
|
||||
requestId
|
||||
);
|
||||
|
||||
if (!requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(
|
||||
requestId
|
||||
);
|
||||
|
||||
// redirect requests have the same `requestId`,
|
||||
if (
|
||||
requestWillBeSentEvent &&
|
||||
(requestWillBeSentEvent.request.url !== event.request.url ||
|
||||
requestWillBeSentEvent.request.method !== event.request.method)
|
||||
) {
|
||||
this._requestIdToRequestWillBeSentEvent.delete(requestId);
|
||||
requestWillBeSentEvent = null;
|
||||
}
|
||||
|
||||
if (requestWillBeSentEvent) {
|
||||
this._onRequest(requestWillBeSentEvent, interceptionId);
|
||||
this._requestIdToRequestWillBeSentEvent.delete(requestId);
|
||||
} else {
|
||||
this._requestIdToInterceptionId.set(requestId, interceptionId);
|
||||
this._requestIdToRequestPausedEvent.set(requestId, event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,8 +407,7 @@ export class NetworkManager extends EventEmitter {
|
||||
response._resolveBody(
|
||||
new Error('Response body is unavailable for redirect responses')
|
||||
);
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this._forgetRequest(request, false);
|
||||
this.emit(NetworkManagerEmittedEvents.Response, response);
|
||||
this.emit(NetworkManagerEmittedEvents.RequestFinished, request);
|
||||
}
|
||||
@ -361,6 +421,19 @@ export class NetworkManager extends EventEmitter {
|
||||
this.emit(NetworkManagerEmittedEvents.Response, response);
|
||||
}
|
||||
|
||||
_forgetRequest(request: HTTPRequest, events: boolean): void {
|
||||
const requestId = request._requestId;
|
||||
const interceptionId = request._interceptionId;
|
||||
|
||||
this._requestIdToRequest.delete(requestId);
|
||||
this._attemptedAuthentications.delete(interceptionId);
|
||||
|
||||
if (events) {
|
||||
this._requestIdToRequestWillBeSentEvent.delete(requestId);
|
||||
this._requestIdToRequestPausedEvent.delete(requestId);
|
||||
}
|
||||
}
|
||||
|
||||
_onLoadingFinished(event: Protocol.Network.LoadingFinishedEvent): void {
|
||||
const request = this._requestIdToRequest.get(event.requestId);
|
||||
// For certain requestIds we never receive requestWillBeSent event.
|
||||
@ -370,8 +443,7 @@ export class NetworkManager extends EventEmitter {
|
||||
// Under certain conditions we never get the Network.responseReceived
|
||||
// event from protocol. @see https://crbug.com/883475
|
||||
if (request.response()) request.response()._resolveBody(null);
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this._forgetRequest(request, true);
|
||||
this.emit(NetworkManagerEmittedEvents.RequestFinished, request);
|
||||
}
|
||||
|
||||
@ -383,8 +455,7 @@ export class NetworkManager extends EventEmitter {
|
||||
request._failureText = event.errorText;
|
||||
const response = request.response();
|
||||
if (response) response._resolveBody(null);
|
||||
this._requestIdToRequest.delete(request._requestId);
|
||||
this._attemptedAuthentications.delete(request._interceptionId);
|
||||
this._forgetRequest(request, true);
|
||||
this.emit(NetworkManagerEmittedEvents.RequestFailed, request);
|
||||
}
|
||||
}
|
||||
|
9
test/assets/cached/one-style-font.css
Normal file
9
test/assets/cached/one-style-font.css
Normal file
@ -0,0 +1,9 @@
|
||||
@font-face {
|
||||
font-family: 'one-style';
|
||||
src: url('./one-style.woff') format('woff');
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: pink;
|
||||
font-family: 'one-style', sans-serif;
|
||||
}
|
2
test/assets/cached/one-style-font.html
Normal file
2
test/assets/cached/one-style-font.html
Normal file
@ -0,0 +1,2 @@
|
||||
<link rel='stylesheet' href='./one-style-font.css'>
|
||||
<div>hello, world!</div>
|
@ -525,6 +525,15 @@ describe('request interception', function () {
|
||||
await page.reload();
|
||||
expect(cached.length).toBe(1);
|
||||
});
|
||||
it('should load fonts if cache-safe', async () => {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.setRequestInterception(true, true);
|
||||
page.on('request', (request) => request.continue());
|
||||
|
||||
await page.goto(server.PREFIX + '/cached/one-style-font.html');
|
||||
await page.waitForResponse((r) => r.url().endsWith('/one-style.woff'));
|
||||
});
|
||||
});
|
||||
|
||||
describeFailsFirefox('Request.continue', function () {
|
||||
|
Loading…
Reference in New Issue
Block a user