feat(fetch): support new headers api (#8843)

This commit is contained in:
Yury Semikhatsky 2021-09-10 14:03:56 -07:00 committed by GitHub
parent b1b801a3a7
commit ebdad167f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 14 deletions

View file

@ -555,6 +555,10 @@ export class FetchResponse {
return { ...this._headers }; return { ...this._headers };
} }
headersArray(): string[][] {
return this._initializer.headers.map(({name, value}) => [name, value]);
}
async body(): Promise<Buffer> { async body(): Promise<Buffer> {
return this._context._wrapApiCall(async (channel: channels.BrowserContextChannel) => { return this._context._wrapApiCall(async (channel: channels.BrowserContextChannel) => {
const result = await channel.fetchResponseBody({ fetchUid: this._fetchUid() }); const result = await channel.fetchResponseBody({ fetchUid: this._fetchUid() });

View file

@ -196,7 +196,7 @@ async function sendRequest(context: BrowserContext, url: URL, options: https.Req
url: response.url || url.toString(), url: response.url || url.toString(),
status: response.statusCode || 0, status: response.statusCode || 0,
statusText: response.statusMessage || '', statusText: response.statusMessage || '',
headers: flattenHeaders(response.headers), headers: toHeadersArray(response.rawHeaders),
body body
}); });
}); });
@ -219,18 +219,10 @@ async function sendRequest(context: BrowserContext, url: URL, options: https.Req
}); });
} }
function flattenHeaders(headers: http.IncomingHttpHeaders): types.HeadersArray { function toHeadersArray(rawHeaders: string[]): types.HeadersArray {
const result: types.HeadersArray = []; const result: types.HeadersArray = [];
for (const [name, values] of Object.entries(headers)) { for (let i = 0; i < rawHeaders.length; i += 2)
if (values === undefined) result.push({ name: rawHeaders[i], value: rawHeaders[i + 1] });
continue;
if (typeof values === 'string') {
result.push({name, value: values as string});
} else {
for (const value of values)
result.push({name, value});
}
}
return result; return result;
} }

View file

@ -18,7 +18,6 @@ import http from 'http';
import zlib from 'zlib'; import zlib from 'zlib';
import { pipeline } from 'stream'; import { pipeline } from 'stream';
import { contextTest as it, expect } from './config/browserTest'; import { contextTest as it, expect } from './config/browserTest';
import type { Response } from '..';
import { suppressCertificateWarning } from './config/utils'; import { suppressCertificateWarning } from './config/utils';
it.skip(({ mode }) => mode !== 'default'); it.skip(({ mode }) => mode !== 'default');
@ -43,13 +42,14 @@ it.afterAll(() => {
it('should work', async ({context, server}) => { it('should work', async ({context, server}) => {
// @ts-expect-error // @ts-expect-error
const response: Response = await context._fetch(server.PREFIX + '/simple.json'); const response = await context._fetch(server.PREFIX + '/simple.json');
expect(response.url()).toBe(server.PREFIX + '/simple.json'); expect(response.url()).toBe(server.PREFIX + '/simple.json');
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
expect(response.statusText()).toBe('OK'); expect(response.statusText()).toBe('OK');
expect(response.ok()).toBeTruthy(); expect(response.ok()).toBeTruthy();
expect(response.url()).toBe(server.PREFIX + '/simple.json'); expect(response.url()).toBe(server.PREFIX + '/simple.json');
expect(response.headers()['content-type']).toBe('application/json; charset=utf-8'); expect(response.headers()['content-type']).toBe('application/json; charset=utf-8');
expect(response.headersArray()).toContainEqual(['Content-Type', 'application/json; charset=utf-8']);
expect(await response.text()).toBe('{"foo": "bar"}\n'); expect(await response.text()).toBe('{"foo": "bar"}\n');
}); });
@ -264,6 +264,30 @@ it('should handle cookies on redirects', async ({context, server, browserName, i
])); ]));
}); });
it('should return raw headers', async ({context, page, server}) => {
server.setRoute('/headers', (req, res) => {
// Headers array is only supported since Node v14.14.0 so we write directly to the socket.
// res.writeHead(200, ['name-a', 'v1','name-b', 'v4','Name-a', 'v2', 'name-A', 'v3']);
const conn = res.connection;
conn.write('HTTP/1.1 200 OK\r\n');
conn.write('Name-A: v1\r\n');
conn.write('name-b: v4\r\n');
conn.write('Name-a: v2\r\n');
conn.write('name-A: v3\r\n');
conn.write('\r\n');
conn.uncork();
conn.end();
});
// @ts-expect-error
const response = await context._fetch(`${server.PREFIX}/headers`);
expect(response.status()).toBe(200);
const headers = response.headersArray().filter(([name, value]) => name.toLowerCase().includes('name-'));
expect(headers).toEqual([['Name-A', 'v1'], ['name-b', 'v4'], ['Name-a', 'v2'], ['name-A', 'v3']]);
// Last value wins, this matches Response.headers()
expect(response.headers()['name-a']).toBe('v3');
expect(response.headers()['name-b']).toBe('v4');
});
it('should work with context level proxy', async ({browserOptions, browserType, contextOptions, server, proxyServer}) => { it('should work with context level proxy', async ({browserOptions, browserType, contextOptions, server, proxyServer}) => {
server.setRoute('/target.html', async (req, res) => { server.setRoute('/target.html', async (req, res) => {
res.end('<title>Served by the proxy</title>'); res.end('<title>Served by the proxy</title>');