| Index: trunk/src/content/renderer/render_view_impl.cc
|
| ===================================================================
|
| --- trunk/src/content/renderer/render_view_impl.cc (revision 253009)
|
| +++ trunk/src/content/renderer/render_view_impl.cc (working copy)
|
| @@ -42,7 +42,6 @@
|
| #include "content/common/database_messages.h"
|
| #include "content/common/dom_storage/dom_storage_types.h"
|
| #include "content/common/drag_messages.h"
|
| -#include "content/common/frame_messages.h"
|
| #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
|
| #include "content/common/input_messages.h"
|
| #include "content/common/java_bridge_messages.h"
|
| @@ -362,13 +361,12 @@
|
| static RenderViewImpl* (*g_create_render_view_impl)(RenderViewImplParams*) =
|
| NULL;
|
|
|
| -// static
|
| -bool RenderViewImpl::IsReload(const FrameMsg_Navigate_Params& params) {
|
| +static bool IsReload(const ViewMsg_Navigate_Params& params) {
|
| return
|
| - params.navigation_type == FrameMsg_Navigate_Type::RELOAD ||
|
| - params.navigation_type == FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE ||
|
| + params.navigation_type == ViewMsg_Navigate_Type::RELOAD ||
|
| + params.navigation_type == ViewMsg_Navigate_Type::RELOAD_IGNORING_CACHE ||
|
| params.navigation_type ==
|
| - FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
|
| + ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
|
| }
|
|
|
| // static
|
| @@ -379,6 +377,67 @@
|
| request.referrerPolicy());
|
| }
|
|
|
| +NOINLINE static void CrashIntentionally() {
|
| + // NOTE(shess): Crash directly rather than using NOTREACHED() so
|
| + // that the signature is easier to triage in crash reports.
|
| + volatile int* zero = NULL;
|
| + *zero = 0;
|
| +}
|
| +
|
| +#if defined(ADDRESS_SANITIZER)
|
| +NOINLINE static void MaybeTriggerAsanError(const GURL& url) {
|
| + // NOTE(rogerm): We intentionally perform an invalid heap access here in
|
| + // order to trigger an Address Sanitizer (ASAN) error report.
|
| + static const char kCrashDomain[] = "crash";
|
| + static const char kHeapOverflow[] = "/heap-overflow";
|
| + static const char kHeapUnderflow[] = "/heap-underflow";
|
| + static const char kUseAfterFree[] = "/use-after-free";
|
| + static const int kArraySize = 5;
|
| +
|
| + if (!url.DomainIs(kCrashDomain, sizeof(kCrashDomain) - 1))
|
| + return;
|
| +
|
| + if (!url.has_path())
|
| + return;
|
| +
|
| + scoped_ptr<int[]> array(new int[kArraySize]);
|
| + std::string crash_type(url.path());
|
| + int dummy = 0;
|
| + if (crash_type == kHeapOverflow) {
|
| + dummy = array[kArraySize];
|
| + } else if (crash_type == kHeapUnderflow ) {
|
| + dummy = array[-1];
|
| + } else if (crash_type == kUseAfterFree) {
|
| + int* dangling = array.get();
|
| + array.reset();
|
| + dummy = dangling[kArraySize / 2];
|
| + }
|
| +
|
| + // Make sure the assignments to the dummy value aren't optimized away.
|
| + base::debug::Alias(&dummy);
|
| +}
|
| +#endif // ADDRESS_SANITIZER
|
| +
|
| +static void MaybeHandleDebugURL(const GURL& url) {
|
| + if (!url.SchemeIs(kChromeUIScheme))
|
| + return;
|
| + if (url == GURL(kChromeUICrashURL)) {
|
| + CrashIntentionally();
|
| + } else if (url == GURL(kChromeUIKillURL)) {
|
| + base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
|
| + } else if (url == GURL(kChromeUIHangURL)) {
|
| + for (;;) {
|
| + base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
|
| + }
|
| + } else if (url == GURL(kChromeUIShorthangURL)) {
|
| + base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
|
| + }
|
| +
|
| +#if defined(ADDRESS_SANITIZER)
|
| + MaybeTriggerAsanError(url);
|
| +#endif // ADDRESS_SANITIZER
|
| +}
|
| +
|
| // Returns false unless this is a top-level navigation.
|
| static bool IsTopLevelNavigation(WebFrame* frame) {
|
| return frame->parent() == NULL;
|
| @@ -417,8 +476,7 @@
|
| return false;
|
| }
|
|
|
| -// static
|
| -void RenderViewImpl::NotifyTimezoneChange(blink::WebFrame* frame) {
|
| +static void NotifyTimezoneChange(blink::WebFrame* frame) {
|
| v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
|
| v8::Context::Scope context_scope(frame->mainWorldScriptContext());
|
| v8::Date::DateTimeConfigurationChangeNotification(v8::Isolate::GetCurrent());
|
| @@ -1140,7 +1198,7 @@
|
| OnSetEditCommandsForNextKeyEvent)
|
| IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo)
|
| IPC_MESSAGE_HANDLER(InputMsg_Unselect, OnUnselect)
|
| - IPC_MESSAGE_HANDLER(FrameMsg_Navigate, OnNavigate)
|
| + IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
|
| IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
|
| IPC_MESSAGE_HANDLER(ViewMsg_ReloadFrame, OnReloadFrame)
|
| IPC_MESSAGE_HANDLER(ViewMsg_SetName, OnSetName)
|
| @@ -1252,12 +1310,182 @@
|
| return handled;
|
| }
|
|
|
| -void RenderViewImpl::OnNavigate(const FrameMsg_Navigate_Params& params) {
|
| +void RenderViewImpl::OnNavigate(const ViewMsg_Navigate_Params& params) {
|
| + MaybeHandleDebugURL(params.url);
|
| + if (!webview())
|
| + return;
|
| +
|
| FOR_EACH_OBSERVER(RenderViewObserver, observers_, Navigate(params.url));
|
| +
|
| + bool is_reload = IsReload(params);
|
| + WebURLRequest::CachePolicy cache_policy =
|
| + WebURLRequest::UseProtocolCachePolicy;
|
| +
|
| + // If this is a stale back/forward (due to a recent navigation the browser
|
| + // didn't know about), ignore it.
|
| + if (IsBackForwardToStaleEntry(params, is_reload))
|
| + return;
|
| +
|
| + // Swap this renderer back in if necessary.
|
| + if (is_swapped_out_) {
|
| + // We marked the view as hidden when swapping the view out, so be sure to
|
| + // reset the visibility state before navigating to the new URL.
|
| + webview()->setVisibilityState(visibilityState(), false);
|
| +
|
| + // If this is an attempt to reload while we are swapped out, we should not
|
| + // reload swappedout://, but the previous page, which is stored in
|
| + // params.state. Setting is_reload to false will treat this like a back
|
| + // navigation to accomplish that.
|
| + is_reload = false;
|
| + cache_policy = WebURLRequest::ReloadIgnoringCacheData;
|
| +
|
| + // We refresh timezone when a view is swapped in since timezone
|
| + // can get out of sync when the system timezone is updated while
|
| + // the view is swapped out.
|
| + NotifyTimezoneChange(webview()->mainFrame());
|
| +
|
| + SetSwappedOut(false);
|
| + }
|
| +
|
| + if (params.should_clear_history_list) {
|
| + CHECK_EQ(params.pending_history_list_offset, -1);
|
| + CHECK_EQ(params.current_history_list_offset, -1);
|
| + CHECK_EQ(params.current_history_list_length, 0);
|
| + }
|
| + history_list_offset_ = params.current_history_list_offset;
|
| + history_list_length_ = params.current_history_list_length;
|
| + if (history_list_length_ >= 0)
|
| + history_page_ids_.resize(history_list_length_, -1);
|
| + if (params.pending_history_list_offset >= 0 &&
|
| + params.pending_history_list_offset < history_list_length_)
|
| + history_page_ids_[params.pending_history_list_offset] = params.page_id;
|
| +
|
| + GetContentClient()->SetActiveURL(params.url);
|
| +
|
| + WebFrame* frame = webview()->mainFrame();
|
| + if (!params.frame_to_navigate.empty()) {
|
| + frame = webview()->findFrameByName(
|
| + WebString::fromUTF8(params.frame_to_navigate));
|
| + CHECK(frame) << "Invalid frame name passed: " << params.frame_to_navigate;
|
| + }
|
| +
|
| + if (is_reload && frame->currentHistoryItem().isNull()) {
|
| + // We cannot reload if we do not have any history state. This happens, for
|
| + // example, when recovering from a crash.
|
| + is_reload = false;
|
| + cache_policy = WebURLRequest::ReloadIgnoringCacheData;
|
| + }
|
| +
|
| + pending_navigation_params_.reset(new ViewMsg_Navigate_Params(params));
|
| +
|
| + // If we are reloading, then WebKit will use the history state of the current
|
| + // page, so we should just ignore any given history state. Otherwise, if we
|
| + // have history state, then we need to navigate to it, which corresponds to a
|
| + // back/forward navigation event.
|
| + if (is_reload) {
|
| + bool reload_original_url =
|
| + (params.navigation_type ==
|
| + ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
|
| + bool ignore_cache = (params.navigation_type ==
|
| + ViewMsg_Navigate_Type::RELOAD_IGNORING_CACHE);
|
| +
|
| + if (reload_original_url)
|
| + frame->reloadWithOverrideURL(params.url, true);
|
| + else
|
| + frame->reload(ignore_cache);
|
| + } else if (params.page_state.IsValid()) {
|
| + // We must know the page ID of the page we are navigating back to.
|
| + DCHECK_NE(params.page_id, -1);
|
| + WebHistoryItem item = PageStateToHistoryItem(params.page_state);
|
| + if (!item.isNull()) {
|
| + // Ensure we didn't save the swapped out URL in UpdateState, since the
|
| + // browser should never be telling us to navigate to swappedout://.
|
| + CHECK(item.urlString() != WebString::fromUTF8(kSwappedOutURL));
|
| + frame->loadHistoryItem(item, cache_policy);
|
| + }
|
| + } else if (!params.base_url_for_data_url.is_empty()) {
|
| + // A loadData request with a specified base URL.
|
| + std::string mime_type, charset, data;
|
| + if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) {
|
| + frame->loadData(
|
| + WebData(data.c_str(), data.length()),
|
| + WebString::fromUTF8(mime_type),
|
| + WebString::fromUTF8(charset),
|
| + params.base_url_for_data_url,
|
| + params.history_url_for_data_url,
|
| + false);
|
| + } else {
|
| + CHECK(false) <<
|
| + "Invalid URL passed: " << params.url.possibly_invalid_spec();
|
| + }
|
| + } else {
|
| + // Navigate to the given URL.
|
| + WebURLRequest request(params.url);
|
| +
|
| + // A session history navigation should have been accompanied by state.
|
| + CHECK_EQ(params.page_id, -1);
|
| +
|
| + if (frame->isViewSourceModeEnabled())
|
| + request.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad);
|
| +
|
| + if (params.referrer.url.is_valid()) {
|
| + WebString referrer = WebSecurityPolicy::generateReferrerHeader(
|
| + params.referrer.policy,
|
| + params.url,
|
| + WebString::fromUTF8(params.referrer.url.spec()));
|
| + if (!referrer.isEmpty())
|
| + request.setHTTPReferrer(referrer, params.referrer.policy);
|
| + }
|
| +
|
| + if (!params.extra_headers.empty()) {
|
| + for (net::HttpUtil::HeadersIterator i(params.extra_headers.begin(),
|
| + params.extra_headers.end(), "\n");
|
| + i.GetNext(); ) {
|
| + request.addHTTPHeaderField(WebString::fromUTF8(i.name()),
|
| + WebString::fromUTF8(i.values()));
|
| + }
|
| + }
|
| +
|
| + if (params.is_post) {
|
| + request.setHTTPMethod(WebString::fromUTF8("POST"));
|
| +
|
| + // Set post data.
|
| + WebHTTPBody http_body;
|
| + http_body.initialize();
|
| + const char* data = NULL;
|
| + if (params.browser_initiated_post_data.size()) {
|
| + data = reinterpret_cast<const char*>(
|
| + ¶ms.browser_initiated_post_data.front());
|
| + }
|
| + http_body.appendData(
|
| + WebData(data, params.browser_initiated_post_data.size()));
|
| + request.setHTTPBody(http_body);
|
| + }
|
| +
|
| + frame->loadRequest(request);
|
| +
|
| + // If this is a cross-process navigation, the browser process will send
|
| + // along the proper navigation start value.
|
| + if (!params.browser_navigation_start.is_null() &&
|
| + frame->provisionalDataSource()) {
|
| + // browser_navigation_start is likely before this process existed, so we
|
| + // can't use InterProcessTimeTicksConverter. Instead, the best we can do
|
| + // is just ensure we don't report a bogus value in the future.
|
| + base::TimeTicks navigation_start = std::min(
|
| + base::TimeTicks::Now(), params.browser_navigation_start);
|
| + double navigation_start_seconds =
|
| + (navigation_start - base::TimeTicks()).InSecondsF();
|
| + frame->provisionalDataSource()->setNavigationStartTime(
|
| + navigation_start_seconds);
|
| + }
|
| + }
|
| +
|
| + // In case LoadRequest failed before DidCreateDataSource was called.
|
| + pending_navigation_params_.reset();
|
| }
|
|
|
| bool RenderViewImpl::IsBackForwardToStaleEntry(
|
| - const FrameMsg_Navigate_Params& params,
|
| + const ViewMsg_Navigate_Params& params,
|
| bool is_reload) {
|
| // Make sure this isn't a back/forward to an entry we have already cropped
|
| // or replaced from our history, before the browser knew about it. If so,
|
| @@ -2917,14 +3145,14 @@
|
|
|
| void RenderViewImpl::PopulateDocumentStateFromPending(
|
| DocumentState* document_state) {
|
| - const FrameMsg_Navigate_Params& params = *pending_navigation_params_.get();
|
| + const ViewMsg_Navigate_Params& params = *pending_navigation_params_.get();
|
| document_state->set_request_time(params.request_time);
|
|
|
| InternalDocumentStateData* internal_data =
|
| InternalDocumentStateData::FromDocumentState(document_state);
|
|
|
| if (!params.url.SchemeIs(kJavaScriptScheme) &&
|
| - params.navigation_type == FrameMsg_Navigate_Type::RESTORE) {
|
| + params.navigation_type == ViewMsg_Navigate_Type::RESTORE) {
|
| // We're doing a load of a page that was restored from the last session. By
|
| // default this prefers the cache over loading (LOAD_PREFERRING_CACHE) which
|
| // can result in stale data for pages that are set to expire. We explicitly
|
| @@ -2949,12 +3177,12 @@
|
| internal_data->set_is_overriding_user_agent(params.is_overriding_user_agent);
|
| internal_data->set_must_reset_scroll_and_scale_state(
|
| params.navigation_type ==
|
| - FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
|
| + ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
|
| document_state->set_can_load_local_resources(params.can_load_local_resources);
|
| }
|
|
|
| NavigationState* RenderViewImpl::CreateNavigationStateFromPending() {
|
| - const FrameMsg_Navigate_Params& params = *pending_navigation_params_.get();
|
| + const ViewMsg_Navigate_Params& params = *pending_navigation_params_.get();
|
| NavigationState* navigation_state = NULL;
|
|
|
| // A navigation resulting from loading a javascript URL should not be treated
|
|
|