Skip to content

Commit

Permalink
feat(rpc): disallow deps into rpc client from outside (#3199)
Browse files Browse the repository at this point in the history
For this, common converters are extracted from rpc serializers.
  • Loading branch information
dgozman authored Jul 28, 2020
1 parent 3e023f6 commit 6cb1e03
Show file tree
Hide file tree
Showing 20 changed files with 148 additions and 124 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"tsc-installer": "tsc -p ./src/install/tsconfig.json",
"doc": "node utils/doclint/cli.js",
"test-infra": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js && node utils/testrunner/test/test.js",
"lint": "npm run eslint && npm run tsc && npm run doc && npm run test-types && npm run test-infra",
"lint": "npm run eslint && npm run tsc && npm run doc && npm run check-deps && npm run test-types && npm run test-infra",
"debug-test": "node --inspect-brk test/test.js",
"clean": "rimraf lib && rimraf types",
"prepare": "node install-from-github.js",
Expand Down
123 changes: 123 additions & 0 deletions src/converters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as fs from 'fs';
import * as mime from 'mime';
import * as path from 'path';
import * as util from 'util';
import * as types from './types';
import { helper, assert } from './helper';

export async function normalizeFilePayloads(files: string | types.FilePayload | string[] | types.FilePayload[]): Promise<types.FilePayload[]> {
let ff: string[] | types.FilePayload[];
if (!Array.isArray(files))
ff = [ files ] as string[] | types.FilePayload[];
else
ff = files;
const filePayloads: types.FilePayload[] = [];
for (const item of ff) {
if (typeof item === 'string') {
const file: types.FilePayload = {
name: path.basename(item),
mimeType: mime.getType(item) || 'application/octet-stream',
buffer: await util.promisify(fs.readFile)(item)
};
filePayloads.push(file);
} else {
filePayloads.push(item);
}
}
return filePayloads;
}

export async function normalizeFulfillParameters(params: types.FulfillResponse & { path?: string }): Promise<types.NormalizedFulfillResponse> {
let body = '';
let isBase64 = false;
let length = 0;
if (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: types.Headers = {};
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: headersObjectToArray(headers),
body,
isBase64
};
}

export function normalizeContinueOverrides(overrides: types.ContinueOverrides): types.NormalizedContinueOverrides {
return {
method: overrides.method,
headers: overrides.headers ? headersObjectToArray(overrides.headers) : undefined,
postData: helper.isString(overrides.postData) ? Buffer.from(overrides.postData, 'utf8') : overrides.postData,
};
}

export function headersObjectToArray(headers: types.Headers): types.HeadersArray {
const result: types.HeadersArray = [];
for (const name in headers) {
if (!Object.is(headers[name], undefined)) {
const value = headers[name];
assert(helper.isString(value), `Expected value of header "${name}" to be String, but "${typeof value}" is found.`);
result.push({ name, value });
}
}
return result;
}

export function headersArrayToObject(headers: types.HeadersArray): types.Headers {
const result: types.Headers = {};
for (const { name, value } of headers)
result[name] = value;
return result;
}

export function envObjectToArray(env: types.Env): types.EnvArray {
const result: types.EnvArray = [];
for (const name in env) {
if (!Object.is(env[name], undefined))
result.push({ name, value: String(env[name]) });
}
return result;
}

export function envArrayToObject(env: types.EnvArray): types.Env {
const result: types.Env = {};
for (const { name, value } of env)
result[name] = value;
return result;
}
2 changes: 1 addition & 1 deletion src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import * as types from './types';
import { Progress } from './progress';
import DebugScript from './debug/injected/debugScript';
import { FatalDOMError, RetargetableDOMError } from './common/domErrors';
import { normalizeFilePayloads } from './rpc/serializers';
import { normalizeFilePayloads } from './converters';

export class FrameExecutionContext extends js.ExecutionContext {
readonly frame: frames.Frame;
Expand Down
2 changes: 1 addition & 1 deletion src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as frames from './frames';
import * as types from './types';
import { assert, helper } from './helper';
import { URLSearchParams } from 'url';
import { normalizeFulfillParameters, normalizeContinueOverrides } from './rpc/serializers';
import { normalizeFulfillParameters, normalizeContinueOverrides } from './converters';

export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): types.NetworkCookie[] {
const parsedURLs = urls.map(s => new URL(s));
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { ChannelOwner } from './channelOwner';
import { Events } from '../../events';
import { LoggerSink } from '../../loggerSink';
import { BrowserType } from './browserType';
import { headersObjectToArray } from '../serializers';
import { headersObjectToArray } from '../../converters';

export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
readonly _contexts = new Set<BrowserContext>();
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { Browser } from './browser';
import { Events } from '../../events';
import { TimeoutSettings } from '../../timeoutSettings';
import { Waiter } from './waiter';
import { headersObjectToArray } from '../serializers';
import { headersObjectToArray } from '../../converters';

export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserContextInitializer> {
_pages = new Set<Page>();
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/browserType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { BrowserServer } from './browserServer';
import { LoggerSink } from '../../loggerSink';
import { headersObjectToArray, envObjectToArray } from '../serializers';
import { headersObjectToArray, envObjectToArray } from '../../converters';
import { serializeArgument } from './jsHandle';
import { assert } from '../../helper';

Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { TimeoutSettings } from '../../timeoutSettings';
import { Waiter } from './waiter';
import { Events } from '../../events';
import { LoggerSink } from '../../loggerSink';
import { envObjectToArray } from '../serializers';
import { envObjectToArray } from '../../converters';

export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer> {
static from(electron: ElectronChannel): Electron {
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/elementHandle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { Frame } from './frame';
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
import { ChannelOwner } from './channelOwner';
import { helper, assert } from '../../helper';
import { normalizeFilePayloads } from '../serializers';
import { normalizeFilePayloads } from '../../converters';

export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
readonly _elementChannel: ElementHandleChannel;
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as types from '../../types';
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
import { ChannelOwner } from './channelOwner';
import { Frame } from './frame';
import { normalizeFulfillParameters, headersArrayToObject, normalizeContinueOverrides } from '../serializers';
import { normalizeFulfillParameters, headersArrayToObject, normalizeContinueOverrides } from '../../converters';

export type NetworkCookie = {
name: string,
Expand Down
3 changes: 2 additions & 1 deletion src/rpc/client/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import { assert, assertMaxArguments, helper, Listener } from '../../helper';
import { TimeoutSettings } from '../../timeoutSettings';
import * as types from '../../types';
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PagePdfParams } from '../channels';
import { parseError, headersObjectToArray, serializeError } from '../serializers';
import { parseError, serializeError } from '../serializers';
import { headersObjectToArray } from '../../converters';
import { Accessibility } from './accessibility';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
Expand Down
107 changes: 1 addition & 106 deletions src/rpc/serializers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@
* limitations under the License.
*/

import * as fs from 'fs';
import * as mime from 'mime';
import * as path from 'path';
import * as util from 'util';
import { TimeoutError } from '../errors';
import * as types from '../types';
import { helper, assert } from '../helper';
import { helper } from '../helper';
import { SerializedError, AXNode, SerializedValue } from './channels';

export function serializeError(e: any): SerializedError {
Expand All @@ -45,107 +41,6 @@ export function parseError(error: SerializedError): Error {
return e;
}

export async function normalizeFilePayloads(files: string | types.FilePayload | string[] | types.FilePayload[]): Promise<types.FilePayload[]> {
let ff: string[] | types.FilePayload[];
if (!Array.isArray(files))
ff = [ files ] as string[] | types.FilePayload[];
else
ff = files;
const filePayloads: types.FilePayload[] = [];
for (const item of ff) {
if (typeof item === 'string') {
const file: types.FilePayload = {
name: path.basename(item),
mimeType: mime.getType(item) || 'application/octet-stream',
buffer: await util.promisify(fs.readFile)(item)
};
filePayloads.push(file);
} else {
filePayloads.push(item);
}
}
return filePayloads;
}

export async function normalizeFulfillParameters(params: types.FulfillResponse & { path?: string }): Promise<types.NormalizedFulfillResponse> {
let body = '';
let isBase64 = false;
let length = 0;
if (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: types.Headers = {};
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: headersObjectToArray(headers),
body,
isBase64
};
}

export function normalizeContinueOverrides(overrides: types.ContinueOverrides): types.NormalizedContinueOverrides {
return {
method: overrides.method,
headers: overrides.headers ? headersObjectToArray(overrides.headers) : undefined,
postData: helper.isString(overrides.postData) ? Buffer.from(overrides.postData, 'utf8') : overrides.postData,
};
}

export function headersObjectToArray(headers: types.Headers): types.HeadersArray {
const result: types.HeadersArray = [];
for (const name in headers) {
if (!Object.is(headers[name], undefined)) {
const value = headers[name];
assert(helper.isString(value), `Expected value of header "${name}" to be String, but "${typeof value}" is found.`);
result.push({ name, value });
}
}
return result;
}

export function headersArrayToObject(headers: types.HeadersArray): types.Headers {
const result: types.Headers = {};
for (const { name, value } of headers)
result[name] = value;
return result;
}

export function envObjectToArray(env: types.Env): types.EnvArray {
const result: types.EnvArray = [];
for (const name in env) {
if (!Object.is(env[name], undefined))
result.push({ name, value: String(env[name]) });
}
return result;
}

export function envArrayToObject(env: types.EnvArray): types.Env {
const result: types.Env = {};
for (const { name, value } of env)
result[name] = value;
return result;
}

export function axNodeToProtocol(axNode: types.SerializedAXNode): AXNode {
const result: AXNode = {
...axNode,
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server/browserContextDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { RouteDispatcher, RequestDispatcher } from './networkDispatchers';
import { CRBrowserContext } from '../../chromium/crBrowser';
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
import { Events as ChromiumEvents } from '../../chromium/events';
import { headersArrayToObject } from '../serializers';
import { headersArrayToObject } from '../../converters';

export class BrowserContextDispatcher extends Dispatcher<BrowserContext, BrowserContextInitializer> implements BrowserContextChannel {
private _context: BrowserContextBase;
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server/browserDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { CDPSessionDispatcher } from './cdpSessionDispatcher';
import { Dispatcher, DispatcherScope } from './dispatcher';
import { CRBrowser } from '../../chromium/crBrowser';
import { PageDispatcher } from './pageDispatcher';
import { headersArrayToObject } from '../serializers';
import { headersArrayToObject } from '../../converters';

export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> implements BrowserChannel {
constructor(scope: DispatcherScope, browser: BrowserBase) {
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server/browserTypeDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Dispatcher, DispatcherScope } from './dispatcher';
import { BrowserContextBase } from '../../browserContext';
import { BrowserContextDispatcher } from './browserContextDispatcher';
import { BrowserServerDispatcher } from './browserServerDispatcher';
import { headersArrayToObject, envArrayToObject } from '../serializers';
import { headersArrayToObject, envArrayToObject } from '../../converters';
import { parseValue } from './jsHandleDispatcher';

export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeInitializer> implements BrowserTypeChannel {
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server/electronDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { BrowserContextBase } from '../../browserContext';
import { PageDispatcher } from './pageDispatcher';
import { parseArgument, serializeResult } from './jsHandleDispatcher';
import { createHandle } from './elementHandlerDispatcher';
import { envArrayToObject } from '../serializers';
import { envArrayToObject } from '../../converters';

export class ElectronDispatcher extends Dispatcher<Electron, ElectronInitializer> implements ElectronChannel {
constructor(scope: DispatcherScope, electron: Electron) {
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server/networkDispatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Request, Response, Route } from '../../network';
import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary } from '../channels';
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher';
import { FrameDispatcher } from './frameDispatcher';
import { headersObjectToArray, headersArrayToObject } from '../serializers';
import { headersObjectToArray, headersArrayToObject } from '../../converters';
import * as types from '../../types';

export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> implements RequestChannel {
Expand Down
3 changes: 2 additions & 1 deletion src/rpc/server/pageDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { Page, Worker } from '../../page';
import * as types from '../../types';
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary, SerializedArgument, PagePdfParams, SerializedError, PageAccessibilitySnapshotResult, SerializedValue, PageEmulateMediaParams } from '../channels';
import { Dispatcher, DispatcherScope, lookupDispatcher, lookupNullableDispatcher } from './dispatcher';
import { parseError, serializeError, headersArrayToObject, axNodeToProtocol } from '../serializers';
import { parseError, serializeError, axNodeToProtocol } from '../serializers';
import { headersArrayToObject } from '../../converters';
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
import { DialogDispatcher } from './dialogDispatcher';
import { DownloadDispatcher } from './downloadDispatcher';
Expand Down
Loading

0 comments on commit 6cb1e03

Please sign in to comment.