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