Browse Source

fix: ensure standard schemes are registered in nw service process (#22867)

* fix: ensure standard schemes are registered in nw service process

Refs https://github.com/electron/electron/pull/20546

* chore: add test

* chore: apply suggestions from code review

Co-Authored-By: Jeremy Apthorp <[email protected]>

Co-authored-by: Jeremy Apthorp <[email protected]>
Robo 5 years ago
parent
commit
bac1c7f532

+ 22 - 8
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);

+ 5 - 0
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<std::string> 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

+ 21 - 0
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`;

+ 18 - 0
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());
+});