| 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 126fbad1e2936ad7797250eeecff561ac341f249..025c888848af48305ecacb909c0d5b8c8e1ab049 100644
|
| --- a/content/browser/loader/resource_dispatcher_host_unittest.cc
|
| +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
|
| @@ -2,14 +2,19 @@
|
| // 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/command_line.h"
|
| #include "base/files/file_path.h"
|
| #include "base/files/file_util.h"
|
| #include "base/location.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| #include "base/memory/scoped_vector.h"
|
| #include "base/memory/shared_memory.h"
|
| #include "base/pickle.h"
|
| @@ -47,9 +52,12 @@
|
| #include "content/public/test/test_renderer_host.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"
|
| +#include "net/http/http_response_headers.h"
|
| +#include "net/http/http_response_info.h"
|
| #include "net/http/http_util.h"
|
| #include "net/url_request/url_request.h"
|
| #include "net/url_request/url_request_context.h"
|
| @@ -830,8 +838,10 @@ class ResourceDispatcherHostTest : public testing::Test,
|
| typedef ResourceDispatcherHostImpl::LoadInfo LoadInfo;
|
| typedef ResourceDispatcherHostImpl::LoadInfoMap LoadInfoMap;
|
|
|
| - ResourceDispatcherHostTest()
|
| + ResourceDispatcherHostTest(
|
| + scoped_ptr<net::TestNetworkDelegate> network_delegate)
|
| : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
|
| + network_delegate_(network_delegate.Pass()),
|
| old_factory_(NULL),
|
| send_data_received_acks_(false) {
|
| browser_context_.reset(new TestBrowserContext());
|
| @@ -843,9 +853,15 @@ class ResourceDispatcherHostTest : public testing::Test,
|
| browser_context_->GetResourceContext()->GetRequestContext();
|
| job_factory_.reset(new TestURLRequestJobFactory(this));
|
| request_context->set_job_factory(job_factory_.get());
|
| - request_context->set_network_delegate(&network_delegate_);
|
| + request_context->set_network_delegate(network_delegate_.get());
|
| + // TODO(ricea): Remove this when it becomes the default.
|
| + host_.async_revalidation_enabled_ = true;
|
| }
|
|
|
| + ResourceDispatcherHostTest()
|
| + : ResourceDispatcherHostTest(
|
| + make_scoped_ptr(new net::TestNetworkDelegate)) {}
|
| +
|
| // IPC::Sender implementation
|
| bool Send(IPC::Message* msg) override {
|
| accum_.AddMessage(*msg);
|
| @@ -961,7 +977,9 @@ class ResourceDispatcherHostTest : public testing::Test,
|
| void CompleteStartRequest(int request_id);
|
| void CompleteStartRequest(ResourceMessageFilter* filter, int request_id);
|
|
|
| - net::TestNetworkDelegate* network_delegate() { return &network_delegate_; }
|
| + net::TestNetworkDelegate* network_delegate() {
|
| + return network_delegate_.get();
|
| + }
|
|
|
| void EnsureSchemeIsAllowed(const std::string& scheme) {
|
| ChildProcessSecurityPolicyImpl* policy =
|
| @@ -1021,9 +1039,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_;
|
| @@ -1031,7 +1062,7 @@ class ResourceDispatcherHostTest : public testing::Test,
|
| scoped_ptr<TestWebContentsObserver> web_contents_observer_;
|
| scoped_refptr<ForwardingFilter> filter_;
|
| scoped_refptr<TestFilterSpecifyingChild> web_contents_filter_;
|
| - net::TestNetworkDelegate network_delegate_;
|
| + scoped_ptr<net::TestNetworkDelegate> network_delegate_;
|
| ResourceDispatcherHostImpl host_;
|
| ResourceIPCAccumulator accum_;
|
| std::string response_headers_;
|
| @@ -3397,6 +3428,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);
|
| @@ -3443,4 +3478,294 @@ 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, 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);
|
| +}
|
| +
|
| +TEST_F(ResourceDispatcherHostTest, AsyncRevalidationNotSupportedForRedirect) {
|
| + static const char kRedirectHeaders[] =
|
| + "HTTP/1.1 302 MOVED\n"
|
| + "Location: http://example.com/var\n"
|
| + "\n";
|
| + // Scheme has to be HTTP or HTTPS to support async revalidation.
|
| + HandleScheme("http");
|
| + // Prevent the job from completing synchronously.
|
| + job_factory_->SetDelayedCompleteJobGeneration(true);
|
| + SetResponse(kRedirectHeaders, "");
|
| +
|
| + MakeTestRequest(0, 1, GURL("http://example.com/baz"));
|
| +
|
| + 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 URLRequestJob implementation 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 URLRequestJob implementation which serves a redirect and sets the
|
| +// |async_revalidation_required| flag on the HttpResponseInfo object to true if
|
| +// the request has the LOAD_SUPPORT_ASYNC_REVALIDATION flag.
|
| +class RedirectAndRevalidateURLRequestTestJob : 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 RedirectAndRevalidateURLRequestTestJob(request,
|
| + network_delegate);
|
| + }
|
| +
|
| + void GetResponseInfo(net::HttpResponseInfo* info) override {
|
| + URLRequestTestJob::GetResponseInfo(info);
|
| + if (request()->load_flags() & net::LOAD_SUPPORT_ASYNC_REVALIDATION)
|
| + info->async_revalidation_required = true;
|
| + }
|
| +
|
| + private:
|
| + RedirectAndRevalidateURLRequestTestJob(net::URLRequest* request,
|
| + net::NetworkDelegate* network_delegate)
|
| + : URLRequestTestJob(
|
| + request,
|
| + network_delegate,
|
| + std::string(CreateRedirectHeaders()),
|
| + std::string(),
|
| + false) {}
|
| +
|
| + ~RedirectAndRevalidateURLRequestTestJob() override {}
|
| +
|
| + static std::string CreateRedirectHeaders() {
|
| + static const char kRedirectHeaders[] =
|
| + "HTTP/1.1 302 MOVED\0"
|
| + "Location: http://example.com/var\0"
|
| + "\0";
|
| + return std::string(kRedirectHeaders, arraysize(kRedirectHeaders));
|
| + }
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(RedirectAndRevalidateURLRequestTestJob);
|
| +};
|
| +
|
| +// A NetworkDelegate that records the URLRequests as they are created.
|
| +class URLRequestRecordingNetworkDelegate : public net::TestNetworkDelegate {
|
| + public:
|
| + URLRequestRecordingNetworkDelegate() : requests_() {}
|
| +
|
| + net::URLRequest* NextRequest() {
|
| + if (requests_.empty())
|
| + return nullptr;
|
| + net::URLRequest* request = requests_.front();
|
| + requests_.pop();
|
| + return request;
|
| + }
|
| +
|
| + bool IsEmpty() {
|
| + return requests_.empty();
|
| + }
|
| +
|
| + int OnBeforeURLRequest(net::URLRequest* request,
|
| + const net::CompletionCallback& callback,
|
| + GURL* new_url) override {
|
| + requests_.push(request);
|
| + return TestNetworkDelegate::OnBeforeURLRequest(request, callback, new_url);
|
| + }
|
| +
|
| + private:
|
| + std::queue<net::URLRequest*> requests_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(URLRequestRecordingNetworkDelegate);
|
| +};
|
| +
|
| +class ResourceDispatcherHostAsyncRevalidationTest
|
| + : public ResourceDispatcherHostTest {
|
| + public:
|
| + ResourceDispatcherHostAsyncRevalidationTest()
|
| + : ResourceDispatcherHostTest(
|
| + make_scoped_ptr(new URLRequestRecordingNetworkDelegate)) {
|
| + // Scheme has to be HTTP or HTTPS to support async revalidation.
|
| + HandleScheme("http");
|
| + // Use the AsyncRevalidationRequiredURLRequestTestJob.
|
| + SetCustomURLRequestJobCreateCallback(
|
| + base::Bind(&AsyncRevalidationRequiredURLRequestTestJob::Create));
|
| + }
|
| +
|
| + URLRequestRecordingNetworkDelegate* recording_network_delegate() {
|
| + return static_cast<URLRequestRecordingNetworkDelegate*>(network_delegate());
|
| + }
|
| +
|
| + net::URLRequest* NextRequest() {
|
| + return recording_network_delegate()->NextRequest();
|
| + }
|
| +
|
| + bool IsEmpty() {
|
| + return recording_network_delegate()->IsEmpty();
|
| + }
|
| +};
|
| +
|
| +// Verify that an async revalidation is actually created when needed.
|
| +TEST_F(ResourceDispatcherHostAsyncRevalidationTest, Issued) {
|
| + // Create the original request.
|
| + MakeTestRequest(0, 1, GURL("http://example.com/baz"));
|
| +
|
| + net::URLRequest* initial_request = NextRequest();
|
| + ASSERT_TRUE(initial_request);
|
| + EXPECT_TRUE(initial_request->load_flags() &
|
| + net::LOAD_SUPPORT_ASYNC_REVALIDATION);
|
| +
|
| + net::URLRequest* async_request = NextRequest();
|
| + ASSERT_TRUE(async_request);
|
| +}
|
| +
|
| +// Verify the the URL of the async revalidation matches the original request.
|
| +TEST_F(ResourceDispatcherHostAsyncRevalidationTest, URLMatches) {
|
| + // Create the original request.
|
| + MakeTestRequest(0, 1, GURL("http://example.com/special-baz"));
|
| +
|
| + // Discard the original request.
|
| + NextRequest();
|
| +
|
| + net::URLRequest* async_request = NextRequest();
|
| + ASSERT_TRUE(async_request);
|
| + EXPECT_EQ(GURL("http://example.com/special-baz"), async_request->url());
|
| +}
|
| +
|
| +TEST_F(ResourceDispatcherHostAsyncRevalidationTest,
|
| + AsyncRevalidationsDoNotSupportAsyncRevalidation) {
|
| + // Create the original request.
|
| + MakeTestRequest(0, 1, GURL("http://example.com/baz"));
|
| +
|
| + // Discard the original request.
|
| + NextRequest();
|
| +
|
| + // Get the async revalidation request.
|
| + net::URLRequest* async_request = NextRequest();
|
| + ASSERT_TRUE(async_request);
|
| + EXPECT_FALSE(async_request->load_flags() &
|
| + net::LOAD_SUPPORT_ASYNC_REVALIDATION);
|
| +}
|
| +
|
| +TEST_F(ResourceDispatcherHostAsyncRevalidationTest,
|
| + AsyncRevalidationsNotDuplicated) {
|
| + // Create the original request.
|
| + MakeTestRequest(0, 1, GURL("http://example.com/baz"));
|
| +
|
| + // Discard the original request.
|
| + NextRequest();
|
| +
|
| + // Get the async revalidation request.
|
| + net::URLRequest* async_request = NextRequest();
|
| + EXPECT_TRUE(async_request);
|
| +
|
| + // Start a second request to the same URL.
|
| + MakeTestRequest(0, 2, GURL("http://example.com/baz"));
|
| +
|
| + // Discard the second request.
|
| + NextRequest();
|
| +
|
| + // There should not be another async revalidation request.
|
| + EXPECT_TRUE(IsEmpty());
|
| +}
|
| +
|
| +// Async revalidation to different URLs should not be treated as duplicates.
|
| +TEST_F(ResourceDispatcherHostAsyncRevalidationTest,
|
| + AsyncRevalidationsToSeparateURLsAreSeparate) {
|
| + // Create two requests to two URLs.
|
| + MakeTestRequest(0, 1, GURL("http://example.com/baz"));
|
| + MakeTestRequest(0, 2, GURL("http://example.com/far"));
|
| +
|
| + net::URLRequest* initial_request = NextRequest();
|
| + ASSERT_TRUE(initial_request);
|
| + net::URLRequest* initial_async_revalidation = NextRequest();
|
| + ASSERT_TRUE(initial_async_revalidation);
|
| + net::URLRequest* second_request = NextRequest();
|
| + ASSERT_TRUE(second_request);
|
| + net::URLRequest* second_async_revalidation = NextRequest();
|
| + ASSERT_TRUE(second_async_revalidation);
|
| +
|
| + 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());
|
| +}
|
| +
|
| +// A stale-while-revalidate applicable redirect response should not result in an
|
| +// async revalidation.
|
| +TEST_F(ResourceDispatcherHostAsyncRevalidationTest, RedirectNotApplicable) {
|
| + // Use the appropriate URLRequestJob for the test.
|
| + SetCustomURLRequestJobCreateCallback(
|
| + base::Bind(&RedirectAndRevalidateURLRequestTestJob::Create));
|
| + MakeTestRequest(0, 1, GURL("http://example.com/redirect"));
|
| +
|
| + net::URLRequest* initial_request = NextRequest();
|
| + EXPECT_TRUE(initial_request);
|
| +
|
| + // There should not be an async revalidation request.
|
| + EXPECT_TRUE(IsEmpty());
|
| +}
|
| +
|
| } // namespace content
|
|
|