Skip to content

Commit 7f61715

Browse files
authored
feat(rpc): use headers array in the protocol (#2959)
1 parent 3189303 commit 7f61715

13 files changed

+102
-67
lines changed

src/chromium/crNetworkManager.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,12 @@ class InterceptableRequest implements network.RouteDelegate {
348348
this.request = new network.Request(allowInterception ? this : null, frame, redirectedFrom, documentId, url, type, method, postData, headersObject(headers));
349349
}
350350

351-
async continue(overrides: { method?: string; headers?: types.Headers; postData?: string } = {}) {
351+
async continue(overrides: types.NormalizedContinueOverrides) {
352352
// In certain cases, protocol will return error if the request was already canceled
353353
// or the page was closed. We should tolerate these errors.
354354
await this._client._sendMayFail('Fetch.continueRequest', {
355355
requestId: this._interceptionId!,
356-
headers: overrides.headers ? headersArray(overrides.headers) : undefined,
356+
headers: overrides.headers,
357357
method: overrides.method,
358358
postData: overrides.postData
359359
});
@@ -368,7 +368,7 @@ class InterceptableRequest implements network.RouteDelegate {
368368
requestId: this._interceptionId!,
369369
responseCode: response.status,
370370
responsePhrase: network.STATUS_TEXTS[String(response.status)],
371-
responseHeaders: headersArray(response.headers),
371+
responseHeaders: response.headers,
372372
body,
373373
});
374374
}
@@ -402,15 +402,6 @@ const errorReasons: { [reason: string]: Protocol.Network.ErrorReason } = {
402402
'failed': 'Failed',
403403
};
404404

405-
function headersArray(headers: { [s: string]: string; }): { name: string; value: string; }[] {
406-
const result = [];
407-
for (const name in headers) {
408-
if (!Object.is(headers[name], undefined))
409-
result.push({name, value: headers[name] + ''});
410-
}
411-
return result;
412-
}
413-
414405
function headersObject(headers: Protocol.Network.Headers): types.Headers {
415406
const result: types.Headers = {};
416407
for (const key of Object.keys(headers))

src/firefox/ffNetworkManager.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -158,17 +158,12 @@ class InterceptableRequest implements network.RouteDelegate {
158158
payload.url, internalCauseToResourceType[payload.internalCause] || causeToResourceType[payload.cause] || 'other', payload.method, payload.postData || null, headers);
159159
}
160160

161-
async continue(overrides: { method?: string; headers?: types.Headers; postData?: string }) {
162-
const {
163-
method,
164-
headers,
165-
postData
166-
} = overrides;
161+
async continue(overrides: types.NormalizedContinueOverrides) {
167162
await this._session.sendMayFail('Network.resumeInterceptedRequest', {
168163
requestId: this._id,
169-
method,
170-
headers: headers ? headersArray(headers) : undefined,
171-
postData: postData ? Buffer.from(postData).toString('base64') : undefined
164+
method: overrides.method,
165+
headers: overrides.headers,
166+
postData: overrides.postData ? Buffer.from(overrides.postData).toString('base64') : undefined
172167
});
173168
}
174169

@@ -179,7 +174,7 @@ class InterceptableRequest implements network.RouteDelegate {
179174
requestId: this._id,
180175
status: response.status,
181176
statusText: network.STATUS_TEXTS[String(response.status)] || '',
182-
headers: headersArray(response.headers),
177+
headers: response.headers,
183178
base64body,
184179
});
185180
}

src/network.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import * as frames from './frames';
1818
import * as types from './types';
1919
import { assert, helper } from './helper';
2020
import { URLSearchParams } from 'url';
21-
import { normalizeFulfillParameters } from './rpc/serializers';
21+
import { normalizeFulfillParameters, normalizeContinueOverrides } from './rpc/serializers';
2222

2323
export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): types.NetworkCookie[] {
2424
const parsedURLs = urls.map(s => new URL(s));
@@ -221,9 +221,9 @@ export class Route {
221221
await this._delegate.fulfill(await normalizeFulfillParameters(response));
222222
}
223223

224-
async continue(overrides: { method?: string; headers?: types.Headers; postData?: string } = {}) {
224+
async continue(overrides: types.ContinueOverrides = {}) {
225225
assert(!this._handled, 'Route is already handled!');
226-
await this._delegate.continue(overrides);
226+
await this._delegate.continue(normalizeContinueOverrides(overrides));
227227
}
228228
}
229229

@@ -316,7 +316,7 @@ export class Response {
316316
export interface RouteDelegate {
317317
abort(errorCode: string): Promise<void>;
318318
fulfill(response: types.NormalizedFulfillResponse): Promise<void>;
319-
continue(overrides: { method?: string; headers?: types.Headers; postData?: string; }): Promise<void>;
319+
continue(overrides: types.NormalizedContinueOverrides): Promise<void>;
320320
}
321321

322322
// List taken from https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml with extra 306 and 418 codes.

src/rpc/channels.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export interface BrowserContextChannel extends Channel {
9595
newPage(): Promise<{ page: PageChannel }>;
9696
setDefaultNavigationTimeoutNoReply(params: { timeout: number }): void;
9797
setDefaultTimeoutNoReply(params: { timeout: number }): void;
98-
setExtraHTTPHeaders(params: { headers: types.Headers }): Promise<void>;
98+
setExtraHTTPHeaders(params: { headers: types.HeadersArray }): Promise<void>;
9999
setGeolocation(params: { geolocation: types.Geolocation | null }): Promise<void>;
100100
setHTTPCredentials(params: { httpCredentials: types.Credentials | null }): Promise<void>;
101101
setNetworkInterceptionEnabled(params: { enabled: boolean }): Promise<void>;
@@ -143,7 +143,7 @@ export interface PageChannel extends Channel {
143143
opener(): Promise<{ page: PageChannel | null }>;
144144
reload(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }>;
145145
screenshot(params: types.ScreenshotOptions): Promise<{ binary: Binary }>;
146-
setExtraHTTPHeaders(params: { headers: types.Headers }): Promise<void>;
146+
setExtraHTTPHeaders(params: { headers: types.HeadersArray }): Promise<void>;
147147
setNetworkInterceptionEnabled(params: { enabled: boolean }): Promise<void>;
148148
setViewportSize(params: { viewportSize: types.Size }): Promise<void>;
149149

@@ -282,21 +282,16 @@ export type RequestInitializer = {
282282
resourceType: string,
283283
method: string,
284284
postData: string | null,
285-
headers: types.Headers,
285+
headers: types.HeadersArray,
286286
isNavigationRequest: boolean,
287287
redirectedFrom: RequestChannel | null,
288288
};
289289

290290

291291
export interface RouteChannel extends Channel {
292292
abort(params: { errorCode: string }): Promise<void>;
293-
continue(params: { method?: string, headers?: types.Headers, postData?: string }): Promise<void>;
294-
fulfill(params: {
295-
status?: number,
296-
headers?: types.Headers,
297-
body: string,
298-
isBase64: boolean,
299-
}): Promise<void>;
293+
continue(params: types.NormalizedContinueOverrides): Promise<void>;
294+
fulfill(params: types.NormalizedFulfillResponse): Promise<void>;
300295
}
301296
export type RouteInitializer = {
302297
request: RequestChannel,
@@ -312,7 +307,7 @@ export type ResponseInitializer = {
312307
url: string,
313308
status: number,
314309
statusText: string,
315-
headers: types.Headers,
310+
headers: types.HeadersArray,
316311
};
317312

318313

src/rpc/client/browserContext.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { Events } from '../../events';
2727
import { TimeoutSettings } from '../../timeoutSettings';
2828
import { Waiter } from './waiter';
2929
import { TimeoutError } from '../../errors';
30+
import { headersObjectToArray } from '../serializers';
3031

3132
export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserContextInitializer> {
3233
_pages = new Set<Page>();
@@ -131,7 +132,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
131132
}
132133

133134
async setExtraHTTPHeaders(headers: types.Headers): Promise<void> {
134-
await this._channel.setExtraHTTPHeaders({ headers });
135+
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
135136
}
136137

137138
async setOffline(offline: boolean): Promise<void> {

src/rpc/client/network.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import * as types from '../../types';
1919
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
2020
import { ChannelOwner } from './channelOwner';
2121
import { Frame } from './frame';
22-
import { normalizeFulfillParameters } from '../serializers';
22+
import { normalizeFulfillParameters, headersArrayToObject, normalizeContinueOverrides } from '../serializers';
2323

2424
export type NetworkCookie = {
2525
name: string,
@@ -48,6 +48,7 @@ export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
4848
private _redirectedFrom: Request | null = null;
4949
private _redirectedTo: Request | null = null;
5050
_failureText: string | null = null;
51+
private _headers: types.Headers;
5152

5253
static from(request: RequestChannel): Request {
5354
return (request as any)._object;
@@ -62,6 +63,7 @@ export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
6263
this._redirectedFrom = Request.fromNullable(initializer.redirectedFrom);
6364
if (this._redirectedFrom)
6465
this._redirectedFrom._redirectedTo = this;
66+
this._headers = headersArrayToObject(initializer.headers);
6567
}
6668

6769
url(): string {
@@ -99,8 +101,8 @@ export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
99101
return JSON.parse(this._initializer.postData);
100102
}
101103

102-
headers(): {[key: string]: string} {
103-
return { ...this._initializer.headers };
104+
headers(): types.Headers {
105+
return { ...this._headers };
104106
}
105107

106108
async response(): Promise<Response | null> {
@@ -154,14 +156,16 @@ export class Route extends ChannelOwner<RouteChannel, RouteInitializer> {
154156
await this._channel.fulfill(normalized);
155157
}
156158

157-
async continue(overrides: { method?: string; headers?: types.Headers; postData?: string } = {}) {
158-
await this._channel.continue(overrides);
159+
async continue(overrides: types.ContinueOverrides = {}) {
160+
await this._channel.continue(normalizeContinueOverrides(overrides));
159161
}
160162
}
161163

162164
export type RouteHandler = (route: Route, request: Request) => void;
163165

164166
export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer> {
167+
private _headers: types.Headers;
168+
165169
static from(response: ResponseChannel): Response {
166170
return (response as any)._object;
167171
}
@@ -172,6 +176,7 @@ export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer>
172176

173177
constructor(parent: ChannelOwner, type: string, guid: string, initializer: ResponseInitializer) {
174178
super(parent, type, guid, initializer);
179+
this._headers = headersArrayToObject(initializer.headers);
175180
}
176181

177182
url(): string {
@@ -190,8 +195,8 @@ export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer>
190195
return this._initializer.statusText;
191196
}
192197

193-
headers(): object {
194-
return { ...this._initializer.headers };
198+
headers(): types.Headers {
199+
return { ...this._headers };
195200
}
196201

197202
async finished(): Promise<Error | null> {

src/rpc/client/page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { assert, assertMaxArguments, helper, Listener } from '../../helper';
2121
import { TimeoutSettings } from '../../timeoutSettings';
2222
import * as types from '../../types';
2323
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PDFOptions } from '../channels';
24-
import { parseError, serializeError } from '../serializers';
24+
import { parseError, serializeError, headersObjectToArray } from '../serializers';
2525
import { Accessibility } from './accessibility';
2626
import { BrowserContext } from './browserContext';
2727
import { ChannelOwner } from './channelOwner';
@@ -282,7 +282,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
282282
}
283283

284284
async setExtraHTTPHeaders(headers: types.Headers) {
285-
await this._channel.setExtraHTTPHeaders({ headers });
285+
await this._channel.setExtraHTTPHeaders({ headers: headersObjectToArray(headers) });
286286
}
287287

288288
url(): string {

src/rpc/serializers.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import * as path from 'path';
2020
import * as util from 'util';
2121
import { TimeoutError } from '../errors';
2222
import * as types from '../types';
23-
import { helper } from '../helper';
23+
import { helper, assert } from '../helper';
2424

2525

2626
export function serializeError(e: any): types.Error {
@@ -82,7 +82,7 @@ export async function normalizeFulfillParameters(params: types.FulfillResponse &
8282
isBase64 = true;
8383
length = params.body.length;
8484
}
85-
const headers: { [s: string]: string; } = {};
85+
const headers: types.Headers = {};
8686
for (const header of Object.keys(params.headers || {}))
8787
headers[header.toLowerCase()] = String(params.headers![header]);
8888
if (params.contentType)
@@ -94,8 +94,35 @@ export async function normalizeFulfillParameters(params: types.FulfillResponse &
9494

9595
return {
9696
status: params.status || 200,
97-
headers,
97+
headers: headersObjectToArray(headers),
9898
body,
9999
isBase64
100100
};
101101
}
102+
103+
export function normalizeContinueOverrides(overrides: types.ContinueOverrides): types.NormalizedContinueOverrides {
104+
return {
105+
method: overrides.method,
106+
headers: overrides.headers ? headersObjectToArray(overrides.headers) : undefined,
107+
postData: overrides.postData,
108+
};
109+
}
110+
111+
export function headersObjectToArray(headers: types.Headers): types.HeadersArray {
112+
const result: types.HeadersArray = [];
113+
for (const name in headers) {
114+
if (!Object.is(headers[name], undefined)) {
115+
const value = headers[name];
116+
assert(helper.isString(value), `Expected value of header "${name}" to be String, but "${typeof value}" is found.`);
117+
result.push({ name, value });
118+
}
119+
}
120+
return result;
121+
}
122+
123+
export function headersArrayToObject(headers: types.HeadersArray): types.Headers {
124+
const result: types.Headers = {};
125+
for (const { name, value } of headers)
126+
result[name] = value;
127+
return result;
128+
}

src/rpc/server/browserContextDispatcher.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { RouteDispatcher, RequestDispatcher } from './networkDispatchers';
2424
import { CRBrowserContext } from '../../chromium/crBrowser';
2525
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
2626
import { Events as ChromiumEvents } from '../../chromium/events';
27+
import { headersArrayToObject } from '../serializers';
2728

2829
export class BrowserContextDispatcher extends Dispatcher<BrowserContext, BrowserContextInitializer> implements BrowserContextChannel {
2930
private _context: BrowserContextBase;
@@ -94,8 +95,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, Browser
9495
await this._context.setGeolocation(params.geolocation);
9596
}
9697

97-
async setExtraHTTPHeaders(params: { headers: types.Headers }): Promise<void> {
98-
await this._context.setExtraHTTPHeaders(params.headers);
98+
async setExtraHTTPHeaders(params: { headers: types.HeadersArray }): Promise<void> {
99+
await this._context.setExtraHTTPHeaders(headersArrayToObject(params.headers));
99100
}
100101

101102
async setOffline(params: { offline: boolean }): Promise<void> {

src/rpc/server/networkDispatchers.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
*/
1616

1717
import { Request, Response, Route } from '../../network';
18-
import * as types from '../../types';
1918
import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary } from '../channels';
2019
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher';
2120
import { FrameDispatcher } from './frameDispatcher';
21+
import { headersObjectToArray, headersArrayToObject } from '../serializers';
22+
import * as types from '../../types';
2223

2324
export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> implements RequestChannel {
2425

@@ -38,7 +39,7 @@ export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> i
3839
resourceType: request.resourceType(),
3940
method: request.method(),
4041
postData: request.postData(),
41-
headers: request.headers(),
42+
headers: headersObjectToArray(request.headers()),
4243
isNavigationRequest: request.isNavigationRequest(),
4344
redirectedFrom: RequestDispatcher.fromNullable(scope, request.redirectedFrom()),
4445
});
@@ -58,7 +59,7 @@ export class ResponseDispatcher extends Dispatcher<Response, ResponseInitializer
5859
url: response.url(),
5960
status: response.status(),
6061
statusText: response.statusText(),
61-
headers: response.headers(),
62+
headers: headersObjectToArray(response.headers()),
6263
});
6364
}
6465

@@ -80,14 +81,18 @@ export class RouteDispatcher extends Dispatcher<Route, RouteInitializer> impleme
8081
});
8182
}
8283

83-
async continue(params: { method?: string, headers?: types.Headers, postData?: string }): Promise<void> {
84-
await this._object.continue(params);
84+
async continue(params: types.NormalizedContinueOverrides): Promise<void> {
85+
await this._object.continue({
86+
method: params.method,
87+
headers: params.headers ? headersArrayToObject(params.headers) : undefined,
88+
postData: params.postData,
89+
});
8590
}
8691

87-
async fulfill(params: { status?: number, headers?: types.Headers, contentType?: string, body: string, isBase64: boolean }): Promise<void> {
92+
async fulfill(params: types.NormalizedFulfillResponse): Promise<void> {
8893
await this._object.fulfill({
8994
status: params.status,
90-
headers: params.headers,
95+
headers: params.headers ? headersArrayToObject(params.headers) : undefined,
9196
body: params.isBase64 ? Buffer.from(params.body, 'base64') : params.body,
9297
});
9398
}

0 commit comments

Comments
 (0)