// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include #include "include/cef_app.h" #include "include/wrapper/cef_message_router.h" #include "util.h" #if defined(OS_MACOSX) // When generating projects with CMake the CEF_USE_SANDBOX value will be defined // automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable // use of the sandbox. #if defined(CEF_USE_SANDBOX) #include "include/cef_sandbox_mac.h" #endif #include "include/wrapper/cef_library_loader.h" #endif // defined(OS_MACOSX) #if defined(OS_WIN) #include #endif namespace { // comparator to check if configuration values are the same struct cmpCfg { bool operator()(const CefMessageRouterConfig& lValue, const CefMessageRouterConfig& rValue) const { std::less comp; return comp(lValue.js_query_function.ToString(), rValue.js_query_function.ToString()); } }; class CefHelperApp : public CefApp, public CefRenderProcessHandler { public: CefHelperApp() {} void OnRegisterCustomSchemes( CefRawPtr registrar) override { std::fstream fStream; std::string fName = util::GetTempFileName("scheme", true); char schemeName[512] = ""; int options; fStream.open(fName.c_str(), std::fstream::in); while (fStream.is_open() && !fStream.eof()) { fStream.getline(schemeName, 512, ','); if (strlen(schemeName) == 0) break; fStream >> options; registrar->AddCustomScheme(schemeName, options); } fStream.close(); } virtual CefRefPtr GetRenderProcessHandler() override { return this; } void OnBrowserCreated(CefRefPtr browser, CefRefPtr extra_info) override { if (!extra_info) { return; } auto router_configs = extra_info->GetList("router_configs"); if (router_configs) { // Configuration from BrowserProcessHandler::GetMessageRouterConfigs. for (size_t idx = 0; idx < router_configs->GetSize(); idx++) { CefRefPtr dict = router_configs->GetDictionary((int)idx); // Create the renderer-side router for query handling. CefMessageRouterConfig config; config.js_query_function = dict->GetString("js_query_function"); config.js_cancel_function = dict->GetString("js_cancel_function"); CefRefPtr router = CefMessageRouterRendererSide::Create(config); message_router_.insert(std::make_pair(config, router)); } } } void OnContextCreated(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override { std::map, cmpCfg>::iterator iter; for (iter = message_router_.begin(); iter != message_router_.end(); iter++) { iter->second->OnContextCreated(browser, frame, context); } } void OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override { std::map, cmpCfg>::iterator iter; for (iter = message_router_.begin(); iter != message_router_.end(); iter++) { iter->second->OnContextReleased(browser, frame, context); } } bool OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId source_process, CefRefPtr message) override { if (message->GetName() == "AddMessageRouter") { CefRefPtr args = message->GetArgumentList(); CefMessageRouterConfig config; config.js_query_function = args->GetString(0); config.js_cancel_function = args->GetString(1); // only add a new message router if it wasn't already created if (message_router_.find(config) != message_router_.end()) { return true; } CefRefPtr router = CefMessageRouterRendererSide::Create(config); message_router_.insert(std::make_pair(config, router)); return true; } else if (message->GetName() == "RemoveMessageRouter") { CefRefPtr args = message->GetArgumentList(); CefMessageRouterConfig config; config.js_query_function = args->GetString(0); config.js_cancel_function = args->GetString(1); message_router_.erase(config); return true; } bool handled = false; std::map, cmpCfg>::iterator iter; for (iter = message_router_.begin(); iter != message_router_.end(); iter++) { handled = iter->second->OnProcessMessageReceived(browser, frame, source_process, message); if (handled) break; } return handled; } private: std::map, cmpCfg> message_router_; IMPLEMENT_REFCOUNTING(CefHelperApp); }; } // namespace #if defined(OS_WIN) int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { CefMainArgs main_args(hInstance); #else // !defined(OS_WIN) int main(int argc, char* argv[]) { #if defined(OS_MACOSX) #if defined(CEF_USE_SANDBOX) // Initialize the macOS sandbox for this helper process. CefScopedSandboxContext sandbox_context; if (!sandbox_context.Initialize(argc, argv)) return 1; #endif // defined(CEF_USE_SANDBOX) // Check for the path on the command-line. std::string framework_path; const std::string switchPrefix = "--framework-dir-path="; for (int i = 0; i < argc; ++i) { std::string arg = argv[i]; if (arg.find(switchPrefix) == 0) { framework_path = arg.substr(switchPrefix.length()); break; } } // Load the CEF framework library at runtime instead of linking directly // as required by the macOS sandbox implementation. CefScopedLibraryLoader library_loader; if (!framework_path.empty()) { framework_path += "/Chromium Embedded Framework"; if (!cef_load_library(framework_path.c_str())) return 1; } else if (!library_loader.LoadInHelper()) { return 1; } #endif // defined(OS_MACOSX) CefMainArgs main_args(argc, argv); #endif // !defined(OS_WIN) CefRefPtr app = new CefHelperApp(); const int result = CefExecuteProcess(main_args, app.get(), nullptr); #if defined(OS_MACOSX) if (!framework_path.empty()) cef_unload_library(); #endif return result; }