• 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/browser/browser_info_manager.h"
6 
7 #include <utility>
8 
9 #include "libcef/browser/browser_host_base.h"
10 #include "libcef/browser/browser_platform_delegate.h"
11 #include "libcef/browser/extensions/browser_extensions_util.h"
12 #include "libcef/browser/thread_util.h"
13 #include "libcef/common/cef_messages.h"
14 #include "libcef/common/cef_switches.h"
15 #include "libcef/common/extensions/extensions_util.h"
16 #include "libcef/common/values_impl.h"
17 #include "libcef/features/runtime_checks.h"
18 
19 #include "base/command_line.h"
20 #include "base/logging.h"
21 #include "content/public/browser/render_frame_host.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/child_process_host.h"
25 #include "content/public/common/url_constants.h"
26 
27 namespace {
28 
29 // Timeout delay for new browser info responses.
30 const int64_t kNewBrowserInfoResponseTimeoutMs = 2000;
31 
TranslatePopupFeatures(const blink::mojom::WindowFeatures & webKitFeatures,CefPopupFeatures & features)32 void TranslatePopupFeatures(const blink::mojom::WindowFeatures& webKitFeatures,
33                             CefPopupFeatures& features) {
34   features.x = static_cast<int>(webKitFeatures.x);
35   features.xSet = webKitFeatures.has_x;
36   features.y = static_cast<int>(webKitFeatures.y);
37   features.ySet = webKitFeatures.has_y;
38   features.width = static_cast<int>(webKitFeatures.width);
39   features.widthSet = webKitFeatures.has_width;
40   features.height = static_cast<int>(webKitFeatures.height);
41   features.heightSet = webKitFeatures.has_height;
42 
43   features.menuBarVisible = webKitFeatures.menu_bar_visible;
44   features.statusBarVisible = webKitFeatures.status_bar_visible;
45   features.toolBarVisible = webKitFeatures.tool_bar_visible;
46   features.scrollbarsVisible = webKitFeatures.scrollbars_visible;
47 }
48 
49 CefBrowserInfoManager* g_info_manager = nullptr;
50 
51 }  // namespace
52 
CefBrowserInfoManager()53 CefBrowserInfoManager::CefBrowserInfoManager() {
54   DCHECK(!g_info_manager);
55   g_info_manager = this;
56 }
57 
~CefBrowserInfoManager()58 CefBrowserInfoManager::~CefBrowserInfoManager() {
59   DCHECK(browser_info_list_.empty());
60   g_info_manager = nullptr;
61 }
62 
63 // static
GetInstance()64 CefBrowserInfoManager* CefBrowserInfoManager::GetInstance() {
65   return g_info_manager;
66 }
67 
CreateBrowserInfo(bool is_popup,bool is_windowless,CefRefPtr<CefDictionaryValue> extra_info)68 scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreateBrowserInfo(
69     bool is_popup,
70     bool is_windowless,
71     CefRefPtr<CefDictionaryValue> extra_info) {
72   base::AutoLock lock_scope(browser_info_lock_);
73 
74   scoped_refptr<CefBrowserInfo> browser_info = new CefBrowserInfo(
75       ++next_browser_id_, is_popup, is_windowless, extra_info);
76   browser_info_list_.push_back(browser_info);
77 
78   return browser_info;
79 }
80 
CreatePopupBrowserInfo(content::WebContents * new_contents,bool is_windowless,CefRefPtr<CefDictionaryValue> extra_info)81 scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreatePopupBrowserInfo(
82     content::WebContents* new_contents,
83     bool is_windowless,
84     CefRefPtr<CefDictionaryValue> extra_info) {
85   base::AutoLock lock_scope(browser_info_lock_);
86 
87   auto frame_host = new_contents->GetMainFrame();
88   const int render_process_id = frame_host->GetProcess()->GetID();
89   const auto frame_id = CefFrameHostImpl::MakeFrameId(frame_host);
90 
91   scoped_refptr<CefBrowserInfo> browser_info =
92       new CefBrowserInfo(++next_browser_id_, true, is_windowless, extra_info);
93   browser_info_list_.push_back(browser_info);
94 
95   // Continue any pending NewBrowserInfo request.
96   auto it = pending_new_browser_info_map_.find(frame_id);
97   if (it != pending_new_browser_info_map_.end()) {
98     SendNewBrowserInfoResponse(render_process_id, browser_info,
99                                false /* is_guest_view */,
100                                it->second->reply_msg);
101     pending_new_browser_info_map_.erase(it);
102   }
103 
104   return browser_info;
105 }
106 
CanCreateWindow(content::RenderFrameHost * opener,const GURL & target_url,const content::Referrer & referrer,const std::string & frame_name,WindowOpenDisposition disposition,const blink::mojom::WindowFeatures & features,bool user_gesture,bool opener_suppressed,bool * no_javascript_access)107 bool CefBrowserInfoManager::CanCreateWindow(
108     content::RenderFrameHost* opener,
109     const GURL& target_url,
110     const content::Referrer& referrer,
111     const std::string& frame_name,
112     WindowOpenDisposition disposition,
113     const blink::mojom::WindowFeatures& features,
114     bool user_gesture,
115     bool opener_suppressed,
116     bool* no_javascript_access) {
117   CEF_REQUIRE_UIT();
118 
119   content::OpenURLParams params(target_url, referrer, disposition,
120                                 ui::PAGE_TRANSITION_LINK,
121                                 /*is_renderer_initiated=*/true);
122   params.user_gesture = user_gesture;
123 
124   CefRefPtr<CefBrowserHostBase> browser;
125   if (!MaybeAllowNavigation(opener, params, browser) || !browser) {
126     // Cancel the popup.
127     return false;
128   }
129 
130   CefRefPtr<CefClient> client = browser->GetClient();
131   bool allow = true;
132 
133   std::unique_ptr<CefWindowInfo> window_info(new CefWindowInfo);
134 
135 #if defined(OS_WIN)
136   window_info->SetAsPopup(nullptr, CefString());
137 #endif
138 
139   auto pending_popup = std::make_unique<CefBrowserInfoManager::PendingPopup>();
140   pending_popup->step = CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW;
141   pending_popup->opener_render_process_id = opener->GetProcess()->GetID();
142   pending_popup->opener_render_routing_id = opener->GetRoutingID();
143   pending_popup->target_url = target_url;
144   pending_popup->target_frame_name = frame_name;
145 
146   // Start with the current browser's settings.
147   pending_popup->client = client;
148   pending_popup->settings = browser->settings();
149 
150   if (client.get()) {
151     CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
152     if (handler.get()) {
153       CefRefPtr<CefFrame> opener_frame = browser->GetFrameForHost(opener);
154       DCHECK(opener_frame);
155 
156       CefPopupFeatures cef_features;
157       TranslatePopupFeatures(features, cef_features);
158 
159 #if (defined(OS_WIN) || defined(OS_MAC))
160       // Default to the size from the popup features.
161       if (cef_features.xSet)
162         window_info->x = cef_features.x;
163       if (cef_features.ySet)
164         window_info->y = cef_features.y;
165       if (cef_features.widthSet)
166         window_info->width = cef_features.width;
167       if (cef_features.heightSet)
168         window_info->height = cef_features.height;
169 #endif
170 
171       allow = !handler->OnBeforePopup(
172           browser.get(), opener_frame, pending_popup->target_url.spec(),
173           pending_popup->target_frame_name,
174           static_cast<cef_window_open_disposition_t>(disposition), user_gesture,
175           cef_features, *window_info, pending_popup->client,
176           pending_popup->settings, pending_popup->extra_info,
177           no_javascript_access);
178     }
179   }
180 
181   if (allow) {
182     CefBrowserCreateParams create_params;
183 
184     if (browser->HasView()) {
185       create_params.popup_with_views_hosted_opener = true;
186     } else {
187       create_params.window_info = std::move(window_info);
188     }
189 
190     create_params.settings = pending_popup->settings;
191     create_params.client = pending_popup->client;
192     create_params.extra_info = pending_popup->extra_info;
193 
194     pending_popup->platform_delegate =
195         CefBrowserPlatformDelegate::Create(create_params);
196     CHECK(pending_popup->platform_delegate.get());
197 
198     // Between the calls to CanCreateWindow and GetCustomWebContentsView
199     // RenderViewHostImpl::CreateNewWindow() will call
200     // RenderProcessHostImpl::FilterURL() which, in the case of "javascript:"
201     // URIs, rewrites the URL to "about:blank". We need to apply the same filter
202     // otherwise GetCustomWebContentsView will fail to retrieve the PopupInfo.
203     opener->GetProcess()->FilterURL(false, &pending_popup->target_url);
204 
205     PushPendingPopup(std::move(pending_popup));
206   }
207 
208   return allow;
209 }
210 
GetCustomWebContentsView(const GURL & target_url,int opener_render_process_id,int opener_render_routing_id,content::WebContentsView ** view,content::RenderViewHostDelegateView ** delegate_view)211 void CefBrowserInfoManager::GetCustomWebContentsView(
212     const GURL& target_url,
213     int opener_render_process_id,
214     int opener_render_routing_id,
215     content::WebContentsView** view,
216     content::RenderViewHostDelegateView** delegate_view) {
217   CEF_REQUIRE_UIT();
218   REQUIRE_ALLOY_RUNTIME();
219 
220   std::unique_ptr<CefBrowserInfoManager::PendingPopup> pending_popup =
221       PopPendingPopup(CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW,
222                       opener_render_process_id, opener_render_routing_id,
223                       target_url);
224   DCHECK(pending_popup.get());
225   DCHECK(pending_popup->platform_delegate.get());
226 
227   if (pending_popup->platform_delegate->IsWindowless()) {
228     pending_popup->platform_delegate->CreateViewForWebContents(view,
229                                                                delegate_view);
230   }
231 
232   pending_popup->step =
233       CefBrowserInfoManager::PendingPopup::GET_CUSTOM_WEB_CONTENTS_VIEW;
234   PushPendingPopup(std::move(pending_popup));
235 }
236 
WebContentsCreated(const GURL & target_url,int opener_render_process_id,int opener_render_routing_id,CefBrowserSettings & settings,CefRefPtr<CefClient> & client,std::unique_ptr<CefBrowserPlatformDelegate> & platform_delegate,CefRefPtr<CefDictionaryValue> & extra_info)237 void CefBrowserInfoManager::WebContentsCreated(
238     const GURL& target_url,
239     int opener_render_process_id,
240     int opener_render_routing_id,
241     CefBrowserSettings& settings,
242     CefRefPtr<CefClient>& client,
243     std::unique_ptr<CefBrowserPlatformDelegate>& platform_delegate,
244     CefRefPtr<CefDictionaryValue>& extra_info) {
245   CEF_REQUIRE_UIT();
246 
247   // GET_CUSTOM_WEB_CONTENTS_VIEW is only used with the alloy runtime.
248   const auto previous_step =
249       cef::IsAlloyRuntimeEnabled()
250           ? CefBrowserInfoManager::PendingPopup::GET_CUSTOM_WEB_CONTENTS_VIEW
251           : CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW;
252 
253   std::unique_ptr<CefBrowserInfoManager::PendingPopup> pending_popup =
254       PopPendingPopup(previous_step, opener_render_process_id,
255                       opener_render_routing_id, target_url);
256   DCHECK(pending_popup.get());
257   DCHECK(pending_popup->platform_delegate.get());
258 
259   settings = pending_popup->settings;
260   client = pending_popup->client;
261   platform_delegate = std::move(pending_popup->platform_delegate);
262   extra_info = pending_popup->extra_info;
263 }
264 
OnGetNewBrowserInfo(int render_process_id,int render_routing_id,IPC::Message * reply_msg)265 void CefBrowserInfoManager::OnGetNewBrowserInfo(int render_process_id,
266                                                 int render_routing_id,
267                                                 IPC::Message* reply_msg) {
268   DCHECK_NE(render_process_id, content::ChildProcessHost::kInvalidUniqueID);
269   DCHECK_GT(render_routing_id, 0);
270   DCHECK(reply_msg);
271 
272   base::AutoLock lock_scope(browser_info_lock_);
273 
274   bool is_guest_view = false;
275 
276   scoped_refptr<CefBrowserInfo> browser_info =
277       GetBrowserInfo(render_process_id, render_routing_id, &is_guest_view);
278 
279   if (browser_info.get()) {
280     // Send the response immediately.
281     SendNewBrowserInfoResponse(render_process_id, browser_info, is_guest_view,
282                                reply_msg);
283     return;
284   }
285 
286   const auto frame_id =
287       CefFrameHostImpl::MakeFrameId(render_process_id, render_routing_id);
288 
289   // Verify that no request for the same route is currently queued.
290   DCHECK(pending_new_browser_info_map_.find(frame_id) ==
291          pending_new_browser_info_map_.end());
292 
293   const int timeout_id = ++next_timeout_id_;
294 
295   // Queue the request.
296   std::unique_ptr<PendingNewBrowserInfo> pending(new PendingNewBrowserInfo());
297   pending->render_process_id = render_process_id;
298   pending->render_routing_id = render_routing_id;
299   pending->timeout_id = timeout_id;
300   pending->reply_msg = reply_msg;
301   pending_new_browser_info_map_.insert(
302       std::make_pair(frame_id, std::move(pending)));
303 
304   // Register a timeout for the pending response so that the renderer process
305   // doesn't hang forever.
306   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
307           switches::kDisableNewBrowserInfoTimeout)) {
308     CEF_POST_DELAYED_TASK(
309         CEF_UIT,
310         base::BindOnce(&CefBrowserInfoManager::TimeoutNewBrowserInfoResponse,
311                        frame_id, timeout_id),
312         kNewBrowserInfoResponseTimeoutMs);
313   }
314 }
315 
RemoveBrowserInfo(scoped_refptr<CefBrowserInfo> browser_info)316 void CefBrowserInfoManager::RemoveBrowserInfo(
317     scoped_refptr<CefBrowserInfo> browser_info) {
318   base::AutoLock lock_scope(browser_info_lock_);
319 
320   BrowserInfoList::iterator it = browser_info_list_.begin();
321   for (; it != browser_info_list_.end(); ++it) {
322     if (*it == browser_info) {
323       browser_info_list_.erase(it);
324       return;
325     }
326   }
327 
328   NOTREACHED();
329 }
330 
DestroyAllBrowsers()331 void CefBrowserInfoManager::DestroyAllBrowsers() {
332   BrowserInfoList list;
333 
334   {
335     base::AutoLock lock_scope(browser_info_lock_);
336     list = browser_info_list_;
337   }
338 
339   // Destroy any remaining browser windows.
340   if (!list.empty()) {
341     BrowserInfoList::iterator it = list.begin();
342     for (; it != list.end(); ++it) {
343       CefRefPtr<CefBrowserHostBase> browser = (*it)->browser();
344       DCHECK(browser.get());
345       if (browser.get()) {
346         // DestroyBrowser will call RemoveBrowserInfo.
347         browser->DestroyBrowser();
348       }
349     }
350   }
351 
352 #if DCHECK_IS_ON()
353   {
354     // Verify that all browser windows have been destroyed.
355     base::AutoLock lock_scope(browser_info_lock_);
356     DCHECK(browser_info_list_.empty());
357   }
358 #endif
359 }
360 
361 scoped_refptr<CefBrowserInfo>
GetBrowserInfoForFrameRoute(int render_process_id,int render_routing_id,bool * is_guest_view)362 CefBrowserInfoManager::GetBrowserInfoForFrameRoute(int render_process_id,
363                                                    int render_routing_id,
364                                                    bool* is_guest_view) {
365   base::AutoLock lock_scope(browser_info_lock_);
366   return GetBrowserInfo(render_process_id, render_routing_id, is_guest_view);
367 }
368 
MaybeAllowNavigation(content::RenderFrameHost * opener,const content::OpenURLParams & params,CefRefPtr<CefBrowserHostBase> & browser_out) const369 bool CefBrowserInfoManager::MaybeAllowNavigation(
370     content::RenderFrameHost* opener,
371     const content::OpenURLParams& params,
372     CefRefPtr<CefBrowserHostBase>& browser_out) const {
373   CEF_REQUIRE_UIT();
374 
375   bool is_guest_view = false;
376   auto browser = extensions::GetOwnerBrowserForHost(opener, &is_guest_view);
377   if (!browser) {
378     // Print preview uses a modal dialog where we don't own the WebContents.
379     // Allow that navigation to proceed.
380     return true;
381   }
382 
383   if (!browser->MaybeAllowNavigation(opener, is_guest_view, params)) {
384     return false;
385   }
386 
387   browser_out = browser;
388   return true;
389 }
390 
391 scoped_refptr<CefBrowserInfo>
GetBrowserInfoForFrameTreeNode(int frame_tree_node_id,bool * is_guest_view)392 CefBrowserInfoManager::GetBrowserInfoForFrameTreeNode(int frame_tree_node_id,
393                                                       bool* is_guest_view) {
394   if (is_guest_view)
395     *is_guest_view = false;
396 
397   if (frame_tree_node_id < 0)
398     return nullptr;
399 
400   base::AutoLock lock_scope(browser_info_lock_);
401 
402   for (const auto& browser_info : browser_info_list_) {
403     bool is_guest_view_tmp;
404     auto frame = browser_info->GetFrameForFrameTreeNode(frame_tree_node_id,
405                                                         &is_guest_view_tmp);
406     if (frame || is_guest_view_tmp) {
407       if (is_guest_view)
408         *is_guest_view = is_guest_view_tmp;
409       return browser_info;
410     }
411   }
412 
413   return nullptr;
414 }
415 
416 CefBrowserInfoManager::BrowserInfoList
GetBrowserInfoList()417 CefBrowserInfoManager::GetBrowserInfoList() {
418   base::AutoLock lock_scope(browser_info_lock_);
419   BrowserInfoList copy;
420   copy.assign(browser_info_list_.begin(), browser_info_list_.end());
421   return copy;
422 }
423 
RenderProcessHostDestroyed(content::RenderProcessHost * host)424 void CefBrowserInfoManager::RenderProcessHostDestroyed(
425     content::RenderProcessHost* host) {
426   CEF_REQUIRE_UIT();
427 
428   host->RemoveObserver(this);
429 
430   const int render_process_id = host->GetID();
431   DCHECK_GT(render_process_id, 0);
432 
433   // Remove all pending requests that reference the destroyed host.
434   {
435     base::AutoLock lock_scope(browser_info_lock_);
436 
437     PendingNewBrowserInfoMap::iterator it =
438         pending_new_browser_info_map_.begin();
439     while (it != pending_new_browser_info_map_.end()) {
440       auto info = it->second.get();
441       if (info->render_process_id == render_process_id)
442         it = pending_new_browser_info_map_.erase(it);
443       else
444         ++it;
445     }
446   }
447 
448   // Remove all pending popups that reference the destroyed host as the opener.
449   {
450     PendingPopupList::iterator it = pending_popup_list_.begin();
451     while (it != pending_popup_list_.end()) {
452       PendingPopup* popup = it->get();
453       if (popup->opener_render_process_id == render_process_id) {
454         it = pending_popup_list_.erase(it);
455       } else {
456         ++it;
457       }
458     }
459   }
460 }
461 
PushPendingPopup(std::unique_ptr<PendingPopup> popup)462 void CefBrowserInfoManager::PushPendingPopup(
463     std::unique_ptr<PendingPopup> popup) {
464   CEF_REQUIRE_UIT();
465   pending_popup_list_.push_back(std::move(popup));
466 }
467 
468 std::unique_ptr<CefBrowserInfoManager::PendingPopup>
PopPendingPopup(PendingPopup::Step step,int opener_render_process_id,int opener_render_routing_id,const GURL & target_url)469 CefBrowserInfoManager::PopPendingPopup(PendingPopup::Step step,
470                                        int opener_render_process_id,
471                                        int opener_render_routing_id,
472                                        const GURL& target_url) {
473   CEF_REQUIRE_UIT();
474   DCHECK_GT(opener_render_process_id, 0);
475   DCHECK_GT(opener_render_routing_id, 0);
476 
477   PendingPopupList::iterator it = pending_popup_list_.begin();
478   for (; it != pending_popup_list_.end(); ++it) {
479     PendingPopup* popup = it->get();
480     if (popup->step == step &&
481         popup->opener_render_process_id == opener_render_process_id &&
482         popup->opener_render_routing_id == opener_render_routing_id &&
483         popup->target_url == target_url) {
484       // Transfer ownership of the pointer.
485       it->release();
486       pending_popup_list_.erase(it);
487       return base::WrapUnique(popup);
488     }
489   }
490 
491   return nullptr;
492 }
493 
GetBrowserInfo(int render_process_id,int render_routing_id,bool * is_guest_view)494 scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfo(
495     int render_process_id,
496     int render_routing_id,
497     bool* is_guest_view) {
498   browser_info_lock_.AssertAcquired();
499 
500   if (is_guest_view)
501     *is_guest_view = false;
502 
503   if (render_process_id < 0 || render_routing_id < 0)
504     return nullptr;
505 
506   for (const auto& browser_info : browser_info_list_) {
507     bool is_guest_view_tmp;
508     auto frame = browser_info->GetFrameForRoute(
509         render_process_id, render_routing_id, &is_guest_view_tmp);
510     if (frame || is_guest_view_tmp) {
511       if (is_guest_view)
512         *is_guest_view = is_guest_view_tmp;
513       return browser_info;
514     }
515   }
516 
517   return nullptr;
518 }
519 
520 // static
SendNewBrowserInfoResponse(int render_process_id,scoped_refptr<CefBrowserInfo> browser_info,bool is_guest_view,IPC::Message * reply_msg)521 void CefBrowserInfoManager::SendNewBrowserInfoResponse(
522     int render_process_id,
523     scoped_refptr<CefBrowserInfo> browser_info,
524     bool is_guest_view,
525     IPC::Message* reply_msg) {
526   if (!CEF_CURRENTLY_ON_UIT()) {
527     CEF_POST_TASK(
528         CEF_UIT,
529         base::Bind(&CefBrowserInfoManager::SendNewBrowserInfoResponse,
530                    render_process_id, browser_info, is_guest_view, reply_msg));
531     return;
532   }
533 
534   content::RenderProcessHost* host =
535       content::RenderProcessHost::FromID(render_process_id);
536   if (!host) {
537     delete reply_msg;
538     return;
539   }
540 
541   CefProcessHostMsg_GetNewBrowserInfo_Params params;
542   params.is_guest_view = is_guest_view;
543 
544   if (browser_info) {
545     params.browser_id = browser_info->browser_id();
546     params.is_windowless = browser_info->is_windowless();
547     params.is_popup = browser_info->is_popup();
548 
549     auto extra_info = browser_info->extra_info();
550     if (extra_info) {
551       auto extra_info_impl =
552           static_cast<CefDictionaryValueImpl*>(extra_info.get());
553       auto extra_info_value = extra_info_impl->CopyValue();
554       extra_info_value->Swap(&params.extra_info);
555     }
556   } else {
557     // The new browser info response has timed out.
558     params.browser_id = -1;
559   }
560 
561   CefProcessHostMsg_GetNewBrowserInfo::WriteReplyParams(reply_msg, params);
562   host->Send(reply_msg);
563 }
564 
565 // static
TimeoutNewBrowserInfoResponse(int64_t frame_id,int timeout_id)566 void CefBrowserInfoManager::TimeoutNewBrowserInfoResponse(int64_t frame_id,
567                                                           int timeout_id) {
568   if (!g_info_manager)
569     return;
570 
571   base::AutoLock lock_scope(g_info_manager->browser_info_lock_);
572 
573   // Continue the NewBrowserInfo request if it's still pending.
574   auto it = g_info_manager->pending_new_browser_info_map_.find(frame_id);
575   if (it != g_info_manager->pending_new_browser_info_map_.end()) {
576     const auto& pending_info = it->second;
577     // Don't accidentally timeout a new request for the same frame.
578     if (pending_info->timeout_id != timeout_id)
579       return;
580 
581     LOG(ERROR) << "Timeout of new browser info response for frame process id "
582                << pending_info->render_process_id << " and routing id "
583                << pending_info->render_routing_id;
584 
585     SendNewBrowserInfoResponse(pending_info->render_process_id, nullptr,
586                                false /* is_guest_view */,
587                                pending_info->reply_msg);
588     g_info_manager->pending_new_browser_info_map_.erase(it);
589   }
590 }
591