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