diff options
author | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-04 17:36:55 +0000 |
---|---|---|
committer | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-04 17:36:55 +0000 |
commit | 7ccddb8cc40f885a50541c4f45afc4253ce3c065 (patch) | |
tree | a82976f8905298f6c320ff72331fd41697bc1aa5 /chrome | |
parent | b881ade17222078ce4e0c4dc6cb296ac34ee7387 (diff) | |
download | chromium_src-7ccddb8cc40f885a50541c4f45afc4253ce3c065.zip chromium_src-7ccddb8cc40f885a50541c4f45afc4253ce3c065.tar.gz chromium_src-7ccddb8cc40f885a50541c4f45afc4253ce3c065.tar.bz2 |
Move alternate 404 error page loading out of WebFrame and into RenderView.
This involved adding a new method on WebViewDelegate to allow the embedder to
intercept data being loaded for a document.
I also had to plumb a few more FrameLoaderClient notifications through
WebViewDelegate. See DidReceiveResponse and DidFinishLoading.
R=tony
BUG=15648
TEST=covered by errorpage_uitest.cc
Review URL: http://codereview.chromium.org/160578
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22389 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 4 | ||||
-rw-r--r-- | chrome/renderer/navigation_state.h | 22 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 108 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 18 |
4 files changed, 132 insertions, 20 deletions
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 7fcbe0a..9b11bdc 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -2201,8 +2201,8 @@ GURL TabContents::GetAlternateErrorPageURL() const { WebPreferences TabContents::GetWebkitPrefs() { PrefService* prefs = render_view_host()->process()->profile()->GetPrefs(); - bool isDomUI = false; - return RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, isDomUI); + bool is_dom_ui = false; + return RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, is_dom_ui); } void TabContents::OnJSOutOfMemory() { diff --git a/chrome/renderer/navigation_state.h b/chrome/renderer/navigation_state.h index ec45808..ecb79fd 100644 --- a/chrome/renderer/navigation_state.h +++ b/chrome/renderer/navigation_state.h @@ -144,6 +144,23 @@ class NavigationState : public WebKit::WebDataSource::ExtraData { security_info_ = security_info; } + bool postpone_loading_data() const { + return postpone_loading_data_; + } + void set_postpone_loading_data(bool postpone_loading_data) { + postpone_loading_data_ = postpone_loading_data; + } + + void clear_postponed_data() { + postponed_data_.clear(); + } + void append_postponed_data(const char* data, size_t data_len) { + postponed_data_.append(data, data_len); + } + const std::string& postponed_data() const { + return postponed_data_; + } + private: NavigationState(PageTransition::Type transition_type, const base::Time& request_time, @@ -154,7 +171,8 @@ class NavigationState : public WebKit::WebDataSource::ExtraData { load_histograms_recorded_(false), request_committed_(false), is_content_initiated_(is_content_initiated), - pending_page_id_(pending_page_id) { + pending_page_id_(pending_page_id), + postpone_loading_data_(false) { } PageTransition::Type transition_type_; @@ -173,6 +191,8 @@ class NavigationState : public WebKit::WebDataSource::ExtraData { scoped_ptr<webkit_glue::PasswordForm> password_form_data_; scoped_ptr<webkit_glue::AltErrorPageResourceFetcher> alt_error_page_fetcher_; std::string security_info_; + bool postpone_loading_data_; + std::string postponed_data_; DISALLOW_COPY_AND_ASSIGN(NavigationState); }; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 54305ee..c1ace50 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1283,6 +1283,26 @@ void RenderView::LoadNavigationErrorPage(WebFrame* frame, replace); } +void RenderView::DidReceiveDocumentData(WebFrame* frame, const char* data, + size_t data_len) { + NavigationState* navigation_state = + NavigationState::FromDataSource(frame->GetDataSource()); + if (!navigation_state->postpone_loading_data()) { + frame->CommitDocumentData(data, data_len); + return; + } + + // Continue buffering the response data for the original 404 page. If it + // grows too large, then we'll just let it through. + navigation_state->append_postponed_data(data, data_len); + if (navigation_state->postponed_data().size() >= 512) { + navigation_state->set_postpone_loading_data(false); + frame->CommitDocumentData(navigation_state->postponed_data().data(), + navigation_state->postponed_data().size()); + navigation_state->clear_postponed_data(); + } +} + void RenderView::DidCommitLoadForFrame(WebView *webview, WebFrame* frame, bool is_new_navigation) { NavigationState* navigation_state = @@ -1442,31 +1462,81 @@ void RenderView::WillSubmitForm(WebView* webview, WebFrame* frame, } } -void RenderView::WillSendRequest(WebView* webview, - uint32 identifier, +void RenderView::WillSendRequest(WebFrame* frame, uint32 identifier, WebURLRequest* request) { request->setRequestorID(routing_id_); } -void RenderView::BindDOMAutomationController(WebFrame* webframe) { +void RenderView::DidReceiveResponse(WebFrame* frame, uint32 identifier, + const WebURLResponse& response) { + // Consider loading an alternate error page for 404 responses. + if (response.httpStatusCode() != 404) + return; + + // Only do this for responses that correspond to a provisional data source + // of the top-most frame. If we have a provisional data source, then we + // can't have any sub-resources yet, so we know that this response must + // correspond to a frame load. + if (!frame->GetProvisionalDataSource() || frame->GetParent()) + return; + + // If we are in view source mode, then just let the user see the source of + // the server's 404 error page. + if (frame->GetInViewSourceMode()) + return; + + // Can we even load an alternate error page for this URL? + if (!GetAlternateErrorPageURL(response.url(), HTTP_404).is_valid()) + return; + + NavigationState* navigation_state = + NavigationState::FromDataSource(frame->GetProvisionalDataSource()); + navigation_state->set_postpone_loading_data(true); + navigation_state->clear_postponed_data(); +} + +void RenderView::DidFinishLoading(WebFrame* frame, uint32 identifier) { + NavigationState* navigation_state = + NavigationState::FromDataSource(frame->GetDataSource()); + if (!navigation_state->postpone_loading_data()) + return; + + // The server returned a 404 and the content was < 512 bytes (which we + // suppressed). Go ahead and fetch the alternate page content. + + const GURL& frame_url = frame->GetURL(); + + const GURL& error_page_url = GetAlternateErrorPageURL(frame_url, HTTP_404); + DCHECK(error_page_url.is_valid()); + + WebURLError original_error; + original_error.unreachableURL = frame_url; + + navigation_state->set_alt_error_page_fetcher( + new AltErrorPageResourceFetcher( + error_page_url, frame, original_error, + NewCallback(this, &RenderView::AltErrorPageFinished))); +} + +void RenderView::BindDOMAutomationController(WebFrame* frame) { dom_automation_controller_.set_message_sender(this); dom_automation_controller_.set_routing_id(routing_id_); - dom_automation_controller_.BindToJavascript(webframe, + dom_automation_controller_.BindToJavascript(frame, L"domAutomationController"); } -void RenderView::WindowObjectCleared(WebFrame* webframe) { +void RenderView::WindowObjectCleared(WebFrame* frame) { if (BindingsPolicy::is_dom_automation_enabled(enabled_bindings_)) - BindDOMAutomationController(webframe); + BindDOMAutomationController(frame); if (BindingsPolicy::is_dom_ui_enabled(enabled_bindings_)) { dom_ui_bindings_.set_message_sender(this); dom_ui_bindings_.set_routing_id(routing_id_); - dom_ui_bindings_.BindToJavascript(webframe, L"chrome"); + dom_ui_bindings_.BindToJavascript(frame, L"chrome"); } if (BindingsPolicy::is_external_host_enabled(enabled_bindings_)) { external_host_bindings_.set_message_sender(this); external_host_bindings_.set_routing_id(routing_id_); - external_host_bindings_.BindToJavascript(webframe, L"externalHost"); + external_host_bindings_.BindToJavascript(frame, L"externalHost"); } } @@ -2113,9 +2183,9 @@ void RenderView::OnGetApplicationInfo(int page_id) { Send(new ViewHostMsg_DidGetApplicationInfo(routing_id_, page_id, app_info)); } -GURL RenderView::GetAlternateErrorPageURL(const GURL& failedURL, +GURL RenderView::GetAlternateErrorPageURL(const GURL& failed_url, ErrorPageType error_type) { - if (failedURL.SchemeIsSecure()) { + if (failed_url.SchemeIsSecure()) { // If the URL that failed was secure, then the embedding web page was not // expecting a network attacker to be able to manipulate its contents. As // we fetch alternate error pages over HTTP, we would be allowing a network @@ -2134,7 +2204,7 @@ GURL RenderView::GetAlternateErrorPageURL(const GURL& failedURL, remove_params.ClearPassword(); remove_params.ClearQuery(); remove_params.ClearRef(); - const GURL url_to_send = failedURL.ReplaceComponents(remove_params); + const GURL url_to_send = failed_url.ReplaceComponents(remove_params); // Construct the query params to send to link doctor. std::string params(alternate_error_page_url_.query()); @@ -2862,8 +2932,7 @@ bool RenderView::MaybeLoadAlternateErrorPage(WebFrame* frame, return false; const GURL& error_page_url = GetAlternateErrorPageURL(error.unreachableURL, - ec == net::ERR_NAME_NOT_RESOLVED ? WebViewDelegate::DNS_ERROR - : WebViewDelegate::CONNECTION_ERROR); + ec == net::ERR_NAME_NOT_RESOLVED ? DNS_ERROR : CONNECTION_ERROR); if (!error_page_url.is_valid()) return false; @@ -2906,7 +2975,18 @@ void RenderView::AltErrorPageFinished(WebFrame* frame, const WebURLError& original_error, const std::string& html) { // Here, we replace the blank page we loaded previously. - LoadNavigationErrorPage(frame, WebURLRequest(), original_error, html, true); + + // If we failed to download the alternate error page, fall back to the + // original error page if present. Otherwise, LoadNavigationErrorPage + // will simply display a default error page. + const std::string* html_to_load = &html; + if (html.empty()) { + NavigationState* navigation_state = + NavigationState::FromDataSource(frame->GetDataSource()); + html_to_load = &navigation_state->postponed_data(); + } + LoadNavigationErrorPage( + frame, WebURLRequest(), original_error, *html_to_load, true); } void RenderView::OnMoveOrResizeStarted() { diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 37c40a0..255c7a5 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -186,6 +186,8 @@ class RenderView : public RenderWidget, const WebKit::WebURLError& error, const std::string& html, bool replace); + virtual void DidReceiveDocumentData(WebFrame* frame, const char* data, + size_t data_len); virtual void DidCommitLoadForFrame(WebView* webview, WebFrame* frame, bool is_new_navigation); virtual void DidReceiveTitle(WebView* webview, @@ -216,9 +218,13 @@ class RenderView : public RenderWidget, virtual void WillCloseFrame(WebView* webview, WebFrame* frame); virtual void WillSubmitForm(WebView* webview, WebFrame* frame, const WebKit::WebForm& form); - virtual void WillSendRequest(WebView* webview, + virtual void WillSendRequest(WebFrame* webframe, uint32 identifier, WebKit::WebURLRequest* request); + virtual void DidReceiveResponse(WebFrame* webframe, + uint32 identifier, + const WebKit::WebURLResponse& response); + virtual void DidFinishLoading(WebFrame* webframe, uint32 identifier); virtual void WindowObjectCleared(WebFrame* webframe); virtual void DocumentElementAvailable(WebFrame* webframe); @@ -260,8 +266,6 @@ class RenderView : public RenderWidget, const GURL& image_url, bool errored, const SkBitmap& image); - virtual GURL GetAlternateErrorPageURL(const GURL& failedURL, - ErrorPageType error_type); virtual void ShowContextMenu(WebView* webview, ContextNodeType node_type, @@ -609,7 +613,15 @@ class RenderView : public RenderWidget, // Locates a sub frame with given xpath WebFrame* GetChildFrame(const std::wstring& frame_xpath) const; + enum ErrorPageType { + DNS_ERROR, + HTTP_404, + CONNECTION_ERROR, + }; + // Alternate error page helpers. + GURL GetAlternateErrorPageURL( + const GURL& failed_url, ErrorPageType error_type); bool MaybeLoadAlternateErrorPage( WebFrame* frame, const WebKit::WebURLError& error, bool replace); std::string GetAltHTMLForTemplate( |