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/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 NavigationEntryImpl::FromNavigationEntry(GetActiveEntry()); | 285 NavigationEntryImpl::FromNavigationEntry(GetActiveEntry()); |
286 if (!active_entry) | 286 if (!active_entry) |
287 return; | 287 return; |
288 LoadURL(active_entry->GetURL(), | 288 LoadURL(active_entry->GetURL(), |
289 Referrer(), | 289 Referrer(), |
290 PAGE_TRANSITION_RELOAD, | 290 PAGE_TRANSITION_RELOAD, |
291 active_entry->extra_headers()); | 291 active_entry->extra_headers()); |
292 return; | 292 return; |
293 } | 293 } |
294 | 294 |
295 DiscardNonCommittedEntriesInternal(); | 295 NavigationEntryImpl* entry = NULL; |
296 int current_index = GetCurrentEntryIndex(); | 296 int current_index = -1; |
| 297 |
| 298 // If we are reloading the initial navigation, just use the current |
| 299 // pending entry. Otherwise look up the current entry. |
| 300 if (IsInitialNavigation() && pending_entry_) { |
| 301 entry = pending_entry_; |
| 302 } else { |
| 303 DiscardNonCommittedEntriesInternal(); |
| 304 current_index = GetCurrentEntryIndex(); |
| 305 if (current_index != -1) { |
| 306 entry = NavigationEntryImpl::FromNavigationEntry( |
| 307 GetEntryAtIndex(current_index)); |
| 308 } |
| 309 } |
| 310 |
297 // If we are no where, then we can't reload. TODO(darin): We should add a | 311 // If we are no where, then we can't reload. TODO(darin): We should add a |
298 // CanReload method. | 312 // CanReload method. |
299 if (current_index == -1) { | 313 if (!entry) |
300 return; | 314 return; |
301 } | |
302 | 315 |
303 if (g_check_for_repost && check_for_repost && | 316 if (g_check_for_repost && check_for_repost && |
304 GetEntryAtIndex(current_index)->GetHasPostData()) { | 317 entry->GetHasPostData()) { |
305 // The user is asking to reload a page with POST data. Prompt to make sure | 318 // The user is asking to reload a page with POST data. Prompt to make sure |
306 // they really want to do this. If they do, the dialog will call us back | 319 // they really want to do this. If they do, the dialog will call us back |
307 // with check_for_repost = false. | 320 // with check_for_repost = false. |
308 web_contents_->NotifyBeforeFormRepostWarningShow(); | 321 web_contents_->NotifyBeforeFormRepostWarningShow(); |
309 | 322 |
310 pending_reload_ = reload_type; | 323 pending_reload_ = reload_type; |
311 web_contents_->Activate(); | 324 web_contents_->Activate(); |
312 web_contents_->GetDelegate()->ShowRepostFormWarningDialog(web_contents_); | 325 web_contents_->GetDelegate()->ShowRepostFormWarningDialog(web_contents_); |
313 } else { | 326 } else { |
314 DiscardNonCommittedEntriesInternal(); | 327 if (!IsInitialNavigation()) |
315 | 328 DiscardNonCommittedEntriesInternal(); |
316 NavigationEntryImpl* entry = entries_[current_index].get(); | |
317 SiteInstanceImpl* site_instance = entry->site_instance(); | |
318 DCHECK(site_instance); | |
319 | 329 |
320 // If we are reloading an entry that no longer belongs to the current | 330 // If we are reloading an entry that no longer belongs to the current |
321 // site instance (for example, refreshing a page for just installed app), | 331 // site instance (for example, refreshing a page for just installed app), |
322 // the reload must happen in a new process. | 332 // the reload must happen in a new process. |
323 // The new entry must have a new page_id and site instance, so it behaves | 333 // The new entry must have a new page_id and site instance, so it behaves |
324 // as new navigation (which happens to clear forward history). | 334 // as new navigation (which happens to clear forward history). |
325 // Tabs that are discarded due to low memory conditions may not have a site | 335 // Tabs that are discarded due to low memory conditions may not have a site |
326 // instance, and should not be treated as a cross-site reload. | 336 // instance, and should not be treated as a cross-site reload. |
| 337 SiteInstanceImpl* site_instance = entry->site_instance(); |
327 if (site_instance && | 338 if (site_instance && |
328 site_instance->HasWrongProcessForURL(entry->GetURL())) { | 339 site_instance->HasWrongProcessForURL(entry->GetURL())) { |
329 // Create a navigation entry that resembles the current one, but do not | 340 // Create a navigation entry that resembles the current one, but do not |
330 // copy page id, site instance, content state, or timestamp. | 341 // copy page id, site instance, content state, or timestamp. |
331 NavigationEntryImpl* nav_entry = NavigationEntryImpl::FromNavigationEntry( | 342 NavigationEntryImpl* nav_entry = NavigationEntryImpl::FromNavigationEntry( |
332 CreateNavigationEntry( | 343 CreateNavigationEntry( |
333 entry->GetURL(), entry->GetReferrer(), entry->GetTransitionType(), | 344 entry->GetURL(), entry->GetReferrer(), entry->GetTransitionType(), |
334 false, entry->extra_headers(), browser_context_)); | 345 false, entry->extra_headers(), browser_context_)); |
335 | 346 |
336 // Mark the reload type as NO_RELOAD, so navigation will not be considered | 347 // Mark the reload type as NO_RELOAD, so navigation will not be considered |
337 // a reload in the renderer. | 348 // a reload in the renderer. |
338 reload_type = NavigationController::NO_RELOAD; | 349 reload_type = NavigationController::NO_RELOAD; |
339 | 350 |
340 nav_entry->set_should_replace_entry(true); | 351 nav_entry->set_should_replace_entry(true); |
341 pending_entry_ = nav_entry; | 352 pending_entry_ = nav_entry; |
342 } else { | 353 } else { |
| 354 pending_entry_ = entry; |
343 pending_entry_index_ = current_index; | 355 pending_entry_index_ = current_index; |
344 | 356 |
345 // The title of the page being reloaded might have been removed in the | 357 // The title of the page being reloaded might have been removed in the |
346 // meanwhile, so we need to revert to the default title upon reload and | 358 // meanwhile, so we need to revert to the default title upon reload and |
347 // invalidate the previously cached title (SetTitle will do both). | 359 // invalidate the previously cached title (SetTitle will do both). |
348 // See Chromium issue 96041. | 360 // See Chromium issue 96041. |
349 entries_[pending_entry_index_]->SetTitle(string16()); | 361 pending_entry_->SetTitle(string16()); |
350 | 362 |
351 entries_[pending_entry_index_]->SetTransitionType(PAGE_TRANSITION_RELOAD); | 363 pending_entry_->SetTransitionType(PAGE_TRANSITION_RELOAD); |
352 } | 364 } |
353 | 365 |
354 NavigateToPendingEntry(reload_type); | 366 NavigateToPendingEntry(reload_type); |
355 } | 367 } |
356 } | 368 } |
357 | 369 |
358 void NavigationControllerImpl::CancelPendingReload() { | 370 void NavigationControllerImpl::CancelPendingReload() { |
359 DCHECK(pending_reload_ != NO_RELOAD); | 371 DCHECK(pending_reload_ != NO_RELOAD); |
360 pending_reload_ = NO_RELOAD; | 372 pending_reload_ = NO_RELOAD; |
361 } | 373 } |
(...skipping 27 matching lines...) Expand all Loading... |
389 policy->IsDisabledScheme(entry->GetVirtualURL().scheme())) { | 401 policy->IsDisabledScheme(entry->GetVirtualURL().scheme())) { |
390 VLOG(1) << "URL not loaded because the scheme is blocked by policy: " | 402 VLOG(1) << "URL not loaded because the scheme is blocked by policy: " |
391 << entry->GetURL(); | 403 << entry->GetURL(); |
392 delete entry; | 404 delete entry; |
393 return; | 405 return; |
394 } | 406 } |
395 | 407 |
396 // When navigating to a new page, we don't know for sure if we will actually | 408 // When navigating to a new page, we don't know for sure if we will actually |
397 // end up leaving the current page. The new page load could for example | 409 // end up leaving the current page. The new page load could for example |
398 // result in a download or a 'no content' response (e.g., a mailto: URL). | 410 // result in a download or a 'no content' response (e.g., a mailto: URL). |
| 411 SetPendingEntry(entry); |
| 412 NavigateToPendingEntry(NO_RELOAD); |
| 413 } |
| 414 |
| 415 void NavigationControllerImpl::SetPendingEntry(NavigationEntryImpl* entry) { |
399 DiscardNonCommittedEntriesInternal(); | 416 DiscardNonCommittedEntriesInternal(); |
400 pending_entry_ = entry; | 417 pending_entry_ = entry; |
401 NotificationService::current()->Notify( | 418 NotificationService::current()->Notify( |
402 NOTIFICATION_NAV_ENTRY_PENDING, | 419 NOTIFICATION_NAV_ENTRY_PENDING, |
403 Source<NavigationController>(this), | 420 Source<NavigationController>(this), |
404 Details<NavigationEntry>(entry)); | 421 Details<NavigationEntry>(entry)); |
405 NavigateToPendingEntry(NO_RELOAD); | |
406 } | 422 } |
407 | 423 |
408 NavigationEntry* NavigationControllerImpl::GetActiveEntry() const { | 424 NavigationEntry* NavigationControllerImpl::GetActiveEntry() const { |
409 if (transient_entry_index_ != -1) | 425 if (transient_entry_index_ != -1) |
410 return entries_[transient_entry_index_].get(); | 426 return entries_[transient_entry_index_].get(); |
411 if (pending_entry_) | 427 if (pending_entry_) |
412 return pending_entry_; | 428 return pending_entry_; |
413 return GetLastCommittedEntry(); | 429 return GetLastCommittedEntry(); |
414 } | 430 } |
415 | 431 |
416 NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const { | 432 NavigationEntry* NavigationControllerImpl::GetVisibleEntry() const { |
417 if (transient_entry_index_ != -1) | 433 if (transient_entry_index_ != -1) |
418 return entries_[transient_entry_index_].get(); | 434 return entries_[transient_entry_index_].get(); |
419 // Only return the pending_entry for new (non-history), browser-initiated | 435 // The pending entry is safe to return for new (non-history), browser- |
420 // navigations, in order to prevent URL spoof attacks. | 436 // initiated navigations. Most renderer-initiated navigations should not |
421 // Ideally we would also show the pending entry's URL for new renderer- | 437 // show the pending entry, to prevent URL spoof attacks. |
422 // initiated navigations with no last committed entry (e.g., a link opening | 438 // |
423 // in a new tab), but an attacker can insert content into the about:blank | 439 // We make an exception for renderer-initiated navigations in new tabs, as |
424 // page while the pending URL loads in that case. | 440 // long as no other page has tried to access the initial empty document in |
425 if (pending_entry_ && | 441 // the new tab. If another page modifies this blank page, a URL spoof is |
| 442 // possible, so we must stop showing the pending entry. |
| 443 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>( |
| 444 web_contents_->GetRenderViewHost()); |
| 445 bool safe_to_show_pending = |
| 446 pending_entry_ && |
| 447 // Require a new navigation. |
426 pending_entry_->GetPageID() == -1 && | 448 pending_entry_->GetPageID() == -1 && |
| 449 // Require either browser-initiated or an unmodified new tab. |
| 450 (!pending_entry_->is_renderer_initiated() || |
| 451 (IsInitialNavigation() && |
| 452 !GetLastCommittedEntry() && |
| 453 !rvh->has_accessed_initial_document())); |
| 454 |
| 455 // Also allow showing the pending entry for history navigations in a new tab, |
| 456 // such as Ctrl+Back. In this case, no existing page is visible and no one |
| 457 // can script the new tab before it commits. |
| 458 if (!safe_to_show_pending && |
| 459 pending_entry_ && |
| 460 pending_entry_->GetPageID() != -1 && |
| 461 IsInitialNavigation() && |
427 !pending_entry_->is_renderer_initiated()) | 462 !pending_entry_->is_renderer_initiated()) |
| 463 safe_to_show_pending = true; |
| 464 |
| 465 if (safe_to_show_pending) |
428 return pending_entry_; | 466 return pending_entry_; |
429 return GetLastCommittedEntry(); | 467 return GetLastCommittedEntry(); |
430 } | 468 } |
431 | 469 |
432 int NavigationControllerImpl::GetCurrentEntryIndex() const { | 470 int NavigationControllerImpl::GetCurrentEntryIndex() const { |
433 if (transient_entry_index_ != -1) | 471 if (transient_entry_index_ != -1) |
434 return transient_entry_index_; | 472 return transient_entry_index_; |
435 if (pending_entry_index_ != -1) | 473 if (pending_entry_index_ != -1) |
436 return pending_entry_index_; | 474 return pending_entry_index_; |
437 return last_committed_entry_index_; | 475 return last_committed_entry_index_; |
(...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1047 if (!PageTransitionIsMainFrame(params.transition)) { | 1085 if (!PageTransitionIsMainFrame(params.transition)) { |
1048 // All manual subframes would get new IDs and were handled above, so we | 1086 // All manual subframes would get new IDs and were handled above, so we |
1049 // know this is auto. Since the current page was found in the navigation | 1087 // know this is auto. Since the current page was found in the navigation |
1050 // entry list, we're guaranteed to have a last committed entry. | 1088 // entry list, we're guaranteed to have a last committed entry. |
1051 DCHECK(GetLastCommittedEntry()); | 1089 DCHECK(GetLastCommittedEntry()); |
1052 return NAVIGATION_TYPE_AUTO_SUBFRAME; | 1090 return NAVIGATION_TYPE_AUTO_SUBFRAME; |
1053 } | 1091 } |
1054 | 1092 |
1055 // Anything below here we know is a main frame navigation. | 1093 // Anything below here we know is a main frame navigation. |
1056 if (pending_entry_ && | 1094 if (pending_entry_ && |
| 1095 !pending_entry_->is_renderer_initiated() && |
1057 existing_entry != pending_entry_ && | 1096 existing_entry != pending_entry_ && |
1058 pending_entry_->GetPageID() == -1 && | 1097 pending_entry_->GetPageID() == -1 && |
1059 existing_entry == GetLastCommittedEntry()) { | 1098 existing_entry == GetLastCommittedEntry()) { |
1060 // In this case, we have a pending entry for a URL but WebCore didn't do a | 1099 // In this case, we have a pending entry for a URL but WebCore didn't do a |
1061 // new navigation. This happens when you press enter in the URL bar to | 1100 // new navigation. This happens when you press enter in the URL bar to |
1062 // reload. We will create a pending entry, but WebKit will convert it to | 1101 // reload. We will create a pending entry, but WebKit will convert it to |
1063 // a reload since it's the same page and not create a new entry for it | 1102 // a reload since it's the same page and not create a new entry for it |
1064 // (the user doesn't want to have a new back/forward entry when they do | 1103 // (the user doesn't want to have a new back/forward entry when they do |
1065 // this). If this matches the last committed entry, we want to just ignore | 1104 // this). If this matches the last committed entry, we want to just ignore |
1066 // the pending entry and go back to where we were (the "existing entry"). | 1105 // the pending entry and go back to where we were (the "existing entry"). |
(...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1824 const base::Callback<base::Time()>& get_timestamp_callback) { | 1863 const base::Callback<base::Time()>& get_timestamp_callback) { |
1825 get_timestamp_callback_ = get_timestamp_callback; | 1864 get_timestamp_callback_ = get_timestamp_callback; |
1826 } | 1865 } |
1827 | 1866 |
1828 void NavigationControllerImpl::SetTakeScreenshotCallbackForTest( | 1867 void NavigationControllerImpl::SetTakeScreenshotCallbackForTest( |
1829 const base::Callback<void(RenderViewHost*)>& take_screenshot_callback) { | 1868 const base::Callback<void(RenderViewHost*)>& take_screenshot_callback) { |
1830 take_screenshot_callback_ = take_screenshot_callback; | 1869 take_screenshot_callback_ = take_screenshot_callback; |
1831 } | 1870 } |
1832 | 1871 |
1833 } // namespace content | 1872 } // namespace content |
OLD | NEW |