summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authordarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-04 17:36:55 +0000
committerdarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-04 17:36:55 +0000
commit7ccddb8cc40f885a50541c4f45afc4253ce3c065 (patch)
treea82976f8905298f6c320ff72331fd41697bc1aa5 /chrome
parentb881ade17222078ce4e0c4dc6cb296ac34ee7387 (diff)
downloadchromium_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.cc4
-rw-r--r--chrome/renderer/navigation_state.h22
-rw-r--r--chrome/renderer/render_view.cc108
-rw-r--r--chrome/renderer/render_view.h18
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(