• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4 
5 #include "libcef/renderer/browser_manager.h"
6 
7 #include "base/compiler_specific.h"
8 
9 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
10 #if defined(OS_WIN)
11 #if defined(__clang__)
12 #pragma GCC diagnostic push
13 #pragma GCC diagnostic error "-Wdeprecated-declarations"
14 #else
15 #pragma warning(push)
16 #pragma warning(default : 4996)
17 #endif
18 #endif
19 
20 #include "libcef/common/app_manager.h"
21 #include "libcef/common/cef_messages.h"
22 #include "libcef/common/cef_switches.h"
23 #include "libcef/common/net/scheme_info.h"
24 #include "libcef/common/values_impl.h"
25 #include "libcef/renderer/blink_glue.h"
26 #include "libcef/renderer/browser_impl.h"
27 #include "libcef/renderer/render_frame_observer.h"
28 #include "libcef/renderer/thread_util.h"
29 #include "libcef/renderer/v8_impl.h"
30 
31 #include "base/command_line.h"
32 #include "base/strings/string_number_conversions.h"
33 #include "content/public/renderer/render_frame.h"
34 #include "content/public/renderer/render_thread.h"
35 #include "content/public/renderer/render_view.h"
36 #include "services/network/public/mojom/cors_origin_pattern.mojom.h"
37 #include "third_party/blink/public/web/web_security_policy.h"
38 #include "third_party/blink/public/web/web_view.h"
39 #include "third_party/blink/public/web/web_view_observer.h"
40 
41 namespace {
42 
43 CefBrowserManager* g_manager = nullptr;
44 
45 }  // namespace
46 
47 // Placeholder object for guest views.
48 class CefGuestView : public blink::WebViewObserver {
49  public:
CefGuestView(CefBrowserManager * manager,content::RenderView * render_view,bool is_windowless)50   CefGuestView(CefBrowserManager* manager,
51                content::RenderView* render_view,
52                bool is_windowless)
53       : blink::WebViewObserver(render_view->GetWebView()),
54         manager_(manager),
55         is_windowless_(is_windowless) {}
56 
is_windowless() const57   bool is_windowless() const { return is_windowless_; }
58 
59  private:
60   // RenderViewObserver methods.
OnDestruct()61   void OnDestruct() override { manager_->OnGuestViewDestroyed(this); }
62 
63   CefBrowserManager* const manager_;
64   const bool is_windowless_;
65 };
66 
CefBrowserManager()67 CefBrowserManager::CefBrowserManager() {
68   DCHECK(!g_manager);
69   g_manager = this;
70 }
71 
~CefBrowserManager()72 CefBrowserManager::~CefBrowserManager() {
73   g_manager = nullptr;
74 }
75 
76 // static
Get()77 CefBrowserManager* CefBrowserManager::Get() {
78   CEF_REQUIRE_RT_RETURN(nullptr);
79   return g_manager;
80 }
81 
RenderThreadConnected()82 void CefBrowserManager::RenderThreadConnected() {
83   content::RenderThread* thread = content::RenderThread::Get();
84 
85   // Retrieve the new render thread information synchronously.
86   CefProcessHostMsg_GetNewRenderThreadInfo_Params params;
87   thread->Send(new CefProcessHostMsg_GetNewRenderThreadInfo(&params));
88 
89   // Cross-origin entries need to be added after WebKit is initialized.
90   cross_origin_whitelist_entries_ = params.cross_origin_whitelist_entries;
91 
92   WebKitInitialized();
93 }
94 
RenderFrameCreated(content::RenderFrame * render_frame,CefRenderFrameObserver * render_frame_observer,bool & browser_created,base::Optional<bool> & is_windowless)95 void CefBrowserManager::RenderFrameCreated(
96     content::RenderFrame* render_frame,
97     CefRenderFrameObserver* render_frame_observer,
98     bool& browser_created,
99     base::Optional<bool>& is_windowless) {
100   auto browser = MaybeCreateBrowser(render_frame->GetRenderView(), render_frame,
101                                     &browser_created, &is_windowless);
102   if (browser) {
103     // Attach the frame to the observer for message routing purposes.
104     render_frame_observer->AttachFrame(
105         browser->GetWebFrameImpl(render_frame->GetWebFrame()).get());
106   }
107 }
108 
RenderViewCreated(content::RenderView * render_view,bool & browser_created,base::Optional<bool> & is_windowless)109 void CefBrowserManager::RenderViewCreated(content::RenderView* render_view,
110                                           bool& browser_created,
111                                           base::Optional<bool>& is_windowless) {
112   MaybeCreateBrowser(render_view, render_view->GetMainRenderFrame(),
113                      &browser_created, &is_windowless);
114 }
115 
DevToolsAgentAttached()116 void CefBrowserManager::DevToolsAgentAttached() {
117   ++devtools_agent_count_;
118 }
119 
DevToolsAgentDetached()120 void CefBrowserManager::DevToolsAgentDetached() {
121   --devtools_agent_count_;
122   if (devtools_agent_count_ == 0 && uncaught_exception_stack_size_ > 0) {
123     // When the last DevToolsAgent is detached the stack size is set to 0.
124     // Restore the user-specified stack size here.
125     CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_);
126   }
127 }
128 
GetBrowserForView(content::RenderView * view)129 CefRefPtr<CefBrowserImpl> CefBrowserManager::GetBrowserForView(
130     content::RenderView* view) {
131   BrowserMap::const_iterator it = browsers_.find(view);
132   if (it != browsers_.end())
133     return it->second;
134   return nullptr;
135 }
136 
GetBrowserForMainFrame(blink::WebFrame * frame)137 CefRefPtr<CefBrowserImpl> CefBrowserManager::GetBrowserForMainFrame(
138     blink::WebFrame* frame) {
139   BrowserMap::const_iterator it = browsers_.begin();
140   for (; it != browsers_.end(); ++it) {
141     auto web_view = it->second->GetWebView();
142     if (web_view && web_view->MainFrame() == frame) {
143       return it->second;
144     }
145   }
146 
147   return nullptr;
148 }
149 
WebKitInitialized()150 void CefBrowserManager::WebKitInitialized() {
151   const base::CommandLine* command_line =
152       base::CommandLine::ForCurrentProcess();
153 
154   // Create global objects associated with the default Isolate.
155   CefV8IsolateCreated();
156 
157   const CefAppManager::SchemeInfoList* schemes =
158       CefAppManager::Get()->GetCustomSchemes();
159   if (!schemes->empty()) {
160     // Register the custom schemes. Some attributes are excluded here because
161     // they use url/url_util.h APIs instead.
162     CefAppManager::SchemeInfoList::const_iterator it = schemes->begin();
163     for (; it != schemes->end(); ++it) {
164       const CefSchemeInfo& info = *it;
165       const blink::WebString& scheme =
166           blink::WebString::FromUTF8(info.scheme_name);
167       if (info.is_display_isolated)
168         blink::WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(scheme);
169       if (info.is_fetch_enabled)
170         blink_glue::RegisterURLSchemeAsSupportingFetchAPI(scheme);
171     }
172   }
173 
174   if (!cross_origin_whitelist_entries_.empty()) {
175     // Add the cross-origin white list entries.
176     for (size_t i = 0; i < cross_origin_whitelist_entries_.size(); ++i) {
177       const Cef_CrossOriginWhiteListEntry_Params& entry =
178           cross_origin_whitelist_entries_[i];
179       GURL gurl = GURL(entry.source_origin);
180       blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(
181           gurl, blink::WebString::FromUTF8(entry.target_protocol),
182           blink::WebString::FromUTF8(entry.target_domain),
183           /*destination_port=*/0,
184           entry.allow_target_subdomains
185               ? network::mojom::CorsDomainMatchMode::kAllowSubdomains
186               : network::mojom::CorsDomainMatchMode::kDisallowSubdomains,
187           network::mojom::CorsPortMatchMode::kAllowAnyPort,
188           network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
189     }
190     cross_origin_whitelist_entries_.clear();
191   }
192 
193   // The number of stack trace frames to capture for uncaught exceptions.
194   if (command_line->HasSwitch(switches::kUncaughtExceptionStackSize)) {
195     int uncaught_exception_stack_size = 0;
196     base::StringToInt(command_line->GetSwitchValueASCII(
197                           switches::kUncaughtExceptionStackSize),
198                       &uncaught_exception_stack_size);
199 
200     if (uncaught_exception_stack_size > 0) {
201       uncaught_exception_stack_size_ = uncaught_exception_stack_size;
202       CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_);
203     }
204   }
205 
206   // Notify the render process handler.
207   CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
208   if (application.get()) {
209     CefRefPtr<CefRenderProcessHandler> handler =
210         application->GetRenderProcessHandler();
211     if (handler.get())
212       handler->OnWebKitInitialized();
213   }
214 }
215 
MaybeCreateBrowser(content::RenderView * render_view,content::RenderFrame * render_frame,bool * browser_created,base::Optional<bool> * is_windowless)216 CefRefPtr<CefBrowserImpl> CefBrowserManager::MaybeCreateBrowser(
217     content::RenderView* render_view,
218     content::RenderFrame* render_frame,
219     bool* browser_created,
220     base::Optional<bool>* is_windowless) {
221   if (browser_created)
222     *browser_created = false;
223 
224   if (!render_view || !render_frame)
225     return nullptr;
226 
227   // Don't create another browser or guest view object if one already exists for
228   // the view.
229   auto browser = GetBrowserForView(render_view);
230   if (browser) {
231     if (is_windowless) {
232       *is_windowless = browser->is_windowless();
233     }
234     return browser;
235   }
236 
237   auto guest_view = GetGuestViewForView(render_view);
238   if (guest_view) {
239     if (is_windowless) {
240       *is_windowless = guest_view->is_windowless();
241     }
242     return nullptr;
243   }
244 
245   const int render_frame_routing_id = render_frame->GetRoutingID();
246 
247   // Retrieve the browser information synchronously. This will also register
248   // the routing ids with the browser info object in the browser process.
249   CefProcessHostMsg_GetNewBrowserInfo_Params params;
250   content::RenderThread::Get()->Send(new CefProcessHostMsg_GetNewBrowserInfo(
251       render_frame_routing_id, &params));
252 
253   if (is_windowless) {
254     *is_windowless = params.is_windowless;
255   }
256 
257   if (params.browser_id == 0) {
258     // The popup may have been canceled during creation.
259     return nullptr;
260   }
261 
262   if (params.is_guest_view || params.browser_id < 0) {
263     // Don't create a CefBrowser for guest views, or if the new browser info
264     // response has timed out.
265     guest_views_.insert(std::make_pair(
266         render_view, std::make_unique<CefGuestView>(this, render_view,
267                                                     params.is_windowless)));
268     return nullptr;
269   }
270 
271   browser = new CefBrowserImpl(render_view, params.browser_id, params.is_popup,
272                                params.is_windowless);
273   browsers_.insert(std::make_pair(render_view, browser));
274 
275   // Notify the render process handler.
276   CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
277   if (application.get()) {
278     CefRefPtr<CefRenderProcessHandler> handler =
279         application->GetRenderProcessHandler();
280     if (handler.get()) {
281       CefRefPtr<CefDictionaryValueImpl> dictValuePtr(
282           new CefDictionaryValueImpl(&params.extra_info, false, true));
283       handler->OnBrowserCreated(browser.get(), dictValuePtr.get());
284       dictValuePtr->Detach(nullptr);
285     }
286   }
287 
288   if (browser_created)
289     *browser_created = true;
290 
291   return browser;
292 }
293 
OnBrowserDestroyed(CefBrowserImpl * browser)294 void CefBrowserManager::OnBrowserDestroyed(CefBrowserImpl* browser) {
295   BrowserMap::iterator it = browsers_.begin();
296   for (; it != browsers_.end(); ++it) {
297     if (it->second.get() == browser) {
298       browsers_.erase(it);
299       return;
300     }
301   }
302 
303   // No browser was found in the map.
304   NOTREACHED();
305 }
306 
GetGuestViewForView(content::RenderView * view)307 CefGuestView* CefBrowserManager::GetGuestViewForView(
308     content::RenderView* view) {
309   CEF_REQUIRE_RT_RETURN(nullptr);
310 
311   GuestViewMap::const_iterator it = guest_views_.find(view);
312   if (it != guest_views_.end())
313     return it->second.get();
314   return nullptr;
315 }
316 
OnGuestViewDestroyed(CefGuestView * guest_view)317 void CefBrowserManager::OnGuestViewDestroyed(CefGuestView* guest_view) {
318   GuestViewMap::iterator it = guest_views_.begin();
319   for (; it != guest_views_.end(); ++it) {
320     if (it->second.get() == guest_view) {
321       guest_views_.erase(it);
322       return;
323     }
324   }
325 
326   // No guest view was found in the map.
327   NOTREACHED();
328 }
329 
330 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
331 #if defined(OS_WIN)
332 #if defined(__clang__)
333 #pragma GCC diagnostic pop
334 #else
335 #pragma warning(pop)
336 #endif
337 #endif
338