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