diff --git a/shell/app/electron_content_client.cc b/shell/app/electron_content_client.cc index 431a493d3235..445ab1d82e59 100644 --- a/shell/app/electron_content_client.cc +++ b/shell/app/electron_content_client.cc @@ -15,6 +15,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "content/public/common/content_constants.h" +#include "content/public/common/content_switches.h" #include "electron/buildflags/buildflags.h" #include "extensions/common/constants.h" #include "ppapi/buildflags/buildflags.h" @@ -231,14 +232,27 @@ base::RefCountedMemory* ElectronContentClient::GetDataResourceBytes( } void ElectronContentClient::AddAdditionalSchemes(Schemes* schemes) { - AppendDelimitedSwitchToVector(switches::kServiceWorkerSchemes, - &schemes->service_worker_schemes); - AppendDelimitedSwitchToVector(switches::kSecureSchemes, - &schemes->secure_schemes); - AppendDelimitedSwitchToVector(switches::kBypassCSPSchemes, - &schemes->csp_bypassing_schemes); - AppendDelimitedSwitchToVector(switches::kCORSSchemes, - &schemes->cors_enabled_schemes); + auto* command_line = base::CommandLine::ForCurrentProcess(); + std::string process_type = + command_line->GetSwitchValueASCII(::switches::kProcessType); + // Browser Process registration happens in + // `api::Protocol::RegisterSchemesAsPrivileged` + // + // Renderer Process registration happens in `RendererClientBase` + // + // We use this for registration to network utility process + if (process_type == ::switches::kUtilityProcess) { + AppendDelimitedSwitchToVector(switches::kServiceWorkerSchemes, + &schemes->service_worker_schemes); + AppendDelimitedSwitchToVector(switches::kStandardSchemes, + &schemes->standard_schemes); + AppendDelimitedSwitchToVector(switches::kSecureSchemes, + &schemes->secure_schemes); + AppendDelimitedSwitchToVector(switches::kBypassCSPSchemes, + &schemes->csp_bypassing_schemes); + AppendDelimitedSwitchToVector(switches::kCORSSchemes, + &schemes->cors_enabled_schemes); + } schemes->service_worker_schemes.emplace_back(url::kFileScheme); schemes->standard_schemes.emplace_back(extensions::kExtensionScheme); diff --git a/shell/renderer/renderer_client_base.cc b/shell/renderer/renderer_client_base.cc index 20a0b11fcf76..1daf3dd511ac 100644 --- a/shell/renderer/renderer_client_base.cc +++ b/shell/renderer/renderer_client_base.cc @@ -102,6 +102,11 @@ RendererClientBase::RendererClientBase() { ParseSchemesCLISwitch(command_line, switches::kStandardSchemes); for (const std::string& scheme : standard_schemes_list) url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITH_HOST); + // Parse --cors-schemes=scheme1,scheme2 + std::vector cors_schemes_list = + ParseSchemesCLISwitch(command_line, switches::kCORSSchemes); + for (const std::string& scheme : cors_schemes_list) + url::AddCorsEnabledScheme(scheme.c_str()); isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kContextIsolation); // We rely on the unique process host id which is notified to the diff --git a/spec-main/api-protocol-spec.ts b/spec-main/api-protocol-spec.ts index 6af308a7e092..d7194fcffdc5 100644 --- a/spec-main/api-protocol-spec.ts +++ b/spec-main/api-protocol-spec.ts @@ -2,6 +2,7 @@ import { expect } from 'chai'; import { protocol, webContents, WebContents, session, BrowserWindow, ipcMain } from 'electron'; import { promisify } from 'util'; import { AddressInfo } from 'net'; +import * as ChildProcess from 'child_process'; import * as path from 'path'; import * as http from 'http'; import * as fs from 'fs'; @@ -637,6 +638,26 @@ describe('protocol module', () => { }); }); + describe('protocol.registerSchemeAsPrivileged', () => { + it('does not crash on exit', async () => { + const appPath = path.join(__dirname, 'fixtures', 'api', 'custom-protocol-shutdown.js'); + const appProcess = ChildProcess.spawn(process.execPath, ['--enable-logging', appPath]); + let stdout = ''; + let stderr = ''; + appProcess.stdout.on('data', data => { stdout += data; }); + appProcess.stderr.on('data', data => { stderr += data; }); + const [code] = await emittedOnce(appProcess, 'exit'); + if (code !== 0) { + console.log('Exit code : ', code); + console.log('stdout : ', stdout); + console.log('stderr : ', stderr); + } + expect(code).to.equal(0); + expect(stdout).to.not.contain('VALIDATION_ERROR_DESERIALIZATION_FAILED'); + expect(stderr).to.not.contain('VALIDATION_ERROR_DESERIALIZATION_FAILED'); + }); + }); + describe.skip('protocol.registerSchemesAsPrivileged standard', () => { const standardScheme = (global as any).standardScheme; const origin = `${standardScheme}://fake-host`; diff --git a/spec-main/fixtures/api/custom-protocol-shutdown.js b/spec-main/fixtures/api/custom-protocol-shutdown.js new file mode 100644 index 000000000000..1cf6ddbda5bc --- /dev/null +++ b/spec-main/fixtures/api/custom-protocol-shutdown.js @@ -0,0 +1,18 @@ +const { app, webContents, protocol, session } = require('electron'); + +protocol.registerSchemesAsPrivileged([ + { scheme: 'test', privileges: { standard: true, secure: true } } +]); + +app.whenReady().then(function () { + const ses = session.fromPartition('persist:test-standard-shutdown'); + const web = webContents.create({ session: ses }); + + ses.protocol.registerStringProtocol('test', (request, callback) => { + callback('Hello World!'); + }); + + web.webContents.loadURL('test://abc/hello.txt'); + + web.webContents.on('did-finish-load', () => app.quit()); +});