remote/handlers/app/RemoteAppHandler.cpp (119 lines of code) (raw):

#include "RemoteAppHandler.h" #include "../../log/Log.h" #include <fstream> RemoteAppHandler::RemoteAppHandler(const std::vector<std::string> & switches, const CefSettings & settings, const std::vector<std::pair<std::string, int>> & schemes) : myArgs(switches), mySettings(settings), mySchemes(schemes), myBrowserProcessHandler(new RemoteBrowserProcessHandler()) {} bool RemoteAppHandler::isDefaultRoot() const { return getSettingRootPath().empty(); } std::string RemoteAppHandler::getRootPath() const { std::string rootFromSettings = getSettingRootPath(); if (!rootFromSettings.empty()) return rootFromSettings; #if defined(OS_WIN) return "~\\AppData\\Local\\CEF\\User Data"; #elif defined(OS_LINUX) return "~/.config/cef_user_data"; #elif defined(OS_MAC) return "~/Library/Application Support/CEF/User Data"; #endif } std::string RemoteAppHandler::getSettingRootPath() const { /// The root directory for installation-specific data and the parent directory /// for profile-specific data. All CefSettings.cache_path and /// CefRequestContextSettings.cache_path values must have this parent /// directory in common. If this value is empty and CefSettings.cache_path is /// non-empty then it will default to the CefSettings.cache_path value. If both values are empty then /// the default platform-specific directory will be used /// ("~/.config/cef_user_data" directory on Linux, "~/Library/Application /// Support/CEF/User Data" directory on MacOS, "AppData\Local\CEF\User Data" /// directory under the user profile directory on Windows). /// /// Multiple application instances writing to the same root_cache_path /// directory could result in data corruption. A process singleton lock based /// on the root_cache_path value is therefore used to protect against this. /// This singleton behavior applies to all CEF-based applications using /// version 120 or newer. You should customize root_cache_path for your /// application and implement CefBrowserProcessHandler:: /// OnAlreadyRunningAppRelaunch, which will then be called on any app relaunch /// with the same root_cache_path value. /// /// Failure to set the root_cache_path value correctly may result in startup /// crashes or other unexpected behaviors (for example, the sandbox blocking /// read/write access to certain files). /// std::string root = CefString(&mySettings.root_cache_path).ToString(); if (!root.empty()) return root; std::string cache = CefString(&mySettings.cache_path).ToString(); if (!cache.empty()) return cache; return ""; } void RemoteAppHandler::OnBeforeCommandLineProcessing( const CefString& process_type, CefRefPtr<CefCommandLine> command_line ) { if (!process_type.empty()) return; Log::debug("OnBeforeCommandLineProcessing: original command line:\n%s", command_line->GetCommandLineString().ToString().c_str()); std::string additionalItems; if (!myArgs.empty()) { // Copy-paste from CefAppHandlerAdapter.onBeforeCommandLineProcessing // Forward switches and arguments from Java to Cef bool parseSwitchesDone = false; for (const auto& arg : myArgs) { if (parseSwitchesDone || arg.length() < 2) { command_line->AppendArgument(arg); additionalItems += arg + ", "; continue; } // Arguments with '--', '-' and, on Windows, '/' prefixes are considered switches. int switchCnt = (arg.find("--") == 0) ? 2 : (arg.find("/") == 0) ? 1 : (arg.find("-") == 0) ? 1 : 0; switch (switchCnt) { case 2: // An argument of "--" will terminate switch parsing with all subsequent // tokens if (arg.length() == 2) { parseSwitchesDone = true; continue; } // FALL THRU case 1: { // Switches can optionally have a value specified using the '=' delimiter // (e.g. "-switch=value"). const std::string switchStr = arg.substr(switchCnt); const size_t eqPos = switchStr.find("="); if (eqPos != std::string::npos && eqPos > 0) { std::string s0 = switchStr.substr(0, eqPos); std::string s1 = switchStr.substr(eqPos + 1); command_line->AppendSwitchWithValue(s0, s1); additionalItems += s0 + "|" + s1 + ", "; } else { command_line->AppendSwitch(switchStr); additionalItems += switchStr + ", "; } break; } case 0: command_line->AppendArgument(arg); additionalItems += arg + ", "; break; } } } if (additionalItems.length() > 0) Log::debug("OnBeforeCommandLineProcessing: additional command line switches:\n%s", additionalItems.c_str()); // Copy-paste from ClientApp::OnBeforeCommandLineProcessing #if defined(OS_MAC) command_line->AppendSwitch("use-mock-keychain"); Log::debug("OnBeforeCommandLineProcessing: added OSX switch 'use-mock-keychain' (to skip keychain prompt on startup)."); #endif // defined(OS_MAC) if (mySettings.cache_path.length <= 0 && !command_line->HasSwitch("disable-gpu-shader-disk-cache")) { command_line->AppendSwitch("disable-gpu-shader-disk-cache"); Log::debug("OnBeforeCommandLineProcessing: added switch 'disable-gpu-shader-disk-cache' (don't create a 'GPUCache' directory when settings.cache_path is unspecified)"); } } void RemoteAppHandler::OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) { // The registered scheme has to be forwarded to all other processes which will // be created by the browser process (e.g. the render-process). Otherwise // things like JS "localStorage" get/set will end up in a crashed // render process. if (mySchemes.empty()) return; std::string tmpName = utils::GetTempFile("scheme", false); std::ofstream fStream(tmpName.c_str(),std::ofstream::out | std::ofstream::trunc); Log::trace("OnRegisterCustomSchemes: write custom schemes to file=%s:", tmpName.c_str()); for (const auto& cs: mySchemes) { int options = 0; if (cs.second & (1 << 0)) options |= CEF_SCHEME_OPTION_STANDARD; if (cs.second & (1 << 1)) options |= CEF_SCHEME_OPTION_LOCAL; if (cs.second & (1 << 2)) options |= CEF_SCHEME_OPTION_DISPLAY_ISOLATED; if (cs.second & (1 << 3)) options |= CEF_SCHEME_OPTION_SECURE; if (cs.second & (1 << 4)) options |= CEF_SCHEME_OPTION_CORS_ENABLED; if (cs.second & (1 << 5)) options |= CEF_SCHEME_OPTION_CSP_BYPASSING; if (cs.second & (1 << 6)) options |= CEF_SCHEME_OPTION_FETCH_ENABLED; registrar->AddCustomScheme(cs.first, options); Log::trace("\t%s [%d:%d]", cs.first.c_str(), cs.second, options); if (fStream.is_open()) fStream << cs.first.c_str() << "," << options; } if (fStream.is_open()) fStream.close(); // TODO Register file to be deleted in CefShutdown() // ClientApp::registerTempFile(tmpName); }