Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: respond multiple headers with same key #8183

Merged
merged 1 commit into from Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api.md
Expand Up @@ -5122,7 +5122,7 @@ ResourceType will be one of the following: `document`, `stylesheet`, `image`, `m

- `response` <[Object]> Response that will fulfill this request
- `status` <[number]> Response status code, defaults to `200`.
- `headers` <[Object]> Optional response headers. Header values will be converted to a string.
- `headers` <[Object]> Optional response headers. Header values should be a string or a string array.
- `contentType` <[string]> If set, equals to setting `Content-Type` response header
- `body` <[string]|[Buffer]> Optional response body
- `priority` <[number]> - Optional intercept abort priority. If provided, intercept will be resolved using coopeative handling rules. Otherwise, intercept will be resolved immediately.
Expand Down
24 changes: 16 additions & 8 deletions src/common/HTTPRequest.ts
Expand Up @@ -555,12 +555,15 @@ export class HTTPRequest {
? Buffer.from(response.body)
: (response.body as Buffer) || null;

const responseHeaders: Record<string, string> = {};
const responseHeaders: Record<string, string | string[]> = {};
if (response.headers) {
for (const header of Object.keys(response.headers))
responseHeaders[header.toLowerCase()] = String(
response.headers[header]
);
for (const header of Object.keys(response.headers)) {
const value = response.headers[header];

responseHeaders[header.toLowerCase()] = Array.isArray(value)
? value.map((item) => String(item))
: String(value);
}
}
if (response.contentType)
responseHeaders['content-type'] = response.contentType;
Expand Down Expand Up @@ -696,12 +699,17 @@ const errorReasons: Record<ErrorCode, Protocol.Network.ErrorReason> = {
export type ActionResult = 'continue' | 'abort' | 'respond';

function headersArray(
headers: Record<string, string>
headers: Record<string, string | string[]>
): Array<{ name: string; value: string }> {
const result = [];
for (const name in headers) {
if (!Object.is(headers[name], undefined))
result.push({ name, value: headers[name] + '' });
const value = headers[name];

if (!Object.is(value, undefined)) {
const values = Array.isArray(value) ? value : [value];

result.push(...values.map((value) => ({ name, value: value + '' })));
}
}
return result;
}
Expand Down
27 changes: 27 additions & 0 deletions test/requestinterception.spec.ts
Expand Up @@ -710,6 +710,33 @@ describe('request interception', function () {
);
expect(response.url()).toBe(server.EMPTY_PAGE);
});
it('should allow mocking multiple headers with same key', async () => {
const { page, server } = getTestState();

await page.setRequestInterception(true);
page.on('request', (request) => {
request.respond({
status: 200,
headers: {
foo: 'bar',
arr: ['1', '2'],
'set-cookie': ['first=1', 'second=2'],
},
body: 'Hello world',
});
});
const response = await page.goto(server.EMPTY_PAGE);
const cookies = await page.cookies();
const firstCookie = cookies.find((cookie) => cookie.name === 'first');
const secondCookie = cookies.find((cookie) => cookie.name === 'second');
expect(response.status()).toBe(200);
expect(response.headers().foo).toBe('bar');
expect(response.headers().arr).toBe('1\n2');
// request.respond() will not trigger Network.responseReceivedExtraInfo
// fail to get 'set-cookie' header from response
expect(firstCookie?.value).toBe('1');
expect(secondCookie?.value).toBe('2');
});
it('should allow mocking binary responses', async () => {
const { page, server } = getTestState();

Expand Down