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