mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-05 19:04:43 +03:00
chore: do not serialize buffers into base64 in local mode (#15316)
This commit is contained in:
parent
ef5a56ce18
commit
4eccb89a79
@ -166,10 +166,9 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
||||
|
||||
async screenshot(options: { path?: string } = {}): Promise<Buffer> {
|
||||
const { binary } = await this._channel.screenshot();
|
||||
const buffer = Buffer.from(binary, 'base64');
|
||||
if (options.path)
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
return buffer;
|
||||
await fs.promises.writeFile(options.path, binary);
|
||||
return binary;
|
||||
}
|
||||
|
||||
async close() {
|
||||
@ -179,7 +178,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
||||
|
||||
async shell(command: string): Promise<Buffer> {
|
||||
const { result } = await this._channel.shell({ command });
|
||||
return Buffer.from(result, 'base64');
|
||||
return result;
|
||||
}
|
||||
|
||||
async open(command: string): Promise<AndroidSocket> {
|
||||
@ -222,12 +221,12 @@ export class AndroidSocket extends ChannelOwner<channels.AndroidSocketChannel> i
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.AndroidSocketInitializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._channel.on('data', ({ data }) => this.emit(Events.AndroidSocket.Data, Buffer.from(data, 'base64')));
|
||||
this._channel.on('data', ({ data }) => this.emit(Events.AndroidSocket.Data, data));
|
||||
this._channel.on('close', () => this.emit(Events.AndroidSocket.Close));
|
||||
}
|
||||
|
||||
async write(data: Buffer): Promise<void> {
|
||||
await this._channel.write({ data: data.toString('base64') });
|
||||
await this._channel.write({ data });
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
@ -235,10 +234,10 @@ export class AndroidSocket extends ChannelOwner<channels.AndroidSocketChannel> i
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFile(file: string | Buffer): Promise<string> {
|
||||
async function loadFile(file: string | Buffer): Promise<Buffer> {
|
||||
if (isString(file))
|
||||
return fs.promises.readFile(file, { encoding: 'base64' }).toString();
|
||||
return file.toString('base64');
|
||||
return fs.promises.readFile(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
export class AndroidInput implements api.AndroidInput {
|
||||
|
@ -99,7 +99,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
||||
}
|
||||
|
||||
async stopTracing(): Promise<Buffer> {
|
||||
return Buffer.from((await this._channel.stopTracing()).binary, 'base64');
|
||||
return (await this._channel.stopTracing()).binary;
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
|
@ -89,7 +89,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
|
||||
apiZone.reported = true;
|
||||
if (csi && stackTrace && stackTrace.apiName)
|
||||
csi.onApiCallBegin(renderCallWithParams(stackTrace.apiName, params), stackTrace, callCookie);
|
||||
return this._connection.sendMessageToServer(this, this._type, prop, validator(params, '', { tChannelImpl: tChannelImplToWire }), stackTrace);
|
||||
return this._connection.sendMessageToServer(this, this._type, prop, validator(params, '', { tChannelImpl: tChannelImplToWire, binary: this._connection.isRemote() ? 'toBase64' : 'buffer' }), stackTrace);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ export class Connection extends EventEmitter {
|
||||
callback.reject(parseError(error));
|
||||
} else {
|
||||
const validator = findValidator(callback.type, callback.method, 'Result');
|
||||
callback.resolve(validator(result, '', { tChannelImpl: this._tChannelImplFromWire.bind(this) }));
|
||||
callback.resolve(validator(result, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this.isRemote() ? 'fromBase64' : 'buffer' }));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -154,7 +154,7 @@ export class Connection extends EventEmitter {
|
||||
if (!object)
|
||||
throw new Error(`Cannot find object to emit "${method}": ${guid}`);
|
||||
const validator = findValidator(object._type, method, 'Event');
|
||||
(object._channel as any).emit(method, validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this) }));
|
||||
(object._channel as any).emit(method, validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this.isRemote() ? 'fromBase64' : 'buffer' }));
|
||||
}
|
||||
|
||||
close(errorMessage: string = 'Connection closed') {
|
||||
@ -181,7 +181,7 @@ export class Connection extends EventEmitter {
|
||||
throw new Error(`Cannot find parent object ${parentGuid} to create ${guid}`);
|
||||
let result: ChannelOwner<any>;
|
||||
const validator = findValidator(type, '', 'Initializer');
|
||||
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplFromWire.bind(this) });
|
||||
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this.isRemote() ? 'fromBase64' : 'buffer' });
|
||||
switch (type) {
|
||||
case 'Android':
|
||||
result = new Android(parent, type, guid, initializer);
|
||||
|
@ -202,12 +202,11 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
|
||||
}));
|
||||
}
|
||||
const result = await this._elementChannel.screenshot(copy);
|
||||
const buffer = Buffer.from(result.binary, 'base64');
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
await fs.promises.writeFile(options.path, result.binary);
|
||||
}
|
||||
return buffer;
|
||||
return result.binary;
|
||||
}
|
||||
|
||||
async $(selector: string): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
||||
@ -291,13 +290,13 @@ export async function convertInputFiles(files: string | FilePayload | string[] |
|
||||
if (typeof item === 'string') {
|
||||
return {
|
||||
name: path.basename(item),
|
||||
buffer: (await fs.promises.readFile(item)).toString('base64')
|
||||
buffer: await fs.promises.readFile(item)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
name: item.name,
|
||||
mimeType: item.mimeType,
|
||||
buffer: item.buffer.toString('base64'),
|
||||
buffer: item.buffer,
|
||||
};
|
||||
}
|
||||
}));
|
||||
|
@ -189,13 +189,12 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
}
|
||||
if (postDataBuffer === undefined && jsonData === undefined && formData === undefined && multipartData === undefined)
|
||||
postDataBuffer = request?.postDataBuffer() || undefined;
|
||||
const postData = (postDataBuffer ? postDataBuffer.toString('base64') : undefined);
|
||||
const result = await this._channel.fetch({
|
||||
url,
|
||||
params,
|
||||
method,
|
||||
headers,
|
||||
postData,
|
||||
postData: postDataBuffer,
|
||||
jsonData,
|
||||
formData,
|
||||
multipartData,
|
||||
@ -257,7 +256,7 @@ export class APIResponse implements api.APIResponse {
|
||||
const result = await this._request._channel.fetchResponseBody({ fetchUid: this._fetchUid() });
|
||||
if (result.binary === undefined)
|
||||
throw new Error('Response has been disposed');
|
||||
return Buffer.from(result.binary!, 'base64');
|
||||
return result.binary;
|
||||
} catch (e) {
|
||||
if (e.message.includes(kBrowserOrContextClosedError))
|
||||
throw new Error('Response has been disposed');
|
||||
@ -300,7 +299,7 @@ function filePayloadToJson(payload: FilePayload): ServerFilePayload {
|
||||
return {
|
||||
name: payload.name,
|
||||
mimeType: payload.mimeType,
|
||||
buffer: payload.buffer.toString('base64'),
|
||||
buffer: payload.buffer,
|
||||
};
|
||||
}
|
||||
|
||||
@ -314,7 +313,7 @@ async function readStreamToJson(stream: fs.ReadStream): Promise<ServerFilePayloa
|
||||
const streamPath: string = Buffer.isBuffer(stream.path) ? stream.path.toString('utf8') : stream.path;
|
||||
return {
|
||||
name: path.basename(streamPath),
|
||||
buffer: buffer.toString('base64'),
|
||||
buffer,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ export class HarRouter {
|
||||
url: request.url(),
|
||||
method: request.method(),
|
||||
headers: (await request.headersArray()),
|
||||
postData: request.postDataBuffer()?.toString('base64'),
|
||||
postData: request.postDataBuffer() || undefined,
|
||||
isNavigationRequest: request.isNavigationRequest()
|
||||
});
|
||||
|
||||
@ -66,7 +66,7 @@ export class HarRouter {
|
||||
await route.fulfill({
|
||||
status: response.status,
|
||||
headers: Object.fromEntries(response.headers!.map(h => [h.name, h.value])),
|
||||
body: Buffer.from(response.body!, 'base64')
|
||||
body: response.body!
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
|
||||
if (this._redirectedFrom)
|
||||
this._redirectedFrom._redirectedTo = this;
|
||||
this._provisionalHeaders = new RawHeaders(initializer.headers);
|
||||
this._postData = initializer.postData !== undefined ? Buffer.from(initializer.postData, 'base64') : null;
|
||||
this._postData = initializer.postData ?? null;
|
||||
this._timing = {
|
||||
startTime: 0,
|
||||
domainLookupStart: -1,
|
||||
@ -385,7 +385,7 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
|
||||
url: options.url,
|
||||
method: options.method,
|
||||
headers: options.headers ? headersObjectToArray(options.headers) : undefined,
|
||||
postData: postDataBuffer ? postDataBuffer.toString('base64') : undefined,
|
||||
postData: postDataBuffer,
|
||||
}));
|
||||
}, !!internal);
|
||||
}
|
||||
@ -491,7 +491,7 @@ export class Response extends ChannelOwner<channels.ResponseChannel> implements
|
||||
}
|
||||
|
||||
async body(): Promise<Buffer> {
|
||||
return Buffer.from((await this._channel.body()).binary, 'base64');
|
||||
return (await this._channel.body()).binary;
|
||||
}
|
||||
|
||||
async text(): Promise<string> {
|
||||
@ -533,13 +533,13 @@ export class WebSocket extends ChannelOwner<channels.WebSocketChannel> implement
|
||||
super(parent, type, guid, initializer);
|
||||
this._isClosed = false;
|
||||
this._page = parent as Page;
|
||||
this._channel.on('frameSent', (event: { opcode: number, data: string }) => {
|
||||
this._channel.on('frameSent', event => {
|
||||
if (event.opcode === 1)
|
||||
this.emit(Events.WebSocket.FrameSent, { payload: event.data });
|
||||
else if (event.opcode === 2)
|
||||
this.emit(Events.WebSocket.FrameSent, { payload: Buffer.from(event.data, 'base64') });
|
||||
});
|
||||
this._channel.on('frameReceived', (event: { opcode: number, data: string }) => {
|
||||
this._channel.on('frameReceived', event => {
|
||||
if (event.opcode === 1)
|
||||
this.emit(Events.WebSocket.FrameReceived, { payload: event.data });
|
||||
else if (event.opcode === 2)
|
||||
|
@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Buffer } from 'buffer';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import type * as structs from '../../types/structs';
|
||||
@ -503,12 +502,11 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
}));
|
||||
}
|
||||
const result = await this._channel.screenshot(copy);
|
||||
const buffer = Buffer.from(result.binary, 'base64');
|
||||
if (options.path) {
|
||||
await mkdirIfNeeded(options.path);
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
await fs.promises.writeFile(options.path, result.binary);
|
||||
}
|
||||
return buffer;
|
||||
return result.binary;
|
||||
}
|
||||
|
||||
async _expectScreenshot(customStackTrace: ParsedStackTrace, options: ExpectScreenshotOptions): Promise<{ actual?: Buffer, previous?: Buffer, diff?: Buffer, errorMessage?: string, log?: string[]}> {
|
||||
@ -521,25 +519,15 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
frame: options.locator._frame._channel,
|
||||
selector: options.locator._selector,
|
||||
} : undefined;
|
||||
const expected = options.expected ? options.expected.toString('base64') : undefined;
|
||||
|
||||
const result = await this._channel.expectScreenshot({
|
||||
return await this._channel.expectScreenshot({
|
||||
...options,
|
||||
isNot: !!options.isNot,
|
||||
expected,
|
||||
locator,
|
||||
screenshotOptions: {
|
||||
...options.screenshotOptions,
|
||||
mask,
|
||||
}
|
||||
});
|
||||
return {
|
||||
log: result.log,
|
||||
actual: result.actual ? Buffer.from(result.actual, 'base64') : undefined,
|
||||
previous: result.previous ? Buffer.from(result.previous, 'base64') : undefined,
|
||||
diff: result.diff ? Buffer.from(result.diff, 'base64') : undefined,
|
||||
errorMessage: result.errorMessage,
|
||||
};
|
||||
}, false /* isInternal */, customStackTrace);
|
||||
}
|
||||
|
||||
@ -742,12 +730,11 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
transportOptions.margin![index] = transportOptions.margin![index] + 'px';
|
||||
}
|
||||
const result = await this._channel.pdf(transportOptions);
|
||||
const buffer = Buffer.from(result.pdf, 'base64');
|
||||
if (options.path) {
|
||||
await fs.promises.mkdir(path.dirname(options.path), { recursive: true });
|
||||
await fs.promises.writeFile(options.path, buffer);
|
||||
await fs.promises.writeFile(options.path, result.pdf);
|
||||
}
|
||||
return buffer;
|
||||
return result.pdf;
|
||||
}
|
||||
|
||||
async _resetForReuse() {
|
||||
|
@ -42,8 +42,8 @@ class StreamImpl extends Readable {
|
||||
|
||||
override async _read(size: number) {
|
||||
const result = await this._channel.read({ size });
|
||||
if (result.binary)
|
||||
this.push(Buffer.from(result.binary, 'base64'));
|
||||
if (result.binary.byteLength)
|
||||
this.push(result.binary);
|
||||
else
|
||||
this.push(null);
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ class WritableStreamImpl extends Writable {
|
||||
this._channel = channel;
|
||||
}
|
||||
|
||||
override async _write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void) {
|
||||
const error = await this._channel.write({ binary: chunk.toString('base64') }).catch(e => e);
|
||||
override async _write(chunk: Buffer | string, encoding: BufferEncoding, callback: (error?: Error | null) => void) {
|
||||
const error = await this._channel.write({ binary: typeof chunk === 'string' ? Buffer.from(chunk) : chunk }).catch(e => e);
|
||||
callback(error || null);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ export function createInProcessPlaywright(): PlaywrightAPI {
|
||||
const playwright = createPlaywright('javascript');
|
||||
|
||||
const clientConnection = new Connection();
|
||||
const dispatcherConnection = new DispatcherConnection();
|
||||
const dispatcherConnection = new DispatcherConnection(true /* local */);
|
||||
|
||||
// Dispatch synchronously at first.
|
||||
dispatcherConnection.onmessage = message => clientConnection.dispatch(message);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
// This file is generated by generate_channels.js, do not edit manually.
|
||||
|
||||
export type Binary = string;
|
||||
export type Binary = Buffer;
|
||||
|
||||
export interface Channel {
|
||||
}
|
||||
@ -408,11 +408,11 @@ export type LocalUtilsHarLookupParams = {
|
||||
url: string,
|
||||
method: string,
|
||||
headers: NameValue[],
|
||||
postData?: string,
|
||||
postData?: Binary,
|
||||
isNavigationRequest: boolean,
|
||||
};
|
||||
export type LocalUtilsHarLookupOptions = {
|
||||
postData?: string,
|
||||
postData?: Binary,
|
||||
};
|
||||
export type LocalUtilsHarLookupResult = {
|
||||
action: 'error' | 'redirect' | 'fulfill' | 'noentry',
|
||||
@ -420,7 +420,7 @@ export type LocalUtilsHarLookupResult = {
|
||||
redirectURL?: string,
|
||||
status?: number,
|
||||
headers?: NameValue[],
|
||||
body?: string,
|
||||
body?: Binary,
|
||||
};
|
||||
export type LocalUtilsHarCloseParams = {
|
||||
harId: string,
|
||||
|
@ -500,7 +500,7 @@ LocalUtils:
|
||||
headers:
|
||||
type: array
|
||||
items: NameValue
|
||||
postData: string?
|
||||
postData: binary?
|
||||
isNavigationRequest: boolean
|
||||
returns:
|
||||
action:
|
||||
@ -516,7 +516,7 @@ LocalUtils:
|
||||
headers:
|
||||
type: array?
|
||||
items: NameValue
|
||||
body: string?
|
||||
body: binary?
|
||||
|
||||
harClose:
|
||||
parameters:
|
||||
|
@ -224,7 +224,7 @@ scheme.LocalUtilsHarLookupParams = tObject({
|
||||
url: tString,
|
||||
method: tString,
|
||||
headers: tArray(tType('NameValue')),
|
||||
postData: tOptional(tString),
|
||||
postData: tOptional(tBinary),
|
||||
isNavigationRequest: tBoolean,
|
||||
});
|
||||
scheme.LocalUtilsHarLookupResult = tObject({
|
||||
@ -233,7 +233,7 @@ scheme.LocalUtilsHarLookupResult = tObject({
|
||||
redirectURL: tOptional(tString),
|
||||
status: tOptional(tNumber),
|
||||
headers: tOptional(tArray(tType('NameValue'))),
|
||||
body: tOptional(tString),
|
||||
body: tOptional(tBinary),
|
||||
});
|
||||
scheme.LocalUtilsHarCloseParams = tObject({
|
||||
harId: tString,
|
||||
|
@ -20,6 +20,7 @@ export class ValidationError extends Error {}
|
||||
export type Validator = (arg: any, path: string, context: ValidatorContext) => any;
|
||||
export type ValidatorContext = {
|
||||
tChannelImpl: (names: '*' | string[], arg: any, path: string, context: ValidatorContext) => any,
|
||||
binary: 'toBase64' | 'fromBase64' | 'buffer',
|
||||
};
|
||||
export const scheme: { [key: string]: Validator } = {};
|
||||
|
||||
@ -59,11 +60,24 @@ export const tString: Validator = (arg: any, path: string, context: ValidatorCon
|
||||
throw new ValidationError(`${path}: expected string, got ${typeof arg}`);
|
||||
};
|
||||
export const tBinary: Validator = (arg: any, path: string, context: ValidatorContext) => {
|
||||
if (arg instanceof String)
|
||||
return arg.valueOf();
|
||||
if (typeof arg === 'string')
|
||||
if (context.binary === 'fromBase64') {
|
||||
if (arg instanceof String)
|
||||
return Buffer.from(arg.valueOf(), 'base64');
|
||||
if (typeof arg === 'string')
|
||||
return Buffer.from(arg, 'base64');
|
||||
throw new ValidationError(`${path}: expected base64-encoded buffer, got ${typeof arg}`);
|
||||
}
|
||||
if (context.binary === 'toBase64') {
|
||||
if (!(arg instanceof Buffer))
|
||||
throw new ValidationError(`${path}: expected Buffer, got ${typeof arg}`);
|
||||
return (arg as Buffer).toString('base64');
|
||||
}
|
||||
if (context.binary === 'buffer') {
|
||||
if (!(arg instanceof Buffer))
|
||||
throw new ValidationError(`${path}: expected Buffer, got ${typeof arg}`);
|
||||
return arg;
|
||||
throw new ValidationError(`${path}: expected base64-encoded buffer, got ${typeof arg}`);
|
||||
}
|
||||
throw new ValidationError(`Unsupported binary behavior "${context.binary}"`);
|
||||
};
|
||||
export const tUndefined: Validator = (arg: any, path: string, context: ValidatorContext) => {
|
||||
if (Object.is(arg, undefined))
|
||||
|
@ -136,11 +136,11 @@ export class AndroidDeviceDispatcher extends Dispatcher<AndroidDevice, channels.
|
||||
}
|
||||
|
||||
async screenshot(params: channels.AndroidDeviceScreenshotParams): Promise<channels.AndroidDeviceScreenshotResult> {
|
||||
return { binary: (await this._object.screenshot()).toString('base64') };
|
||||
return { binary: await this._object.screenshot() };
|
||||
}
|
||||
|
||||
async shell(params: channels.AndroidDeviceShellParams): Promise<channels.AndroidDeviceShellResult> {
|
||||
return { result: (await this._object.shell(params.command)).toString('base64') };
|
||||
return { result: await this._object.shell(params.command) };
|
||||
}
|
||||
|
||||
async open(params: channels.AndroidDeviceOpenParams, metadata: CallMetadata): Promise<channels.AndroidDeviceOpenResult> {
|
||||
@ -149,11 +149,11 @@ export class AndroidDeviceDispatcher extends Dispatcher<AndroidDevice, channels.
|
||||
}
|
||||
|
||||
async installApk(params: channels.AndroidDeviceInstallApkParams) {
|
||||
await this._object.installApk(Buffer.from(params.file, 'base64'), { args: params.args });
|
||||
await this._object.installApk(params.file, { args: params.args });
|
||||
}
|
||||
|
||||
async push(params: channels.AndroidDevicePushParams) {
|
||||
await this._object.push(Buffer.from(params.file, 'base64'), params.path, params.mode);
|
||||
await this._object.push(params.file, params.path, params.mode);
|
||||
}
|
||||
|
||||
async launchBrowser(params: channels.AndroidDeviceLaunchBrowserParams): Promise<channels.AndroidDeviceLaunchBrowserResult> {
|
||||
@ -179,7 +179,7 @@ export class AndroidSocketDispatcher extends Dispatcher<SocketBackend, channels.
|
||||
|
||||
constructor(scope: DispatcherScope, socket: SocketBackend) {
|
||||
super(scope, socket, 'AndroidSocket', {}, true);
|
||||
socket.on('data', (data: Buffer) => this._dispatchEvent('data', { data: data.toString('base64') }));
|
||||
socket.on('data', (data: Buffer) => this._dispatchEvent('data', { data }));
|
||||
socket.on('close', () => {
|
||||
this._dispatchEvent('close');
|
||||
this._dispose();
|
||||
@ -187,7 +187,7 @@ export class AndroidSocketDispatcher extends Dispatcher<SocketBackend, channels.
|
||||
}
|
||||
|
||||
async write(params: channels.AndroidSocketWriteParams, metadata: CallMetadata): Promise<void> {
|
||||
await this._object.write(Buffer.from(params.data, 'base64'));
|
||||
await this._object.write(params.data);
|
||||
}
|
||||
|
||||
async close(params: channels.AndroidSocketCloseParams, metadata: CallMetadata): Promise<void> {
|
||||
|
@ -70,8 +70,7 @@ export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserChann
|
||||
if (!this._object.options.isChromium)
|
||||
throw new Error(`Tracing is only available in Chromium`);
|
||||
const crBrowser = this._object as CRBrowser;
|
||||
const buffer = await crBrowser.stopTracing();
|
||||
return { binary: buffer.toString('base64') };
|
||||
return { binary: await crBrowser.stopTracing() };
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,8 +123,7 @@ export class ConnectedBrowserDispatcher extends Dispatcher<Browser, channels.Bro
|
||||
if (!this._object.options.isChromium)
|
||||
throw new Error(`Tracing is only available in Chromium`);
|
||||
const crBrowser = this._object as CRBrowser;
|
||||
const buffer = await crBrowser.stopTracing();
|
||||
return { binary: buffer.toString('base64') };
|
||||
return { binary: await crBrowser.stopTracing() };
|
||||
}
|
||||
|
||||
async cleanupContexts() {
|
||||
|
@ -27,6 +27,7 @@ import * as socks from '../../common/socksProxy';
|
||||
import EventEmitter from 'events';
|
||||
import { ProgressController } from '../progress';
|
||||
import { WebSocketTransport } from '../transport';
|
||||
import { findValidator, ValidationError, type ValidatorContext } from '../../protocol/validator';
|
||||
|
||||
export class BrowserTypeDispatcher extends Dispatcher<BrowserType, channels.BrowserTypeChannel> implements channels.BrowserTypeChannel {
|
||||
_type_BrowserType = true;
|
||||
@ -113,6 +114,8 @@ class SocksInterceptor {
|
||||
try {
|
||||
const id = --lastId;
|
||||
this._ids.add(id);
|
||||
const validator = findValidator('SocksSupport', prop, 'Params');
|
||||
params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64' });
|
||||
transport.send({ id, guid: socksSupportObjectGuid, method: prop, params, metadata: { stack: [], apiName: '', internal: true } } as any);
|
||||
} catch (e) {
|
||||
}
|
||||
@ -120,13 +123,13 @@ class SocksInterceptor {
|
||||
},
|
||||
}) as channels.SocksSupportChannel & EventEmitter;
|
||||
this._handler.on(socks.SocksProxyHandler.Events.SocksConnected, (payload: socks.SocksSocketConnectedPayload) => this._channel.socksConnected(payload));
|
||||
this._handler.on(socks.SocksProxyHandler.Events.SocksData, (payload: socks.SocksSocketDataPayload) => this._channel.socksData({ uid: payload.uid, data: payload.data.toString('base64') }));
|
||||
this._handler.on(socks.SocksProxyHandler.Events.SocksData, (payload: socks.SocksSocketDataPayload) => this._channel.socksData(payload));
|
||||
this._handler.on(socks.SocksProxyHandler.Events.SocksError, (payload: socks.SocksSocketErrorPayload) => this._channel.socksError(payload));
|
||||
this._handler.on(socks.SocksProxyHandler.Events.SocksFailed, (payload: socks.SocksSocketFailedPayload) => this._channel.socksFailed(payload));
|
||||
this._handler.on(socks.SocksProxyHandler.Events.SocksEnd, (payload: socks.SocksSocketEndPayload) => this._channel.socksEnd(payload));
|
||||
this._channel.on('socksRequested', payload => this._handler.socketRequested(payload));
|
||||
this._channel.on('socksClosed', payload => this._handler.socketClosed(payload));
|
||||
this._channel.on('socksData', payload => this._handler.sendSocketData({ uid: payload.uid, data: Buffer.from(payload.data, 'base64') }));
|
||||
this._channel.on('socksData', payload => this._handler.sendSocketData(payload));
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
@ -139,9 +142,15 @@ class SocksInterceptor {
|
||||
return true;
|
||||
}
|
||||
if (message.guid === this._socksSupportObjectGuid) {
|
||||
this._channel.emit(message.method, message.params);
|
||||
const validator = findValidator('SocksSupport', message.method, 'Event');
|
||||
const params = validator(message.params, '', { tChannelImpl: tChannelForSocks, binary: 'fromBase64' });
|
||||
this._channel.emit(message.method, params);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function tChannelForSocks(names: '*' | string[], arg: any, path: string, context: ValidatorContext) {
|
||||
throw new ValidationError(`${path}: channels are not expected in SocksSupport`);
|
||||
}
|
||||
|
@ -144,16 +144,21 @@ export class DispatcherConnection {
|
||||
readonly _dispatchers = new Map<string, Dispatcher<any, any>>();
|
||||
onmessage = (message: object) => {};
|
||||
private _waitOperations = new Map<string, CallMetadata>();
|
||||
private _isLocal: boolean;
|
||||
|
||||
constructor(isLocal?: boolean) {
|
||||
this._isLocal = !!isLocal;
|
||||
}
|
||||
|
||||
sendEvent(dispatcher: Dispatcher<any, any>, event: string, params: any, sdkObject?: SdkObject) {
|
||||
const validator = findValidator(dispatcher._type, event, 'Event');
|
||||
params = validator(params, '', { tChannelImpl: this._tChannelImplToWire.bind(this) });
|
||||
params = validator(params, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
|
||||
this._sendMessageToClient(dispatcher._guid, dispatcher._type, event, params, sdkObject);
|
||||
}
|
||||
|
||||
sendCreate(parent: Dispatcher<any, any>, type: string, guid: string, initializer: any, sdkObject?: SdkObject) {
|
||||
const validator = findValidator(type, '', 'Initializer');
|
||||
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplToWire.bind(this) });
|
||||
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
|
||||
this._sendMessageToClient(parent._guid, type, '__create__', { type, initializer, guid }, sdkObject);
|
||||
}
|
||||
|
||||
@ -216,8 +221,8 @@ export class DispatcherConnection {
|
||||
let validMetadata: channels.Metadata;
|
||||
try {
|
||||
const validator = findValidator(dispatcher._type, method, 'Params');
|
||||
validParams = validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this) });
|
||||
validMetadata = metadataValidator(metadata, '', { tChannelImpl: this._tChannelImplFromWire.bind(this) });
|
||||
validParams = validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._isLocal ? 'buffer' : 'fromBase64' });
|
||||
validMetadata = metadataValidator(metadata, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._isLocal ? 'buffer' : 'fromBase64' });
|
||||
if (typeof (dispatcher as any)[method] !== 'function')
|
||||
throw new Error(`Mismatching dispatcher: "${dispatcher._type}" does not implement "${method}"`);
|
||||
} catch (e) {
|
||||
@ -277,7 +282,7 @@ export class DispatcherConnection {
|
||||
try {
|
||||
const result = await (dispatcher as any)[method](validParams, callMetadata);
|
||||
const validator = findValidator(dispatcher._type, method, 'Result');
|
||||
callMetadata.result = validator(result, '', { tChannelImpl: this._tChannelImplToWire.bind(this) });
|
||||
callMetadata.result = validator(result, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
|
||||
} catch (e) {
|
||||
// Dispatching error
|
||||
// We want original, unmodified error in metadata.
|
||||
|
@ -191,7 +191,7 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements chann
|
||||
frame: (frame as FrameDispatcher)._object,
|
||||
selector,
|
||||
}));
|
||||
return { binary: (await this._elementHandle.screenshot(metadata, { ...params, mask })).toString('base64') };
|
||||
return { binary: await this._elementHandle.screenshot(metadata, { ...params, mask }) };
|
||||
}
|
||||
|
||||
async querySelector(params: channels.ElementHandleQuerySelectorParams, metadata: CallMetadata): Promise<channels.ElementHandleQuerySelectorResult> {
|
||||
|
@ -114,7 +114,7 @@ export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.
|
||||
const harBackend = this._harBakends.get(params.harId);
|
||||
if (!harBackend)
|
||||
return { action: 'error', message: `Internal error: har was not opened` };
|
||||
return await harBackend.lookup(params.url, params.method, params.headers, params.postData ? Buffer.from(params.postData, 'base64') : undefined, params.isNavigationRequest);
|
||||
return await harBackend.lookup(params.url, params.method, params.headers, params.postData, params.isNavigationRequest);
|
||||
}
|
||||
|
||||
async harClose(params: channels.LocalUtilsHarCloseParams, metadata?: channels.Metadata): Promise<void> {
|
||||
@ -160,8 +160,7 @@ class HarBackend {
|
||||
redirectURL?: string,
|
||||
status?: number,
|
||||
headers?: HeadersArray,
|
||||
body?: string,
|
||||
base64Encoded?: boolean }> {
|
||||
body?: Buffer }> {
|
||||
let entry;
|
||||
try {
|
||||
entry = await this._harFindResponse(url, method, headers, postData);
|
||||
@ -183,7 +182,7 @@ class HarBackend {
|
||||
action: 'fulfill',
|
||||
status: response.status,
|
||||
headers: response.headers,
|
||||
body: buffer.toString('base64'),
|
||||
body: buffer,
|
||||
};
|
||||
} catch (e) {
|
||||
return { action: 'error', message: e.message };
|
||||
|
@ -45,7 +45,7 @@ export class RequestDispatcher extends Dispatcher<Request, channels.RequestChann
|
||||
url: request.url(),
|
||||
resourceType: request.resourceType(),
|
||||
method: request.method(),
|
||||
postData: postData === null ? undefined : postData.toString('base64'),
|
||||
postData: postData === null ? undefined : postData,
|
||||
headers: request.headers(),
|
||||
isNavigationRequest: request.isNavigationRequest(),
|
||||
redirectedFrom: RequestDispatcher.fromNullable(scope, request.redirectedFrom()),
|
||||
@ -88,7 +88,7 @@ export class ResponseDispatcher extends Dispatcher<Response, channels.ResponseCh
|
||||
}
|
||||
|
||||
async body(): Promise<channels.ResponseBodyResult> {
|
||||
return { binary: (await this._object.body()).toString('base64') };
|
||||
return { binary: await this._object.body() };
|
||||
}
|
||||
|
||||
async securityDetails(): Promise<channels.ResponseSecurityDetailsResult> {
|
||||
@ -128,7 +128,7 @@ export class RouteDispatcher extends Dispatcher<Route, channels.RouteChannel> im
|
||||
url: params.url,
|
||||
method: params.method,
|
||||
headers: params.headers,
|
||||
postData: params.postData !== undefined ? Buffer.from(params.postData, 'base64') : undefined,
|
||||
postData: params.postData,
|
||||
});
|
||||
}
|
||||
|
||||
@ -204,8 +204,7 @@ export class APIRequestContextDispatcher extends Dispatcher<APIRequestContext, c
|
||||
}
|
||||
|
||||
async fetchResponseBody(params: channels.APIRequestContextFetchResponseBodyParams, metadata?: channels.Metadata): Promise<channels.APIRequestContextFetchResponseBodyResult> {
|
||||
const buffer = this._object.fetchResponses.get(params.fetchUid);
|
||||
return { binary: buffer ? buffer.toString('base64') : undefined };
|
||||
return { binary: this._object.fetchResponses.get(params.fetchUid) };
|
||||
}
|
||||
|
||||
async fetchLog(params: channels.APIRequestContextFetchLogParams, metadata?: channels.Metadata): Promise<channels.APIRequestContextFetchLogResult> {
|
||||
|
@ -167,23 +167,14 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel> imple
|
||||
frame: (params.locator.frame as FrameDispatcher)._object,
|
||||
selector: params.locator.selector,
|
||||
} : undefined;
|
||||
const expected = params.expected ? Buffer.from(params.expected, 'base64') : undefined;
|
||||
const result = await this._page.expectScreenshot(metadata, {
|
||||
return await this._page.expectScreenshot(metadata, {
|
||||
...params,
|
||||
expected,
|
||||
locator,
|
||||
screenshotOptions: {
|
||||
...params.screenshotOptions,
|
||||
mask,
|
||||
},
|
||||
});
|
||||
return {
|
||||
diff: result.diff?.toString('base64'),
|
||||
errorMessage: result.errorMessage,
|
||||
actual: result.actual?.toString('base64'),
|
||||
previous: result.previous?.toString('base64'),
|
||||
log: result.log,
|
||||
};
|
||||
}
|
||||
|
||||
async screenshot(params: channels.PageScreenshotParams, metadata: CallMetadata): Promise<channels.PageScreenshotResult> {
|
||||
@ -191,7 +182,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel> imple
|
||||
frame: (frame as FrameDispatcher)._object,
|
||||
selector,
|
||||
}));
|
||||
return { binary: (await this._page.screenshot(metadata, { ...params, mask })).toString('base64') };
|
||||
return { binary: await this._page.screenshot(metadata, { ...params, mask }) };
|
||||
}
|
||||
|
||||
async close(params: channels.PageCloseParams, metadata: CallMetadata): Promise<void> {
|
||||
@ -258,7 +249,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel> imple
|
||||
if (!this._page.pdf)
|
||||
throw new Error('PDF generation is only supported for Headless Chromium');
|
||||
const buffer = await this._page.pdf(params);
|
||||
return { pdf: buffer.toString('base64') };
|
||||
return { pdf: buffer };
|
||||
}
|
||||
|
||||
async bringToFront(params: channels.PageBringToFrontParams, metadata: CallMetadata): Promise<void> {
|
||||
|
@ -81,7 +81,7 @@ class SocksSupportDispatcher extends Dispatcher<{ guid: string }, channels.Socks
|
||||
this._type_SocksSupport = true;
|
||||
this._socksProxy = socksProxy;
|
||||
socksProxy.on(SocksProxy.Events.SocksRequested, (payload: SocksSocketRequestedPayload) => this._dispatchEvent('socksRequested', payload));
|
||||
socksProxy.on(SocksProxy.Events.SocksData, (payload: SocksSocketDataPayload) => this._dispatchEvent('socksData', { uid: payload.uid, data: payload.data.toString('base64') }));
|
||||
socksProxy.on(SocksProxy.Events.SocksData, (payload: SocksSocketDataPayload) => this._dispatchEvent('socksData', payload));
|
||||
socksProxy.on(SocksProxy.Events.SocksClosed, (payload: SocksSocketClosedPayload) => this._dispatchEvent('socksClosed', payload));
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ class SocksSupportDispatcher extends Dispatcher<{ guid: string }, channels.Socks
|
||||
}
|
||||
|
||||
async socksData(params: channels.SocksSupportSocksDataParams): Promise<void> {
|
||||
this._socksProxy?.sendSocketData({ uid: params.uid, data: Buffer.from(params.data, 'base64') });
|
||||
this._socksProxy?.sendSocketData(params);
|
||||
}
|
||||
|
||||
async socksError(params: channels.SocksSupportSocksErrorParams): Promise<void> {
|
||||
|
@ -33,7 +33,7 @@ export class StreamDispatcher extends Dispatcher<{ guid: string, stream: stream.
|
||||
async read(params: channels.StreamReadParams): Promise<channels.StreamReadResult> {
|
||||
const stream = this._object.stream;
|
||||
if (this._ended)
|
||||
return { binary: '' };
|
||||
return { binary: Buffer.from('') };
|
||||
if (!stream.readableLength) {
|
||||
await new Promise((fulfill, reject) => {
|
||||
stream.once('readable', fulfill);
|
||||
@ -42,7 +42,7 @@ export class StreamDispatcher extends Dispatcher<{ guid: string, stream: stream.
|
||||
});
|
||||
}
|
||||
const buffer = stream.read(Math.min(stream.readableLength, params.size || stream.readableLength));
|
||||
return { binary: buffer ? buffer.toString('base64') : '' };
|
||||
return { binary: buffer || Buffer.from('') };
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
@ -29,7 +29,7 @@ export class WritableStreamDispatcher extends Dispatcher<{ guid: string, stream:
|
||||
async write(params: channels.WritableStreamWriteParams): Promise<channels.WritableStreamWriteResult> {
|
||||
const stream = this._object.stream;
|
||||
await new Promise<void>((fulfill, reject) => {
|
||||
stream.write(Buffer.from(params.binary, 'base64'), error => {
|
||||
stream.write(params.binary, error => {
|
||||
if (error)
|
||||
reject(error);
|
||||
else
|
||||
|
@ -615,10 +615,15 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
|
||||
async _setInputFiles(progress: Progress, items: InputFilesItems, options: types.NavigatingActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||
const { files, localPaths } = items;
|
||||
let filePayloads: types.FilePayload[] | undefined;
|
||||
if (files) {
|
||||
filePayloads = [];
|
||||
for (const payload of files) {
|
||||
if (!payload.mimeType)
|
||||
payload.mimeType = mime.getType(payload.name) || 'application/octet-stream';
|
||||
filePayloads.push({
|
||||
name: payload.name,
|
||||
mimeType: payload.mimeType || mime.getType(payload.name) || 'application/octet-stream',
|
||||
buffer: payload.buffer.toString('base64'),
|
||||
});
|
||||
}
|
||||
}
|
||||
const multiple = files && files.length > 1 || localPaths && localPaths.length > 1;
|
||||
@ -641,7 +646,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
if (localPaths)
|
||||
await this._page._delegate.setInputFilePaths(retargeted, localPaths);
|
||||
else
|
||||
await this._page._delegate.setInputFiles(retargeted, files as types.FilePayload[]);
|
||||
await this._page._delegate.setInputFiles(retargeted, filePayloads!);
|
||||
});
|
||||
await this._page._doSlowMo();
|
||||
return 'done';
|
||||
|
@ -643,7 +643,7 @@ function serializePostData(params: channels.APIRequestContextFetchParams, header
|
||||
return formData.finish();
|
||||
} else if (params.postData !== undefined) {
|
||||
headers['content-type'] ??= 'application/octet-stream';
|
||||
return Buffer.from(params.postData, 'base64');
|
||||
return params.postData;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export class MultipartFormData {
|
||||
this._chunks.push(Buffer.from(`; filename="${value.name}"`));
|
||||
this._chunks.push(Buffer.from(`\r\ncontent-type: ${value.mimeType || mime.getType(value.name) || 'application/octet-stream'}`));
|
||||
this._finishMultiPartHeader();
|
||||
this._chunks.push(Buffer.from(value.buffer, 'base64'));
|
||||
this._chunks.push(value.buffer);
|
||||
this._finishMultiPartField();
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ const channels_ts = [
|
||||
|
||||
// This file is generated by ${path.basename(__filename).split(path.sep).join(path.posix.sep)}, do not edit manually.
|
||||
|
||||
export type Binary = string;
|
||||
export type Binary = Buffer;
|
||||
|
||||
export interface Channel {
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user