chore(rpc): misc serializer improvements (#2832)

This commit is contained in:
Pavel Feldman 2020-07-03 18:04:08 -07:00 committed by GitHub
parent 7f60c4df62
commit 2540805bf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 81 additions and 97 deletions

View file

@ -362,15 +362,7 @@ class InterceptableRequest implements network.RouteDelegate {
}
async fulfill(response: types.NormalizedFulfillResponse) {
const responseBody = response.body && helper.isString(response.body) ? Buffer.from(response.body) : (response.body || null);
const responseHeaders: { [s: string]: string; } = {};
for (const header of Object.keys(response.headers))
responseHeaders[header.toLowerCase()] = response.headers[header];
if (response.contentType)
responseHeaders['content-type'] = response.contentType;
if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
const body = response.isBase64 ? response.body : Buffer.from(response.body).toString('base64');
// In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors.
@ -378,8 +370,8 @@ class InterceptableRequest implements network.RouteDelegate {
requestId: this._interceptionId!,
responseCode: response.status,
responsePhrase: network.STATUS_TEXTS[String(response.status)],
responseHeaders: headersArray(responseHeaders),
body: responseBody ? responseBody.toString('base64') : undefined,
responseHeaders: headersArray(response.headers),
body,
});
}

View file

@ -173,22 +173,14 @@ class InterceptableRequest implements network.RouteDelegate {
}
async fulfill(response: types.NormalizedFulfillResponse) {
const responseBody = response.body && helper.isString(response.body) ? Buffer.from(response.body) : (response.body || null);
const responseHeaders: { [s: string]: string; } = {};
for (const header of Object.keys(response.headers))
responseHeaders[header.toLowerCase()] = response.headers[header];
if (response.contentType)
responseHeaders['content-type'] = response.contentType;
if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
const base64body = response.isBase64 ? response.body : Buffer.from(response.body).toString('base64');
await this._session.sendMayFail('Network.fulfillInterceptedRequest', {
requestId: this._id,
status: response.status,
statusText: network.STATUS_TEXTS[String(response.status)] || '',
headers: headersArray(responseHeaders),
base64body: responseBody ? responseBody.toString('base64') : undefined,
headers: headersArray(response.headers),
base64body,
});
}

View file

@ -148,8 +148,8 @@ export type PageInitializer = {
export interface FrameChannel extends Channel {
$$eval(params: { selector: string; expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any>;
$eval(params: { selector: string; expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any>;
evalOnSelector(params: { selector: string; expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any>;
evalOnSelectorAll(params: { selector: string; expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any>;
addScriptTag(params: { options: { url?: string | undefined, path?: string | undefined, content?: string | undefined, type?: string | undefined }, isPage?: boolean }): Promise<ElementHandleChannel>;
addStyleTag(params: { options: { url?: string | undefined, path?: string | undefined, content?: string | undefined }, isPage?: boolean }): Promise<ElementHandleChannel>;
check(params: { selector: string, options: types.TimeoutOptions & { force?: boolean } & { noWaitAfter?: boolean }, isPage?: boolean }): Promise<void>;
@ -205,6 +205,7 @@ export interface JSHandleChannel extends Channel {
evaluateExpression(params: { expression: string, isFunction: boolean, arg: any }): Promise<any>;
evaluateExpressionHandle(params: { expression: string, isFunction: boolean, arg: any}): Promise<JSHandleChannel>;
getPropertyList(): Promise<{ name: string, value: JSHandleChannel}[]>;
getProperty(params: { name: string }): Promise<JSHandleChannel>;
jsonValue(): Promise<any>;
}
export type JSHandleInitializer = {
@ -213,8 +214,8 @@ export type JSHandleInitializer = {
export interface ElementHandleChannel extends JSHandleChannel {
$$evalExpression(params: { selector: string; expression: string, isFunction: boolean, arg: any }): Promise<any>;
$evalExpression(params: { selector: string; expression: string, isFunction: boolean, arg: any }): Promise<any>;
evalOnSelector(params: { selector: string; expression: string, isFunction: boolean, arg: any }): Promise<any>;
evalOnSelectorAll(params: { selector: string; expression: string, isFunction: boolean, arg: any }): Promise<any>;
boundingBox(): Promise<types.Rect | null>;
check(params: { options?: types.TimeoutOptions & { force?: boolean } & { noWaitAfter?: boolean } }): Promise<void>;
click(params: { options?: types.PointerActionOptions & types.MouseClickOptions & types.TimeoutOptions & { force?: boolean } & { noWaitAfter?: boolean } }): Promise<void>;
@ -264,8 +265,8 @@ export interface RouteChannel extends Channel {
response: {
status?: number,
headers?: types.Headers,
contentType?: string,
body: Binary,
body: string,
isBase64: boolean,
}
}): Promise<void>;
}

View file

@ -187,7 +187,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
this._browser._contexts.delete(this);
for (const [listener, event] of this._pendingWaitForEvents) {
if (event === Events.Page.Close)
if (event === Events.BrowserContext.Close)
continue;
listener(new Error('Context closed'));
}

View file

@ -84,8 +84,7 @@ export class Connection {
debug('pw:channel:event')(parsedMessage);
if (method === '__create__') {
const scopeObject = this._objects.get(guid);
const scope = scopeObject ? scopeObject._scope : this._rootScript;
const scope = this._scopes.get(guid)!;
scope.createRemoteObject(params.type, params.guid, params.initializer);
return;
}

View file

@ -139,13 +139,13 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R>;
async $eval<R>(selector: string, pageFunction: FuncOn<Element, void, R>, arg?: any): Promise<R>;
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
return parseResult(await this._elementChannel.$evalExpression({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
return parseResult(await this._elementChannel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
}
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
async $$eval<R>(selector: string, pageFunction: FuncOn<Element[], void, R>, arg?: any): Promise<R>;
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
return parseResult(await this._elementChannel.$$evalExpression({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
return parseResult(await this._elementChannel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) }));
}
}

View file

@ -105,14 +105,14 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
async $eval<R>(selector: string, pageFunction: FuncOn<Element, void, R>, arg?: any): Promise<R>;
async $eval<R, Arg>(selector: string, pageFunction: FuncOn<Element, Arg, R>, arg: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
return await this._channel.$eval({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), isPage: this._page!._isPageCall });
return await this._channel.evalOnSelector({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), isPage: this._page!._isPageCall });
}
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R>;
async $$eval<R>(selector: string, pageFunction: FuncOn<Element[], void, R>, arg?: any): Promise<R>;
async $$eval<R, Arg>(selector: string, pageFunction: FuncOn<Element[], Arg, R>, arg: Arg): Promise<R> {
assertMaxArguments(arguments.length, 3);
return await this._channel.$$eval({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), isPage: this._page!._isPageCall });
return await this._channel.evalOnSelectorAll({ selector, expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg), isPage: this._page!._isPageCall });
}
async $$(selector: string): Promise<ElementHandle<Element>[]> {

View file

@ -37,7 +37,7 @@ export class Keyboard {
await this._channel.keyboardInsertText({ text });
}
async type(text: string, options?: { delay?: number }) {
async type(text: string, options: { delay?: number } = {}) {
await this._channel.keyboardType({ text, options });
}

View file

@ -62,20 +62,13 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel, JSHandleIni
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>>;
async evaluateHandle<R>(pageFunction: FuncOn<T, void, R>, arg?: any): Promise<SmartHandle<R>>;
async evaluateHandle<R, Arg>(pageFunction: FuncOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>> {
const handleChannel = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
const handleChannel = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
return JSHandle.from(handleChannel) as SmartHandle<R>;
}
async getProperty(propertyName: string): Promise<JSHandle> {
const objectHandle = await this.evaluateHandle((object: any, propertyName: string) => {
const result: any = {__proto__: null};
result[propertyName] = object[propertyName];
return result;
}, propertyName);
const properties = await objectHandle.getProperties();
const result = properties.get(propertyName)!;
objectHandle.dispose();
return result;
async getProperty(name: string): Promise<JSHandle> {
const handleChannel = await this._channel.getProperty({ name });
return JSHandle.from(handleChannel);
}
async getProperties(): Promise<Map<string, JSHandle>> {

View file

@ -152,12 +152,7 @@ export class Route extends ChannelOwner<RouteChannel, RouteInitializer> {
async fulfill(response: types.FulfillResponse & { path?: string }) {
const normalized = await normalizeFulfillParameters(response);
await this._channel.fulfill({ response: {
status: normalized.status,
headers: normalized.headers,
contentType: normalized.contentType,
body: (typeof normalized.body === 'string' ? Buffer.from(normalized.body) : normalized.body).toString('base64')
}});
await this._channel.fulfill({ response: normalized });
}
async continue(overrides: { method?: string; headers?: types.Headers; postData?: string } = {}) {

View file

@ -144,8 +144,10 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
async _onBinding(bindingCall: BindingCall) {
const func = this._bindings.get(bindingCall._initializer.name);
if (func)
if (func) {
bindingCall.call(func);
return;
}
this._browserContext!._onBinding(bindingCall);
}

View file

@ -20,6 +20,7 @@ import * as path from 'path';
import * as util from 'util';
import { TimeoutError } from '../errors';
import * as types from '../types';
import { helper } from '../helper';
export function serializeError(e: any): types.Error {
@ -64,18 +65,37 @@ export async function normalizeFilePayloads(files: string | types.FilePayload |
}
export async function normalizeFulfillParameters(params: types.FulfillResponse & { path?: string }): Promise<types.NormalizedFulfillResponse> {
let body = '';
let isBase64 = false;
let length = 0;
if (params.path) {
return {
status: params.status || 200,
headers: params.headers || {},
contentType: mime.getType(params.path) || 'application/octet-stream',
body: await util.promisify(fs.readFile)(params.path)
};
const buffer = await util.promisify(fs.readFile)(params.path);
body = buffer.toString('base64');
isBase64 = true;
length = buffer.length;
} else if (helper.isString(params.body)) {
body = params.body;
isBase64 = false;
length = Buffer.byteLength(body);
} else if (params.body) {
body = params.body.toString('base64');
isBase64 = true;
length = params.body.length;
}
const headers: { [s: string]: string; } = {};
for (const header of Object.keys(params.headers || {}))
headers[header.toLowerCase()] = String(params.headers![header]);
if (params.contentType)
headers['content-type'] = String(params.contentType);
else if (params.path)
headers['content-type'] = mime.getType(params.path) || 'application/octet-stream';
if (length && !('content-length' in headers))
headers['content-length'] = String(length);
return {
status: params.status || 200,
headers: params.headers || {},
contentType: params.contentType,
body: params.body || ''
headers,
body,
isBase64
};
}

View file

@ -139,11 +139,11 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme
return elements.map(e => new ElementHandleDispatcher(this._scope, e));
}
async $evalExpression(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
async evalOnSelector(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
return serializeResult(await this._elementHandle._$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
}
async $$evalExpression(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
async evalOnSelectorAll(params: { selector: string, expression: string, isFunction: boolean, arg: any }): Promise<any> {
return serializeResult(await this._elementHandle._$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
}
}

View file

@ -78,12 +78,12 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
return target.dispatchEvent(params.selector, params.type, parseArgument(params.eventInit), params.options);
}
async $eval(params: { selector: string, expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any> {
async evalOnSelector(params: { selector: string, expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any> {
const target = params.isPage ? this._frame._page : this._frame;
return serializeResult(await target._$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
}
async $$eval(params: { selector: string, expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any> {
async evalOnSelectorAll(params: { selector: string, expression: string, isFunction: boolean, arg: any, isPage?: boolean }): Promise<any> {
const target = params.isPage ? this._frame._page : this._frame;
return serializeResult(await target._$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg)));
}

View file

@ -38,6 +38,11 @@ export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitiali
return createHandle(this._scope, jsHandle);
}
async getProperty(params: { name: string }): Promise<JSHandleChannel> {
const jsHandle = await this._object.getProperty(params.name);
return createHandle(this._scope, jsHandle);
}
async getPropertyList(): Promise<{ name: string, value: JSHandleChannel }[]> {
const map = await this._object.getProperties();
const result = [];

View file

@ -84,13 +84,12 @@ export class RouteDispatcher extends Dispatcher<Route, RouteInitializer> impleme
await this._object.continue(params.overrides);
}
async fulfill(params: { response: { status?: number, headers?: types.Headers, contentType?: string, body: Binary } }): Promise<void> {
async fulfill(params: { response: { status?: number, headers?: types.Headers, contentType?: string, body: string, isBase64: boolean } }): Promise<void> {
const { response } = params;
await this._object.fulfill({
status: response.status,
headers: response.headers,
contentType: response.contentType,
body: Buffer.from(response.body, 'base64'),
body: response.isBase64 ? Buffer.from(response.body, 'base64') : response.body,
});
}

View file

@ -33,10 +33,10 @@ export class Transport {
this.onclose = undefined;
}
send(message: any) {
send(message: string) {
if (this._closed)
throw new Error('Pipe has been closed');
const data = Buffer.from(JSON.stringify(message), 'utf-8');
const data = Buffer.from(message, 'utf-8');
const dataLength = Buffer.alloc(4);
dataLength.writeUInt32LE(data.length, 0);
this._pipeWrite.write(dataLength);
@ -70,7 +70,7 @@ export class Transport {
this._bytesLeft = 0;
this._waitForNextTask(() => {
if (this.onmessage)
this.onmessage.call(null, JSON.parse(message.toString('utf-8')));
this.onmessage(message.toString('utf-8'));
});
}
}

View file

@ -199,8 +199,8 @@ export type FulfillResponse = {
export type NormalizedFulfillResponse = {
status: number,
headers: Headers,
contentType?: string,
body: string | Buffer,
body: string,
isBase64: boolean,
};
export type NetworkCookie = {

View file

@ -16,7 +16,7 @@
*/
import * as frames from '../frames';
import { assert, helper } from '../helper';
import { assert } from '../helper';
import * as network from '../network';
import * as types from '../types';
import { Protocol } from './protocol';
@ -69,34 +69,20 @@ export class WKInterceptableRequest implements network.RouteDelegate {
async fulfill(response: types.NormalizedFulfillResponse) {
await this._interceptedPromise;
const base64Encoded = !!response.body && !helper.isString(response.body);
const responseBody = response.body ? (base64Encoded ? response.body.toString('base64') : response.body as string) : '';
const responseHeaders: { [s: string]: string; } = {};
for (const header of Object.keys(response.headers))
responseHeaders[header.toLowerCase()] = String(response.headers[header]);
let mimeType = base64Encoded ? 'application/octet-stream' : 'text/plain';
if (response.contentType) {
responseHeaders['content-type'] = response.contentType;
const index = response.contentType.indexOf(';');
if (index !== -1)
mimeType = response.contentType.substring(0, index).trimEnd();
else
mimeType = response.contentType.trim();
}
if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
// In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors.
let mimeType = response.isBase64 ? 'application/octet-stream' : 'text/plain';
const contentType = response.headers['content-type'];
if (contentType)
mimeType = contentType.split(';')[0].trim();
await this._session.sendMayFail('Network.interceptRequestWithResponse', {
requestId: this._requestId,
status: response.status,
statusText: network.STATUS_TEXTS[String(response.status)],
mimeType,
headers: responseHeaders,
base64Encoded,
content: responseBody
headers: response.headers,
base64Encoded: response.isBase64,
content: response.body
});
}