mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-12 11:50:22 +03:00
feat(network): expose bodySize, transferSize, and headerSize (#8234)
This commit is contained in:
parent
89245de0ef
commit
f3dde0650f
@ -183,6 +183,17 @@ following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttr
|
||||
|
||||
Returns the matching [Response] object, or `null` if the response was not received due to error.
|
||||
|
||||
## method: Request.sizes
|
||||
- returns: <[Object]>
|
||||
- `requestBodySize` <[int]> Size of the request body (POST data payload) in bytes. Set to 0 if there was no body.
|
||||
- `requestHeadersSize` <[float]> Total number of bytes from the start of the HTTP request message until (and including) the double CRLF before the body.
|
||||
- `responseBodySize` <[int]> Size of the received response body in bytes.
|
||||
- `responseHeadersSize` <[float]> Total number of bytes from the start of the HTTP response message until (and including) the double CRLF before the body.
|
||||
- `responseTransferSize` <[float]> Total number of bytes received for the request.
|
||||
|
||||
Returns resource size information for given request. Requires the response to be finished via [`method: Response.finished`]
|
||||
to ensure the info is available.
|
||||
|
||||
## method: Request.timing
|
||||
- returns: <[Object]>
|
||||
- `startTime` <[float]> Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC
|
||||
|
@ -86,7 +86,9 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
||||
});
|
||||
this._channel.on('request', ({ request, page }) => 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, responseEndTiming, page }) => this._onRequestFinished(network.Request.from(request), responseEndTiming, Page.fromNullable(page)));
|
||||
this._channel.on('requestFinished', ({ request, responseEndTiming, page, requestSizes }) =>
|
||||
this._onRequestFinished(network.Request.from(request), responseEndTiming, requestSizes, Page.fromNullable(page))
|
||||
);
|
||||
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));
|
||||
}
|
||||
@ -124,9 +126,10 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
|
||||
page.emit(Events.Page.RequestFailed, request);
|
||||
}
|
||||
|
||||
private _onRequestFinished(request: network.Request, responseEndTiming: number, page: Page | null) {
|
||||
private _onRequestFinished(request: network.Request, responseEndTiming: number, requestSizes: channels.RequestSizes, page: Page | null) {
|
||||
if (request._timing)
|
||||
request._timing.responseEnd = responseEndTiming;
|
||||
request._sizes = requestSizes;
|
||||
this.emit(Events.BrowserContext.RequestFinished, request);
|
||||
if (page)
|
||||
page.emit(Events.Page.RequestFinished, request);
|
||||
|
@ -59,6 +59,7 @@ export class Request extends ChannelOwner<channels.RequestChannel, channels.Requ
|
||||
_headers: Headers;
|
||||
private _postData: Buffer | null;
|
||||
_timing: ResourceTiming;
|
||||
_sizes: RequestSizes = { requestBodySize: 0, requestHeadersSize: 0, responseBodySize: 0, responseHeadersSize: 0, responseTransferSize: 0 };
|
||||
|
||||
static from(request: channels.RequestChannel): Request {
|
||||
return (request as any)._object;
|
||||
@ -167,6 +168,10 @@ export class Request extends ChannelOwner<channels.RequestChannel, channels.Requ
|
||||
return this._timing;
|
||||
}
|
||||
|
||||
sizes(): RequestSizes {
|
||||
return this._sizes;
|
||||
}
|
||||
|
||||
_finalRequest(): Request {
|
||||
return this._redirectedTo ? this._redirectedTo._finalRequest() : this;
|
||||
}
|
||||
@ -368,6 +373,14 @@ export type ResourceTiming = {
|
||||
responseEnd: number;
|
||||
};
|
||||
|
||||
export type RequestSizes = {
|
||||
requestBodySize: number;
|
||||
requestHeadersSize: number;
|
||||
responseBodySize: number;
|
||||
responseHeadersSize: number;
|
||||
responseTransferSize: number;
|
||||
};
|
||||
|
||||
export class Response extends ChannelOwner<channels.ResponseChannel, channels.ResponseInitializer> implements api.Response {
|
||||
private _headers: Headers;
|
||||
private _request: Request;
|
||||
|
@ -86,7 +86,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
||||
context.on(BrowserContext.Events.RequestFinished, (request: Request) => this._dispatchEvent('requestFinished', {
|
||||
request: RequestDispatcher.from(scope, request),
|
||||
responseEndTiming: request._responseEndTiming,
|
||||
page: PageDispatcher.fromNullable(this._scope, request.frame()._page.initializedOrUndefined())
|
||||
requestSizes: request.sizes(),
|
||||
page: PageDispatcher.fromNullable(this._scope, request.frame()._page.initializedOrUndefined()),
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -766,6 +766,7 @@ export type BrowserContextRequestFailedEvent = {
|
||||
export type BrowserContextRequestFinishedEvent = {
|
||||
request: RequestChannel,
|
||||
responseEndTiming: number,
|
||||
requestSizes: RequestSizes,
|
||||
page?: PageChannel,
|
||||
};
|
||||
export type BrowserContextResponseEvent = {
|
||||
@ -2638,6 +2639,14 @@ export type SecurityDetails = {
|
||||
validTo?: number,
|
||||
};
|
||||
|
||||
export type RequestSizes = {
|
||||
requestBodySize: number,
|
||||
requestHeadersSize: number,
|
||||
responseBodySize: number,
|
||||
responseHeadersSize: number,
|
||||
responseTransferSize: number,
|
||||
};
|
||||
|
||||
export type RemoteAddr = {
|
||||
ipAddress: string,
|
||||
port: number,
|
||||
|
@ -756,6 +756,7 @@ BrowserContext:
|
||||
parameters:
|
||||
request: Request
|
||||
responseEndTiming: number
|
||||
requestSizes: RequestSizes
|
||||
page: Page?
|
||||
|
||||
response:
|
||||
@ -2232,6 +2233,15 @@ SecurityDetails:
|
||||
validFrom: number?
|
||||
validTo: number?
|
||||
|
||||
RequestSizes:
|
||||
type: object
|
||||
properties:
|
||||
requestBodySize: number
|
||||
requestHeadersSize: number
|
||||
responseBodySize: number
|
||||
responseHeadersSize: number
|
||||
responseTransferSize: number
|
||||
|
||||
|
||||
RemoteAddr:
|
||||
type: object
|
||||
|
@ -1055,6 +1055,13 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
||||
validFrom: tOptional(tNumber),
|
||||
validTo: tOptional(tNumber),
|
||||
});
|
||||
scheme.RequestSizes = tObject({
|
||||
requestBodySize: tNumber,
|
||||
requestHeadersSize: tNumber,
|
||||
responseBodySize: tNumber,
|
||||
responseHeadersSize: tNumber,
|
||||
responseTransferSize: tNumber,
|
||||
});
|
||||
scheme.RemoteAddr = tObject({
|
||||
ipAddress: tString,
|
||||
port: tNumber,
|
||||
|
@ -215,6 +215,16 @@ export class Request extends SdkObject {
|
||||
headersSize += header.name.length + header.value.length + 4; // 4 = ': ' + '\r\n'
|
||||
return headersSize;
|
||||
}
|
||||
|
||||
sizes() {
|
||||
return {
|
||||
requestBodySize: this.bodySize(),
|
||||
requestHeadersSize: this.headersSize(),
|
||||
responseBodySize: this._sizes.responseBodySize,
|
||||
responseHeadersSize: this._existingResponse()!.headersSize(),
|
||||
responseTransferSize: this._sizes.transferSize,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class Route extends SdkObject {
|
||||
|
@ -265,3 +265,63 @@ it('should return navigation bit when navigating to image', async ({page, server
|
||||
await page.goto(server.PREFIX + '/pptr.png');
|
||||
expect(requests[0].isNavigationRequest()).toBe(true);
|
||||
});
|
||||
|
||||
it('should set bodySize and headersSize', async ({page, server,browserName, platform}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [request] = await Promise.all([
|
||||
page.waitForEvent('request'),
|
||||
page.evaluate(() => fetch('./get', { method: 'POST', body: '12345'}).then(r => r.text())),
|
||||
]);
|
||||
await (await request.response()).finished();
|
||||
expect(request.sizes().requestBodySize).toBe(5);
|
||||
expect(request.sizes().requestHeadersSize).toBeGreaterThanOrEqual(300);
|
||||
});
|
||||
|
||||
it('should should set bodySize to 0 if there was no body', async ({page, server,browserName, platform}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [request] = await Promise.all([
|
||||
page.waitForEvent('request'),
|
||||
page.evaluate(() => fetch('./get').then(r => r.text())),
|
||||
]);
|
||||
await (await request.response()).finished();
|
||||
expect(request.sizes().requestBodySize).toBe(0);
|
||||
expect(request.sizes().requestHeadersSize).toBeGreaterThanOrEqual(250);
|
||||
});
|
||||
|
||||
it('should should set bodySize, headersSize, and transferSize', async ({page, server, browserName, platform}) => {
|
||||
server.setRoute('/get', (req, res) => {
|
||||
// In Firefox, |fetch| will be hanging until it receives |Content-Type| header
|
||||
// from server.
|
||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||
res.end('abc134');
|
||||
});
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [response] = await Promise.all([
|
||||
page.waitForEvent('response'),
|
||||
page.evaluate(async () => fetch('./get').then(r => r.text())),
|
||||
server.waitForRequest('/get'),
|
||||
]);
|
||||
await response.finished();
|
||||
expect(response.request().sizes().responseBodySize).toBe(6);
|
||||
expect(response.request().sizes().responseHeadersSize).toBeGreaterThanOrEqual(150);
|
||||
expect(response.request().sizes().responseTransferSize).toBeGreaterThanOrEqual(160);
|
||||
});
|
||||
|
||||
it('should should set bodySize to 0 when there was no response body', async ({page, server, browserName, platform}) => {
|
||||
server.setRoute('/get', (req, res) => {
|
||||
// In Firefox, |fetch| will be hanging until it receives |Content-Type| header
|
||||
// from server.
|
||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||
res.end('');
|
||||
});
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const [response] = await Promise.all([
|
||||
page.waitForEvent('response'),
|
||||
page.evaluate(async () => fetch('./get').then(r => r.text())),
|
||||
server.waitForRequest('/get'),
|
||||
]);
|
||||
await response.finished();
|
||||
expect(response.request().sizes().responseBodySize).toBe(0);
|
||||
expect(response.request().sizes().responseHeadersSize).toBeGreaterThanOrEqual(150);
|
||||
expect(response.request().sizes().responseTransferSize).toBeGreaterThanOrEqual(160);
|
||||
});
|
||||
|
31
types/types.d.ts
vendored
31
types/types.d.ts
vendored
@ -11668,6 +11668,37 @@ export interface Request {
|
||||
*/
|
||||
response(): Promise<null|Response>;
|
||||
|
||||
/**
|
||||
* Returns resource size information for given request. Requires the response to be finished via
|
||||
* [response.finished()](https://playwright.dev/docs/api/class-response#response-finished) to ensure the info is available.
|
||||
*/
|
||||
sizes(): {
|
||||
/**
|
||||
* Size of the request body (POST data payload) in bytes. Set to 0 if there was no body.
|
||||
*/
|
||||
requestBodySize: number;
|
||||
|
||||
/**
|
||||
* Total number of bytes from the start of the HTTP request message until (and including) the double CRLF before the body.
|
||||
*/
|
||||
requestHeadersSize: number;
|
||||
|
||||
/**
|
||||
* Size of the received response body in bytes.
|
||||
*/
|
||||
responseBodySize: number;
|
||||
|
||||
/**
|
||||
* Total number of bytes from the start of the HTTP response message until (and including) the double CRLF before the body.
|
||||
*/
|
||||
responseHeadersSize: number;
|
||||
|
||||
/**
|
||||
* Total number of bytes received for the request.
|
||||
*/
|
||||
responseTransferSize: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns resource timing information for given request. Most of the timing values become available upon the response,
|
||||
* `responseEnd` becomes available when request finishes. Find more information at
|
||||
|
Loading…
Reference in New Issue
Block a user