OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/web_contents/navigation_controller_impl.h" | 5 #include "content/browser/web_contents/navigation_controller_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/string_number_conversions.h" // Temporary | 9 #include "base/string_number_conversions.h" // Temporary |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 NavigationEntryImpl::FromNavigationEntry(GetActiveEntry()); | 275 NavigationEntryImpl::FromNavigationEntry(GetActiveEntry()); |
276 if (!active_entry) | 276 if (!active_entry) |
277 return; | 277 return; |
278 LoadURL(active_entry->GetURL(), | 278 LoadURL(active_entry->GetURL(), |
279 Referrer(), | 279 Referrer(), |
280 PAGE_TRANSITION_RELOAD, | 280 PAGE_TRANSITION_RELOAD, |
281 active_entry->extra_headers()); | 281 active_entry->extra_headers()); |
282 return; | 282 return; |
283 } | 283 } |
284 | 284 |
285 DiscardNonCommittedEntriesInternal(); | 285 NavigationEntryImpl* entry = NULL; |
286 int current_index = GetCurrentEntryIndex(); | 286 int current_index = -1; |
| 287 |
| 288 // If we are reloading the initial navigation, just use the current |
| 289 // pending entry. Otherwise look up the current entry. |
| 290 if (IsInitialNavigation() && pending_entry_) { |
| 291 entry = pending_entry_; |
| 292 // The pending entry might be in entries_ (e.g., after a Clone), so we |
| 293 // should also update the current_index. |
| 294 current_index = pending_entry_index_; |
| 295 } else { |
| 296 DiscardNonCommittedEntriesInternal(); |
| 297 current_index = GetCurrentEntryIndex(); |
| 298 if (current_index != -1) { |
| 299 entry = NavigationEntryImpl::FromNavigationEntry( |
| 300 GetEntryAtIndex(current_index)); |
| 301 } |
| 302 } |
| 303 |
287 // If we are no where, then we can't reload. TODO(darin): We should add a | 304 // If we are no where, then we can't reload. TODO(darin): We should add a |
288 // CanReload method. | 305 // CanReload method. |
289 if (current_index == -1) { | 306 if (!entry) |
290 return; | 307 return; |
291 } | |
292 | 308 |
293 if (g_check_for_repost && check_for_repost && | 309 if (g_check_for_repost && check_for_repost && |
294 GetEntryAtIndex(current_index)->GetHasPostData()) { | 310 entry->GetHasPostData()) { |
295 // The user is asking to reload a page with POST data. Prompt to make sure | 311 // The user is asking to reload a page with POST data. Prompt to make sure |
296 // they really want to do this. If they do, the dialog will call us back | 312 // they really want to do this. If they do, the dialog will call us back |
297 // with check_for_repost = false. | 313 // with check_for_repost = false. |
298 web_contents_->NotifyBeforeFormRepostWarningShow(); | 314 web_contents_->NotifyBeforeFormRepostWarningShow(); |
299 | 315 |
300 pending_reload_ = reload_type; | 316 pending_reload_ = reload_type; |
301 web_contents_->Activate(); | 317 web_contents_->Activate(); |
302 web_contents_->GetDelegate()->ShowRepostFormWarningDialog(web_contents_); | 318 web_contents_->GetDelegate()->ShowRepostFormWarningDialog(web_contents_); |
303 } else { | 319 } else { |
304 DiscardNonCommittedEntriesInternal(); | 320 if (!IsInitialNavigation()) |
305 | 321 DiscardNonCommittedEntriesInternal(); |
306 NavigationEntryImpl* entry = entries_[current_index].get(); | |
307 SiteInstanceImpl* site_instance = entry->site_instance(); | |
308 DCHECK(site_instance); | |
309 | 322 |
310 // If we are reloading an entry that no longer belongs to the current | 323 // If we are reloading an entry that no longer belongs to the current |
311 // site instance (for example, refreshing a page for just installed app), | 324 // site instance (for example, refreshing a page for just installed app), |
312 // the reload must happen in a new process. | 325 // the reload must happen in a new process. |
313 // The new entry must have a new page_id and site instance, so it behaves | 326 // The new entry must have a new page_id and site instance, so it behaves |
314 // as new navigation (which happens to clear forward history). | 327 // as new navigation (which happens to clear forward history). |
315 // Tabs that are discarded due to low memory conditions may not have a site | 328 // Tabs that are discarded due to low memory conditions may not have a site |
316 // instance, and should not be treated as a cross-site reload. | 329 // instance, and should not be treated as a cross-site reload. |
| 330 SiteInstanceImpl* site_instance = entry->site_instance(); |
317 if (site_instance && | 331 if (site_instance && |
318 site_instance->HasWrongProcessForURL(entry->GetURL())) { | 332 site_instance->HasWrongProcessForURL(entry->GetURL())) { |
319 // Create a navigation entry that resembles the current one, but do not | 333 // Create a navigation entry that resembles the current one, but do not |
320 // copy page id, site instance, content state, or timestamp. | 334 // copy page id, site instance, content state, or timestamp. |
321 NavigationEntryImpl* nav_entry = NavigationEntryImpl::FromNavigationEntry( | 335 NavigationEntryImpl* nav_entry = NavigationEntryImpl::FromNavigationEntry( |
322 CreateNavigationEntry( | 336 CreateNavigationEntry( |
323 entry->GetURL(), entry->GetReferrer(), entry->GetTransitionType(), | 337 entry->GetURL(), entry->GetReferrer(), entry->GetTransitionType(), |
324 false, entry->extra_headers(), browser_context_)); | 338 false, entry->extra_headers(), browser_context_)); |
325 | 339 |
326 // Mark the reload type as NO_RELOAD, so navigation will not be considered | 340 // Mark the reload type as NO_RELOAD, so navigation will not be considered |
327 // a reload in the renderer. | 341 // a reload in the renderer. |
328 reload_type = NavigationController::NO_RELOAD; | 342 reload_type = NavigationController::NO_RELOAD; |
329 | 343 |
330 nav_entry->set_should_replace_entry(true); | 344 nav_entry->set_should_replace_entry(true); |
331 pending_entry_ = nav_entry; | 345 pending_entry_ = nav_entry; |
332 } else { | 346 } else { |
| 347 pending_entry_ = entry; |
333 pending_entry_index_ = current_index; | 348 pending_entry_index_ = current_index; |
334 | 349 |
335 // The title of the page being reloaded might have been removed in the | 350 // The title of the page being reloaded might have been removed in the |
336 // meanwhile, so we need to revert to the default title upon reload and | 351 // meanwhile, so we need to revert to the default title upon reload and |
337 // invalidate the previously cached title (SetTitle will do both). | 352 // invalidate the previously cached title (SetTitle will do both). |
338 // See Chromium issue 96041. | 353 // See Chromium issue 96041. |
339 entries_[pending_entry_index_]->SetTitle(string16()); | 354 pending_entry_->SetTitle(string16()); |
340 | 355 |
341 entries_[pending_entry_index_]->SetTransitionType(PAGE_TRANSITION_RELOAD); | 356 pending_entry_->SetTransitionType(PAGE_TRANSITION_RELOAD); |
342 } | 357 } |
343 | 358 |
344 NavigateToPendingEntry(reload_type); | 359 NavigateToPendingEntry(reload_type); |
345 } | 360 } |
346 } | 361 } |
347 | 362 |
348 void NavigationControllerImpl::CancelPendingReload() { | 363 void NavigationControllerImpl::CancelPendingReload() { |
349 DCHECK(pending_reload_ != NO_RELOAD); | 364 DCHECK(pending_reload_ != NO_RELOAD); |
350 pending_reload_ = NO_RELOAD; | 365 pending_reload_ = NO_RELOAD; |
351 } | 366 } |
(...skipping 27 matching lines...) Expand all Loading... |
379 policy->IsDisabledScheme(entry->GetVirtualURL().scheme())) { | 394 policy->IsDisabledScheme(entry->GetVirtualURL().scheme())) { |
380 VLOG(1) << "URL not loaded because the scheme is blocked by policy: " | 395 VLOG(1) << "URL not loaded because the scheme is blocked by policy: " |
381 << entry->GetURL(); | 396 << entry->GetURL(); |
382 delete entry; | 397 delete entry; |
383 return; | 398 return; |
384 } | 399 } |
385 | 400 |
386 // When navigating to a new page, we don't know for sure if we will actually | 401 // When navigating to a new page, we don't know for sure if we will actually |
387 // end up leaving the current page. The new page load could for example | 402 // end up leaving the current page. The new page load could for example |
388 // result in a download or a 'no content' response (e.g., a mailto: URL). | 403 // result in a download or a 'no content' response (e.g., a mailto: URL). |
| 404 SetPendingEntry(entry); |
| 405 NavigateToPendingEntry(NO_RELOAD); |
| 406 } |
| 407 |
| 408 void NavigationControllerImpl::SetPendingEntry(NavigationEntryImpl* entry) { |
389 DiscardNonCommittedEntriesInternal(); | 409 DiscardNonCommittedEntriesInternal(); |
390 pending_entry_ = entry; | 410 pending_entry_ = entry; |
391 NotificationService::current()->Notify( | 411 NotificationService::current()->Notify( |
392 NOTIFICATION_NAV_ENTRY_PENDING, | 412 NOTIFICATION_NAV_ENTRY_PENDING, |
393 Source<NavigationController>(this), | 413 Source<NavigationController>(this), |
394 Details<NavigationEntry>(entry)); | 414 Details<NavigationEntry>(entry)); |
395 NavigateToPendingEntry(NO_RELOAD); | |
396 } | 415 } |
397 | 416 |
398 NavigationEntry* NavigationControllerImpl::GetActiveEntry() const { | 417 NavigationEntry* NavigationControllerImpl::GetActiveEntry() const { |
399 if (transient_entry_index_ != -1) | 418 if (transient_entry_index_ != -1) |
400 return entries_[transient_entry_index_].get(); | 419 return entries_[transient_entry_index_].get(); |
401 if (pending_entry_) | 420 if (pending_entry_) |
402 return pending_entry_; | 421 return pending_entry_; |
403 return GetLastCommittedEntry(); | 422 return GetLastCommittedEntry(); |
404 } | 423 } |
405 | 424 |
406 NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const { | 425 NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const { |
407 if (transient_entry_index_ != -1) | 426 if (transient_entry_index_ != -1) |
408 return entries_[transient_entry_index_].get(); | 427 return entries_[transient_entry_index_].get(); |
409 // Only return the pending_entry for new (non-history), browser-initiated | 428 // The pending entry is safe to return for new (non-history), browser- |
410 // navigations, in order to prevent URL spoof attacks. | 429 // initiated navigations. Most renderer-initiated navigations should not |
411 // Ideally we would also show the pending entry's URL for new renderer- | 430 // show the pending entry, to prevent URL spoof attacks. |
412 // initiated navigations with no last committed entry (e.g., a link opening | 431 // |
413 // in a new tab), but an attacker can insert content into the about:blank | 432 // We make an exception for renderer-initiated navigations in new tabs, as |
414 // page while the pending URL loads in that case. | 433 // long as no other page has tried to access the initial empty document in |
415 if (pending_entry_ && | 434 // the new tab. If another page modifies this blank page, a URL spoof is |
| 435 // possible, so we must stop showing the pending entry. |
| 436 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>( |
| 437 web_contents_->GetRenderViewHost()); |
| 438 bool safe_to_show_pending = |
| 439 pending_entry_ && |
| 440 // Require a new navigation. |
416 pending_entry_->GetPageID() == -1 && | 441 pending_entry_->GetPageID() == -1 && |
| 442 // Require either browser-initiated or an unmodified new tab. |
| 443 (!pending_entry_->is_renderer_initiated() || |
| 444 (IsInitialNavigation() && |
| 445 !GetLastCommittedEntry() && |
| 446 !rvh->has_accessed_initial_document())); |
| 447 |
| 448 // Also allow showing the pending entry for history navigations in a new tab, |
| 449 // such as Ctrl+Back. In this case, no existing page is visible and no one |
| 450 // can script the new tab before it commits. |
| 451 if (!safe_to_show_pending && |
| 452 pending_entry_ && |
| 453 pending_entry_->GetPageID() != -1 && |
| 454 IsInitialNavigation() && |
417 !pending_entry_->is_renderer_initiated()) | 455 !pending_entry_->is_renderer_initiated()) |
| 456 safe_to_show_pending = true; |
| 457 |
| 458 if (safe_to_show_pending) |
418 return pending_entry_; | 459 return pending_entry_; |
419 return GetLastCommittedEntry(); | 460 return GetLastCommittedEntry(); |
420 } | 461 } |
421 | 462 |
422 int NavigationControllerImpl::GetCurrentEntryIndex() const { | 463 int NavigationControllerImpl::GetCurrentEntryIndex() const { |
423 if (transient_entry_index_ != -1) | 464 if (transient_entry_index_ != -1) |
424 return transient_entry_index_; | 465 return transient_entry_index_; |
425 if (pending_entry_index_ != -1) | 466 if (pending_entry_index_ != -1) |
426 return pending_entry_index_; | 467 return pending_entry_index_; |
427 return last_committed_entry_index_; | 468 return last_committed_entry_index_; |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 if (!PageTransitionIsMainFrame(params.transition)) { | 939 if (!PageTransitionIsMainFrame(params.transition)) { |
899 // All manual subframes would get new IDs and were handled above, so we | 940 // All manual subframes would get new IDs and were handled above, so we |
900 // know this is auto. Since the current page was found in the navigation | 941 // know this is auto. Since the current page was found in the navigation |
901 // entry list, we're guaranteed to have a last committed entry. | 942 // entry list, we're guaranteed to have a last committed entry. |
902 DCHECK(GetLastCommittedEntry()); | 943 DCHECK(GetLastCommittedEntry()); |
903 return NAVIGATION_TYPE_AUTO_SUBFRAME; | 944 return NAVIGATION_TYPE_AUTO_SUBFRAME; |
904 } | 945 } |
905 | 946 |
906 // Anything below here we know is a main frame navigation. | 947 // Anything below here we know is a main frame navigation. |
907 if (pending_entry_ && | 948 if (pending_entry_ && |
| 949 !pending_entry_->is_renderer_initiated() && |
908 existing_entry != pending_entry_ && | 950 existing_entry != pending_entry_ && |
909 pending_entry_->GetPageID() == -1 && | 951 pending_entry_->GetPageID() == -1 && |
910 existing_entry == GetLastCommittedEntry()) { | 952 existing_entry == GetLastCommittedEntry()) { |
911 // In this case, we have a pending entry for a URL but WebCore didn't do a | 953 // In this case, we have a pending entry for a URL but WebCore didn't do a |
912 // new navigation. This happens when you press enter in the URL bar to | 954 // new navigation. This happens when you press enter in the URL bar to |
913 // reload. We will create a pending entry, but WebKit will convert it to | 955 // reload. We will create a pending entry, but WebKit will convert it to |
914 // a reload since it's the same page and not create a new entry for it | 956 // a reload since it's the same page and not create a new entry for it |
915 // (the user doesn't want to have a new back/forward entry when they do | 957 // (the user doesn't want to have a new back/forward entry when they do |
916 // this). If this matches the last committed entry, we want to just ignore | 958 // this). If this matches the last committed entry, we want to just ignore |
917 // the pending entry and go back to where we were (the "existing entry"). | 959 // the pending entry and go back to where we were (the "existing entry"). |
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1651 } | 1693 } |
1652 } | 1694 } |
1653 } | 1695 } |
1654 | 1696 |
1655 void NavigationControllerImpl::SetGetTimestampCallbackForTest( | 1697 void NavigationControllerImpl::SetGetTimestampCallbackForTest( |
1656 const base::Callback<base::Time()>& get_timestamp_callback) { | 1698 const base::Callback<base::Time()>& get_timestamp_callback) { |
1657 get_timestamp_callback_ = get_timestamp_callback; | 1699 get_timestamp_callback_ = get_timestamp_callback; |
1658 } | 1700 } |
1659 | 1701 |
1660 } // namespace content | 1702 } // namespace content |
OLD | NEW |