feat(headers): add Headers.headers that would mimic the behavior of the deprecated getters (#8665)
This commit is contained in:
parent
962a33993f
commit
0d5b41ce7b
|
|
@ -25,6 +25,7 @@ Header name, case-insensitive.
|
||||||
Returns all header names in this headers collection.
|
Returns all header names in this headers collection.
|
||||||
|
|
||||||
## method: Headers.headers
|
## method: Headers.headers
|
||||||
- returns: <[Array]<{ name: string, value: string }>>
|
- returns: <[Object]<[string], [string]>>
|
||||||
|
|
||||||
Returns all raw headers.
|
Returns all headers as a dictionary. Header names are normalized to lower case, multi-value headers are concatenated
|
||||||
|
using comma.
|
||||||
|
|
|
||||||
|
|
@ -652,7 +652,10 @@ export class RawHeaders implements api.Headers {
|
||||||
}
|
}
|
||||||
|
|
||||||
get(name: string): string | null {
|
get(name: string): string | null {
|
||||||
return this.getAll(name)[0] || null;
|
const values = this.getAll(name);
|
||||||
|
if (!values)
|
||||||
|
return null;
|
||||||
|
return values.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll(name: string): string[] {
|
getAll(name: string): string[] {
|
||||||
|
|
@ -660,10 +663,13 @@ export class RawHeaders implements api.Headers {
|
||||||
}
|
}
|
||||||
|
|
||||||
headerNames(): string[] {
|
headerNames(): string[] {
|
||||||
return [...new Set(this._headersArray.map(h => h.name))];
|
return [...this._headersMap.keys()];
|
||||||
}
|
}
|
||||||
|
|
||||||
headers(): HeadersArray {
|
headers(): Headers {
|
||||||
return this._headersArray;
|
const result: Headers = {};
|
||||||
|
for (const name of this._headersMap.keys())
|
||||||
|
result[name] = this.get(name)!;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as channels from '../protocol/channels';
|
import * as channels from '../protocol/channels';
|
||||||
import type { NameValue, Size } from '../common/types';
|
import type { Size } from '../common/types';
|
||||||
import type { ParsedStackTrace } from '../utils/stackTrace';
|
import type { ParsedStackTrace } from '../utils/stackTrace';
|
||||||
export { Size, Point, Rect, Quad, URLMatch, TimeoutOptions } from '../common/types';
|
export { Size, Point, Rect, Quad, URLMatch, TimeoutOptions, HeadersArray } from '../common/types';
|
||||||
|
|
||||||
type LoggerSeverity = 'verbose' | 'info' | 'warning' | 'error';
|
type LoggerSeverity = 'verbose' | 'info' | 'warning' | 'error';
|
||||||
export interface Logger {
|
export interface Logger {
|
||||||
|
|
@ -32,7 +32,6 @@ export interface ClientSideInstrumentation {
|
||||||
|
|
||||||
export type StrictOptions = { strict?: boolean };
|
export type StrictOptions = { strict?: boolean };
|
||||||
export type Headers = { [key: string]: string };
|
export type Headers = { [key: string]: string };
|
||||||
export type HeadersArray = NameValue[];
|
|
||||||
export type Env = { [key: string]: string | number | boolean | undefined };
|
export type Env = { [key: string]: string | number | boolean | undefined };
|
||||||
|
|
||||||
export type WaitForEventOptions = Function | { predicate?: Function, timeout?: number };
|
export type WaitForEventOptions = Function | { predicate?: Function, timeout?: number };
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,4 @@ export type Quad = [ Point, Point, Point, Point ];
|
||||||
export type URLMatch = string | RegExp | ((url: URL) => boolean);
|
export type URLMatch = string | RegExp | ((url: URL) => boolean);
|
||||||
export type TimeoutOptions = { timeout?: number };
|
export type TimeoutOptions = { timeout?: number };
|
||||||
export type NameValue = { name: string, value: string };
|
export type NameValue = { name: string, value: string };
|
||||||
|
export type HeadersArray = NameValue[];
|
||||||
|
|
|
||||||
|
|
@ -675,10 +675,10 @@ class ResponseExtraInfoTracker {
|
||||||
const response = info.responses[index];
|
const response = info.responses[index];
|
||||||
const requestExtraInfo = info.requestWillBeSentExtraInfo[index];
|
const requestExtraInfo = info.requestWillBeSentExtraInfo[index];
|
||||||
if (response && requestExtraInfo)
|
if (response && requestExtraInfo)
|
||||||
response.setRawRequestHeaders(headersObjectToArray(requestExtraInfo.headers));
|
response.setRawRequestHeaders(headersObjectToArray(requestExtraInfo.headers, '\n'));
|
||||||
const responseExtraInfo = info.responseReceivedExtraInfo[index];
|
const responseExtraInfo = info.responseReceivedExtraInfo[index];
|
||||||
if (response && responseExtraInfo)
|
if (response && responseExtraInfo)
|
||||||
response.setRawResponseHeaders(headersObjectToArray(responseExtraInfo.headers));
|
response.setRawResponseHeaders(headersObjectToArray(responseExtraInfo.headers, '\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _checkFinished(info: RequestInfo) {
|
private _checkFinished(info: RequestInfo) {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import * as frames from '../frames';
|
||||||
import * as types from '../types';
|
import * as types from '../types';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { InterceptedResponse } from '../network';
|
import { InterceptedResponse } from '../network';
|
||||||
|
import { HeadersArray } from '../../server/types';
|
||||||
|
|
||||||
export class FFNetworkManager {
|
export class FFNetworkManager {
|
||||||
private _session: FFSession;
|
private _session: FFSession;
|
||||||
|
|
@ -96,7 +97,7 @@ export class FFNetworkManager {
|
||||||
requestStart: relativeToStart(event.timing.requestStart),
|
requestStart: relativeToStart(event.timing.requestStart),
|
||||||
responseStart: relativeToStart(event.timing.responseStart),
|
responseStart: relativeToStart(event.timing.responseStart),
|
||||||
};
|
};
|
||||||
const response = new network.Response(request.request, event.status, event.statusText, event.headers, timing, getResponseBody);
|
const response = new network.Response(request.request, event.status, event.statusText, parseMultivalueHeaders(event.headers), timing, getResponseBody);
|
||||||
if (event?.remoteIPAddress && typeof event?.remotePort === 'number') {
|
if (event?.remoteIPAddress && typeof event?.remotePort === 'number') {
|
||||||
response._serverAddrFinished({
|
response._serverAddrFinished({
|
||||||
ipAddress: event.remoteIPAddress,
|
ipAddress: event.remoteIPAddress,
|
||||||
|
|
@ -252,3 +253,14 @@ class FFRouteImpl implements network.RouteDelegate {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseMultivalueHeaders(headers: HeadersArray) {
|
||||||
|
const result: HeadersArray = [];
|
||||||
|
for (const header of headers) {
|
||||||
|
const separator = header.name.toLowerCase() === 'set-cookie' ? '\n' : ',';
|
||||||
|
const tokens = header.value.split(separator).map(s => s.trim());
|
||||||
|
for (const token of tokens)
|
||||||
|
result.push({ name: header.name, value: token });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -446,21 +446,31 @@ export class Response extends SdkObject {
|
||||||
headersSize += 8; // httpVersion;
|
headersSize += 8; // httpVersion;
|
||||||
headersSize += 3; // statusCode;
|
headersSize += 3; // statusCode;
|
||||||
headersSize += this.statusText().length;
|
headersSize += this.statusText().length;
|
||||||
const headers = this._rawResponseHeadersPromise ? await this._rawResponseHeadersPromise : this._headers;
|
const headers = await this._bestEffortResponseHeaders();
|
||||||
for (const header of headers)
|
for (const header of headers)
|
||||||
headersSize += header.name.length + header.value.length + 4; // 4 = ': ' + '\r\n'
|
headersSize += header.name.length + header.value.length + 4; // 4 = ': ' + '\r\n'
|
||||||
headersSize += 2; // '\r\n'
|
headersSize += 2; // '\r\n'
|
||||||
return headersSize;
|
return headersSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _bestEffortResponseHeaders(): Promise<types.HeadersArray> {
|
||||||
|
return this._rawResponseHeadersPromise ? await this._rawResponseHeadersPromise : this._headers;
|
||||||
|
}
|
||||||
|
|
||||||
async sizes(): Promise<ResourceSizes> {
|
async sizes(): Promise<ResourceSizes> {
|
||||||
await this._finishedPromise;
|
await this._finishedPromise;
|
||||||
const requestHeadersSize = await this._requestHeadersSize();
|
const requestHeadersSize = await this._requestHeadersSize();
|
||||||
const responseHeadersSize = await this._responseHeadersSize();
|
const responseHeadersSize = await this._responseHeadersSize();
|
||||||
let { bodySize, encodedBodySize, transferSize } = this._request.responseSize;
|
let { bodySize, encodedBodySize, transferSize } = this._request.responseSize;
|
||||||
|
if (!bodySize) {
|
||||||
|
const headers = await this._bestEffortResponseHeaders();
|
||||||
|
const contentLength = headers.find(h => h.name.toLowerCase() === 'content-length')?.value;
|
||||||
|
bodySize = contentLength ? +contentLength : 0;
|
||||||
|
}
|
||||||
if (!encodedBodySize && transferSize) {
|
if (!encodedBodySize && transferSize) {
|
||||||
// Chromium only populates transferSize
|
// Chromium only populates transferSize
|
||||||
encodedBodySize = transferSize - responseHeadersSize;
|
// Firefox can return 0 transferSize
|
||||||
|
encodedBodySize = Math.max(0, transferSize - responseHeadersSize);
|
||||||
// Firefox only populate transferSize.
|
// Firefox only populate transferSize.
|
||||||
if (!bodySize)
|
if (!bodySize)
|
||||||
bodySize = encodedBodySize;
|
bodySize = encodedBodySize;
|
||||||
|
|
|
||||||
|
|
@ -252,8 +252,9 @@ export class HarTracer {
|
||||||
status: response.status(),
|
status: response.status(),
|
||||||
statusText: response.statusText(),
|
statusText: response.statusText(),
|
||||||
httpVersion: response.httpVersion(),
|
httpVersion: response.httpVersion(),
|
||||||
cookies: cookiesForHar(response.headerValue('set-cookie'), '\n'),
|
// These are bad values that will be overwritten bellow.
|
||||||
headers: response.headers().map(header => ({ name: header.name, value: header.value })),
|
cookies: [],
|
||||||
|
headers: [],
|
||||||
content: {
|
content: {
|
||||||
size: -1,
|
size: -1,
|
||||||
mimeType: 'x-unknown',
|
mimeType: 'x-unknown',
|
||||||
|
|
@ -292,12 +293,12 @@ export class HarTracer {
|
||||||
}));
|
}));
|
||||||
this._addBarrier(page, response.rawRequestHeaders().then(headers => {
|
this._addBarrier(page, response.rawRequestHeaders().then(headers => {
|
||||||
for (const header of headers.filter(header => header.name.toLowerCase() === 'cookie'))
|
for (const header of headers.filter(header => header.name.toLowerCase() === 'cookie'))
|
||||||
harEntry.request.cookies.push(...cookiesForHar(header.value, ';'));
|
harEntry.request.cookies.push(...header.value.split(';').map(parseCookie));
|
||||||
harEntry.request.headers = headers;
|
harEntry.request.headers = headers;
|
||||||
}));
|
}));
|
||||||
this._addBarrier(page, response.rawResponseHeaders().then(headers => {
|
this._addBarrier(page, response.rawResponseHeaders().then(headers => {
|
||||||
for (const header of headers.filter(header => header.name.toLowerCase() === 'set-cookie'))
|
for (const header of headers.filter(header => header.name.toLowerCase() === 'set-cookie'))
|
||||||
harEntry.response.cookies.push(...cookiesForHar(header.value, '\n'));
|
harEntry.response.cookies.push(parseCookie(header.value));
|
||||||
harEntry.response.headers = headers;
|
harEntry.response.headers = headers;
|
||||||
const contentType = headers.find(header => header.name.toLowerCase() === 'content-type');
|
const contentType = headers.find(header => header.name.toLowerCase() === 'content-type');
|
||||||
if (contentType)
|
if (contentType)
|
||||||
|
|
@ -365,12 +366,6 @@ function postDataForHar(request: network.Request, content: 'omit' | 'sha1' | 'em
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cookiesForHar(header: string | undefined, separator: string): har.Cookie[] {
|
|
||||||
if (!header)
|
|
||||||
return [];
|
|
||||||
return header.split(separator).map(c => parseCookie(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseCookie(c: string): har.Cookie {
|
function parseCookie(c: string): har.Cookie {
|
||||||
const cookie: har.Cookie = {
|
const cookie: har.Cookie = {
|
||||||
name: '',
|
name: '',
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,8 @@ export class WKInterceptableRequest {
|
||||||
requestStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.requestStart) : -1,
|
requestStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.requestStart) : -1,
|
||||||
responseStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.responseStart) : -1,
|
responseStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.responseStart) : -1,
|
||||||
};
|
};
|
||||||
return new network.Response(this.request, responsePayload.status, responsePayload.statusText, headersObjectToArray(responsePayload.headers), timing, getResponseBody);
|
const setCookieSeparator = process.platform === 'linux' ? '\n' : ',';
|
||||||
|
return new network.Response(this.request, responsePayload.status, responsePayload.statusText, headersObjectToArray(responsePayload.headers, ',', setCookieSeparator), timing, getResponseBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -246,11 +246,19 @@ export async function mkdirIfNeeded(filePath: string) {
|
||||||
type HeadersArray = { name: string, value: string }[];
|
type HeadersArray = { name: string, value: string }[];
|
||||||
type HeadersObject = { [key: string]: string };
|
type HeadersObject = { [key: string]: string };
|
||||||
|
|
||||||
export function headersObjectToArray(headers: HeadersObject): HeadersArray {
|
export function headersObjectToArray(headers: HeadersObject, separator?: string, setCookieSeparator?: string): HeadersArray {
|
||||||
|
if (!setCookieSeparator)
|
||||||
|
setCookieSeparator = separator;
|
||||||
const result: HeadersArray = [];
|
const result: HeadersArray = [];
|
||||||
for (const name in headers) {
|
for (const name in headers) {
|
||||||
if (!Object.is(headers[name], undefined))
|
const values = headers[name];
|
||||||
result.push({ name, value: headers[name] });
|
if (separator) {
|
||||||
|
const sep = name.toLowerCase() === 'set-cookie' ? setCookieSeparator : separator;
|
||||||
|
for (const value of values.split(sep!))
|
||||||
|
result.push({ name, value: value.trim() });
|
||||||
|
} else {
|
||||||
|
result.push({ name, value: values });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,9 +194,7 @@ it('should include cookies', async ({ contextFactory, server }, testInfo) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include set-cookies', async ({ contextFactory, server, browserName, platform }, testInfo) => {
|
it('should include set-cookies', async ({ contextFactory, server }, testInfo) => {
|
||||||
it.fail(browserName === 'webkit' && platform === 'darwin', 'Does not work yet');
|
|
||||||
|
|
||||||
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
||||||
server.setRoute('/empty.html', (req, res) => {
|
server.setRoute('/empty.html', (req, res) => {
|
||||||
res.setHeader('Set-Cookie', [
|
res.setHeader('Set-Cookie', [
|
||||||
|
|
@ -214,18 +212,20 @@ it('should include set-cookies', async ({ contextFactory, server, browserName, p
|
||||||
expect(new Date(cookies[2].expires).valueOf()).toBeGreaterThan(Date.now());
|
expect(new Date(cookies[2].expires).valueOf()).toBeGreaterThan(Date.now());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include set-cookies with comma', async ({ contextFactory, server }, testInfo) => {
|
it('should include set-cookies with comma', async ({ contextFactory, server, browserName }, testInfo) => {
|
||||||
|
it.fixme(browserName === 'webkit', 'We get "name1=val, ue1, name2=val, ue2" as a header value');
|
||||||
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
const { page, getLog } = await pageWithHar(contextFactory, testInfo);
|
||||||
server.setRoute('/empty.html', (req, res) => {
|
server.setRoute('/empty.html', (req, res) => {
|
||||||
res.setHeader('Set-Cookie', [
|
res.setHeader('Set-Cookie', [
|
||||||
'name1=val,ue1',
|
'name1=val, ue1', 'name2=val, ue2',
|
||||||
]);
|
]);
|
||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
const log = await getLog();
|
const log = await getLog();
|
||||||
const cookies = log.entries[0].response.cookies;
|
const cookies = log.entries[0].response.cookies;
|
||||||
expect(cookies[0]).toEqual({ name: 'name1', value: 'val,ue1' });
|
expect(cookies[0]).toEqual({ name: 'name1', value: 'val, ue1' });
|
||||||
|
expect(cookies[1]).toEqual({ name: 'name2', value: 'val, ue2' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include secure set-cookies', async ({ contextFactory, httpsServer }, testInfo) => {
|
it('should include secure set-cookies', async ({ contextFactory, httpsServer }, testInfo) => {
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,7 @@ it('should get the same headers as the server', async ({ page, server, browserNa
|
||||||
});
|
});
|
||||||
const response = await page.goto(server.PREFIX + '/empty.html');
|
const response = await page.goto(server.PREFIX + '/empty.html');
|
||||||
const headers = await response.request().allHeaders();
|
const headers = await response.request().allHeaders();
|
||||||
const result = {};
|
expect(headers.headers()).toEqual(serverRequest.headers);
|
||||||
for (const header of headers.headers())
|
|
||||||
result[header.name.toLowerCase()] = header.value;
|
|
||||||
expect(result).toEqual(serverRequest.headers);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get the same headers as the server CORS', async ({page, server, browserName, platform}) => {
|
it('should get the same headers as the server CORS', async ({page, server, browserName, platform}) => {
|
||||||
|
|
@ -114,11 +111,7 @@ it('should get the same headers as the server CORS', async ({page, server, brows
|
||||||
expect(text).toBe('done');
|
expect(text).toBe('done');
|
||||||
const response = await responsePromise;
|
const response = await responsePromise;
|
||||||
const headers = await response.request().allHeaders();
|
const headers = await response.request().allHeaders();
|
||||||
const result = {};
|
expect(headers.headers()).toEqual(serverRequest.headers);
|
||||||
for (const header of headers.headers())
|
|
||||||
result[header.name.toLowerCase()] = header.value;
|
|
||||||
|
|
||||||
expect(result).toEqual(serverRequest.headers);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return postData', async ({page, server, isAndroid}) => {
|
it('should return postData', async ({page, server, isAndroid}) => {
|
||||||
|
|
@ -273,17 +266,28 @@ it('should return navigation bit when navigating to image', async ({page, server
|
||||||
expect(requests[0].isNavigationRequest()).toBe(true);
|
expect(requests[0].isNavigationRequest()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report raw headers', async ({ page, server, browserName }) => {
|
it('should report all headers', async ({ page, server, browserName, platform }) => {
|
||||||
const response = await page.goto(server.EMPTY_PAGE);
|
const expectedHeaders = {};
|
||||||
const requestHeaders = await response.request().allHeaders();
|
server.setRoute('/headers', (req, res) => {
|
||||||
expect(requestHeaders.headerNames().map(h => h.toLowerCase())).toContain('accept');
|
for (let i = 0; i < req.rawHeaders.length; i += 2)
|
||||||
expect(requestHeaders.getAll('host')).toHaveLength(1);
|
expectedHeaders[req.rawHeaders[i].toLowerCase()] = req.rawHeaders[i + 1];
|
||||||
expect(requestHeaders.get('host')).toBe(`localhost:${server.PORT}`);
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
const responseHeaders = await response.allHeaders();
|
await page.goto(server.EMPTY_PAGE);
|
||||||
expect(responseHeaders.headerNames().map(h => h.toLowerCase())).toContain('content-type');
|
const [request] = await Promise.all([
|
||||||
expect(responseHeaders.getAll('content-type')).toHaveLength(1);
|
page.waitForRequest('**/*'),
|
||||||
expect(responseHeaders.get('content-type')).toBe('text/html; charset=utf-8');
|
page.evaluate(() => fetch('/headers', {
|
||||||
|
headers: [
|
||||||
|
['header-a', 'value-a'],
|
||||||
|
['header-b', 'value-b'],
|
||||||
|
['header-a', 'value-a-1'],
|
||||||
|
['header-a', 'value-a-2'],
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
]);
|
||||||
|
const headers = await request.allHeaders();
|
||||||
|
expect(headers.headers()).toEqual(expectedHeaders);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report raw response headers in redirects', async ({ page, server, browserName }) => {
|
it('should report raw response headers in redirects', async ({ page, server, browserName }) => {
|
||||||
|
|
@ -310,3 +314,22 @@ it('should report raw response headers in redirects', async ({ page, server, bro
|
||||||
expect(redirectChain).toEqual(expectedUrls);
|
expect(redirectChain).toEqual(expectedUrls);
|
||||||
expect(headersChain).toEqual(expectedHeaders);
|
expect(headersChain).toEqual(expectedHeaders);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should report all cookies in one header', async ({ page, server }) => {
|
||||||
|
const expectedHeaders = {};
|
||||||
|
server.setRoute('/headers', (req, res) => {
|
||||||
|
for (let i = 0; i < req.rawHeaders.length; i += 2)
|
||||||
|
expectedHeaders[req.rawHeaders[i]] = req.rawHeaders[i + 1];
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await page.evaluate(() => {
|
||||||
|
document.cookie = 'myCookie=myValue';
|
||||||
|
document.cookie = 'myOtherCookie=myOtherValue';
|
||||||
|
});
|
||||||
|
const response = await page.goto(server.EMPTY_PAGE);
|
||||||
|
const headers = await response.request().allHeaders();
|
||||||
|
const cookie = headers.get('cookie');
|
||||||
|
expect(cookie).toBe('myCookie=myValue; myOtherCookie=myOtherValue');
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -117,3 +117,52 @@ it('should return status text', async ({page, server}) => {
|
||||||
const response = await page.goto(server.PREFIX + '/cool');
|
const response = await page.goto(server.PREFIX + '/cool');
|
||||||
expect(response.statusText()).toBe('cool!');
|
expect(response.statusText()).toBe('cool!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should report all headers', async ({ page, server }) => {
|
||||||
|
const expectedHeaders = {
|
||||||
|
'header-a': ['value-a', 'value-a-1', 'value-a-2'],
|
||||||
|
'header-b': ['value-b'],
|
||||||
|
};
|
||||||
|
server.setRoute('/headers', (req, res) => {
|
||||||
|
res.writeHead(200, expectedHeaders);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
const [response] = await Promise.all([
|
||||||
|
page.waitForResponse('**/*'),
|
||||||
|
page.evaluate(() => fetch('/headers'))
|
||||||
|
]);
|
||||||
|
const headers = await response.allHeaders();
|
||||||
|
const actualHeaders = {};
|
||||||
|
for (const name of headers.headerNames())
|
||||||
|
actualHeaders[name] = headers.getAll(name);
|
||||||
|
delete actualHeaders['Keep-Alive'];
|
||||||
|
delete actualHeaders['keep-alive'];
|
||||||
|
delete actualHeaders['Connection'];
|
||||||
|
delete actualHeaders['connection'];
|
||||||
|
delete actualHeaders['Date'];
|
||||||
|
delete actualHeaders['date'];
|
||||||
|
delete actualHeaders['Transfer-Encoding'];
|
||||||
|
delete actualHeaders['transfer-encoding'];
|
||||||
|
expect(actualHeaders).toEqual(expectedHeaders);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should report multiple set-cookie headers', async ({ page, server }) => {
|
||||||
|
server.setRoute('/headers', (req, res) => {
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Set-Cookie': ['a=b', 'c=d']
|
||||||
|
});
|
||||||
|
res.write('\r\n');
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
const [response] = await Promise.all([
|
||||||
|
page.waitForResponse('**/*'),
|
||||||
|
page.evaluate(() => fetch('/headers'))
|
||||||
|
]);
|
||||||
|
const headers = await response.allHeaders();
|
||||||
|
const cookies = headers.getAll('set-cookie');
|
||||||
|
expect(cookies).toEqual(['a=b', 'c=d']);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ it('should set bodySize, headersSize, and transferSize', async ({page, server, b
|
||||||
]);
|
]);
|
||||||
const sizes = await response.request().sizes();
|
const sizes = await response.request().sizes();
|
||||||
expect(sizes.responseBodySize).toBe(6);
|
expect(sizes.responseBodySize).toBe(6);
|
||||||
expect(sizes.responseHeadersSize).toBeGreaterThanOrEqual(150);
|
expect(sizes.responseHeadersSize).toBeGreaterThanOrEqual(100);
|
||||||
expect(sizes.responseTransferSize).toBeGreaterThanOrEqual(160);
|
expect(sizes.responseTransferSize).toBeGreaterThanOrEqual(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set bodySize to 0 when there was no response body', async ({page, server, browserName, platform}) => {
|
it('should set bodySize to 0 when there was no response body', async ({page, server, browserName, platform}) => {
|
||||||
|
|
|
||||||
|
|
@ -98,10 +98,9 @@ it('should work when header manipulation headers with redirect', async ({page, s
|
||||||
// @see https://github.com/GoogleChrome/puppeteer/issues/4743
|
// @see https://github.com/GoogleChrome/puppeteer/issues/4743
|
||||||
it('should be able to remove headers', async ({page, server}) => {
|
it('should be able to remove headers', async ({page, server}) => {
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
await page.route('**/*', route => {
|
await page.route('**/*', async route => {
|
||||||
const headers = Object.assign({}, route.request().headers(), {
|
const headers = { ...route.request().headers() };
|
||||||
foo: undefined, // remove "foo" header
|
delete headers['foo'];
|
||||||
});
|
|
||||||
route.continue({ headers });
|
route.continue({ headers });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import { test as it, expect } from './pageTest';
|
||||||
it('should work', async ({page, server}) => {
|
it('should work', async ({page, server}) => {
|
||||||
await page.setExtraHTTPHeaders({
|
await page.setExtraHTTPHeaders({
|
||||||
foo: 'bar',
|
foo: 'bar',
|
||||||
baz: undefined,
|
|
||||||
});
|
});
|
||||||
const [request] = await Promise.all([
|
const [request] = await Promise.all([
|
||||||
server.waitForRequest('/empty.html'),
|
server.waitForRequest('/empty.html'),
|
||||||
|
|
|
||||||
5
types/types.d.ts
vendored
5
types/types.d.ts
vendored
|
|
@ -12682,9 +12682,10 @@ export interface Headers {
|
||||||
headerNames(): Array<string>;
|
headerNames(): Array<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all raw headers.
|
* Returns all headers as a dictionary. Header names are normalized to lower case, multi-value headers are concatenated
|
||||||
|
* using comma.
|
||||||
*/
|
*/
|
||||||
headers(): Array<{ name: string, value: string }>;
|
headers(): { [key: string]: string; };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue