Index: content/browser/loader/resource_dispatcher_host_unittest.cc |
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc |
index 9db7d37188e5d8e7068e16d5f5fc976784c70785..54f74d4145329ca3f7bfd148678852f8bcfeda57 100644 |
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc |
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc |
@@ -2,10 +2,13 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <queue> |
+#include <string> |
#include <vector> |
#include "base/basictypes.h" |
#include "base/bind.h" |
+#include "base/callback.h" |
#include "base/files/file_path.h" |
#include "base/files/file_util.h" |
#include "base/memory/scoped_vector.h" |
@@ -38,6 +41,7 @@ |
#include "content/public/test/test_browser_thread_bundle.h" |
#include "content/test/test_content_browser_client.h" |
#include "net/base/elements_upload_data_stream.h" |
+#include "net/base/load_flags.h" |
#include "net/base/net_errors.h" |
#include "net/base/request_priority.h" |
#include "net/base/upload_bytes_element_reader.h" |
@@ -785,6 +789,8 @@ class ResourceDispatcherHostTest : public testing::Test, |
job_factory_.reset(new TestURLRequestJobFactory(this)); |
request_context->set_job_factory(job_factory_.get()); |
request_context->set_network_delegate(&network_delegate_); |
+ // TODO(ricea): Remove this when it becomes the default. |
+ host_.async_revalidation_enabled_ = true; |
} |
// IPC::Sender implementation |
@@ -942,9 +948,22 @@ class ResourceDispatcherHostTest : public testing::Test, |
wait_for_request_complete_loop_.reset(); |
} |
+ typedef base::Callback<net::URLRequestJob*(net::URLRequest*, |
+ net::NetworkDelegate*)> |
+ URLRequestJobCreateCallback; |
+ |
+ void SetCustomURLRequestJobCreateCallback( |
+ const URLRequestJobCreateCallback& callback) { |
+ custom_url_request_job_create_callback_.reset( |
+ new URLRequestJobCreateCallback(callback)); |
+ } |
+ |
scoped_ptr<LoadInfoTestRequestInfo> loader_test_request_info_; |
scoped_ptr<base::RunLoop> wait_for_request_create_loop_; |
+ scoped_ptr<URLRequestJobCreateCallback> |
+ custom_url_request_job_create_callback_; |
+ |
content::TestBrowserThreadBundle thread_bundle_; |
scoped_ptr<TestBrowserContext> browser_context_; |
scoped_ptr<TestURLRequestJobFactory> job_factory_; |
@@ -3202,6 +3221,10 @@ net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler( |
return new URLRequestLoadInfoJob(request, network_delegate, |
info->load_state, info->upload_progress); |
} |
+ if (test_fixture_->custom_url_request_job_create_callback_) { |
+ return test_fixture_->custom_url_request_job_create_callback_->Run( |
+ request, network_delegate); |
+ } |
if (test_fixture_->response_headers_.empty()) { |
if (delay_start_) { |
return new URLRequestTestDelayedStartJob(request, network_delegate); |
@@ -3248,4 +3271,220 @@ net::URLRequestJob* TestURLRequestJobFactory::MaybeInterceptResponse( |
return nullptr; |
} |
+TEST_F(ResourceDispatcherHostTest, SupportsAsyncRevalidation) { |
+ // Scheme has to be HTTP or HTTPS to support async revalidation. |
+ HandleScheme("http"); |
+ // Prevent the job from completing synchronously. |
+ job_factory_->SetDelayedCompleteJobGeneration(true); |
+ SetResponse(net::URLRequestTestJob::test_headers(), "delay complete"); |
+ MakeTestRequest(0, 1, GURL("http://example.com/baz")); |
+ |
+ net::URLRequest* url_request( |
+ host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); |
+ ASSERT_TRUE(url_request); |
+ |
+ EXPECT_TRUE(url_request->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION); |
+} |
+ |
+TEST_F(ResourceDispatcherHostTest, RequestsNotAsyncByDefault) { |
+ // Scheme has to be HTTP or HTTPS to support async revalidation. |
+ HandleScheme("http"); |
+ // Prevent the job from completing synchronously. |
+ job_factory_->SetDelayedCompleteJobGeneration(true); |
+ SetResponse(net::URLRequestTestJob::test_headers(), "delay complete"); |
+ MakeTestRequest(0, 1, GURL("http://example.com/baz")); |
+ |
+ ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest( |
+ host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); |
+ ASSERT_TRUE(info); |
+ |
+ EXPECT_FALSE(info->IsAsyncRevalidation()); |
+} |
+ |
+TEST_F(ResourceDispatcherHostTest, AsyncRevalidationNotSupportedForPOST) { |
+ // Scheme has to be HTTP or HTTPS to support async revalidation. |
+ HandleScheme("http"); |
+ // Prevent the job from completing synchronously. |
+ job_factory_->SetDelayedCompleteJobGeneration(true); |
+ SetResponse(net::URLRequestTestJob::test_headers(), "delay complete"); |
+ // Create POST request. |
+ ResourceHostMsg_Request request = CreateResourceRequest( |
+ "POST", RESOURCE_TYPE_SUB_RESOURCE, GURL("http://example.com/baz.php")); |
+ ResourceHostMsg_RequestResource msg(0, 1, request); |
+ host_.OnMessageReceived(msg, filter_.get()); |
+ KickOffRequest(); |
+ |
+ net::URLRequest* url_request( |
+ host_.GetURLRequest(GlobalRequestID(filter_->child_id(), 1))); |
+ ASSERT_TRUE(url_request); |
+ |
+ EXPECT_FALSE(url_request->load_flags() & |
+ net::LOAD_SUPPORT_ASYNC_REVALIDATION); |
+} |
+ |
+// A URLRequest job type which sets the |async_revalidation_required| flag on |
+// the HttpResponseInfo object to true if the request has the |
+// LOAD_SUPPORT_ASYNC_REVALIDATION flag. |
+class AsyncRevalidationRequiredURLRequestTestJob |
+ : public net::URLRequestTestJob { |
+ public: |
+ // The Create() method is useful for wrapping the construction of the object |
+ // in a Callback. |
+ static net::URLRequestJob* Create(net::URLRequest* request, |
+ net::NetworkDelegate* network_delegate) { |
+ return new AsyncRevalidationRequiredURLRequestTestJob(request, |
+ network_delegate); |
+ } |
+ |
+ void GetResponseInfo(net::HttpResponseInfo* info) override { |
+ if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION) |
+ info->async_revalidation_required = true; |
+ } |
+ |
+ private: |
+ AsyncRevalidationRequiredURLRequestTestJob( |
+ net::URLRequest* request, |
+ net::NetworkDelegate* network_delegate) |
+ : URLRequestTestJob(request, |
+ network_delegate, |
+ net::URLRequestTestJob::test_headers(), |
+ std::string(), |
+ false) {} |
+ |
+ ~AsyncRevalidationRequiredURLRequestTestJob() override {} |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AsyncRevalidationRequiredURLRequestTestJob); |
+}; |
+ |
+// A ResourceDispatcherHostDelegate that records the URLRequests that it sees |
+// in a queue. |
+class URLRequestRecordingResourceDispatcherHostDelegate |
+ : public ResourceDispatcherHostDelegate { |
+ public: |
+ URLRequestRecordingResourceDispatcherHostDelegate() : requests_() {} |
+ |
+ net::URLRequest* NextRequest() { |
+ CHECK(!requests_.empty()); |
+ net::URLRequest* request = requests_.front(); |
+ requests_.pop(); |
+ return request; |
+ } |
+ |
+ bool IsEmpty() { |
+ return requests_.empty(); |
+ } |
+ |
+ void OnResponseStarted(net::URLRequest* request, |
+ ResourceContext* resource_context, |
+ ResourceResponse* response, |
+ IPC::Sender* sender) override { |
+ requests_.push(request); |
+ } |
+ |
+ private: |
+ std::queue<net::URLRequest*> requests_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(URLRequestRecordingResourceDispatcherHostDelegate); |
+}; |
+ |
+TEST_F(ResourceDispatcherHostTest, AsyncRevalidationIssued) { |
+ // Scheme has to be HTTP or HTTPS to support async revalidation. |
+ HandleScheme("http"); |
+ // Use the AsyncRevalidationRequiredURLRequestTestJob. |
+ SetCustomURLRequestJobCreateCallback( |
+ base::Bind(&AsyncRevalidationRequiredURLRequestTestJob::Create)); |
+ URLRequestRecordingResourceDispatcherHostDelegate delegate; |
+ host_.SetDelegate(&delegate); |
+ MakeTestRequest(0, 1, GURL("http://example.com/baz")); |
+ |
+ net::URLRequest* initial_request = delegate.NextRequest(); |
+ ASSERT_TRUE(initial_request); |
+ ResourceRequestInfoImpl* initial_info = |
+ ResourceRequestInfoImpl::ForRequest(initial_request); |
+ ASSERT_TRUE(initial_info); |
+ |
+ EXPECT_FALSE(initial_info->IsAsyncRevalidation()); |
+ |
+ net::URLRequest* async_request = delegate.NextRequest(); |
+ ASSERT_TRUE(async_request); |
+ ResourceRequestInfoImpl* async_info = |
+ ResourceRequestInfoImpl::ForRequest(async_request); |
+ ASSERT_TRUE(async_info); |
+ |
+ EXPECT_TRUE(async_info->IsAsyncRevalidation()); |
+} |
+ |
+TEST_F(ResourceDispatcherHostTest, |
+ AsyncRevalidationsDoNotSupportAsyncRevalidation) { |
+ // Scheme has to be HTTP or HTTPS to support async revalidation. |
+ HandleScheme("http"); |
+ // Use the AsyncRevalidationRequiredURLRequestTestJob. |
+ SetCustomURLRequestJobCreateCallback( |
+ base::Bind(&AsyncRevalidationRequiredURLRequestTestJob::Create)); |
+ URLRequestRecordingResourceDispatcherHostDelegate delegate; |
+ host_.SetDelegate(&delegate); |
+ MakeTestRequest(0, 1, GURL("http://example.com/baz")); |
+ |
+ // Discard the original request. |
+ delegate.NextRequest(); |
+ |
+ // Get the async revalidation request. |
+ net::URLRequest* async_request = delegate.NextRequest(); |
+ |
+ EXPECT_FALSE(async_request->load_flags() & |
+ net::LOAD_SUPPORT_ASYNC_REVALIDATION); |
+} |
+ |
+TEST_F(ResourceDispatcherHostTest, AsyncRevalidationsNotDuplicated) { |
+ // Scheme has to be HTTP or HTTPS to support async revalidation. |
+ HandleScheme("http"); |
+ // Use the AsyncRevalidationRequiredURLRequestTestJob. |
+ SetCustomURLRequestJobCreateCallback( |
+ base::Bind(&AsyncRevalidationRequiredURLRequestTestJob::Create)); |
+ URLRequestRecordingResourceDispatcherHostDelegate delegate; |
+ host_.SetDelegate(&delegate); |
+ MakeTestRequest(0, 1, GURL("http://example.com/baz")); |
+ |
+ // Discard the original request. |
+ delegate.NextRequest(); |
+ |
+ // Get the async revalidation request info. |
+ ResourceRequestInfoImpl* async_info = |
+ ResourceRequestInfoImpl::ForRequest(delegate.NextRequest()); |
+ |
+ // Start a second request to the same URL. |
+ MakeTestRequest(0, 2, GURL("http://example.com/baz")); |
+ |
+ ResourceRequestInfoImpl* second_request_info = |
+ ResourceRequestInfoImpl::ForRequest(delegate.NextRequest()); |
+ |
+ EXPECT_TRUE(async_info->IsAsyncRevalidation()); |
+ EXPECT_FALSE(second_request_info->IsAsyncRevalidation()); |
+ EXPECT_TRUE(delegate.IsEmpty()); |
+} |
+ |
+// Async revalidation to different URLs should not be treated as duplicates. |
+TEST_F(ResourceDispatcherHostTest, |
+ AsyncRevalidationsToSeparateURLsAreSeparate) { |
+ // Scheme has to be HTTP or HTTPS to support async revalidation. |
+ HandleScheme("http"); |
+ // Use the AsyncRevalidationRequiredURLRequestTestJob. |
+ SetCustomURLRequestJobCreateCallback( |
+ base::Bind(&AsyncRevalidationRequiredURLRequestTestJob::Create)); |
+ URLRequestRecordingResourceDispatcherHostDelegate delegate; |
+ host_.SetDelegate(&delegate); |
+ MakeTestRequest(0, 1, GURL("http://example.com/baz")); |
+ MakeTestRequest(0, 2, GURL("http://example.com/far")); |
+ |
+ net::URLRequest* initial_request = delegate.NextRequest(); |
+ net::URLRequest* initial_async_revalidation = delegate.NextRequest(); |
+ net::URLRequest* second_request = delegate.NextRequest(); |
+ net::URLRequest* second_async_revalidation = delegate.NextRequest(); |
+ |
+ EXPECT_EQ("http://example.com/baz", initial_request->url().spec()); |
+ EXPECT_EQ("http://example.com/baz", initial_async_revalidation->url().spec()); |
+ EXPECT_EQ("http://example.com/far", second_request->url().spec()); |
+ EXPECT_EQ("http://example.com/far", second_async_revalidation->url().spec()); |
+} |
+ |
} // namespace content |