From 93f6129c8001fd550e0b398ab9efb8a1a3611273 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Thu, 7 May 2020 21:27:55 -0700 Subject: [PATCH] chore: support --remote-debugging-pipe (#23433) --- shell/browser/electron_browser_main_parts.cc | 9 +++-- spec-main/chromium-spec.ts | 35 ++++++++++++++++++ spec-main/pipe-transport.ts | 37 ++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 spec-main/pipe-transport.ts diff --git a/shell/browser/electron_browser_main_parts.cc b/shell/browser/electron_browser_main_parts.cc index c78a19edf6d5..c1b3e105e5cd 100644 --- a/shell/browser/electron_browser_main_parts.cc +++ b/shell/browser/electron_browser_main_parts.cc @@ -439,10 +439,14 @@ void ElectronBrowserMainParts::PreMainMessageLoopRun() { content::WebUIControllerFactory::RegisterFactory( ElectronWebUIControllerFactory::GetInstance()); - // --remote-debugging-port auto* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kRemoteDebuggingPort)) + if (command_line->HasSwitch(switches::kRemoteDebuggingPipe)) { + // --remote-debugging-pipe + content::DevToolsAgentHost::StartRemoteDebuggingPipeHandler(); + } else if (command_line->HasSwitch(switches::kRemoteDebuggingPort)) { + // --remote-debugging-port DevToolsManagerDelegate::StartHttpHandler(); + } #if !defined(OS_MACOSX) // The corresponding call in macOS is in ElectronApplicationDelegate. @@ -511,6 +515,7 @@ void ElectronBrowserMainParts::PostMainMessageLoopRun() { node_env_.reset(); fake_browser_process_->PostMainMessageLoopRun(); + content::DevToolsAgentHost::StopRemoteDebuggingPipeHandler(); } #if !defined(OS_MACOSX) diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index c9d4dfd6829f..85e45e8e642d 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -12,6 +12,7 @@ import { EventEmitter } from 'events'; import { promisify } from 'util'; import { ifit, ifdescribe } from './spec-helpers'; import { AddressInfo } from 'net'; +import { PipeTransport } from './pipe-transport'; const features = process.electronBinding('features'); @@ -267,6 +268,40 @@ describe('command line switches', () => { it('should not set an invalid locale', (done) => testLocale('asdfkl', currentLocale, done)); }); + describe('--remote-debugging-pipe switch', () => { + it('should expose CDP via pipe', async () => { + const electronPath = process.execPath; + const appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe'], { + stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'] + }); + const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream]; + const pipe = new PipeTransport(stdio[3], stdio[4]); + const versionPromise = new Promise(resolve => { pipe.onmessage = resolve; }); + pipe.send({ id: 1, method: 'Browser.getVersion', params: {} }); + const message = (await versionPromise) as any; + expect(message.id).to.equal(1); + expect(message.result.product).to.contain('Chrome'); + expect(message.result.userAgent).to.contain('Electron'); + appProcess.kill(); + }); + it('should override --remote-debugging-port switch', async () => { + const electronPath = process.execPath; + const appProcess = ChildProcess.spawn(electronPath, ['--remote-debugging-pipe', '--remote-debugging-port=0'], { + stdio: ['pipe', 'pipe', 'pipe', 'pipe', 'pipe'] + }); + let stderr = ''; + appProcess.stderr.on('data', (data) => { stderr += data; }); + const stdio = appProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream]; + const pipe = new PipeTransport(stdio[3], stdio[4]); + const versionPromise = new Promise(resolve => { pipe.onmessage = resolve; }); + pipe.send({ id: 1, method: 'Browser.getVersion', params: {} }); + const message = (await versionPromise) as any; + expect(message.id).to.equal(1); + expect(stderr).to.not.include('DevTools listening on'); + appProcess.kill(); + }); + }); + describe('--remote-debugging-port switch', () => { it('should display the discovery page', (done) => { const electronPath = process.execPath; diff --git a/spec-main/pipe-transport.ts b/spec-main/pipe-transport.ts new file mode 100644 index 000000000000..044df4138e52 --- /dev/null +++ b/spec-main/pipe-transport.ts @@ -0,0 +1,37 @@ +// A small pipe transport for talking to Electron over CDP. +export class PipeTransport { + private _pipeWrite: NodeJS.WritableStream | null; + private _pendingMessage = ''; + + onmessage?: (message: string) => void; + + constructor (pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream) { + this._pipeWrite = pipeWrite; + pipeRead.on('data', buffer => this._dispatch(buffer)); + } + + send (message: Object) { + this._pipeWrite!.write(JSON.stringify(message)); + this._pipeWrite!.write('\0'); + } + + _dispatch (buffer: Buffer) { + let end = buffer.indexOf('\0'); + if (end === -1) { + this._pendingMessage += buffer.toString(); + return; + } + const message = this._pendingMessage + buffer.toString(undefined, 0, end); + if (this.onmessage) { this.onmessage.call(null, JSON.parse(message)); } + + let start = end + 1; + end = buffer.indexOf('\0', start); + while (end !== -1) { + const message = buffer.toString(undefined, start, end); + if (this.onmessage) { this.onmessage.call(null, JSON.parse(message)); } + start = end + 1; + end = buffer.indexOf('\0', start); + } + this._pendingMessage = buffer.toString(undefined, start); + } +}