Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / browser_navigator.cc
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
9 #include "base/command_line.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browser_about_handler.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/google/google_url_tracker.h"
18 #include "chrome/browser/prefs/incognito_mode_prefs.h"
19 #include "chrome/browser/prerender/prerender_manager.h"
20 #include "chrome/browser/prerender/prerender_manager_factory.h"
21 #include "chrome/browser/prerender/prerender_util.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/tab_contents/tab_util.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_finder.h"
26 #include "chrome/browser/ui/browser_instant_controller.h"
27 #include "chrome/browser/ui/browser_window.h"
28 #include "chrome/browser/ui/host_desktop.h"
29 #include "chrome/browser/ui/omnibox/location_bar.h"
30 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
31 #include "chrome/browser/ui/singleton_tabs.h"
32 #include "chrome/browser/ui/status_bubble.h"
33 #include "chrome/browser/ui/tab_helpers.h"
34 #include "chrome/browser/ui/tabs/tab_strip_model.h"
35 #include "chrome/browser/web_applications/web_app.h"
36 #include "chrome/common/pref_names.h"
37 #include "chrome/common/url_constants.h"
38 #include "content/public/browser/browser_url_handler.h"
39 #include "content/public/browser/navigation_entry.h"
40 #include "content/public/browser/notification_service.h"
41 #include "content/public/browser/render_view_host.h"
42 #include "content/public/browser/web_contents.h"
43 #include "content/public/browser/web_contents_view.h"
44 #include "extensions/common/extension.h"
45
46 #if defined(USE_ASH)
47 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
48 #endif
49 #if defined(USE_AURA)
50 #include "ui/aura/window.h"
51 #endif
52
53 using content::GlobalRequestID;
54 using content::NavigationController;
55 using content::WebContents;
56
57 class BrowserNavigatorWebContentsAdoption {
58  public:
59   static void AttachTabHelpers(content::WebContents* contents) {
60     TabHelpers::AttachTabHelpers(contents);
61   }
62 };
63
64 namespace {
65
66 // Returns true if the specified Browser can open tabs. Not all Browsers support
67 // multiple tabs, such as app frames and popups. This function returns false for
68 // those types of Browser.
69 bool WindowCanOpenTabs(Browser* browser) {
70   return browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP) ||
71       browser->tab_strip_model()->empty();
72 }
73
74 // Finds an existing Browser compatible with |profile|, making a new one if no
75 // such Browser is located.
76 Browser* GetOrCreateBrowser(Profile* profile,
77                             chrome::HostDesktopType host_desktop_type) {
78   Browser* browser = chrome::FindTabbedBrowser(profile, false,
79                                                host_desktop_type);
80   return browser ? browser : new Browser(
81       Browser::CreateParams(profile, host_desktop_type));
82 }
83
84 // Change some of the navigation parameters based on the particular URL.
85 // Currently this applies to some chrome:// pages which we always want to open
86 // in a non-incognito window. Note that even though a ChromeOS guest session is
87 // technically an incognito window, these URLs are allowed.
88 // Returns true on success. Otherwise, if changing params leads the browser into
89 // an erroneous state, returns false.
90 bool AdjustNavigateParamsForURL(chrome::NavigateParams* params) {
91   if (params->target_contents != NULL ||
92       chrome::IsURLAllowedInIncognito(params->url,
93                                       params->initiating_profile) ||
94       params->initiating_profile->IsGuestSession()) {
95     return true;
96   }
97
98   Profile* profile = params->initiating_profile;
99
100   if (profile->IsOffTheRecord() || params->disposition == OFF_THE_RECORD) {
101     profile = profile->GetOriginalProfile();
102
103     // If incognito is forced, we punt.
104     PrefService* prefs = profile->GetPrefs();
105     if (prefs && IncognitoModePrefs::GetAvailability(prefs) ==
106             IncognitoModePrefs::FORCED) {
107       return false;
108     }
109
110     params->disposition = SINGLETON_TAB;
111     params->browser = GetOrCreateBrowser(profile, params->host_desktop_type);
112     params->window_action = chrome::NavigateParams::SHOW_WINDOW;
113   }
114
115   return true;
116 }
117
118 // Returns a Browser that can host the navigation or tab addition specified in
119 // |params|. This might just return the same Browser specified in |params|, or
120 // some other if that Browser is deemed incompatible.
121 Browser* GetBrowserForDisposition(chrome::NavigateParams* params) {
122   // If no source WebContents was specified, we use the selected one from
123   // the target browser. This must happen first, before
124   // GetBrowserForDisposition() has a chance to replace |params->browser| with
125   // another one.
126   if (!params->source_contents && params->browser) {
127     params->source_contents =
128         params->browser->tab_strip_model()->GetActiveWebContents();
129   }
130
131   Profile* profile = params->initiating_profile;
132
133   switch (params->disposition) {
134     case CURRENT_TAB:
135       if (params->browser)
136         return params->browser;
137       // Find a compatible window and re-execute this command in it. Otherwise
138       // re-run with NEW_WINDOW.
139       return GetOrCreateBrowser(profile, params->host_desktop_type);
140     case SINGLETON_TAB:
141     case NEW_FOREGROUND_TAB:
142     case NEW_BACKGROUND_TAB:
143       // See if we can open the tab in the window this navigator is bound to.
144       if (params->browser && WindowCanOpenTabs(params->browser))
145         return params->browser;
146       // Find a compatible window and re-execute this command in it. Otherwise
147       // re-run with NEW_WINDOW.
148       return GetOrCreateBrowser(profile, params->host_desktop_type);
149     case NEW_POPUP: {
150       // Make a new popup window.
151       // Coerce app-style if |source| represents an app.
152       std::string app_name;
153       if (!params->extension_app_id.empty()) {
154         app_name = web_app::GenerateApplicationNameFromExtensionId(
155             params->extension_app_id);
156       } else if (params->browser && !params->browser->app_name().empty()) {
157         app_name = params->browser->app_name();
158       } else if (params->source_contents) {
159         extensions::TabHelper* extensions_tab_helper =
160             extensions::TabHelper::FromWebContents(params->source_contents);
161         if (extensions_tab_helper && extensions_tab_helper->is_app()) {
162           app_name = web_app::GenerateApplicationNameFromExtensionId(
163               extensions_tab_helper->extension_app()->id());
164         }
165       }
166       if (app_name.empty()) {
167         Browser::CreateParams browser_params(
168             Browser::TYPE_POPUP, profile, params->host_desktop_type);
169         browser_params.initial_bounds = params->window_bounds;
170         return new Browser(browser_params);
171       }
172
173       return new Browser(Browser::CreateParams::CreateForApp(
174           Browser::TYPE_POPUP, app_name, params->window_bounds, profile,
175           params->host_desktop_type));
176     }
177     case NEW_WINDOW: {
178       // Make a new normal browser window.
179       return new Browser(Browser::CreateParams(profile,
180                                                params->host_desktop_type));
181     }
182     case OFF_THE_RECORD:
183       // Make or find an incognito window.
184       return GetOrCreateBrowser(profile->GetOffTheRecordProfile(),
185                                 params->host_desktop_type);
186     // The following types all result in no navigation.
187     case SUPPRESS_OPEN:
188     case SAVE_TO_DISK:
189     case IGNORE_ACTION:
190       return NULL;
191     default:
192       NOTREACHED();
193   }
194   return NULL;
195 }
196
197 // Fix disposition and other parameter values depending on prevailing
198 // conditions.
199 void NormalizeDisposition(chrome::NavigateParams* params) {
200   // Calculate the WindowOpenDisposition if necessary.
201   if (params->browser->tab_strip_model()->empty() &&
202       (params->disposition == NEW_BACKGROUND_TAB ||
203        params->disposition == CURRENT_TAB ||
204        params->disposition == SINGLETON_TAB)) {
205     params->disposition = NEW_FOREGROUND_TAB;
206   }
207   if (params->browser->profile()->IsOffTheRecord() &&
208       params->disposition == OFF_THE_RECORD) {
209     params->disposition = NEW_FOREGROUND_TAB;
210   }
211   if (!params->source_contents && params->disposition == CURRENT_TAB)
212     params->disposition = NEW_FOREGROUND_TAB;
213
214   switch (params->disposition) {
215     case NEW_BACKGROUND_TAB:
216       // Disposition trumps add types. ADD_ACTIVE is a default, so we need to
217       // remove it if disposition implies the tab is going to open in the
218       // background.
219       params->tabstrip_add_types &= ~TabStripModel::ADD_ACTIVE;
220       break;
221
222     case NEW_WINDOW:
223     case NEW_POPUP:
224       // Code that wants to open a new window typically expects it to be shown
225       // automatically.
226       if (params->window_action == chrome::NavigateParams::NO_ACTION)
227         params->window_action = chrome::NavigateParams::SHOW_WINDOW;
228       // Fall-through.
229     case NEW_FOREGROUND_TAB:
230     case SINGLETON_TAB:
231       params->tabstrip_add_types |= TabStripModel::ADD_ACTIVE;
232       break;
233
234     default:
235       break;
236   }
237 }
238
239 // Obtain the profile used by the code that originated the Navigate() request.
240 Profile* GetSourceProfile(chrome::NavigateParams* params) {
241   if (params->source_contents) {
242     return Profile::FromBrowserContext(
243         params->source_contents->GetBrowserContext());
244   }
245
246   return params->initiating_profile;
247 }
248
249 void LoadURLInContents(WebContents* target_contents,
250                        const GURL& url,
251                        chrome::NavigateParams* params) {
252   NavigationController::LoadURLParams load_url_params(url);
253   load_url_params.referrer = params->referrer;
254   load_url_params.frame_tree_node_id = params->frame_tree_node_id;
255   load_url_params.redirect_chain = params->redirect_chain;
256   load_url_params.transition_type = params->transition;
257   load_url_params.extra_headers = params->extra_headers;
258   load_url_params.should_replace_current_entry =
259       params->should_replace_current_entry;
260
261   if (params->transferred_global_request_id != GlobalRequestID()) {
262     load_url_params.is_renderer_initiated = params->is_renderer_initiated;
263     load_url_params.transferred_global_request_id =
264         params->transferred_global_request_id;
265   } else if (params->is_renderer_initiated) {
266     load_url_params.is_renderer_initiated = true;
267   }
268
269   // Only allows the browser-initiated navigation to use POST.
270   if (params->uses_post && !params->is_renderer_initiated) {
271     load_url_params.load_type =
272         NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
273     load_url_params.browser_initiated_post_data =
274         params->browser_initiated_post_data;
275   }
276   target_contents->GetController().LoadURLWithParams(load_url_params);
277 }
278
279 // This class makes sure the Browser object held in |params| is made visible
280 // by the time it goes out of scope, provided |params| wants it to be shown.
281 class ScopedBrowserShower {
282  public:
283   explicit ScopedBrowserShower(chrome::NavigateParams* params)
284       : params_(params) {
285   }
286   ~ScopedBrowserShower() {
287     if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW_INACTIVE)
288       params_->browser->window()->ShowInactive();
289     else if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW)
290       params_->browser->window()->Show();
291   }
292  private:
293   chrome::NavigateParams* params_;
294   DISALLOW_COPY_AND_ASSIGN(ScopedBrowserShower);
295 };
296
297 // This class manages the lifetime of a WebContents created by the
298 // Navigate() function. When Navigate() creates a WebContents for a URL,
299 // an instance of this class takes ownership of it via TakeOwnership() until the
300 // WebContents is added to a tab strip at which time ownership is
301 // relinquished via ReleaseOwnership(). If this object goes out of scope without
302 // being added to a tab strip, the created WebContents is deleted to
303 // avoid a leak and the params->target_contents field is set to NULL.
304 class ScopedTargetContentsOwner {
305  public:
306   explicit ScopedTargetContentsOwner(chrome::NavigateParams* params)
307       : params_(params) {
308   }
309   ~ScopedTargetContentsOwner() {
310     if (target_contents_owner_.get())
311       params_->target_contents = NULL;
312   }
313
314   // Assumes ownership of |params_|' target_contents until ReleaseOwnership
315   // is called.
316   void TakeOwnership() {
317     target_contents_owner_.reset(params_->target_contents);
318   }
319
320   // Relinquishes ownership of |params_|' target_contents.
321   WebContents* ReleaseOwnership() {
322     return target_contents_owner_.release();
323   }
324
325  private:
326   chrome::NavigateParams* params_;
327   scoped_ptr<WebContents> target_contents_owner_;
328   DISALLOW_COPY_AND_ASSIGN(ScopedTargetContentsOwner);
329 };
330
331 content::WebContents* CreateTargetContents(const chrome::NavigateParams& params,
332                                            const GURL& url) {
333   WebContents::CreateParams create_params(
334       params.browser->profile(),
335       tab_util::GetSiteInstanceForNewTab(params.browser->profile(), url));
336   if (params.source_contents) {
337     create_params.initial_size =
338         params.source_contents->GetView()->GetContainerSize();
339     if (params.should_set_opener)
340       create_params.opener = params.source_contents;
341   }
342   if (params.disposition == NEW_BACKGROUND_TAB)
343     create_params.initially_hidden = true;
344
345 #if defined(USE_AURA)
346   if (params.browser->window() &&
347       params.browser->window()->GetNativeWindow()) {
348     create_params.context =
349         params.browser->window()->GetNativeWindow();
350   }
351 #endif
352
353   WebContents* target_contents = WebContents::Create(create_params);
354
355   // New tabs can have WebUI URLs that will make calls back to arbitrary
356   // tab helpers, so the entire set of tab helpers needs to be set up
357   // immediately.
358   BrowserNavigatorWebContentsAdoption::AttachTabHelpers(target_contents);
359   extensions::TabHelper::FromWebContents(target_contents)->
360       SetExtensionAppById(params.extension_app_id);
361   return target_contents;
362 }
363
364 // If a prerendered page exists for |url|, replace the page at
365 // |params->target_contents| with it and update to point to the swapped-in
366 // WebContents.
367 bool SwapInPrerender(const GURL& url, chrome::NavigateParams* params) {
368   Profile* profile =
369       Profile::FromBrowserContext(params->target_contents->GetBrowserContext());
370   InstantSearchPrerenderer* prerenderer =
371       InstantSearchPrerenderer::GetForProfile(profile);
372   if (prerenderer && prerenderer->UsePrerenderedPage(url, params))
373     return true;
374
375   prerender::PrerenderManager* prerender_manager =
376       prerender::PrerenderManagerFactory::GetForProfile(profile);
377   return prerender_manager &&
378       prerender_manager->MaybeUsePrerenderedPage(url, params);
379 }
380
381 chrome::HostDesktopType GetHostDesktop(Browser* browser) {
382   if (browser)
383     return browser->host_desktop_type();
384   return chrome::GetActiveDesktop();
385 }
386
387 }  // namespace
388
389 namespace chrome {
390
391 NavigateParams::NavigateParams(Browser* a_browser,
392                                const GURL& a_url,
393                                content::PageTransition a_transition)
394     : url(a_url),
395       frame_tree_node_id(-1),
396       uses_post(false),
397       target_contents(NULL),
398       source_contents(NULL),
399       disposition(CURRENT_TAB),
400       transition(a_transition),
401       is_renderer_initiated(false),
402       tabstrip_index(-1),
403       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
404       window_action(NO_ACTION),
405       user_gesture(true),
406       path_behavior(RESPECT),
407       ref_behavior(IGNORE_REF),
408       browser(a_browser),
409       initiating_profile(NULL),
410       host_desktop_type(GetHostDesktop(a_browser)),
411       should_replace_current_entry(false),
412       should_set_opener(false) {
413 }
414
415 NavigateParams::NavigateParams(Browser* a_browser,
416                                WebContents* a_target_contents)
417     : frame_tree_node_id(-1),
418       uses_post(false),
419       target_contents(a_target_contents),
420       source_contents(NULL),
421       disposition(CURRENT_TAB),
422       transition(content::PAGE_TRANSITION_LINK),
423       is_renderer_initiated(false),
424       tabstrip_index(-1),
425       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
426       window_action(NO_ACTION),
427       user_gesture(true),
428       path_behavior(RESPECT),
429       ref_behavior(IGNORE_REF),
430       browser(a_browser),
431       initiating_profile(NULL),
432       host_desktop_type(GetHostDesktop(a_browser)),
433       should_replace_current_entry(false),
434       should_set_opener(false) {
435 }
436
437 NavigateParams::NavigateParams(Profile* a_profile,
438                                const GURL& a_url,
439                                content::PageTransition a_transition)
440     : url(a_url),
441       frame_tree_node_id(-1),
442       uses_post(false),
443       target_contents(NULL),
444       source_contents(NULL),
445       disposition(NEW_FOREGROUND_TAB),
446       transition(a_transition),
447       is_renderer_initiated(false),
448       tabstrip_index(-1),
449       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
450       window_action(SHOW_WINDOW),
451       user_gesture(true),
452       path_behavior(RESPECT),
453       ref_behavior(IGNORE_REF),
454       browser(NULL),
455       initiating_profile(a_profile),
456       host_desktop_type(chrome::GetActiveDesktop()),
457       should_replace_current_entry(false),
458       should_set_opener(false) {
459 }
460
461 NavigateParams::~NavigateParams() {}
462
463 void FillNavigateParamsFromOpenURLParams(chrome::NavigateParams* nav_params,
464                                          const content::OpenURLParams& params) {
465   nav_params->referrer = params.referrer;
466   nav_params->frame_tree_node_id = params.frame_tree_node_id;
467   nav_params->redirect_chain = params.redirect_chain;
468   nav_params->extra_headers = params.extra_headers;
469   nav_params->disposition = params.disposition;
470   nav_params->is_renderer_initiated = params.is_renderer_initiated;
471   nav_params->transferred_global_request_id =
472       params.transferred_global_request_id;
473   nav_params->should_replace_current_entry =
474       params.should_replace_current_entry;
475   nav_params->uses_post = params.uses_post;
476   nav_params->browser_initiated_post_data = params.browser_initiated_post_data;
477 }
478
479 void Navigate(NavigateParams* params) {
480   Browser* source_browser = params->browser;
481   if (source_browser)
482     params->initiating_profile = source_browser->profile();
483   DCHECK(params->initiating_profile);
484
485   if (!AdjustNavigateParamsForURL(params))
486     return;
487
488   ExtensionService* service = params->initiating_profile->GetExtensionService();
489   if (service)
490     service->ShouldBlockUrlInBrowserTab(&params->url);
491
492   // The browser window may want to adjust the disposition.
493   if (params->disposition == NEW_POPUP &&
494       source_browser &&
495       source_browser->window()) {
496     params->disposition =
497         source_browser->window()->GetDispositionForPopupBounds(
498             params->window_bounds);
499   }
500
501   params->browser = GetBrowserForDisposition(params);
502   if (!params->browser)
503     return;
504
505 #if defined(USE_ASH)
506   if (source_browser && source_browser != params->browser) {
507     // When the newly created browser was spawned by a browser which visits
508     // another user's desktop, it should be shown on the same desktop as the
509     // originating one. (This is part of the desktop separation per profile).
510     MultiUserWindowManager* manager = MultiUserWindowManager::GetInstance();
511     // Some unit tests have no manager instantiated.
512     if (manager) {
513       aura::Window* src_window = source_browser->window()->GetNativeWindow();
514       aura::Window* new_window = params->browser->window()->GetNativeWindow();
515       const std::string& src_user =
516           manager->GetUserPresentingWindow(src_window);
517       if (src_user != manager->GetUserPresentingWindow(new_window)) {
518         // Once the window gets presented, it should be shown on the same
519         // desktop as the desktop of the creating browser. Note that this
520         // command will not show the window if it wasn't shown yet by the
521         // browser creation.
522         manager->ShowWindowForUser(new_window, src_user);
523       }
524     }
525   }
526 #endif
527
528   // Navigate() must not return early after this point.
529
530   if (GetSourceProfile(params) != params->browser->profile()) {
531     // A tab is being opened from a link from a different profile, we must reset
532     // source information that may cause state to be shared.
533     params->source_contents = NULL;
534     params->referrer = content::Referrer();
535   }
536
537   // Make sure the Browser is shown if params call for it.
538   ScopedBrowserShower shower(params);
539
540   // Makes sure any WebContents created by this function is destroyed if
541   // not properly added to a tab strip.
542   ScopedTargetContentsOwner target_contents_owner(params);
543
544   // Some dispositions need coercion to base types.
545   NormalizeDisposition(params);
546
547   // If a new window has been created, it needs to be shown.
548   if (params->window_action == NavigateParams::NO_ACTION &&
549       source_browser != params->browser &&
550       params->browser->tab_strip_model()->empty()) {
551     params->window_action = NavigateParams::SHOW_WINDOW;
552   }
553
554   // If we create a popup window from a non user-gesture, don't activate it.
555   if (params->window_action == NavigateParams::SHOW_WINDOW &&
556       params->disposition == NEW_POPUP &&
557       params->user_gesture == false) {
558     params->window_action = NavigateParams::SHOW_WINDOW_INACTIVE;
559   }
560
561   // Determine if the navigation was user initiated. If it was, we need to
562   // inform the target WebContents, and we may need to update the UI.
563   content::PageTransition base_transition =
564       content::PageTransitionStripQualifier(params->transition);
565   bool user_initiated =
566       params->transition & content::PAGE_TRANSITION_FROM_ADDRESS_BAR ||
567       base_transition == content::PAGE_TRANSITION_TYPED ||
568       base_transition == content::PAGE_TRANSITION_AUTO_BOOKMARK ||
569       base_transition == content::PAGE_TRANSITION_GENERATED ||
570       base_transition == content::PAGE_TRANSITION_AUTO_TOPLEVEL ||
571       base_transition == content::PAGE_TRANSITION_RELOAD ||
572       base_transition == content::PAGE_TRANSITION_KEYWORD;
573
574   // Check if this is a singleton tab that already exists
575   int singleton_index = chrome::GetIndexOfSingletonTab(params);
576
577   // Did we use a prerender?
578   bool swapped_in_prerender = false;
579
580   // If no target WebContents was specified, we need to construct one if
581   // we are supposed to target a new tab; unless it's a singleton that already
582   // exists.
583   if (!params->target_contents && singleton_index < 0) {
584     GURL url;
585     if (params->url.is_empty()) {
586       url = params->browser->profile()->GetHomePage();
587       params->transition = content::PageTransitionFromInt(
588           params->transition | content::PAGE_TRANSITION_HOME_PAGE);
589     } else {
590       url = params->url;
591     }
592
593     if (params->disposition != CURRENT_TAB) {
594       params->target_contents = CreateTargetContents(*params, url);
595
596       // This function takes ownership of |params->target_contents| until it
597       // is added to a TabStripModel.
598       target_contents_owner.TakeOwnership();
599     } else {
600       // ... otherwise if we're loading in the current tab, the target is the
601       // same as the source.
602       DCHECK(params->source_contents);
603       params->target_contents = params->source_contents;
604       DCHECK(params->target_contents);
605       // Prerender expects |params->target_contents| to be attached to a browser
606       // window, so only call for CURRENT_TAB navigations. (Others are currently
607       // unsupported because of session storage namespaces anyway.)
608       // Notice that this includes middle-clicking, since middle clicking
609       // translates into a chrome::Navigate call with no URL followed by a
610       // CURRENT_TAB navigation.
611       // TODO(tburkard): We can actually swap in in non-CURRENT_TAB cases, as
612       // long as the WebContents we swap into is part of a TabStrip model.
613       // Therefore, we should swap in regardless of CURRENT_TAB, and instead,
614       // check in the swapin function whether the WebContents is not in a
615       // TabStrip model, in which case we must not swap in.
616       swapped_in_prerender = SwapInPrerender(url, params);
617     }
618
619     if (user_initiated)
620       params->target_contents->UserGestureDone();
621
622     if (!swapped_in_prerender) {
623       // Try to handle non-navigational URLs that popup dialogs and such, these
624       // should not actually navigate.
625       if (!HandleNonNavigationAboutURL(url)) {
626         // Perform the actual navigation, tracking whether it came from the
627         // renderer.
628
629         LoadURLInContents(params->target_contents, url, params);
630         // For prerender bookkeeping purposes, record that this pending navigate
631         // originated from chrome::Navigate.
632         content::NavigationEntry* entry =
633             params->target_contents->GetController().GetPendingEntry();
634         if (entry)
635           entry->SetExtraData(prerender::kChromeNavigateExtraDataKey,
636                               base::string16());
637       }
638     }
639   } else {
640     // |target_contents| was specified non-NULL, and so we assume it has already
641     // been navigated appropriately. We need to do nothing more other than
642     // add it to the appropriate tabstrip.
643   }
644
645   // If the user navigated from the omnibox, and the selected tab is going to
646   // lose focus, then make sure the focus for the source tab goes away from the
647   // omnibox.
648   if (params->source_contents &&
649       (params->disposition == NEW_FOREGROUND_TAB ||
650        params->disposition == NEW_WINDOW) &&
651       (params->tabstrip_add_types & TabStripModel::ADD_INHERIT_OPENER))
652     params->source_contents->GetView()->Focus();
653
654   if (params->source_contents == params->target_contents ||
655       (swapped_in_prerender && params->disposition == CURRENT_TAB)) {
656     // The navigation occurred in the source tab.
657     params->browser->UpdateUIForNavigationInTab(params->target_contents,
658                                                 params->transition,
659                                                 user_initiated);
660   } else if (singleton_index == -1) {
661     // If some non-default value is set for the index, we should tell the
662     // TabStripModel to respect it.
663     if (params->tabstrip_index != -1)
664       params->tabstrip_add_types |= TabStripModel::ADD_FORCE_INDEX;
665
666     // The navigation should insert a new tab into the target Browser.
667     params->browser->tab_strip_model()->AddWebContents(
668         params->target_contents,
669         params->tabstrip_index,
670         params->transition,
671         params->tabstrip_add_types);
672     // Now that the |params->target_contents| is safely owned by the target
673     // Browser's TabStripModel, we can release ownership.
674     target_contents_owner.ReleaseOwnership();
675   }
676
677   if (singleton_index >= 0) {
678     WebContents* target =
679         params->browser->tab_strip_model()->GetWebContentsAt(singleton_index);
680
681     if (target->IsCrashed()) {
682       target->GetController().Reload(true);
683     } else if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE &&
684         target->GetURL() != params->url) {
685       LoadURLInContents(target, params->url, params);
686       // For prerender bookkeeping purposes, record that this pending navigate
687       // originated from chrome::Navigate.
688       content::NavigationEntry* entry =
689           target->GetController().GetPendingEntry();
690       if (entry)
691         entry->SetExtraData(prerender::kChromeNavigateExtraDataKey,
692                             base::string16());
693     }
694
695     // If the singleton tab isn't already selected, select it.
696     if (params->source_contents != params->target_contents) {
697       params->browser->tab_strip_model()->ActivateTabAt(singleton_index,
698                                                         user_initiated);
699     }
700   }
701
702   if (params->disposition != CURRENT_TAB) {
703     content::NotificationService::current()->Notify(
704         chrome::NOTIFICATION_TAB_ADDED,
705         content::Source<content::WebContentsDelegate>(params->browser),
706         content::Details<WebContents>(params->target_contents));
707   }
708 }
709
710 bool IsURLAllowedInIncognito(const GURL& url,
711                              content::BrowserContext* browser_context) {
712   if (url.scheme() == content::kViewSourceScheme) {
713     // A view-source URL is allowed in incognito mode only if the URL itself
714     // is allowed in incognito mode. Remove the "view-source:" from the start
715     // of the URL and validate the rest.
716     std::string stripped_spec = url.spec();
717     DCHECK_GT(stripped_spec.size(), strlen(content::kViewSourceScheme));
718     stripped_spec.erase(0, strlen(content::kViewSourceScheme) + 1);
719     GURL stripped_url(stripped_spec);
720     return stripped_url.is_valid() &&
721         IsURLAllowedInIncognito(stripped_url, browser_context);
722   }
723   // Most URLs are allowed in incognito; the following are exceptions.
724   // chrome://extensions is on the list because it redirects to
725   // chrome://settings.
726   if (url.scheme() == content::kChromeUIScheme &&
727       (url.host() == chrome::kChromeUISettingsHost ||
728        url.host() == chrome::kChromeUISettingsFrameHost ||
729        url.host() == chrome::kChromeUIExtensionsHost ||
730        url.host() == chrome::kChromeUIBookmarksHost ||
731 #if defined(ENABLE_ENHANCED_BOOKMARKS)
732        url.host() == chrome::kChromeUIEnhancedBookmarksHost ||
733 #endif
734 #if !defined(OS_CHROMEOS)
735        url.host() == chrome::kChromeUIChromeSigninHost ||
736 #endif
737        url.host() == chrome::kChromeUIUberHost ||
738        url.host() == chrome::kChromeUIThumbnailHost ||
739        url.host() == chrome::kChromeUIThumbnailHost2 ||
740        url.host() == chrome::kChromeUIThumbnailListHost)) {
741     return false;
742   }
743
744   if (url.scheme() == chrome::kChromeSearchScheme &&
745       (url.host() == chrome::kChromeUIThumbnailHost ||
746        url.host() == chrome::kChromeUIThumbnailHost2 ||
747        url.host() == chrome::kChromeUIThumbnailListHost)) {
748     return false;
749   }
750
751   GURL rewritten_url = url;
752   bool reverse_on_redirect = false;
753   content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary(
754       &rewritten_url, browser_context, &reverse_on_redirect);
755
756   // Some URLs are mapped to uber subpages. Do not allow them in incognito.
757   return !(rewritten_url.scheme() == content::kChromeUIScheme &&
758            rewritten_url.host() == chrome::kChromeUIUberHost);
759 }
760
761 }  // namespace chrome