1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/browser_navigator.h"
6 
7 #include <algorithm>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 
12 #include "base/command_line.h"
13 #include "base/macros.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "build/build_config.h"
16 #include "chrome/browser/browser_about_handler.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/platform_util.h"
19 #include "chrome/browser/prefetch/no_state_prefetch/prerender_manager_factory.h"
20 #include "chrome/browser/prefs/incognito_mode_prefs.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
23 #include "chrome/browser/signin/signin_promo.h"
24 #include "chrome/browser/tab_contents/tab_util.h"
25 #include "chrome/browser/task_manager/web_contents_tags.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_finder.h"
28 #include "chrome/browser/ui/browser_list.h"
29 #include "chrome/browser/ui/browser_navigator_params.h"
30 #include "chrome/browser/ui/browser_window.h"
31 #include "chrome/browser/ui/location_bar/location_bar.h"
32 #include "chrome/browser/ui/singleton_tabs.h"
33 #include "chrome/browser/ui/status_bubble.h"
34 #include "chrome/browser/ui/tab_helpers.h"
35 #include "chrome/browser/ui/tabs/tab_strip_model.h"
36 #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
37 #include "chrome/browser/web_applications/components/web_app_helpers.h"
38 #include "chrome/common/url_constants.h"
39 #include "components/captive_portal/core/buildflags.h"
40 #include "components/no_state_prefetch/browser/prerender_manager.h"
41 #include "components/prefs/pref_service.h"
42 #include "content/public/browser/browser_url_handler.h"
43 #include "content/public/browser/navigation_entry.h"
44 #include "content/public/browser/notification_service.h"
45 #include "content/public/browser/render_frame_host.h"
46 #include "content/public/browser/render_process_host.h"
47 #include "content/public/browser/render_view_host.h"
48 #include "content/public/browser/web_contents.h"
49 #include "extensions/buildflags/buildflags.h"
50 #include "url/url_constants.h"
51 
52 #if defined(OS_CHROMEOS)
53 #include "ash/public/cpp/multi_user_window_manager.h"
54 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
55 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
56 #include "components/account_id/account_id.h"
57 #endif
58 
59 #if defined(USE_AURA)
60 #include "ui/aura/window.h"
61 #endif
62 
63 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
64 #include "components/captive_portal/content/captive_portal_tab_helper.h"
65 #endif
66 
67 #if BUILDFLAG(ENABLE_EXTENSIONS)
68 #include "chrome/browser/apps/app_service/launch_utils.h"
69 #include "chrome/browser/web_applications/components/web_app_helpers.h"
70 #include "extensions/common/extension.h"
71 #endif
72 
73 using content::GlobalRequestID;
74 using content::NavigationController;
75 using content::WebContents;
76 
77 class BrowserNavigatorWebContentsAdoption {
78  public:
AttachTabHelpers(content::WebContents * contents)79   static void AttachTabHelpers(content::WebContents* contents) {
80     TabHelpers::AttachTabHelpers(contents);
81 
82     // Make the tab show up in the task manager.
83     task_manager::WebContentsTags::CreateForTabContents(contents);
84   }
85 };
86 
87 namespace {
88 
89 bool allow_os_settings_in_tab = false;
90 
91 // Returns true if |params.browser| exists and can open a new tab for
92 // |params.url|. Not all browsers support multiple tabs, such as app frames and
93 // popups. TYPE_APP will only open a new tab if the URL is within the app scope.
WindowCanOpenTabs(const NavigateParams & params)94 bool WindowCanOpenTabs(const NavigateParams& params) {
95   if (!params.browser)
96     return false;
97 
98   if (params.browser->app_controller() &&
99       !params.browser->app_controller()->IsUrlInAppScope(params.url)) {
100     return false;
101   }
102 
103   return params.browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP) ||
104          params.browser->tab_strip_model()->empty();
105 }
106 
107 // Finds an existing Browser compatible with |profile|, making a new one if no
108 // such Browser is located.
GetOrCreateBrowser(Profile * profile,bool user_gesture)109 Browser* GetOrCreateBrowser(Profile* profile, bool user_gesture) {
110   Browser* browser = chrome::FindTabbedBrowser(profile, false);
111   return browser
112              ? browser
113              : Browser::Create(Browser::CreateParams(profile, user_gesture));
114 }
115 
116 // Change some of the navigation parameters based on the particular URL.
117 // Currently this applies to some chrome:// pages which we always want to open
118 // in a non-incognito window. Note that even though a ChromeOS guest session is
119 // technically an incognito window, these URLs are allowed.
120 // Returns true on success. Otherwise, if changing params leads the browser into
121 // an erroneous state, returns false.
AdjustNavigateParamsForURL(NavigateParams * params)122 bool AdjustNavigateParamsForURL(NavigateParams* params) {
123   if (params->contents_to_insert || params->switch_to_singleton_tab ||
124       IsURLAllowedInIncognito(params->url, params->initiating_profile) ||
125       params->initiating_profile->IsGuestSession()) {
126     return true;
127   }
128 
129   Profile* profile = params->initiating_profile;
130 
131   if (profile->IsOffTheRecord() ||
132       params->disposition == WindowOpenDisposition::OFF_THE_RECORD) {
133     profile = profile->GetOriginalProfile();
134 
135     // If incognito is forced, we punt.
136     PrefService* prefs = profile->GetPrefs();
137     if (prefs && IncognitoModePrefs::GetAvailability(prefs) ==
138                      IncognitoModePrefs::FORCED) {
139       return false;
140     }
141 
142     params->disposition = WindowOpenDisposition::SINGLETON_TAB;
143     params->browser = GetOrCreateBrowser(profile, params->user_gesture);
144     params->window_action = NavigateParams::SHOW_WINDOW;
145   }
146 
147   return true;
148 }
149 
150 // Returns a Browser and tab index. The browser can host the navigation or
151 // tab addition specified in |params|.  This might just return the same
152 // Browser specified in |params|, or some other if that Browser is deemed
153 // incompatible. The tab index will be -1 unless a singleton or tab switch
154 // was requested, in which case it might be the target tab index, or -1
155 // if not found.
GetBrowserAndTabForDisposition(const NavigateParams & params)156 std::pair<Browser*, int> GetBrowserAndTabForDisposition(
157     const NavigateParams& params) {
158   Profile* profile = params.initiating_profile;
159 
160 #if BUILDFLAG(ENABLE_EXTENSIONS)
161   if (params.open_pwa_window_if_possible) {
162     base::Optional<web_app::AppId> app_id =
163         web_app::FindInstalledAppWithUrlInScope(profile, params.url,
164                                                 /*window_only=*/true);
165     if (app_id) {
166       std::string app_name = web_app::GenerateApplicationNameFromAppId(*app_id);
167       return {
168           Browser::Create(Browser::CreateParams::CreateForApp(
169               app_name,
170               true,  // trusted_source. Installed PWAs are considered trusted.
171               params.window_bounds, profile, params.user_gesture)),
172           -1};
173     }
174   }
175 #endif
176 
177   switch (params.disposition) {
178     case WindowOpenDisposition::SWITCH_TO_TAB:
179 #if !defined(OS_ANDROID)
180     {
181       std::pair<Browser*, int> index =
182           GetIndexAndBrowserOfExistingTab(profile, params);
183       if (index.first)
184         return index;
185     }
186 #endif
187       FALLTHROUGH;
188     case WindowOpenDisposition::CURRENT_TAB:
189       if (params.browser)
190         return {params.browser, -1};
191       // Find a compatible window and re-execute this command in it. Otherwise
192       // re-run with NEW_WINDOW.
193       return {GetOrCreateBrowser(profile, params.user_gesture), -1};
194     case WindowOpenDisposition::SINGLETON_TAB: {
195       // If we have a browser window, check it first.
196       if (params.browser) {
197         int index = GetIndexOfExistingTab(params.browser, params);
198         if (index >= 0)
199           return {params.browser, index};
200       }
201       // If we don't have a a window, or if this window can't open tabs, then
202       // it would load in a random window, potentially opening a second copy.
203       // Instead, make an extra effort to see if there's an already open copy.
204       if (!WindowCanOpenTabs(params)) {
205         std::pair<Browser*, int> index =
206             GetIndexAndBrowserOfExistingTab(profile, params);
207         if (index.first)
208           return index;
209       }
210     }
211       FALLTHROUGH;
212     case WindowOpenDisposition::NEW_FOREGROUND_TAB:
213     case WindowOpenDisposition::NEW_BACKGROUND_TAB:
214       // See if we can open the tab in the window this navigator is bound to.
215       if (WindowCanOpenTabs(params))
216         return {params.browser, -1};
217 
218       // Find a compatible window and re-execute this command in it. Otherwise
219       // re-run with NEW_WINDOW.
220       return {GetOrCreateBrowser(profile, params.user_gesture), -1};
221     case WindowOpenDisposition::NEW_POPUP: {
222       // Make a new popup window.
223       // Coerce app-style if |source| represents an app.
224       std::string app_name;
225 #if BUILDFLAG(ENABLE_EXTENSIONS)
226       if (!params.extension_app_id.empty()) {
227         app_name =
228             web_app::GenerateApplicationNameFromAppId(params.extension_app_id);
229       } else if (params.browser && !params.browser->app_name().empty()) {
230         app_name = params.browser->app_name();
231       }
232 #endif
233       if (app_name.empty()) {
234         Browser::CreateParams browser_params(Browser::TYPE_POPUP, profile,
235                                              params.user_gesture);
236         browser_params.trusted_source = params.trusted_source;
237         browser_params.initial_bounds = params.window_bounds;
238         return {Browser::Create(browser_params), -1};
239       }
240       return {Browser::Create(Browser::CreateParams::CreateForAppPopup(
241                   app_name, params.trusted_source, params.window_bounds,
242                   profile, params.user_gesture)),
243               -1};
244     }
245     case WindowOpenDisposition::NEW_WINDOW:
246       // Make a new normal browser window.
247       return {
248           Browser::Create(Browser::CreateParams(profile, params.user_gesture)),
249           -1};
250     case WindowOpenDisposition::OFF_THE_RECORD:
251       // Make or find an incognito window.
252       return {GetOrCreateBrowser(profile->GetPrimaryOTRProfile(),
253                                  params.user_gesture),
254               -1};
255     // The following types result in no navigation.
256     case WindowOpenDisposition::SAVE_TO_DISK:
257     case WindowOpenDisposition::IGNORE_ACTION:
258       return {nullptr, -1};
259     default:
260       NOTREACHED();
261   }
262   return {nullptr, -1};
263 }
264 
265 // Fix disposition and other parameter values depending on prevailing
266 // conditions.
NormalizeDisposition(NavigateParams * params)267 void NormalizeDisposition(NavigateParams* params) {
268   // Calculate the WindowOpenDisposition if necessary.
269   if (params->browser->tab_strip_model()->empty() &&
270       (params->disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
271        params->disposition == WindowOpenDisposition::CURRENT_TAB ||
272        params->disposition == WindowOpenDisposition::SINGLETON_TAB)) {
273     params->disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
274   }
275   if (params->browser->profile()->IsOffTheRecord() &&
276       params->disposition == WindowOpenDisposition::OFF_THE_RECORD) {
277     params->disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
278   }
279   if (!params->source_contents &&
280       params->disposition == WindowOpenDisposition::CURRENT_TAB)
281     params->disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
282 
283   switch (params->disposition) {
284     case WindowOpenDisposition::NEW_BACKGROUND_TAB:
285       // Disposition trumps add types. ADD_ACTIVE is a default, so we need to
286       // remove it if disposition implies the tab is going to open in the
287       // background.
288       params->tabstrip_add_types &= ~TabStripModel::ADD_ACTIVE;
289       break;
290 
291     case WindowOpenDisposition::NEW_WINDOW:
292     case WindowOpenDisposition::NEW_POPUP: {
293       // Code that wants to open a new window typically expects it to be shown
294       // automatically.
295       if (params->window_action == NavigateParams::NO_ACTION)
296         params->window_action = NavigateParams::SHOW_WINDOW;
297       FALLTHROUGH;
298     }
299     case WindowOpenDisposition::NEW_FOREGROUND_TAB:
300     case WindowOpenDisposition::SINGLETON_TAB:
301       params->tabstrip_add_types |= TabStripModel::ADD_ACTIVE;
302       break;
303 
304     default:
305       break;
306   }
307 }
308 
309 // Obtain the profile used by the code that originated the Navigate() request.
GetSourceProfile(NavigateParams * params)310 Profile* GetSourceProfile(NavigateParams* params) {
311   // |source_site_instance| needs to be checked before |source_contents|. This
312   // might matter when chrome.windows.create is used to open multiple URLs,
313   // which would reuse |params| and modify |params->source_contents| across
314   // navigations.
315   if (params->source_site_instance) {
316     return Profile::FromBrowserContext(
317         params->source_site_instance->GetBrowserContext());
318   }
319 
320   if (params->source_contents) {
321     return Profile::FromBrowserContext(
322         params->source_contents->GetBrowserContext());
323   }
324 
325   return params->initiating_profile;
326 }
327 
LoadURLInContents(WebContents * target_contents,const GURL & url,NavigateParams * params)328 void LoadURLInContents(WebContents* target_contents,
329                        const GURL& url,
330                        NavigateParams* params) {
331   NavigationController::LoadURLParams load_url_params(url);
332   load_url_params.initiator_routing_id = params->initiator_routing_id;
333   load_url_params.initiator_origin = params->initiator_origin;
334   load_url_params.source_site_instance = params->source_site_instance;
335   load_url_params.referrer = params->referrer;
336   load_url_params.frame_name = params->frame_name;
337   load_url_params.frame_tree_node_id = params->frame_tree_node_id;
338   load_url_params.redirect_chain = params->redirect_chain;
339   load_url_params.transition_type = params->transition;
340   load_url_params.extra_headers = params->extra_headers;
341   load_url_params.should_replace_current_entry =
342       params->should_replace_current_entry;
343   load_url_params.is_renderer_initiated = params->is_renderer_initiated;
344   load_url_params.started_from_context_menu = params->started_from_context_menu;
345   load_url_params.has_user_gesture = params->user_gesture;
346   load_url_params.blob_url_loader_factory = params->blob_url_loader_factory;
347   load_url_params.input_start = params->input_start;
348   load_url_params.was_activated = params->was_activated;
349   load_url_params.href_translate = params->href_translate;
350   load_url_params.reload_type = params->reload_type;
351   load_url_params.impression = params->impression;
352 
353   // |frame_tree_node_id| is kNoFrameTreeNodeId for main frame navigations.
354   if (params->frame_tree_node_id ==
355       content::RenderFrameHost::kNoFrameTreeNodeId) {
356     load_url_params.navigation_ui_data =
357         ChromeNavigationUIData::CreateForMainFrameNavigation(
358             target_contents, params->disposition);
359   }
360 
361   if (params->post_data) {
362     load_url_params.load_type = NavigationController::LOAD_TYPE_HTTP_POST;
363     load_url_params.post_data = params->post_data;
364   }
365 
366   target_contents->GetController().LoadURLWithParams(load_url_params);
367 }
368 
369 // This class makes sure the Browser object held in |params| is made visible
370 // by the time it goes out of scope, provided |params| wants it to be shown.
371 class ScopedBrowserShower {
372  public:
ScopedBrowserShower(NavigateParams * params,content::WebContents ** contents)373   explicit ScopedBrowserShower(NavigateParams* params,
374                                content::WebContents** contents)
375       : params_(params), contents_(contents) {}
~ScopedBrowserShower()376   ~ScopedBrowserShower() {
377     if (params_->window_action == NavigateParams::SHOW_WINDOW_INACTIVE) {
378       params_->browser->window()->ShowInactive();
379     } else if (params_->window_action == NavigateParams::SHOW_WINDOW) {
380       BrowserWindow* window = params_->browser->window();
381       window->Show();
382       // If a user gesture opened a popup window, focus the contents.
383       if (params_->user_gesture &&
384           params_->disposition == WindowOpenDisposition::NEW_POPUP &&
385           *contents_) {
386         (*contents_)->Focus();
387         window->Activate();
388       }
389     }
390   }
391 
392  private:
393   NavigateParams* params_;
394   content::WebContents** contents_;
395   DISALLOW_COPY_AND_ASSIGN(ScopedBrowserShower);
396 };
397 
CreateTargetContents(const NavigateParams & params,const GURL & url)398 std::unique_ptr<content::WebContents> CreateTargetContents(
399     const NavigateParams& params,
400     const GURL& url) {
401   // Always create the new WebContents in a new SiteInstance (and therefore a
402   // new BrowsingInstance), *unless* there's a |params.opener|.
403   //
404   // Note that the SiteInstance below is only for the "initial" placement of the
405   // new WebContents (i.e. if subsequent navigation [including the initial
406   // navigation] triggers a cross-process transfer, then the opener and new
407   // contents can end up in separate processes).  This is fine, because even if
408   // subsequent navigation is cross-process (i.e. cross-SiteInstance), then it
409   // will stay in the same BrowsingInstance (creating frame proxies as needed)
410   // preserving the requested opener relationship along the way.
411   scoped_refptr<content::SiteInstance> initial_site_instance_for_new_contents =
412       params.opener
413           ? params.opener->GetSiteInstance()
414           : tab_util::GetSiteInstanceForNewTab(params.browser->profile(), url);
415 
416   WebContents::CreateParams create_params(
417       params.browser->profile(), initial_site_instance_for_new_contents);
418   create_params.main_frame_name = params.frame_name;
419   if (params.opener) {
420     create_params.opener_render_frame_id = params.opener->GetRoutingID();
421     create_params.opener_render_process_id =
422         params.opener->GetProcess()->GetID();
423   }
424   if (params.source_contents) {
425     create_params.created_with_opener = params.created_with_opener;
426   }
427   if (params.disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB)
428     create_params.initially_hidden = true;
429 
430 #if defined(USE_AURA)
431   if (params.browser->window() && params.browser->window()->GetNativeWindow())
432     create_params.context = params.browser->window()->GetNativeWindow();
433 #endif
434 
435   std::unique_ptr<WebContents> target_contents =
436       WebContents::Create(create_params);
437 
438   // New tabs can have WebUI URLs that will make calls back to arbitrary
439   // tab helpers, so the entire set of tab helpers needs to be set up
440   // immediately.
441   BrowserNavigatorWebContentsAdoption::AttachTabHelpers(target_contents.get());
442 #if BUILDFLAG(ENABLE_EXTENSIONS)
443   apps::SetAppIdForWebContents(params.browser->profile(), target_contents.get(),
444                                params.extension_app_id);
445 #endif
446 
447 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
448   if (params.is_captive_portal_popup) {
449     DCHECK_EQ(WindowOpenDisposition::NEW_POPUP, params.disposition);
450     captive_portal::CaptivePortalTabHelper::FromWebContents(
451         target_contents.get())
452         ->set_is_captive_portal_window();
453   }
454 #endif
455 
456   return target_contents;
457 }
458 
459 }  // namespace
460 
Navigate(NavigateParams * params)461 void Navigate(NavigateParams* params) {
462   Browser* source_browser = params->browser;
463   if (source_browser)
464     params->initiating_profile = source_browser->profile();
465   DCHECK(params->initiating_profile);
466 
467   if (source_browser &&
468       platform_util::IsBrowserLockedFullscreen(source_browser)) {
469     // Block any navigation requests in locked fullscreen mode.
470     return;
471   }
472 
473   // Open System Apps in their standalone window if necessary.
474   // TODO(crbug.com/1096345): Remove this code after we integrate with intent
475   // handling.
476   const base::Optional<web_app::SystemAppType> capturing_system_app_type =
477       web_app::GetCapturingSystemAppForURL(params->initiating_profile,
478                                            params->url);
479   if (capturing_system_app_type &&
480       (!params->browser ||
481        !web_app::IsBrowserForSystemWebApp(params->browser,
482                                           capturing_system_app_type.value()))) {
483     params->browser = web_app::LaunchSystemWebApp(
484         params->initiating_profile, capturing_system_app_type.value(),
485         params->url);
486 
487     // It's okay to early return here, because LaunchSystemWebApp uses a
488     // different logic to choose (and create if necessary) a browser window for
489     // system apps.
490     //
491     // It's okay to skip the checks and cleanups below. The link captured system
492     // app will either open in its own browser window, or navigate an existing
493     // browser window exclusively used by this app. For the initiating browser,
494     // the navigation should appear to be cancelled.
495     return;
496   }
497 
498   if (!AdjustNavigateParamsForURL(params))
499     return;
500 
501   // Trying to open a background tab when in an app browser results in
502   // focusing a regular browser window and opening a tab in the background
503   // of that window. Change the disposition to NEW_FOREGROUND_TAB so that
504   // the new tab is focused.
505   if (source_browser && source_browser->is_type_app() &&
506       params->disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) {
507     params->disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
508   }
509 
510   // If no source WebContents was specified, we use the selected one from
511   // the target browser. This must happen first, before
512   // GetBrowserForDisposition() has a chance to replace |params->browser| with
513   // another one.
514   if (!params->source_contents && params->browser) {
515     params->source_contents =
516         params->browser->tab_strip_model()->GetActiveWebContents();
517   }
518 
519   WebContents* contents_to_navigate_or_insert =
520       params->contents_to_insert.get();
521   if (params->switch_to_singleton_tab) {
522     DCHECK_EQ(params->disposition, WindowOpenDisposition::SINGLETON_TAB);
523     contents_to_navigate_or_insert = params->switch_to_singleton_tab;
524   }
525   int singleton_index;
526   std::tie(params->browser, singleton_index) =
527       GetBrowserAndTabForDisposition(*params);
528   if (!params->browser)
529     return;
530   if (singleton_index != -1) {
531     contents_to_navigate_or_insert =
532         params->browser->tab_strip_model()->GetWebContentsAt(singleton_index);
533   } else if (params->disposition == WindowOpenDisposition::SWITCH_TO_TAB) {
534     // The user is trying to open a tab that no longer exists. If we open a new
535     // tab, it could leave orphaned NTPs around, but always overwriting the
536     // current tab could could clobber state that the user was trying to
537     // preserve. Fallback to the behavior used for singletons: overwrite the
538     // current tab if it's the NTP, otherwise open a new tab.
539     params->disposition = WindowOpenDisposition::SINGLETON_TAB;
540     ShowSingletonTabOverwritingNTP(params->browser, std::move(*params));
541     return;
542   }
543 #if defined(OS_CHROMEOS)
544   if (source_browser) {
545     // Open OS settings in PWA, even when user types in URL bar.
546     if (params->url.GetOrigin() ==
547             GURL(chrome::kChromeUIOSSettingsURL).GetOrigin() &&
548         !allow_os_settings_in_tab) {
549       chrome::SettingsWindowManager* settings_window_manager =
550           chrome::SettingsWindowManager::GetInstance();
551       if (!settings_window_manager->IsSettingsBrowser(source_browser)) {
552         settings_window_manager->ShowChromePageForProfile(
553             GetSourceProfile(params), params->url);
554         return;
555       }
556     }
557 
558     if (source_browser != params->browser) {
559       // When the newly created browser was spawned by a browser which visits
560       // another user's desktop, it should be shown on the same desktop as the
561       // originating one. (This is part of the desktop separation per profile).
562       auto* window_manager = MultiUserWindowManagerHelper::GetWindowManager();
563       // Some unit tests have no client instantiated.
564       if (window_manager) {
565         aura::Window* src_window = source_browser->window()->GetNativeWindow();
566         aura::Window* new_window = params->browser->window()->GetNativeWindow();
567         const AccountId& src_account_id =
568             window_manager->GetUserPresentingWindow(src_window);
569         if (src_account_id !=
570             window_manager->GetUserPresentingWindow(new_window)) {
571           // Once the window gets presented, it should be shown on the same
572           // desktop as the desktop of the creating browser. Note that this
573           // command will not show the window if it wasn't shown yet by the
574           // browser creation.
575           window_manager->ShowWindowForUser(new_window, src_account_id);
576         }
577       }
578     }
579   }
580 #endif
581 
582   // Navigate() must not return early after this point.
583 
584   if (GetSourceProfile(params) != params->browser->profile()) {
585     // A tab is being opened from a link from a different profile, we must reset
586     // source information that may cause state to be shared.
587     params->opener = nullptr;
588     params->source_contents = nullptr;
589     params->source_site_instance = nullptr;
590     params->referrer = content::Referrer();
591   }
592 
593   // Make sure the Browser is shown if params call for it.
594   ScopedBrowserShower shower(params, &contents_to_navigate_or_insert);
595 
596   // Makes sure any WebContents created by this function is destroyed if
597   // not properly added to a tab strip.
598   std::unique_ptr<WebContents> contents_to_insert =
599       std::move(params->contents_to_insert);
600 
601   // Some dispositions need coercion to base types.
602   NormalizeDisposition(params);
603 
604   // If a new window has been created, it needs to be shown.
605   if (params->window_action == NavigateParams::NO_ACTION &&
606       source_browser != params->browser &&
607       params->browser->tab_strip_model()->empty()) {
608     params->window_action = NavigateParams::SHOW_WINDOW;
609   }
610 
611   // If we create a popup window from a non user-gesture, don't activate it.
612   if (params->window_action == NavigateParams::SHOW_WINDOW &&
613       params->disposition == WindowOpenDisposition::NEW_POPUP &&
614       params->user_gesture == false) {
615     params->window_action = NavigateParams::SHOW_WINDOW_INACTIVE;
616   }
617 
618   // Determine if the navigation was user initiated. If it was, we need to
619   // inform the target WebContents, and we may need to update the UI.
620   bool user_initiated =
621       params->transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR ||
622       !ui::PageTransitionIsWebTriggerable(params->transition);
623 
624   // If no target WebContents was specified (and we didn't seek and find a
625   // singleton), we need to construct one if we are supposed to target a new
626   // tab.
627   if (!contents_to_navigate_or_insert) {
628     DCHECK(!params->url.is_empty());
629     if (params->disposition != WindowOpenDisposition::CURRENT_TAB) {
630       contents_to_insert = CreateTargetContents(*params, params->url);
631       contents_to_navigate_or_insert = contents_to_insert.get();
632     } else {
633       // ... otherwise if we're loading in the current tab, the target is the
634       // same as the source.
635       DCHECK(params->source_contents);
636       contents_to_navigate_or_insert = params->source_contents;
637     }
638 
639     // Try to handle non-navigational URLs that popup dialogs and such, these
640     // should not actually navigate.
641     if (!HandleNonNavigationAboutURL(params->url)) {
642       // Perform the actual navigation, tracking whether it came from the
643       // renderer.
644 
645       LoadURLInContents(contents_to_navigate_or_insert, params->url, params);
646     }
647   } else {
648     // |contents_to_navigate_or_insert| was specified non-NULL, and so we assume
649     // it has already been navigated appropriately. We need to do nothing more
650     // other than add it to the appropriate tabstrip.
651   }
652 
653   // If the user navigated from the omnibox, and the selected tab is going to
654   // lose focus, then make sure the focus for the source tab goes away from the
655   // omnibox.
656   if (params->source_contents &&
657       (params->disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
658        params->disposition == WindowOpenDisposition::NEW_WINDOW) &&
659       (params->tabstrip_add_types & TabStripModel::ADD_INHERIT_OPENER))
660     params->source_contents->Focus();
661 
662   if (params->source_contents == contents_to_navigate_or_insert) {
663     // The navigation occurred in the source tab.
664     params->browser->UpdateUIForNavigationInTab(
665         contents_to_navigate_or_insert, params->transition,
666         params->window_action, user_initiated);
667   } else if (singleton_index == -1) {
668     if (source_browser != params->browser)
669       params->tabstrip_index = params->browser->tab_strip_model()->count();
670 
671     // If some non-default value is set for the index, we should tell the
672     // TabStripModel to respect it.
673     if (params->tabstrip_index != -1)
674       params->tabstrip_add_types |= TabStripModel::ADD_FORCE_INDEX;
675 
676     // Maybe notify that an open operation has been done from a gesture.
677     // TODO(crbug.com/1129028): preferably pipe this information through the
678     // TabStripModel instead. See bug for deeper discussion.
679     if (params->user_gesture && source_browser == params->browser)
680       params->browser->window()->LinkOpeningFromGesture(params->disposition);
681 
682     DCHECK(contents_to_insert);
683     // The navigation should insert a new tab into the target Browser.
684     params->browser->tab_strip_model()->AddWebContents(
685         std::move(contents_to_insert), params->tabstrip_index,
686         params->transition, params->tabstrip_add_types, params->group);
687   }
688 
689   if (singleton_index >= 0) {
690     // If switching browsers, make sure it is shown.
691     if (params->disposition == WindowOpenDisposition::SWITCH_TO_TAB &&
692         params->browser != source_browser)
693       params->window_action = NavigateParams::SHOW_WINDOW;
694 
695     if (contents_to_navigate_or_insert->IsCrashed()) {
696       contents_to_navigate_or_insert->GetController().Reload(
697           content::ReloadType::NORMAL, true);
698     } else if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE &&
699                contents_to_navigate_or_insert->GetURL() != params->url) {
700       LoadURLInContents(contents_to_navigate_or_insert, params->url, params);
701     }
702 
703     // If the singleton tab isn't already selected, select it.
704     if (params->source_contents != contents_to_navigate_or_insert) {
705       // Use the index before the potential close below, because it could
706       // make the index refer to a different tab.
707       auto gesture_type = user_initiated ? TabStripModel::GestureType::kOther
708                                          : TabStripModel::GestureType::kNone;
709       bool should_close_this_tab = false;
710       if (params->disposition == WindowOpenDisposition::SWITCH_TO_TAB) {
711         // Close orphaned NTP (and the like) with no history when the user
712         // switches away from them.
713         if (params->source_contents->GetController().CanGoBack() ||
714             (params->source_contents->GetLastCommittedURL().spec() !=
715                  chrome::kChromeUINewTabURL &&
716              params->source_contents->GetLastCommittedURL().spec() !=
717                  chrome::kChromeSearchLocalNtpUrl &&
718              params->source_contents->GetLastCommittedURL().spec() !=
719                  url::kAboutBlankURL)) {
720           // Blur location bar before state save in ActivateTabAt() below.
721           params->source_contents->Focus();
722         } else {
723           should_close_this_tab = true;
724         }
725       }
726       params->browser->tab_strip_model()->ActivateTabAt(singleton_index,
727                                                         {gesture_type});
728       // Close tab after switch so index remains correct.
729       if (should_close_this_tab)
730         params->source_contents->Close();
731     }
732   }
733 
734   params->navigated_or_inserted_contents = contents_to_navigate_or_insert;
735 }
736 
IsHostAllowedInIncognito(const GURL & url)737 bool IsHostAllowedInIncognito(const GURL& url) {
738   std::string scheme = url.scheme();
739   base::StringPiece host = url.host_piece();
740   if (scheme == chrome::kChromeSearchScheme) {
741     return host != chrome::kChromeUIThumbnailHost &&
742            host != chrome::kChromeUIThumbnailHost2 &&
743            host != chrome::kChromeUIThumbnailListHost &&
744            host != chrome::kChromeUISuggestionsHost;
745   }
746 
747   if (scheme != content::kChromeUIScheme)
748     return true;
749 
750   if (host == chrome::kChromeUIChromeSigninHost) {
751 #if defined(OS_WIN)
752     // Allow incognito mode for the chrome-signin url if we only want to
753     // retrieve the login scope token without touching any profiles. This
754     // option is only available on Windows for use with Google Credential
755     // Provider for Windows.
756     return signin::GetSigninReasonForEmbeddedPromoURL(url) ==
757            signin_metrics::Reason::REASON_FETCH_LST_ONLY;
758 #else
759     return false;
760 #endif  // defined(OS_WIN)
761   }
762 
763   // Most URLs are allowed in incognito; the following are exceptions.
764   // chrome://extensions is on the list because it redirects to
765   // chrome://settings.
766   return host != chrome::kChromeUIAppLauncherPageHost &&
767          host != chrome::kChromeUISettingsHost &&
768 #if defined(OS_CHROMEOS)
769          host != chrome::kChromeUIOSSettingsHost &&
770 #endif
771          host != chrome::kChromeUIHelpHost &&
772          host != chrome::kChromeUIHistoryHost &&
773          host != chrome::kChromeUIExtensionsHost &&
774          host != chrome::kChromeUIBookmarksHost &&
775          host != chrome::kChromeUIThumbnailHost &&
776          host != chrome::kChromeUIThumbnailHost2 &&
777          host != chrome::kChromeUIThumbnailListHost &&
778          host != chrome::kChromeUISuggestionsHost &&
779          host != chrome::kChromeUIDevicesHost &&
780          host != chrome::kChromeUINewTabPageHost;
781 }
782 
IsURLAllowedInIncognito(const GURL & url,content::BrowserContext * browser_context)783 bool IsURLAllowedInIncognito(const GURL& url,
784                              content::BrowserContext* browser_context) {
785   if (url.scheme() == content::kViewSourceScheme) {
786     // A view-source URL is allowed in incognito mode only if the URL itself
787     // is allowed in incognito mode. Remove the "view-source:" from the start
788     // of the URL and validate the rest.
789     std::string stripped_spec = url.spec();
790     DCHECK_GT(stripped_spec.size(), strlen(content::kViewSourceScheme));
791     stripped_spec.erase(0, strlen(content::kViewSourceScheme) + 1);
792     GURL stripped_url(stripped_spec);
793     return stripped_url.is_valid() &&
794            IsURLAllowedInIncognito(stripped_url, browser_context);
795   }
796 
797   return IsHostAllowedInIncognito(url);
798 }
799 
SetAllowOsSettingsInTabForTesting(bool is_allowed)800 void SetAllowOsSettingsInTabForTesting(bool is_allowed) {
801   allow_os_settings_in_tab = is_allowed;
802 }
803