summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/history/redirect_uitest.cc62
-rw-r--r--chrome/renderer/render_view.cc7
-rw-r--r--webkit/glue/webframeloaderclient_impl.cc16
-rw-r--r--webkit/glue/webview_delegate.h2
4 files changed, 81 insertions, 6 deletions
diff --git a/chrome/browser/history/redirect_uitest.cc b/chrome/browser/history/redirect_uitest.cc
index 0ee58f7..dabeddb 100644
--- a/chrome/browser/history/redirect_uitest.cc
+++ b/chrome/browser/history/redirect_uitest.cc
@@ -251,4 +251,64 @@ TEST_F(RedirectTest, ClientFragments) {
EXPECT_EQ(1, redirects.size());
EXPECT_EQ(first_url.spec() + "#myanchor", redirects[0].spec());
-} \ No newline at end of file
+}
+
+// TODO(timsteele): This is disabled because our current testserver can't
+// handle multiple requests in parallel, making it hang on the first request to
+// /slow?60. It's unable to serve our second request for files/title2.html until
+// /slow? completes, which doesn't give the desired behavior. We could
+// alternatively load the second page from disk, but we would need to start the
+// browser for this testcase with --process-per-tab, and I don't think we can do
+// this at test-case-level granularity at the moment.
+TEST_F(RedirectTest, DISABLED_ClientCancelledByNewNavigationAfterProvisionalLoad) {
+ // We want to initiate a second navigation after the provisional load for
+ // the client redirect destination has started, but before this load is
+ // committed. To achieve this, we tell the browser to load a slow page,
+ // which causes it to start a provisional load, and while it is waiting
+ // for the response (which means it hasn't committed the load for the client
+ // redirect destination page yet), we issue a new navigation request.
+ TestServer server(kDocRoot);
+
+ GURL final_url = server.TestServerPageW(std::wstring(L"files/title2.html"));
+ GURL slow = server.TestServerPageW(std::wstring(L"slow?60"));
+ GURL first_url = server.TestServerPageW(
+ std::wstring(L"client-redirect?") + UTF8ToWide(slow.spec()));
+ std::vector<GURL> redirects;
+
+ NavigateToURL(first_url);
+ // We don't sleep here - the first navigation won't have been committed yet
+ // because we told the server to wait a minute. This means the browser has
+ // started it's provisional load for the client redirect destination page but
+ // hasn't completed. Our time is now!
+ NavigateToURL(final_url);
+
+ std::wstring tab_title;
+ std::wstring final_url_title = L"Title Of Awesomeness";
+ // Wait till the final page has been loaded.
+ for (int i = 0; i < 10; ++i) {
+ Sleep(kWaitForActionMaxMsec / 10);
+ scoped_ptr<TabProxy> tab_proxy(GetActiveTab());
+ ASSERT_TRUE(tab_proxy.get());
+ ASSERT_TRUE(tab_proxy->GetTabTitle(&tab_title));
+ if (tab_title == final_url_title) {
+ ASSERT_TRUE(tab_proxy->GetRedirectsFrom(first_url, &redirects));
+ break;
+ }
+ }
+
+ // Check to make sure the navigation did in fact take place and we are
+ // at the expected page.
+ EXPECT_EQ(final_url_title, tab_title);
+
+ bool final_navigation_not_redirect = true;
+ // Check to make sure our request for files/title2.html doesn't get flagged
+ // as a client redirect from the first (/client-redirect?) page.
+ for (std::vector<GURL>::iterator it = redirects.begin();
+ it != redirects.end(); ++it) {
+ if (final_url.spec() == it->spec()) {
+ final_navigation_not_redirect = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(final_navigation_not_redirect);
+}
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 519e37d..28a9195 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -1015,6 +1015,7 @@ void RenderView::UpdateURL(WebFrame* frame) {
// the page contained a client redirect (meta refresh, document.loc...),
// so we set the referrer and transition to match.
if (completed_client_redirect_src_.is_valid()) {
+ DCHECK(completed_client_redirect_src_ == params.redirects[0]);
params.referrer = completed_client_redirect_src_;
params.transition = static_cast<PageTransition::Type>(
params.transition | PageTransition::CLIENT_REDIRECT);
@@ -1146,8 +1147,12 @@ void RenderView::DidStartProvisionalLoadForFrame(
WebView* webview,
WebFrame* frame,
NavigationGesture gesture) {
- if (webview->GetMainFrame() == frame)
+ if (webview->GetMainFrame() == frame) {
navigation_gesture_ = gesture;
+
+ // Make sure redirect tracking state is clear for the new load.
+ completed_client_redirect_src_ = GURL();
+ }
Send(new ViewHostMsg_DidStartProvisionalLoadForFrame(
routing_id_, webview->GetMainFrame() == frame,
diff --git a/webkit/glue/webframeloaderclient_impl.cc b/webkit/glue/webframeloaderclient_impl.cc
index 232230f..ec1ff4b 100644
--- a/webkit/glue/webframeloaderclient_impl.cc
+++ b/webkit/glue/webframeloaderclient_impl.cc
@@ -671,6 +671,7 @@ void WebFrameLoaderClient::dispatchDidStartProvisionalLoad() {
// If this load is what we expected from a client redirect, treat it as a
// redirect from that original page. The expected redirect urls will be
// cleared by DidCancelClientRedirect.
+ bool completing_client_redirect = false;
if (expected_client_redirect_src_.is_valid()) {
// expected_client_redirect_dest_ could be something like
// "javascript:history.go(-1)" thus we need to exclude url starts with
@@ -678,15 +679,22 @@ void WebFrameLoaderClient::dispatchDidStartProvisionalLoad() {
DCHECK(expected_client_redirect_dest_.SchemeIs("javascript") ||
expected_client_redirect_dest_ == url);
ds->AppendRedirect(expected_client_redirect_src_);
- if (d)
- d->DidCompleteClientRedirect(webview, webframe_,
- expected_client_redirect_src_);
+ completing_client_redirect = true;
}
ds->AppendRedirect(url);
- if (d)
+ if (d) {
+ // As the comment for DidCompleteClientRedirect in webview_delegate.h
+ // points out, whatever information its invocation contains should only
+ // be considered relevant until the next provisional load has started.
+ // So we first tell the delegate that the load started, and then tell it
+ // about the client redirect the load is responsible for completing.
d->DidStartProvisionalLoadForFrame(webview, webframe_,
NavigationGestureForLastLoad());
+ if (completing_client_redirect)
+ d->DidCompleteClientRedirect(webview, webframe_,
+ expected_client_redirect_src_);
+ }
// Cancel any pending loads.
if (alt_404_page_fetcher_.get())
diff --git a/webkit/glue/webview_delegate.h b/webkit/glue/webview_delegate.h
index f7aedd5..cf18ca5 100644
--- a/webkit/glue/webview_delegate.h
+++ b/webkit/glue/webview_delegate.h
@@ -404,6 +404,8 @@ class WebViewDelegate : virtual public WebWidgetDelegate {
// Notifies the delegate that the load about to be committed for the specified
// webview and frame was due to a client redirect originating from source URL.
+ // The information/notification obtained from this method is relevant until
+ // the next provisional load is started, at which point it becomes obsolete.
virtual void DidCompleteClientRedirect(WebView* webview,
WebFrame* frame,
const GURL& source) {