#include "Cef3WebviewHandler.h" #include "include/wrapper/cef_helpers.h" #include "include/cef_parser.h" #include #include "Cef3WinUtil.h" #include "Cef3MainContext.h" #include "Cef3ResourceUtil.h" //#include "temp_window_win.h" namespace browser { #if defined(OS_WIN) #define NEWLINE "\r\n" #else #define NEWLINE "\n" #endif // Custom menu command Ids. enum browser_menu_ids { BROWSER_ID_SHOW_DEVTOOLS = MENU_ID_USER_FIRST, BROWSER_ID_CLOSE_DEVTOOLS, BROWSER_ID_INSPECT_ELEMENT, }; std::string GetErrorString(cef_errorcode_t code) { // Case condition that returns |code| as a string. #define CASE(code) case code: return #code switch (code) { CASE(ERR_NONE); CASE(ERR_FAILED); CASE(ERR_ABORTED); CASE(ERR_INVALID_ARGUMENT); CASE(ERR_INVALID_HANDLE); CASE(ERR_FILE_NOT_FOUND); CASE(ERR_TIMED_OUT); CASE(ERR_FILE_TOO_BIG); CASE(ERR_UNEXPECTED); CASE(ERR_ACCESS_DENIED); CASE(ERR_NOT_IMPLEMENTED); CASE(ERR_CONNECTION_CLOSED); CASE(ERR_CONNECTION_RESET); CASE(ERR_CONNECTION_REFUSED); CASE(ERR_CONNECTION_ABORTED); CASE(ERR_CONNECTION_FAILED); CASE(ERR_NAME_NOT_RESOLVED); CASE(ERR_INTERNET_DISCONNECTED); CASE(ERR_SSL_PROTOCOL_ERROR); CASE(ERR_ADDRESS_INVALID); CASE(ERR_ADDRESS_UNREACHABLE); CASE(ERR_SSL_CLIENT_AUTH_CERT_NEEDED); CASE(ERR_TUNNEL_CONNECTION_FAILED); CASE(ERR_NO_SSL_VERSIONS_ENABLED); CASE(ERR_SSL_VERSION_OR_CIPHER_MISMATCH); CASE(ERR_SSL_RENEGOTIATION_REQUESTED); CASE(ERR_CERT_COMMON_NAME_INVALID); CASE(ERR_CERT_DATE_INVALID); CASE(ERR_CERT_AUTHORITY_INVALID); CASE(ERR_CERT_CONTAINS_ERRORS); CASE(ERR_CERT_NO_REVOCATION_MECHANISM); CASE(ERR_CERT_UNABLE_TO_CHECK_REVOCATION); CASE(ERR_CERT_REVOKED); CASE(ERR_CERT_INVALID); CASE(ERR_CERT_END); CASE(ERR_INVALID_URL); CASE(ERR_DISALLOWED_URL_SCHEME); CASE(ERR_UNKNOWN_URL_SCHEME); CASE(ERR_TOO_MANY_REDIRECTS); CASE(ERR_UNSAFE_REDIRECT); CASE(ERR_UNSAFE_PORT); CASE(ERR_INVALID_RESPONSE); CASE(ERR_INVALID_CHUNKED_ENCODING); CASE(ERR_METHOD_NOT_SUPPORTED); CASE(ERR_UNEXPECTED_PROXY_AUTH); CASE(ERR_EMPTY_RESPONSE); CASE(ERR_RESPONSE_HEADERS_TOO_BIG); CASE(ERR_CACHE_MISS); CASE(ERR_INSECURE_RESPONSE); default: return "UNKNOWN"; } } std::string GetDataURI(const std::string& data, const std::string& mime_type) { return "data:" + mime_type + ";base64," + CefURIEncode(CefBase64Encode(data.data(), data.size()), false).ToString(); } // Load a data: URI containing the error message. void LoadErrorPage(CefRefPtr frame, const std::string& failed_url, cef_errorcode_t error_code, const std::string& other_info) { std::stringstream ss; ss << "Page failed to load" "" "

Page failed to load.

" "URL: " << failed_url << "" "
Error: " << GetErrorString(error_code) << " (" << error_code << ")"; if (!other_info.empty()) ss << "
" << other_info; ss << ""; frame->LoadURL(GetDataURI(ss.str(), "text/html")); } CCef3WebviewHandler::CCef3WebviewHandler() : m_posr(NULL) , m_bPageLoaded(FALSE) , m_pMsgHandler(NULL) , first_console_message_(true) , console_log_file_(CCef3MainContext::Get()->GetConsoleLogPath()) { resource_manager_ = new CefResourceManager(); } CCef3WebviewHandler::~CCef3WebviewHandler() { } void CCef3WebviewHandler::CloseDevTools(CefRefPtr browser) { browser->GetHost()->CloseDevTools(); } bool CCef3WebviewHandler::CreatePopupWindow( CefRefPtr browser, bool is_devtools, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr& client, CefBrowserSettings& settings) { // Note: This method will be called on multiple threads. // The popup browser will be parented to a new native window. // Don't show URL bar and navigation buttons on DevTools windows. //MainContext::Get()->CreateBrowserPopup(is_osr(), popupFeatures, windowInfo, client, settings); return false; } // ------------------------------------------------------------------------------ // // cef handler callbacks // // ------------------------------------------------------------------------------ bool CCef3WebviewHandler::GetRootScreenRect(CefRefPtr browser, CefRect& rect) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { return m_posr->GetRootScreenRect(browser, rect); } return false; } bool CCef3WebviewHandler::GetViewRect(CefRefPtr browser, CefRect& rect) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { return m_posr->GetViewRect(browser, rect); } return false; } bool CCef3WebviewHandler::GetScreenPoint(CefRefPtr browser, int viewX, int viewY, int& screenX, int& screenY) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { return m_posr->GetScreenPoint(browser, viewX, viewY, screenX, screenY); } return false; } bool CCef3WebviewHandler::GetScreenInfo(CefRefPtr browser, CefScreenInfo& screen_info) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { return m_posr->GetScreenInfo(browser, screen_info); } return false; } void CCef3WebviewHandler::OnPopupShow(CefRefPtr browser, bool show) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { return m_posr->OnPopupShow(browser, show); } } void CCef3WebviewHandler::OnPopupSize(CefRefPtr browser, const CefRect& rect) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { return m_posr->OnPopupSize(browser, rect); } } void CCef3WebviewHandler::OnPaint(CefRefPtr browser, PaintElementType type, const RectList & dirtyRects, const void* buffer, int width, int height) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { m_posr->OnPaint(browser, type, dirtyRects, buffer, width, height); } } void CCef3WebviewHandler::OnCursorChange(CefRefPtr browser, CefCursorHandle cursor, CursorType type, const CefCursorInfo& custom_cursor_info) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { m_posr->OnCursorChange(browser, cursor, type, custom_cursor_info); } } bool CCef3WebviewHandler::StartDragging( CefRefPtr browser, CefRefPtr drag_data, CefRenderHandler::DragOperationsMask allowed_ops, int x, int y) { CEF_REQUIRE_UI_THREAD(); return false; } void CCef3WebviewHandler::UpdateDragCursor( CefRefPtr browser, CefRenderHandler::DragOperation operation) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { m_posr->UpdateDragCursor(browser, operation); } } void CCef3WebviewHandler::OnImeCompositionRangeChanged( CefRefPtr browser, const CefRange& selection_range, const CefRenderHandler::RectList& character_bounds) { CEF_REQUIRE_UI_THREAD(); if (m_posr) { m_posr->OnImeCompositionRangeChanged(browser, selection_range, character_bounds); } } bool CCef3WebviewHandler::OnPreKeyEvent(CefRefPtr browser, const CefKeyEvent& event, CefEventHandle os_event, bool* is_keyboard_shortcut) { if (!m_bPageLoaded) { return true; } CefWindowHandle hWnd = browser->GetHost()->GetWindowHandle(); // // Í˳ö if (event.character == VK_ESCAPE) { ::PostMessage(::GetParent(hWnd), WM_KEYDOWN, event.character, 0); return true; } // // µ÷ÊÔ¿ì½Ý¼ü if (IsKeyDown(VK_SHIFT)) { STRACE(L"char:%d", event.character); if (event.character == VK_F12) { OpenDevTools(); } else if (event.character == VK_F11) { browser->GetMainFrame()->ViewSource(); } } return false; } bool CCef3WebviewHandler::DoClose(CefRefPtr browser) { return false; } void CCef3WebviewHandler::OnAfterCreated(CefRefPtr browser) { CEF_REQUIRE_UI_THREAD(); m_refBrowser = browser; browser::CCef3MainContext::Get()->AddOpenedBrowserCount(); if (m_posr) { m_posr->OnAfterCreated(browser); } } void CCef3WebviewHandler::OnBeforeClose(CefRefPtr browser) { if (m_refBrowser.get() && m_refBrowser->GetIdentifier() == browser->GetIdentifier()) { // !!! IMPORTANT !!! m_refBrowser = NULL; STRACE(L"main browser closed"); } int n = browser::CCef3MainContext::Get()->DelOpenedBrowserCount(); //STRACE(L"browser left:%d", n); if (n == 0) { STRACE(L"quit message loop"); //CefQuitMessageLoop(); } } // ------------------------------------------------------------------------------ // // browser methods for user & internal methods // // ------------------------------------------------------------------------------ void CCef3WebviewHandler::OpenDevTools() { if (!m_refBrowser) { return; } CefWindowInfo windowInfo; CefBrowserSettings settings; windowInfo.SetAsPopup(m_refBrowser->GetHost()->GetWindowHandle(), "DevTools"); m_refBrowser->GetHost()->ShowDevTools(windowInfo, this, settings, CefPoint()); } bool CCef3WebviewHandler::OnBeforePopup(CefRefPtr browser, CefRefPtr frame, const CefString& target_url, const CefString& target_frame_name, CefLifeSpanHandler::WindowOpenDisposition target_disposition, bool user_gesture, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr& client, CefBrowserSettings& settings, bool* no_javascript_access) { if (m_posr) { m_posr->OnBeforePopup(browser, frame, target_url, target_frame_name, target_disposition, user_gesture, popupFeatures, windowInfo, client, settings, no_javascript_access); } return true;//²»ÔÊÐíµ¯´°¿Ú£¬ÓÉÓ¦ÓÃ×Ô¼º¾ö¶¨µ¯²»µ¯ } BOOL CCef3WebviewHandler::Open(HWND hParent, SOUI::CRect rcView) { CefWindowInfo info; info.SetAsWindowless(hParent, true); return !!CefBrowserHost::CreateBrowser(info, this, "", CefBrowserSettings(), nullptr); } void CCef3WebviewHandler::Close() { if (m_refBrowser) m_refBrowser->GetHost()->CloseBrowser(true); } void CCef3WebviewHandler::CloseAllBrowsers(bool force_close) { if (!CefCurrentlyOn(TID_UI)) { // Execute on the UI thread. CefPostTask(TID_UI, base::Bind(&CCef3WebviewHandler::CloseAllBrowsers, this, force_close)); return; } if (m_refBrowser.get()) { // Request that the main browser close. m_refBrowser->GetHost()->CloseBrowser(force_close); } } void CCef3WebviewHandler::SetRender(OsrDelegate * pHost) { m_posr = pHost; } CefRefPtr CCef3WebviewHandler::GetBrowser() { return m_refBrowser; } void CCef3WebviewHandler::RegisterMessageHandler(MessageHandler * handler) { m_pMsgHandler = handler; } void CCef3WebviewHandler::UnRegisterMessgeHandler(MessageHandler * handler) { m_pMsgHandler = NULL; } void CCef3WebviewHandler::OnTitleChange(CefRefPtr browser, const CefString& title) { } bool CCef3WebviewHandler::OnConsoleMessage(CefRefPtr browser, const CefString& message, const CefString& source, int line) { CEF_REQUIRE_UI_THREAD(); FILE* file = fopen(console_log_file_.c_str(), "a"); if (file) { std::stringstream ss; ss << "Message: " << message.ToString() << NEWLINE << "Source: " << source.ToString() << NEWLINE << "Line: " << line << NEWLINE << "-----------------------" << NEWLINE; fputs(ss.str().c_str(), file); fclose(file); if (first_console_message_) { //test_runner::Alert( browser, "Console messages written to \"" + console_log_file_ + "\""); first_console_message_ = false; } } return false; } void CCef3WebviewHandler::OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& url) { if (m_posr) { m_posr->OnAddressChange(browser, frame, url); } } void CCef3WebviewHandler::OnBeforeContextMenu(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, CefRefPtr model) { model->Clear();//ûÓв˵¥ } bool CCef3WebviewHandler::OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool is_redirect) { CEF_REQUIRE_UI_THREAD(); //message_router_->OnBeforeBrowse(browser, frame); return false; } bool CCef3WebviewHandler::OnOpenURLFromTab( CefRefPtr browser, CefRefPtr frame, const CefString& target_url, CefRequestHandler::WindowOpenDisposition target_disposition, bool user_gesture) { if (target_disposition == WOD_NEW_BACKGROUND_TAB || target_disposition == WOD_NEW_FOREGROUND_TAB) { // Handle middle-click and ctrl + left-click by opening the URL in a new // browser window. return true; } // Open the URL in the current browser window. return false; } cef_return_value_t CCef3WebviewHandler::OnBeforeResourceLoad( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr callback) { CEF_REQUIRE_IO_THREAD(); return resource_manager_->OnBeforeResourceLoad(browser, frame, request, callback); } CefRefPtr CCef3WebviewHandler::GetResourceHandler( CefRefPtr browser, CefRefPtr frame, CefRefPtr request) { CEF_REQUIRE_IO_THREAD(); return resource_manager_->GetResourceHandler(browser, frame, request); } CefRefPtr CCef3WebviewHandler::GetResourceResponseFilter( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) { CEF_REQUIRE_IO_THREAD(); return NULL; //return test_runner::GetResourceResponseFilter(browser, frame, request, response); } bool CCef3WebviewHandler::OnQuotaRequest(CefRefPtr browser, const CefString& origin_url, int64 new_size, CefRefPtr callback) { CEF_REQUIRE_IO_THREAD(); static const int64 max_size = 1024 * 1024 * 20; // 20mb. // Grant the quota request if the size is reasonable. callback->Continue(new_size <= max_size); return true; } void CCef3WebviewHandler::OnProtocolExecution(CefRefPtr browser, const CefString& url, bool& allow_os_execution) { CEF_REQUIRE_UI_THREAD(); // Allow OS execution of Spotify URIs. allow_os_execution = IsAllowOsExce(url); } bool CCef3WebviewHandler::OnCertificateError( CefRefPtr browser, ErrorCode cert_error, const CefString& request_url, CefRefPtr ssl_info, CefRefPtr callback) { CEF_REQUIRE_UI_THREAD(); CefRefPtr cert = ssl_info->GetX509Certificate(); CefRefPtr subject = cert->GetSubject(); CefRefPtr issuer = cert->GetIssuer(); // Build a table showing certificate information. Various types of invalid // certificates can be tested using https://badssl.com/. std::stringstream ss; ss << "X.509 Certificate Information:" "" << "" "" "" "" "" ""; CefX509Certificate::IssuerChainBinaryList der_chain_list; CefX509Certificate::IssuerChainBinaryList pem_chain_list; cert->GetDEREncodedIssuerChain(der_chain_list); cert->GetPEMEncodedIssuerChain(pem_chain_list); DCHECK_EQ(der_chain_list.size(), pem_chain_list.size()); der_chain_list.insert(der_chain_list.begin(), cert->GetDEREncoded()); pem_chain_list.insert(pem_chain_list.begin(), cert->GetPEMEncoded()); for (size_t i = 0U; i < der_chain_list.size(); ++i) { ss << "" "" "" ""; } ss << "
FieldValue
Subject" << (subject.get() ? subject->GetDisplayName().ToString() : " ") << "
Issuer" << (issuer.get() ? issuer->GetDisplayName().ToString() : " ") << "
Serial #*" << browser::GetBinaryString(cert->GetSerialNumber()) << "
Status" << browser::GetCertStatusString(ssl_info->GetCertStatus()) << "
Valid Start" << browser::GetTimeString(cert->GetValidStart()) << "
Valid Expiry" << browser::GetTimeString(cert->GetValidExpiry()) << "
DER Encoded*" << browser::GetBinaryString(der_chain_list[i]) << "
PEM Encoded*" << browser::GetBinaryString(pem_chain_list[i]) << "
* Displayed value is base64 encoded."; // Load the error page. LoadErrorPage(browser->GetMainFrame(), request_url, cert_error, ss.str()); return false; // Cancel the request. } void CCef3WebviewHandler::OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status) { CEF_REQUIRE_UI_THREAD(); //message_router_->OnRenderProcessTerminated(browser); // Don't reload if there's no start URL, or if the crash URL was specified. if (browser::CCef3MainContext::Get()->GetMainURL().empty() || browser::CCef3MainContext::Get()->GetMainURL() == "chrome://crash") return; CefRefPtr frame = browser->GetMainFrame(); std::string url = frame->GetURL(); // Don't reload if the termination occurred before any URL had successfully // loaded. if (url.empty()) return; std::string start_url = browser::CCef3MainContext::Get()->GetMainURL(); // Convert URLs to lowercase for easier comparison. std::transform(url.begin(), url.end(), url.begin(), tolower); std::transform(start_url.begin(), start_url.end(), start_url.begin(), tolower); // Don't reload the URL that just resulted in termination. if (url.find(start_url) == 0) return; frame->LoadURL(browser::CCef3MainContext::Get()->GetMainURL()); } bool CCef3WebviewHandler::IsAllowOsExce(const CefString& url) { std::string urlStr = url; bool bRet = false; if (urlStr.find("spotify:") == 0) bRet= true; else if (urlStr.find("zoommtg:") == 0) //zoomÊÓÆµ»áÒéÆô¶¯ bRet = true; return bRet; } } //namespace browser