diff --git a/docs/src/api/class-response.md b/docs/src/api/class-response.md index cddaf696592ce..8fcef0883d764 100644 --- a/docs/src/api/class-response.md +++ b/docs/src/api/class-response.md @@ -80,6 +80,12 @@ Returns all values of the headers matching the name, for example `set-cookie`. T Name of the header. +## async method: Response.httpVersion +* since: v1.59 +- returns: <[string]> + +Returns the http version used by the response. + ## async method: Response.json * since: v1.8 * langs: js, python diff --git a/packages/playwright-client/types/types.d.ts b/packages/playwright-client/types/types.d.ts index 604208ad14b25..fe0d2ff377920 100644 --- a/packages/playwright-client/types/types.d.ts +++ b/packages/playwright-client/types/types.d.ts @@ -21155,6 +21155,11 @@ export interface Response { */ headerValues(name: string): Promise>; + /** + * Returns the http version used by the response. + */ + httpVersion(): Promise; + /** * Returns the JSON representation of response body. * diff --git a/packages/playwright-core/src/client/network.ts b/packages/playwright-core/src/client/network.ts index e43e3d4ed75be..00728875609a4 100644 --- a/packages/playwright-core/src/client/network.ts +++ b/packages/playwright-core/src/client/network.ts @@ -741,6 +741,12 @@ export class Response extends ChannelOwner implements async securityDetails(): Promise { return (await this._channel.securityDetails()).value || null; } + + async httpVersion(): Promise { + return this._wrapApiCall(async () => { + return (await this._channel.httpVersion()).value; + }, { internal: true }); + } } export class WebSocket extends ChannelOwner implements api.WebSocket { diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 06622ef91f8a3..8a59f8ab5932c 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -2416,6 +2416,10 @@ scheme.ResponseRawResponseHeadersParams = tOptional(tObject({})); scheme.ResponseRawResponseHeadersResult = tObject({ headers: tArray(tType('NameValue')), }); +scheme.ResponseHttpVersionParams = tOptional(tObject({})); +scheme.ResponseHttpVersionResult = tObject({ + value: tString, +}); scheme.ResponseSizesParams = tOptional(tObject({})); scheme.ResponseSizesResult = tObject({ sizes: tType('RequestSizes'), diff --git a/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts b/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts index 41b8618109695..df73f81f78af2 100644 --- a/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts +++ b/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts @@ -117,6 +117,10 @@ export class ResponseDispatcher extends Dispatcher { + return { value: await progress.race(this._object.httpVersion()) }; + } + async sizes(params: channels.ResponseSizesParams, progress: Progress): Promise { return { sizes: await progress.race(this._object.sizes()) }; } diff --git a/packages/playwright-core/src/server/har/harTracer.ts b/packages/playwright-core/src/server/har/harTracer.ts index 601f1821e554d..63574f3ecf87a 100644 --- a/packages/playwright-core/src/server/har/harTracer.ts +++ b/packages/playwright-core/src/server/har/harTracer.ts @@ -323,7 +323,7 @@ export class HarTracer { })); } - const httpVersion = response.httpVersion(); + const httpVersion = await response.httpVersion(); harEntry.request.httpVersion = httpVersion; harEntry.response.httpVersion = httpVersion; @@ -441,7 +441,7 @@ export class HarTracer { } } - private _onResponse(response: network.Response) { + private async _onResponse(response: network.Response) { const harEntry = this._entryForRequest(response.request()); if (!harEntry) return; @@ -452,7 +452,7 @@ export class HarTracer { harEntry.response = { status: response.status(), statusText: response.statusText(), - httpVersion: response.httpVersion(), + httpVersion: await response.httpVersion(), // These are bad values that will be overwritten below. cookies: [], headers: [], diff --git a/packages/playwright-core/src/server/network.ts b/packages/playwright-core/src/server/network.ts index 5a45644d3f3cd..bbd6f194e0a84 100644 --- a/packages/playwright-core/src/server/network.ts +++ b/packages/playwright-core/src/server/network.ts @@ -508,7 +508,7 @@ export class Response extends SdkObject { private _serverAddrPromise = new ManualPromise(); private _securityDetailsPromise = new ManualPromise(); private _rawResponseHeadersPromise = new ManualPromise(); - private _httpVersion: string | undefined; + private _httpVersionPromise = new ManualPromise(); private _fromServiceWorker: boolean; private _encodedBodySizePromise = new ManualPromise(); private _transferSizePromise = new ManualPromise(); @@ -526,7 +526,8 @@ export class Response extends SdkObject { this._headersMap.set(name.toLowerCase(), value); this._getResponseBodyCallback = getResponseBodyCallback; this._request._setResponse(this); - this._httpVersion = httpVersion; + if (httpVersion) + this._httpVersionPromise.resolve(httpVersion); this._fromServiceWorker = fromServiceWorker; } @@ -547,7 +548,7 @@ export class Response extends SdkObject { } _setHttpVersion(httpVersion: string) { - this._httpVersion = httpVersion; + this._httpVersionPromise.resolve(httpVersion); } url(): string { @@ -631,14 +632,17 @@ export class Response extends SdkObject { return this._request.frame(); } - httpVersion(): string { - if (!this._httpVersion) + async httpVersion(): Promise { + const httpVersion = await this._httpVersionPromise || null; + if (!httpVersion) return 'HTTP/1.1'; - if (this._httpVersion === 'http/1.1') + if (httpVersion === 'http/1.1') return 'HTTP/1.1'; - if (this._httpVersion === 'h2') + if (httpVersion === 'h2') return 'HTTP/2.0'; - return this._httpVersion; + if (httpVersion === 'h3') + return 'HTTP/3.0'; + return httpVersion; } fromServiceWorker(): boolean { diff --git a/packages/playwright-core/src/utils/isomorphic/protocolMetainfo.ts b/packages/playwright-core/src/utils/isomorphic/protocolMetainfo.ts index f21f37956abc6..63a7027df02f9 100644 --- a/packages/playwright-core/src/utils/isomorphic/protocolMetainfo.ts +++ b/packages/playwright-core/src/utils/isomorphic/protocolMetainfo.ts @@ -263,6 +263,7 @@ export const methodMetainfo = new Map>; + /** + * Returns the http version used by the response. + */ + httpVersion(): Promise; + /** * Returns the JSON representation of response body. * diff --git a/packages/protocol/src/channels.d.ts b/packages/protocol/src/channels.d.ts index a7c8251861ada..77f9ca5648551 100644 --- a/packages/protocol/src/channels.d.ts +++ b/packages/protocol/src/channels.d.ts @@ -4136,6 +4136,7 @@ export interface ResponseChannel extends ResponseEventTarget, Channel { securityDetails(params?: ResponseSecurityDetailsParams, progress?: Progress): Promise; serverAddr(params?: ResponseServerAddrParams, progress?: Progress): Promise; rawResponseHeaders(params?: ResponseRawResponseHeadersParams, progress?: Progress): Promise; + httpVersion(params?: ResponseHttpVersionParams, progress?: Progress): Promise; sizes(params?: ResponseSizesParams, progress?: Progress): Promise; } export type ResponseBodyParams = {}; @@ -4158,6 +4159,11 @@ export type ResponseRawResponseHeadersOptions = {}; export type ResponseRawResponseHeadersResult = { headers: NameValue[], }; +export type ResponseHttpVersionParams = {}; +export type ResponseHttpVersionOptions = {}; +export type ResponseHttpVersionResult = { + value: string, +}; export type ResponseSizesParams = {}; export type ResponseSizesOptions = {}; export type ResponseSizesResult = { diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index defad2e499f64..347a5a4d0291a 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -3656,6 +3656,11 @@ Response: type: array items: NameValue + httpVersion: + internal: true + returns: + value: string + sizes: internal: true returns: