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