electron/atom/renderer/renderer_client_base.cc
Robo 14ed71fa1b fix: use render client id to track deleted render process hosts (#14520)
* fix: use render client id to track deleted render process hosts

Instead of relying on OS process id, which may not be unique
when a process is reused, we rely on the renderer client id
passed by the content layer when starting the renderer process
which is guaranteed to be unique for the lifetime of the app.

* fix: store context id as int64_t

Ensuring that it doesn't wrap easily with a large number
of context creation on some malformed web pages.
2018-09-11 11:18:10 -07:00

246 lines
9.3 KiB
C++

// Copyright (c) 2017 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/renderer/renderer_client_base.h"
#include <string>
#include <vector>
#include "atom/common/color_util.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/options_switches.h"
#include "atom/renderer/atom_autofill_agent.h"
#include "atom/renderer/atom_render_frame_observer.h"
#include "atom/renderer/atom_render_view_observer.h"
#include "atom/renderer/content_settings_observer.h"
#include "atom/renderer/preferences_manager.h"
#include "base/command_line.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "chrome/renderer/media/chrome_key_systems.h"
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "chrome/renderer/tts_dispatcher.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
#include "native_mate/dictionary.h"
#include "third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h"
#include "third_party/WebKit/public/web/WebCustomElement.h" // NOLINT(build/include_alpha)
#include "third_party/WebKit/public/web/WebFrameWidget.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#if defined(OS_MACOSX)
#include "base/strings/sys_string_conversions.h"
#endif
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#if defined(ENABLE_PDF_VIEWER)
#include "atom/common/atom_constants.h"
#endif // defined(ENABLE_PDF_VIEWER)
#if defined(ENABLE_PEPPER_FLASH)
#include "chrome/renderer/pepper/pepper_helper.h"
#endif // defined(ENABLE_PEPPER_FLASH)
namespace atom {
namespace {
v8::Local<v8::Value> GetRenderProcessPreferences(
const PreferencesManager* preferences_manager,
v8::Isolate* isolate) {
if (preferences_manager->preferences())
return mate::ConvertToV8(isolate, *preferences_manager->preferences());
else
return v8::Null(isolate);
}
std::vector<std::string> ParseSchemesCLISwitch(base::CommandLine* command_line,
const char* switch_name) {
std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name);
return base::SplitString(custom_schemes, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
}
} // namespace
RendererClientBase::RendererClientBase() {
auto* command_line = base::CommandLine::ForCurrentProcess();
// Parse --standard-schemes=scheme1,scheme2
std::vector<std::string> standard_schemes_list =
ParseSchemesCLISwitch(command_line, switches::kStandardSchemes);
for (const std::string& scheme : standard_schemes_list)
url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT);
isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kContextIsolation);
// We rely on the unique process host id which is notified to the
// renderer process via command line switch from the content layer,
// if this switch is removed from the content layer for some reason,
// we should define our own.
DCHECK(command_line->HasSwitch(::switches::kRendererClientId));
renderer_client_id_ =
command_line->GetSwitchValueASCII(::switches::kRendererClientId);
}
RendererClientBase::~RendererClientBase() {}
void RendererClientBase::DidCreateScriptContext(
v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) {
// global.setHidden("contextId", `${processHostId}-${++next_context_id_}`)
auto context_id = base::StringPrintf(
"%s-%" PRId64, renderer_client_id_.c_str(), ++next_context_id_);
v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::String> key = mate::StringToSymbol(isolate, "contextId");
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
v8::Local<v8::Value> value = mate::ConvertToV8(isolate, context_id);
context->Global()->SetPrivate(context, private_key, value);
}
void RendererClientBase::AddRenderBindings(
v8::Isolate* isolate,
v8::Local<v8::Object> binding_object) {
mate::Dictionary dict(isolate, binding_object);
dict.SetMethod(
"getRenderProcessPreferences",
base::Bind(GetRenderProcessPreferences, preferences_manager_.get()));
}
void RendererClientBase::RenderThreadStarted() {
auto* command_line = base::CommandLine::ForCurrentProcess();
blink::WebCustomElement::AddEmbedderCustomElementName("webview");
blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin");
WTF::String extension_scheme("chrome-extension");
// Extension resources are HTTP-like and safe to expose to the fetch API. The
// rules for the fetch API are consistent with XHR.
blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(
extension_scheme);
// Extension resources, when loaded as the top-level document, should bypass
// Blink's strict first-party origin checks.
blink::SchemeRegistry::RegisterURLSchemeAsFirstPartyWhenTopLevel(
extension_scheme);
// In Chrome we should set extension's origins to match the pages they can
// work on, but in Electron currently we just let extensions do anything.
blink::SchemeRegistry::RegisterURLSchemeAsSecure(extension_scheme);
blink::SchemeRegistry::RegisterURLSchemeAsCORSEnabled(extension_scheme);
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
extension_scheme);
// Parse --secure-schemes=scheme1,scheme2
std::vector<std::string> secure_schemes_list =
ParseSchemesCLISwitch(command_line, switches::kSecureSchemes);
for (const std::string& scheme : secure_schemes_list)
blink::SchemeRegistry::RegisterURLSchemeAsSecure(
WTF::String::FromUTF8(scheme.data(), scheme.length()));
// Allow file scheme to handle service worker by default.
// FIXME(zcbenz): Can this be moved elsewhere?
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file");
blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI("file");
preferences_manager_.reset(new PreferencesManager);
#if defined(OS_WIN)
// Set ApplicationUserModelID in renderer process.
base::string16 app_id =
command_line->GetSwitchValueNative(switches::kAppUserModelId);
if (!app_id.empty()) {
SetCurrentProcessExplicitAppUserModelID(app_id.c_str());
}
#endif
}
void RendererClientBase::RenderFrameCreated(
content::RenderFrame* render_frame) {
#if defined(TOOLKIT_VIEWS)
new AutofillAgent(render_frame);
#endif
#if defined(ENABLE_PEPPER_FLASH)
new PepperHelper(render_frame);
#endif
new ContentSettingsObserver(render_frame);
new printing::PrintWebViewHelper(render_frame);
// This is required for widevine plugin detection provided during runtime.
blink::ResetPluginCache();
#if defined(ENABLE_PDF_VIEWER)
// Allow access to file scheme from pdf viewer.
blink::WebSecurityPolicy::AddOriginAccessWhitelistEntry(
GURL(kPdfViewerUIOrigin), "file", "", true);
#endif // defined(ENABLE_PDF_VIEWER)
}
void RendererClientBase::RenderViewCreated(content::RenderView* render_view) {
new AtomRenderViewObserver(render_view);
blink::WebFrameWidget* web_frame_widget = render_view->GetWebFrameWidget();
if (!web_frame_widget)
return;
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview.
web_frame_widget->SetBaseBackgroundColor(SK_ColorTRANSPARENT);
} else { // normal window.
std::string name = cmd->GetSwitchValueASCII(switches::kBackgroundColor);
SkColor color = name.empty() ? SK_ColorTRANSPARENT : ParseHexColor(name);
web_frame_widget->SetBaseBackgroundColor(color);
}
}
void RendererClientBase::DidClearWindowObject(
content::RenderFrame* render_frame) {
// Make sure every page will get a script context created.
render_frame->GetWebFrame()->ExecuteScript(blink::WebScriptSource("void 0"));
}
std::unique_ptr<blink::WebSpeechSynthesizer>
RendererClientBase::OverrideSpeechSynthesizer(
blink::WebSpeechSynthesizerClient* client) {
return std::make_unique<TtsDispatcher>(client);
}
bool RendererClientBase::OverrideCreatePlugin(
content::RenderFrame* render_frame,
const blink::WebPluginParams& params,
blink::WebPlugin** plugin) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (params.mime_type.Utf8() == content::kBrowserPluginMimeType ||
#if defined(ENABLE_PDF_VIEWER)
params.mime_type.Utf8() == kPdfPluginMimeType ||
#endif // defined(ENABLE_PDF_VIEWER)
command_line->HasSwitch(switches::kEnablePlugins))
return false;
*plugin = nullptr;
return true;
}
void RendererClientBase::AddSupportedKeySystems(
std::vector<std::unique_ptr<::media::KeySystemProperties>>* key_systems) {
key_systems_provider_.AddSupportedKeySystems(key_systems);
}
bool RendererClientBase::IsKeySystemsUpdateNeeded() {
return key_systems_provider_.IsKeySystemsUpdateNeeded();
}
v8::Local<v8::Context> RendererClientBase::GetContext(
blink::WebLocalFrame* frame,
v8::Isolate* isolate) const {
if (isolated_world())
return frame->WorldScriptContext(isolate, World::ISOLATED_WORLD);
else
return frame->MainWorldScriptContext();
}
} // namespace atom