diff --git a/src/client/browserContext.ts b/src/client/browserContext.ts index 9b416fb7f1..94f763ac65 100644 --- a/src/client/browserContext.ts +++ b/src/client/browserContext.ts @@ -86,9 +86,7 @@ export class BrowserContext extends ChannelOwner this._onRequest(network.Request.from(request), Page.fromNullable(page))); this._channel.on('requestFailed', ({ request, failureText, responseEndTiming, page }) => this._onRequestFailed(network.Request.from(request), responseEndTiming, failureText, Page.fromNullable(page))); - this._channel.on('requestFinished', ({ request, response, responseEndTiming, responseHeaders, page, requestSizes }) => - this._onRequestFinished(network.Request.from(request), network.Response.fromNullable(response), responseEndTiming, responseHeaders, requestSizes, Page.fromNullable(page)) - ); + this._channel.on('requestFinished', params => this._onRequestFinished(params)); this._channel.on('response', ({ response, page }) => this._onResponse(network.Response.from(response), Page.fromNullable(page))); this._closedPromise = new Promise(f => this.once(Events.BrowserContext.Close, f)); } @@ -126,7 +124,11 @@ export class BrowserContext extends ChannelOwner implements api.Response { _headers: Headers; private _request: Request; + readonly _finishedPromise = new ManualPromise(); static from(response: channels.ResponseChannel): Response { return (response as any)._object; @@ -421,13 +422,8 @@ export class Response extends ChannelOwner { - return this._wrapApiCall(async (channel: channels.ResponseChannel) => { - const result = await channel.finished(); - if (result.error) - return new Error(result.error); - return null; - }); + async finished(): Promise { + return this._finishedPromise.then(() => null); } async body(): Promise { diff --git a/src/dispatchers/networkDispatchers.ts b/src/dispatchers/networkDispatchers.ts index 84bb502d70..db289a7033 100644 --- a/src/dispatchers/networkDispatchers.ts +++ b/src/dispatchers/networkDispatchers.ts @@ -73,10 +73,6 @@ export class ResponseDispatcher extends Dispatcher { - return await this._object._finishedPromise; - } - async body(): Promise { return { binary: (await this._object.body()).toString('base64') }; } diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index fe9024f778..cc746daec6 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -2673,7 +2673,6 @@ export type ResponseInitializer = { }; export interface ResponseChannel extends Channel { body(params?: ResponseBodyParams, metadata?: Metadata): Promise; - finished(params?: ResponseFinishedParams, metadata?: Metadata): Promise; securityDetails(params?: ResponseSecurityDetailsParams, metadata?: Metadata): Promise; serverAddr(params?: ResponseServerAddrParams, metadata?: Metadata): Promise; } @@ -2682,11 +2681,6 @@ export type ResponseBodyOptions = {}; export type ResponseBodyResult = { binary: Binary, }; -export type ResponseFinishedParams = {}; -export type ResponseFinishedOptions = {}; -export type ResponseFinishedResult = { - error?: string, -}; export type ResponseSecurityDetailsParams = {}; export type ResponseSecurityDetailsOptions = {}; export type ResponseSecurityDetailsResult = { diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index 735052d433..1a9429c6d6 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -2199,10 +2199,6 @@ Response: returns: binary: binary - finished: - returns: - error: string? - securityDetails: returns: value: SecurityDetails? diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index 5b24ce3574..15fa701bca 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -1042,7 +1042,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { responseStart: tNumber, }); scheme.ResponseBodyParams = tOptional(tObject({})); - scheme.ResponseFinishedParams = tOptional(tObject({})); scheme.ResponseSecurityDetailsParams = tOptional(tObject({})); scheme.ResponseServerAddrParams = tOptional(tObject({})); scheme.SecurityDetails = tObject({ diff --git a/src/server/chromium/crNetworkManager.ts b/src/server/chromium/crNetworkManager.ts index a9e4e82777..23043aa560 100644 --- a/src/server/chromium/crNetworkManager.ts +++ b/src/server/chromium/crNetworkManager.ts @@ -337,12 +337,12 @@ export class CRNetworkManager { _handleRequestRedirect(request: InterceptableRequest, responsePayload: Protocol.Network.Response, timestamp: number) { const response = this._createResponse(request, responsePayload); - response._requestFinished((timestamp - request._timestamp) * 1000, 'Response body is unavailable for redirect responses'); + response._requestFinished((timestamp - request._timestamp) * 1000); this._requestIdToRequest.delete(request._requestId); if (request._interceptionId) this._attemptedAuthentications.delete(request._interceptionId); this._page._frameManager.requestReceivedResponse(response); - this._page._frameManager.requestFinished(request.request, response); + this._page._frameManager.reportRequestFinished(request.request, response); } _onResponseReceivedExtraInfo(event: Protocol.Network.responseReceivedExtraInfoPayload) { @@ -377,12 +377,12 @@ export class CRNetworkManager { if (response) { request.request._sizes.transferSize = event.encodedDataLength; request.request._sizes.responseBodySize = event.encodedDataLength - response?.headersSize(); - response._requestFinished(helper.secondsToRoundishMillis(event.timestamp - request._timestamp), undefined); + response._requestFinished(helper.secondsToRoundishMillis(event.timestamp - request._timestamp)); } this._requestIdToRequest.delete(request._requestId); if (request._interceptionId) this._attemptedAuthentications.delete(request._interceptionId); - this._page._frameManager.requestFinished(request.request, response); + this._page._frameManager.reportRequestFinished(request.request, response); } _onLoadingFailed(event: Protocol.Network.loadingFailedPayload) { @@ -596,13 +596,22 @@ class ResponseExtraInfoTracker { // This is redirect. this._innerResponseReceived(info, event.redirectResponse); } else { - this._requests.set(event.requestId, { - requestId: event.requestId, + this._getOrCreateEntry(event.requestId); + } + } + + _getOrCreateEntry(requestId: string): RequestInfo { + let info = this._requests.get(requestId); + if (!info) { + info = { + requestId: requestId, responseReceivedExtraInfo: [], responses: [], sawResponseWithoutConnectionId: false - }); + }; + this._requests.set(requestId, info); } + return info; } responseReceived(event: Protocol.Network.responseReceivedPayload) { @@ -620,9 +629,7 @@ class ResponseExtraInfoTracker { } responseReceivedExtraInfo(event: Protocol.Network.responseReceivedExtraInfoPayload) { - const info = this._requests.get(event.requestId); - if (!info) - return; + const info = this._getOrCreateEntry(event.requestId); info.responseReceivedExtraInfo.push(event); this._patchResponseHeaders(info, info.responseReceivedExtraInfo.length - 1); this._checkFinished(info); diff --git a/src/server/firefox/ffNetworkManager.ts b/src/server/firefox/ffNetworkManager.ts index c8ba9198dc..8017b3c989 100644 --- a/src/server/firefox/ffNetworkManager.ts +++ b/src/server/firefox/ffNetworkManager.ts @@ -123,12 +123,12 @@ export class FFNetworkManager { // Keep redirected requests in the map for future reference as redirectedFrom. const isRedirected = response.status() >= 300 && response.status() <= 399; if (isRedirected) { - response._requestFinished(this._relativeTiming(event.responseEndTime), 'Response body is unavailable for redirect responses'); + response._requestFinished(this._relativeTiming(event.responseEndTime)); } else { this._requests.delete(request._id); - response._requestFinished(this._relativeTiming(event.responseEndTime), undefined); + response._requestFinished(this._relativeTiming(event.responseEndTime)); } - this._page._frameManager.requestFinished(request.request, response); + this._page._frameManager.reportRequestFinished(request.request, response); } _onRequestFailed(event: Protocol.Network.requestFailedPayload) { diff --git a/src/server/frames.ts b/src/server/frames.ts index 72743b9846..6d6cfaac86 100644 --- a/src/server/frames.ts +++ b/src/server/frames.ts @@ -275,7 +275,7 @@ export class FrameManager { this._page._browserContext.emit(BrowserContext.Events.Response, response); } - requestFinished(request: network.Request, response: network.Response | null) { + reportRequestFinished(request: network.Request, response: network.Response | null) { this._inflightRequestFinished(request); if (request._isFavicon) return; @@ -286,7 +286,7 @@ export class FrameManager { // Avoid unnecessary microtask, we want to report finished early for regular redirects. if (response?.willWaitForExtraHeaders()) await response?.waitForExtraHeadersIfNeeded(); - this._page._browserContext.emit(BrowserContext.Events.RequestFinished,{ request, response }); + this._page._browserContext.emit(BrowserContext.Events.RequestFinished, { request, response }); } requestFailed(request: network.Request, canceled: boolean) { diff --git a/src/server/network.ts b/src/server/network.ts index 364008059d..dd942146be 100644 --- a/src/server/network.ts +++ b/src/server/network.ts @@ -86,7 +86,7 @@ type RequestSizes = { export class Request extends SdkObject { private _response: Response | null = null; private _redirectedFrom: Request | null; - private _redirectedTo: Request | null = null; + _redirectedTo: Request | null = null; readonly _documentId?: string; readonly _isFavicon: boolean; _failureText: string | null = null; @@ -319,7 +319,7 @@ export type SecurityDetails = { export class Response extends SdkObject { private _request: Request; private _contentPromise: Promise | null = null; - _finishedPromise = new ManualPromise<{ error?: string }>(); + _finishedPromise = new ManualPromise(); private _status: number; private _statusText: string; private _url: string; @@ -355,9 +355,9 @@ export class Response extends SdkObject { this._securityDetailsPromise.resolve(securityDetails); } - _requestFinished(responseEndTiming: number, error?: string) { + _requestFinished(responseEndTiming: number) { this._request._responseEndTiming = Math.max(responseEndTiming, this._timing.responseStart); - this._finishedPromise.resolve({ error }); + this._finishedPromise.resolve(); } _setHttpVersion(httpVersion: string) { @@ -403,10 +403,6 @@ export class Response extends SdkObject { return this._headersMap.get(name); } - finished(): Promise { - return this._finishedPromise.then(({ error }) => error ? new Error(error) : null); - } - timing(): ResourceTiming { return this._timing; } @@ -421,9 +417,9 @@ export class Response extends SdkObject { body(): Promise { if (!this._contentPromise) { - this._contentPromise = this._finishedPromise.then(async ({ error }) => { - if (error) - throw new Error(error); + this._contentPromise = this._finishedPromise.then(async () => { + if (this._request._redirectedTo) + throw new Error('Response body is unavailable for redirect responses'); return this._getResponseBodyCallback(); }); } diff --git a/src/server/webkit/wkPage.ts b/src/server/webkit/wkPage.ts index 25b5ae9d1f..73aac533bc 100644 --- a/src/server/webkit/wkPage.ts +++ b/src/server/webkit/wkPage.ts @@ -978,10 +978,10 @@ export class WKPage implements PageDelegate { const response = request.createResponse(responsePayload); response._securityDetailsFinished(); response._serverAddrFinished(); - response._requestFinished(responsePayload.timing ? helper.secondsToRoundishMillis(timestamp - request._timestamp) : -1, 'Response body is unavailable for redirect responses'); + response._requestFinished(responsePayload.timing ? helper.secondsToRoundishMillis(timestamp - request._timestamp) : -1); this._requestIdToRequest.delete(request._requestId); this._page._frameManager.requestReceivedResponse(response); - this._page._frameManager.requestFinished(request.request, response); + this._page._frameManager.reportRequestFinished(request.request, response); } _onRequestIntercepted(session: WKSession, event: Protocol.Network.requestInterceptedPayload) { @@ -1051,12 +1051,12 @@ export class WKPage implements PageDelegate { request.request._sizes.transferSize += response.headersSize(); if (event.metrics?.protocol) response._setHttpVersion(event.metrics.protocol); - response._requestFinished(helper.secondsToRoundishMillis(event.timestamp - request._timestamp), undefined); + response._requestFinished(helper.secondsToRoundishMillis(event.timestamp - request._timestamp)); } this._requestIdToResponseReceivedPayloadEvent.delete(request._requestId); this._requestIdToRequest.delete(request._requestId); - this._page._frameManager.requestFinished(request.request, response); + this._page._frameManager.reportRequestFinished(request.request, response); } _onLoadingFailed(event: Protocol.Network.loadingFailedPayload) {