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