feat(har): record securityDetails for API Requests (#32664)
While working on https://github.com/microsoft/playwright/pull/32658 I discovered that we're recording `securityDetails` for browser requests, but not for API requests. This PR fixes that.
This commit is contained in:
parent
443f72dcbe
commit
8a97050822
|
|
@ -41,6 +41,7 @@ import type * as types from './types';
|
||||||
import type { HeadersArray, ProxySettings } from './types';
|
import type { HeadersArray, ProxySettings } from './types';
|
||||||
import { getMatchingTLSOptionsForOrigin, rewriteOpenSSLErrorIfNeeded } from './socksClientCertificatesInterceptor';
|
import { getMatchingTLSOptionsForOrigin, rewriteOpenSSLErrorIfNeeded } from './socksClientCertificatesInterceptor';
|
||||||
import type * as har from '@trace/har';
|
import type * as har from '@trace/har';
|
||||||
|
import { TLSSocket } from 'tls';
|
||||||
|
|
||||||
type FetchRequestOptions = {
|
type FetchRequestOptions = {
|
||||||
userAgent: string;
|
userAgent: string;
|
||||||
|
|
@ -73,6 +74,7 @@ export type APIRequestFinishedEvent = {
|
||||||
statusMessage: string;
|
statusMessage: string;
|
||||||
body?: Buffer;
|
body?: Buffer;
|
||||||
timings: har.Timings;
|
timings: har.Timings;
|
||||||
|
securityDetails?: har.SecurityDetails;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SendRequestOptions = https.RequestOptions & {
|
type SendRequestOptions = https.RequestOptions & {
|
||||||
|
|
@ -303,6 +305,8 @@ export abstract class APIRequestContext extends SdkObject {
|
||||||
let tlsHandshakeAt: number | undefined;
|
let tlsHandshakeAt: number | undefined;
|
||||||
let requestFinishAt: number | undefined;
|
let requestFinishAt: number | undefined;
|
||||||
|
|
||||||
|
let securityDetails: har.SecurityDetails | undefined;
|
||||||
|
|
||||||
const request = requestConstructor(url, requestOptions as any, async response => {
|
const request = requestConstructor(url, requestOptions as any, async response => {
|
||||||
const responseAt = monotonicTime();
|
const responseAt = monotonicTime();
|
||||||
const notifyRequestFinished = (body?: Buffer) => {
|
const notifyRequestFinished = (body?: Buffer) => {
|
||||||
|
|
@ -328,6 +332,7 @@ export abstract class APIRequestContext extends SdkObject {
|
||||||
cookies,
|
cookies,
|
||||||
body,
|
body,
|
||||||
timings,
|
timings,
|
||||||
|
securityDetails,
|
||||||
};
|
};
|
||||||
this.emit(APIRequestContext.Events.RequestFinished, requestFinishedEvent);
|
this.emit(APIRequestContext.Events.RequestFinished, requestFinishedEvent);
|
||||||
};
|
};
|
||||||
|
|
@ -482,7 +487,20 @@ export abstract class APIRequestContext extends SdkObject {
|
||||||
// non-happy-eyeballs sockets
|
// non-happy-eyeballs sockets
|
||||||
socket.on('lookup', () => { dnsLookupAt = monotonicTime(); });
|
socket.on('lookup', () => { dnsLookupAt = monotonicTime(); });
|
||||||
socket.on('connect', () => { tcpConnectionAt = monotonicTime(); });
|
socket.on('connect', () => { tcpConnectionAt = monotonicTime(); });
|
||||||
socket.on('secureConnect', () => { tlsHandshakeAt = monotonicTime(); });
|
socket.on('secureConnect', () => {
|
||||||
|
tlsHandshakeAt = monotonicTime();
|
||||||
|
|
||||||
|
if (socket instanceof TLSSocket) {
|
||||||
|
const peerCertificate = socket.getPeerCertificate();
|
||||||
|
securityDetails = {
|
||||||
|
protocol: socket.getProtocol() ?? undefined,
|
||||||
|
subjectName: peerCertificate.subject.CN,
|
||||||
|
validFrom: new Date(peerCertificate.valid_from).getTime() / 1000,
|
||||||
|
validTo: new Date(peerCertificate.valid_to).getTime() / 1000,
|
||||||
|
issuer: peerCertificate.issuer.CN
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
request.on('finish', () => { requestFinishAt = monotonicTime(); });
|
request.on('finish', () => { requestFinishAt = monotonicTime(); });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,9 @@ export class HarTracer {
|
||||||
this._computeHarEntryTotalTime(harEntry);
|
this._computeHarEntryTotalTime(harEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this._options.omitSecurityDetails)
|
||||||
|
harEntry._securityDetails = event.securityDetails;
|
||||||
|
|
||||||
for (let i = 0; i < event.rawHeaders.length; i += 2) {
|
for (let i = 0; i < event.rawHeaders.length; i += 2) {
|
||||||
harEntry.response.headers.push({
|
harEntry.response.headers.push({
|
||||||
name: event.rawHeaders[i],
|
name: event.rawHeaders[i],
|
||||||
|
|
|
||||||
|
|
@ -610,6 +610,7 @@ it('should have security details', async ({ contextFactory, httpsServer, browser
|
||||||
|
|
||||||
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
||||||
await page.goto(httpsServer.EMPTY_PAGE);
|
await page.goto(httpsServer.EMPTY_PAGE);
|
||||||
|
await page.request.get(httpsServer.EMPTY_PAGE);
|
||||||
const log = await getLog();
|
const log = await getLog();
|
||||||
const { serverIPAddress, _serverPort: port, _securityDetails: securityDetails } = log.entries[0];
|
const { serverIPAddress, _serverPort: port, _securityDetails: securityDetails } = log.entries[0];
|
||||||
if (!mode.startsWith('service')) {
|
if (!mode.startsWith('service')) {
|
||||||
|
|
@ -620,6 +621,8 @@ it('should have security details', async ({ contextFactory, httpsServer, browser
|
||||||
expect(securityDetails).toEqual({ protocol: 'TLS 1.3', subjectName: 'playwright-test', validFrom: 1691708270, validTo: 2007068270 });
|
expect(securityDetails).toEqual({ protocol: 'TLS 1.3', subjectName: 'playwright-test', validFrom: 1691708270, validTo: 2007068270 });
|
||||||
else
|
else
|
||||||
expect(securityDetails).toEqual({ issuer: 'playwright-test', protocol: 'TLS 1.3', subjectName: 'playwright-test', validFrom: 1691708270, validTo: 2007068270 });
|
expect(securityDetails).toEqual({ issuer: 'playwright-test', protocol: 'TLS 1.3', subjectName: 'playwright-test', validFrom: 1691708270, validTo: 2007068270 });
|
||||||
|
|
||||||
|
expect(log.entries[1]._securityDetails).toEqual({ issuer: 'playwright-test', protocol: 'TLSv1.3', subjectName: 'playwright-test', validFrom: 1691708270, validTo: 2007068270 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have connection details for redirects', async ({ contextFactory, server, browserName, mode }, testInfo) => {
|
it('should have connection details for redirects', async ({ contextFactory, server, browserName, mode }, testInfo) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue