fix(headers): report raw request headers on Chromium (#4207)
This commit is contained in:
parent
8a42cdad30
commit
72320275ab
|
|
@ -51,7 +51,7 @@ export class Request extends ChannelOwner<channels.RequestChannel, channels.Requ
|
||||||
private _redirectedFrom: Request | null = null;
|
private _redirectedFrom: Request | null = null;
|
||||||
private _redirectedTo: Request | null = null;
|
private _redirectedTo: Request | null = null;
|
||||||
_failureText: string | null = null;
|
_failureText: string | null = null;
|
||||||
private _headers: Headers;
|
_headers: Headers;
|
||||||
private _postData: Buffer | null;
|
private _postData: Buffer | null;
|
||||||
_timing: ResourceTiming;
|
_timing: ResourceTiming;
|
||||||
|
|
||||||
|
|
@ -258,6 +258,7 @@ export class Response extends ChannelOwner<channels.ResponseChannel, channels.Re
|
||||||
super(parent, type, guid, initializer);
|
super(parent, type, guid, initializer);
|
||||||
this._headers = headersArrayToObject(initializer.headers, true /* lowerCase */);
|
this._headers = headersArrayToObject(initializer.headers, true /* lowerCase */);
|
||||||
this._request = Request.from(this._initializer.request);
|
this._request = Request.from(this._initializer.request);
|
||||||
|
this._request._headers = headersArrayToObject(initializer.requestHeaders, true /* lowerCase */);
|
||||||
Object.assign(this._request._timing, this._initializer.timing);
|
Object.assign(this._request._timing, this._initializer.timing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ export class ResponseDispatcher extends Dispatcher<Response, channels.ResponseIn
|
||||||
url: response.url(),
|
url: response.url(),
|
||||||
status: response.status(),
|
status: response.status(),
|
||||||
statusText: response.statusText(),
|
statusText: response.statusText(),
|
||||||
|
requestHeaders: response.request().headers(),
|
||||||
headers: response.headers(),
|
headers: response.headers(),
|
||||||
timing: response.timing()
|
timing: response.timing()
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2152,6 +2152,10 @@ export type ResponseInitializer = {
|
||||||
url: string,
|
url: string,
|
||||||
status: number,
|
status: number,
|
||||||
statusText: string,
|
statusText: string,
|
||||||
|
requestHeaders: {
|
||||||
|
name: string,
|
||||||
|
value: string,
|
||||||
|
}[],
|
||||||
headers: {
|
headers: {
|
||||||
name: string,
|
name: string,
|
||||||
value: string,
|
value: string,
|
||||||
|
|
|
||||||
|
|
@ -1811,6 +1811,13 @@ Response:
|
||||||
url: string
|
url: string
|
||||||
status: number
|
status: number
|
||||||
statusText: string
|
statusText: string
|
||||||
|
requestHeaders:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name: string
|
||||||
|
value: string
|
||||||
headers:
|
headers:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ export class CRNetworkManager {
|
||||||
private _protocolRequestInterceptionEnabled = false;
|
private _protocolRequestInterceptionEnabled = false;
|
||||||
private _requestIdToRequestPausedEvent = new Map<string, Protocol.Fetch.requestPausedPayload>();
|
private _requestIdToRequestPausedEvent = new Map<string, Protocol.Fetch.requestPausedPayload>();
|
||||||
private _eventListeners: RegisteredListener[];
|
private _eventListeners: RegisteredListener[];
|
||||||
|
private _requestIdToExtraInfo = new Map<string, Protocol.Network.requestWillBeSentExtraInfoPayload>();
|
||||||
|
|
||||||
constructor(client: CRSession, page: Page, parentManager: CRNetworkManager | null) {
|
constructor(client: CRSession, page: Page, parentManager: CRNetworkManager | null) {
|
||||||
this._client = client;
|
this._client = client;
|
||||||
|
|
@ -50,6 +51,7 @@ export class CRNetworkManager {
|
||||||
helper.addEventListener(session, 'Fetch.requestPaused', this._onRequestPaused.bind(this, workerFrame)),
|
helper.addEventListener(session, 'Fetch.requestPaused', this._onRequestPaused.bind(this, workerFrame)),
|
||||||
helper.addEventListener(session, 'Fetch.authRequired', this._onAuthRequired.bind(this)),
|
helper.addEventListener(session, 'Fetch.authRequired', this._onAuthRequired.bind(this)),
|
||||||
helper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this, workerFrame)),
|
helper.addEventListener(session, 'Network.requestWillBeSent', this._onRequestWillBeSent.bind(this, workerFrame)),
|
||||||
|
helper.addEventListener(session, 'Network.requestWillBeSentExtraInfo', this._onRequestWillBeSentExtraInfo.bind(this)),
|
||||||
helper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)),
|
helper.addEventListener(session, 'Network.responseReceived', this._onResponseReceived.bind(this)),
|
||||||
helper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)),
|
helper.addEventListener(session, 'Network.loadingFinished', this._onLoadingFinished.bind(this)),
|
||||||
helper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)),
|
helper.addEventListener(session, 'Network.loadingFailed', this._onLoadingFailed.bind(this)),
|
||||||
|
|
@ -116,9 +118,22 @@ export class CRNetworkManager {
|
||||||
} else {
|
} else {
|
||||||
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);
|
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);
|
||||||
}
|
}
|
||||||
return;
|
} else {
|
||||||
|
this._onRequest(workerFrame, event, null);
|
||||||
|
}
|
||||||
|
const extraInfo = this._requestIdToExtraInfo.get(event.requestId);
|
||||||
|
if (extraInfo)
|
||||||
|
this._onRequestWillBeSentExtraInfo(extraInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onRequestWillBeSentExtraInfo(event: Protocol.Network.requestWillBeSentExtraInfoPayload) {
|
||||||
|
const request = this._requestIdToRequest.get(event.requestId);
|
||||||
|
if (request) {
|
||||||
|
request.request._updateWithRawHeaders(headersObjectToArray(event.headers));
|
||||||
|
this._requestIdToExtraInfo.delete(event.requestId);
|
||||||
|
} else {
|
||||||
|
this._requestIdToExtraInfo.set(event.requestId, event);
|
||||||
}
|
}
|
||||||
this._onRequest(workerFrame, event, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAuthRequired(event: Protocol.Fetch.authRequiredPayload) {
|
_onAuthRequired(event: Protocol.Fetch.authRequiredPayload) {
|
||||||
|
|
|
||||||
|
|
@ -128,19 +128,19 @@ export class CRPage implements PageDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateExtraHTTPHeaders(): Promise<void> {
|
async updateExtraHTTPHeaders(): Promise<void> {
|
||||||
await this._forAllFrameSessions(frame => frame._updateExtraHTTPHeaders());
|
await this._forAllFrameSessions(frame => frame._updateExtraHTTPHeaders(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateGeolocation(): Promise<void> {
|
async updateGeolocation(): Promise<void> {
|
||||||
await this._forAllFrameSessions(frame => frame._updateGeolocation());
|
await this._forAllFrameSessions(frame => frame._updateGeolocation(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOffline(): Promise<void> {
|
async updateOffline(): Promise<void> {
|
||||||
await this._forAllFrameSessions(frame => frame._updateOffline());
|
await this._forAllFrameSessions(frame => frame._updateOffline(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateHttpCredentials(): Promise<void> {
|
async updateHttpCredentials(): Promise<void> {
|
||||||
await this._forAllFrameSessions(frame => frame._updateHttpCredentials());
|
await this._forAllFrameSessions(frame => frame._updateHttpCredentials(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setViewportSize(viewportSize: types.Size): Promise<void> {
|
async setViewportSize(viewportSize: types.Size): Promise<void> {
|
||||||
|
|
@ -153,11 +153,11 @@ export class CRPage implements PageDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateEmulateMedia(): Promise<void> {
|
async updateEmulateMedia(): Promise<void> {
|
||||||
await this._forAllFrameSessions(frame => frame._updateEmulateMedia());
|
await this._forAllFrameSessions(frame => frame._updateEmulateMedia(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateRequestInterception(): Promise<void> {
|
async updateRequestInterception(): Promise<void> {
|
||||||
await this._forAllFrameSessions(frame => frame._updateRequestInterception());
|
await this._forAllFrameSessions(frame => frame._updateRequestInterception(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setFileChooserIntercepted(enabled: boolean) {
|
async setFileChooserIntercepted(enabled: boolean) {
|
||||||
|
|
@ -446,12 +446,12 @@ class FrameSession {
|
||||||
promises.push(emulateLocale(this._client, options.locale));
|
promises.push(emulateLocale(this._client, options.locale));
|
||||||
if (options.timezoneId)
|
if (options.timezoneId)
|
||||||
promises.push(emulateTimezone(this._client, options.timezoneId));
|
promises.push(emulateTimezone(this._client, options.timezoneId));
|
||||||
promises.push(this._updateGeolocation());
|
promises.push(this._updateGeolocation(true));
|
||||||
promises.push(this._updateExtraHTTPHeaders());
|
promises.push(this._updateExtraHTTPHeaders(true));
|
||||||
promises.push(this._updateRequestInterception());
|
promises.push(this._updateRequestInterception(true));
|
||||||
promises.push(this._updateOffline());
|
promises.push(this._updateOffline(true));
|
||||||
promises.push(this._updateHttpCredentials());
|
promises.push(this._updateHttpCredentials(true));
|
||||||
promises.push(this._updateEmulateMedia());
|
promises.push(this._updateEmulateMedia(true));
|
||||||
for (const binding of this._crPage._browserContext._pageBindings.values())
|
for (const binding of this._crPage._browserContext._pageBindings.values())
|
||||||
promises.push(this._initBinding(binding));
|
promises.push(this._initBinding(binding));
|
||||||
for (const binding of this._crPage._page._pageBindings.values())
|
for (const binding of this._crPage._page._pageBindings.values())
|
||||||
|
|
@ -794,27 +794,31 @@ class FrameSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateExtraHTTPHeaders(): Promise<void> {
|
async _updateExtraHTTPHeaders(initial: boolean): Promise<void> {
|
||||||
const headers = network.mergeHeaders([
|
const headers = network.mergeHeaders([
|
||||||
this._crPage._browserContext._options.extraHTTPHeaders,
|
this._crPage._browserContext._options.extraHTTPHeaders,
|
||||||
this._page._state.extraHTTPHeaders
|
this._page._state.extraHTTPHeaders
|
||||||
]);
|
]);
|
||||||
await this._client.send('Network.setExtraHTTPHeaders', { headers: headersArrayToObject(headers, false /* lowerCase */) });
|
if (!initial || headers.length)
|
||||||
|
await this._client.send('Network.setExtraHTTPHeaders', { headers: headersArrayToObject(headers, false /* lowerCase */) });
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateGeolocation(): Promise<void> {
|
async _updateGeolocation(initial: boolean): Promise<void> {
|
||||||
const geolocation = this._crPage._browserContext._options.geolocation;
|
const geolocation = this._crPage._browserContext._options.geolocation;
|
||||||
await this._client.send('Emulation.setGeolocationOverride', geolocation || {});
|
if (!initial || geolocation)
|
||||||
|
await this._client.send('Emulation.setGeolocationOverride', geolocation || {});
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateOffline(): Promise<void> {
|
async _updateOffline(initial: boolean): Promise<void> {
|
||||||
const offline = !!this._crPage._browserContext._options.offline;
|
const offline = !!this._crPage._browserContext._options.offline;
|
||||||
await this._networkManager.setOffline(offline);
|
if (!initial || offline)
|
||||||
|
await this._networkManager.setOffline(offline);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateHttpCredentials(): Promise<void> {
|
async _updateHttpCredentials(initial: boolean): Promise<void> {
|
||||||
const credentials = this._crPage._browserContext._options.httpCredentials || null;
|
const credentials = this._crPage._browserContext._options.httpCredentials || null;
|
||||||
await this._networkManager.authenticate(credentials);
|
if (!initial || credentials)
|
||||||
|
await this._networkManager.authenticate(credentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateViewport(): Promise<void> {
|
async _updateViewport(): Promise<void> {
|
||||||
|
|
@ -855,13 +859,13 @@ class FrameSession {
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateEmulateMedia(): Promise<void> {
|
async _updateEmulateMedia(initial: boolean): Promise<void> {
|
||||||
const colorScheme = this._page._state.colorScheme || this._crPage._browserContext._options.colorScheme || 'light';
|
const colorScheme = this._page._state.colorScheme || this._crPage._browserContext._options.colorScheme || 'light';
|
||||||
const features = colorScheme ? [{ name: 'prefers-color-scheme', value: colorScheme }] : [];
|
const features = colorScheme ? [{ name: 'prefers-color-scheme', value: colorScheme }] : [];
|
||||||
await this._client.send('Emulation.setEmulatedMedia', { media: this._page._state.mediaType || '', features });
|
await this._client.send('Emulation.setEmulatedMedia', { media: this._page._state.mediaType || '', features });
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateRequestInterception(): Promise<void> {
|
async _updateRequestInterception(initial: boolean): Promise<void> {
|
||||||
await this._networkManager.setRequestInterception(this._page._needsRequestInterception());
|
await this._networkManager.setRequestInterception(this._page._needsRequestInterception());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,10 @@ export class Request {
|
||||||
return null;
|
return null;
|
||||||
return new Route(this, this._routeDelegate);
|
return new Route(this, this._routeDelegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateWithRawHeaders(headers: types.HeadersArray) {
|
||||||
|
this._headers = headers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Route {
|
export class Route {
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,19 @@ it('should return headers', async ({page, server, isChromium, isFirefox, isWebKi
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get the same headers as the server', (test, { browserName }) => {
|
it('should get the same headers as the server', (test, { browserName }) => {
|
||||||
test.fail(browserName === 'chromium' || browserName === 'webkit', 'Provisional headers differ from those in network stack');
|
test.fail(browserName === 'webkit', 'Provisional headers differ from those in network stack');
|
||||||
|
}, async ({ page, server }) => {
|
||||||
|
let serverRequest;
|
||||||
|
server.setRoute('/empty.html', (request, response) => {
|
||||||
|
serverRequest = request;
|
||||||
|
response.end('done');
|
||||||
|
});
|
||||||
|
const response = await page.goto(server.PREFIX + '/empty.html');
|
||||||
|
expect(response.request().headers()).toEqual(serverRequest.headers);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get the same headers as the server CORP', (test, { browserName }) => {
|
||||||
|
test.fail(browserName === 'webkit', 'Provisional headers differ from those in network stack');
|
||||||
}, async ({page, server}) => {
|
}, async ({page, server}) => {
|
||||||
await page.goto(server.PREFIX + '/empty.html');
|
await page.goto(server.PREFIX + '/empty.html');
|
||||||
let serverRequest;
|
let serverRequest;
|
||||||
|
|
@ -91,14 +103,14 @@ it('should get the same headers as the server', (test, { browserName }) => {
|
||||||
response.writeHead(200, { 'Access-Control-Allow-Origin': '*' });
|
response.writeHead(200, { 'Access-Control-Allow-Origin': '*' });
|
||||||
response.end('done');
|
response.end('done');
|
||||||
});
|
});
|
||||||
const requestPromise = page.waitForEvent('request');
|
const responsePromise = page.waitForEvent('response');
|
||||||
const text = await page.evaluate(async url => {
|
const text = await page.evaluate(async url => {
|
||||||
const data = await fetch(url);
|
const data = await fetch(url);
|
||||||
return data.text();
|
return data.text();
|
||||||
}, server.CROSS_PROCESS_PREFIX + '/something');
|
}, server.CROSS_PROCESS_PREFIX + '/something');
|
||||||
const request = await requestPromise;
|
const response = await responsePromise;
|
||||||
expect(text).toBe('done');
|
expect(text).toBe('done');
|
||||||
expect(request.headers()).toEqual(serverRequest.headers);
|
expect(response.request().headers()).toEqual(serverRequest.headers);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return postData', async ({page, server}) => {
|
it('should return postData', async ({page, server}) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue