diff options
author | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-16 19:10:14 +0000 |
---|---|---|
committer | mmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-16 19:10:14 +0000 |
commit | 0a0e2c7bd89b164298c31eaa89853da10df0d3cf (patch) | |
tree | b8362ead5b5065b5a21bcd695b6fb11225f3c7c9 /content/child/resource_dispatcher_unittest.cc | |
parent | cef56eabc38047340ea3229e85506afcd187984e (diff) | |
download | chromium_src-0a0e2c7bd89b164298c31eaa89853da10df0d3cf.zip chromium_src-0a0e2c7bd89b164298c31eaa89853da10df0d3cf.tar.gz chromium_src-0a0e2c7bd89b164298c31eaa89853da10df0d3cf.tar.bz2 |
Fix a potential file handle leak in ResourceDispatcher
when cancelling a request being downloaded to a file.
Also add a bunch of ResourceDispatcher tests.
BUG=384507
Review URL: https://codereview.chromium.org/330903003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277514 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/child/resource_dispatcher_unittest.cc')
-rw-r--r-- | content/child/resource_dispatcher_unittest.cc | 727 |
1 files changed, 549 insertions, 178 deletions
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc index 0cbd7d1..86dc17f 100644 --- a/content/child/resource_dispatcher_unittest.cc +++ b/content/child/resource_dispatcher_unittest.cc @@ -5,11 +5,14 @@ #include <string> #include <vector> +#include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" #include "base/message_loop/message_loop.h" #include "base/process/process.h" #include "base/process/process_handle.h" #include "base/run_loop.h" +#include "base/stl_util.h" #include "content/child/request_extra_data.h" #include "content/child/request_info.h" #include "content/child/resource_dispatcher.h" @@ -27,20 +30,30 @@ using webkit_glue::ResourceLoaderBridge; namespace content { -static const char test_page_url[] = "http://www.google.com/"; -static const char test_page_headers[] = +static const char kTestPageUrl[] = "http://www.google.com/"; +static const char kTestPageHeaders[] = "HTTP/1.1 200 OK\nContent-Type:text/html\n\n"; -static const char test_page_mime_type[] = "text/html"; -static const char test_page_charset[] = ""; -static const char test_page_contents[] = +static const char kTestPageMimeType[] = "text/html"; +static const char kTestPageCharset[] = ""; +static const char kTestPageContents[] = "<html><head><title>Google</title></head><body><h1>Google</h1></body></html>"; -static const uint32 test_page_contents_len = arraysize(test_page_contents) - 1; +static const char kTestRedirectHeaders[] = + "HTTP/1.1 302 Found\nLocation:http://www.google.com/\n\n"; // Listens for request response data and stores it so that it can be compared // to the reference data. -class TestRequestCallback : public RequestPeer { +class TestRequestPeer : public RequestPeer { public: - TestRequestCallback() : complete_(false) { + TestRequestPeer(ResourceLoaderBridge* bridge) + : follow_redirects_(true), + defer_on_redirect_(false), + seen_redirects_(0), + cancel_on_receive_response_(false), + received_response_(false), + total_encoded_data_length_(0), + total_downloaded_data_length_(0), + complete_(false), + bridge_(bridge) { } virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE { @@ -49,18 +62,28 @@ class TestRequestCallback : public RequestPeer { virtual bool OnReceivedRedirect(const GURL& new_url, const GURL& new_first_party_for_cookies, const ResourceResponseInfo& info) OVERRIDE { - return true; + ++seen_redirects_; + if (defer_on_redirect_) + bridge_->SetDefersLoading(true); + return follow_redirects_; } virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE { + EXPECT_FALSE(received_response_); + received_response_ = true; + if (cancel_on_receive_response_) + bridge_->Cancel(); } virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE { + total_downloaded_data_length_ += len; + total_encoded_data_length_ += encoded_data_length; } virtual void OnReceivedData(const char* data, int data_length, int encoded_data_length) OVERRIDE { + EXPECT_TRUE(received_response_); EXPECT_FALSE(complete_); data_.append(data, data_length); total_encoded_data_length_ += encoded_data_length; @@ -73,30 +96,75 @@ class TestRequestCallback : public RequestPeer { const std::string& security_info, const base::TimeTicks& completion_time, int64 total_transfer_size) OVERRIDE { + EXPECT_TRUE(received_response_); EXPECT_FALSE(complete_); complete_ = true; } - bool complete() const { - return complete_; + void set_follow_redirects(bool follow_redirects) { + follow_redirects_ = follow_redirects; + } + + void set_defer_on_redirect(bool defer_on_redirect) { + defer_on_redirect_ = defer_on_redirect; } + + void set_cancel_on_receive_response(bool cancel_on_receive_response) { + cancel_on_receive_response_ = cancel_on_receive_response; + } + + int seen_redirects() const { return seen_redirects_; } + + bool received_response() const { return received_response_; } + const std::string& data() const { return data_; } int total_encoded_data_length() const { return total_encoded_data_length_; } + int total_downloaded_data_length() const { + return total_downloaded_data_length_; + } + + bool complete() const { return complete_; } private: - bool complete_; + // True if should follow redirects, false if should cancel them. + bool follow_redirects_; + // True if the request should be deferred on redirects. + bool defer_on_redirect_; + // Number of total redirects seen. + int seen_redirects_; + + bool cancel_on_receive_response_; + bool received_response_; + + // Data received. If downloading to file, remains empty. std::string data_; + // Total encoded data length, regardless of whether downloading to a file or + // not. int total_encoded_data_length_; -}; + // Total length when downloading to a file. + int total_downloaded_data_length_; + + bool complete_; + ResourceLoaderBridge* bridge_; -// Sets up the message sender override for the unit test + DISALLOW_COPY_AND_ASSIGN(TestRequestPeer); +}; + +// Sets up the message sender override for the unit test. class ResourceDispatcherTest : public testing::Test, public IPC::Sender { public: + ResourceDispatcherTest() : dispatcher_(this) {} + + virtual ~ResourceDispatcherTest() { + STLDeleteContainerPairSecondPointers(shared_memory_map_.begin(), + shared_memory_map_.end()); + } + // Emulates IPC send operations (IPC::Sender) by adding // pending messages to the queue. virtual bool Send(IPC::Message* msg) OVERRIDE { @@ -105,68 +173,159 @@ class ResourceDispatcherTest : public testing::Test, public IPC::Sender { return true; } - // Emulates the browser process and processes the pending IPC messages, - // returning the hardcoded file contents. - void ProcessMessages() { - while (!message_queue_.empty()) { - ResourceHostMsg_RequestResource::Param params; - ASSERT_TRUE(ResourceHostMsg_RequestResource::Read( - &message_queue_[0], ¶ms)); - int request_id = params.b; - ResourceHostMsg_Request request = params.c; - - // check values - EXPECT_EQ(test_page_url, request.url.spec()); - - // received response message - ResourceResponseHead response; - std::string raw_headers(test_page_headers); - std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0'); - response.headers = new net::HttpResponseHeaders(raw_headers); - response.mime_type = test_page_mime_type; - response.charset = test_page_charset; - dispatcher_->OnReceivedResponse(request_id, response); - - // received data message with the test contents - base::SharedMemory shared_mem; - EXPECT_TRUE(shared_mem.CreateAndMapAnonymous(test_page_contents_len)); - char* put_data_here = static_cast<char*>(shared_mem.memory()); - memcpy(put_data_here, test_page_contents, test_page_contents_len); - base::SharedMemoryHandle dup_handle; - EXPECT_TRUE(shared_mem.GiveToProcess( - base::Process::Current().handle(), &dup_handle)); - dispatcher_->OnSetDataBuffer(request_id, dup_handle, - test_page_contents_len, 0); - dispatcher_->OnReceivedData(request_id, 0, test_page_contents_len, - test_page_contents_len); - - message_queue_.erase(message_queue_.begin()); - - // read the ack message. - Tuple1<int> request_ack; - ASSERT_TRUE(ResourceHostMsg_DataReceived_ACK::Read( - &message_queue_[0], &request_ack)); - - ASSERT_EQ(request_ack.a, request_id); - - message_queue_.erase(message_queue_.begin()); + size_t queued_messages() const { return message_queue_.size(); } + + // Returns the ID of the consumed request. Can't make assumptions about the + // ID, because numbering is based on a global. + int ConsumeRequestResource() { + if (message_queue_.empty()) { + ADD_FAILURE() << "Missing resource request message"; + return -1; + } + + ResourceHostMsg_RequestResource::Param params; + if (ResourceHostMsg_RequestResource::ID != message_queue_[0].type() || + !ResourceHostMsg_RequestResource::Read(&message_queue_[0], ¶ms)) { + ADD_FAILURE() << "Expected ResourceHostMsg_RequestResource message"; + return -1; } + ResourceHostMsg_Request request = params.c; + EXPECT_EQ(kTestPageUrl, request.url.spec()); + message_queue_.erase(message_queue_.begin()); + return params.b; + } + + void ConsumeFollowRedirect(int expected_request_id) { + ASSERT_FALSE(message_queue_.empty()); + Tuple1<int> args; + ASSERT_EQ(ResourceHostMsg_FollowRedirect::ID, message_queue_[0].type()); + ASSERT_TRUE(ResourceHostMsg_FollowRedirect::Read( + &message_queue_[0], &args)); + EXPECT_EQ(expected_request_id, args.a); + message_queue_.erase(message_queue_.begin()); + } + + void ConsumeDataReceived_ACK(int expected_request_id) { + ASSERT_FALSE(message_queue_.empty()); + Tuple1<int> args; + ASSERT_EQ(ResourceHostMsg_DataReceived_ACK::ID, message_queue_[0].type()); + ASSERT_TRUE(ResourceHostMsg_DataReceived_ACK::Read( + &message_queue_[0], &args)); + EXPECT_EQ(expected_request_id, args.a); + message_queue_.erase(message_queue_.begin()); + } + + void ConsumeDataDownloaded_ACK(int expected_request_id) { + ASSERT_FALSE(message_queue_.empty()); + Tuple1<int> args; + ASSERT_EQ(ResourceHostMsg_DataDownloaded_ACK::ID, message_queue_[0].type()); + ASSERT_TRUE(ResourceHostMsg_DataDownloaded_ACK::Read( + &message_queue_[0], &args)); + EXPECT_EQ(expected_request_id, args.a); + message_queue_.erase(message_queue_.begin()); + } + + void ConsumeReleaseDownloadedFile(int expected_request_id) { + ASSERT_FALSE(message_queue_.empty()); + Tuple1<int> args; + ASSERT_EQ(ResourceHostMsg_ReleaseDownloadedFile::ID, + message_queue_[0].type()); + ASSERT_TRUE(ResourceHostMsg_ReleaseDownloadedFile::Read( + &message_queue_[0], &args)); + EXPECT_EQ(expected_request_id, args.a); + message_queue_.erase(message_queue_.begin()); + } + + void ConsumeCancelRequest(int expected_request_id) { + ASSERT_FALSE(message_queue_.empty()); + Tuple1<int> args; + ASSERT_EQ(ResourceHostMsg_CancelRequest::ID, message_queue_[0].type()); + ASSERT_TRUE(ResourceHostMsg_CancelRequest::Read( + &message_queue_[0], &args)); + EXPECT_EQ(expected_request_id, args.a); + message_queue_.erase(message_queue_.begin()); + } + + void NotifyReceivedRedirect(int request_id) { + ResourceResponseHead head; + std::string raw_headers(kTestRedirectHeaders); + std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0'); + head.headers = new net::HttpResponseHeaders(raw_headers); + head.error_code = net::OK; + EXPECT_EQ(true, dispatcher_.OnMessageReceived( + ResourceMsg_ReceivedRedirect(request_id, GURL(kTestPageUrl), + GURL(kTestPageUrl), head))); + } + + void NotifyReceivedResponse(int request_id) { + ResourceResponseHead head; + std::string raw_headers(kTestPageHeaders); + std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0'); + head.headers = new net::HttpResponseHeaders(raw_headers); + head.mime_type = kTestPageMimeType; + head.charset = kTestPageCharset; + head.error_code = net::OK; + EXPECT_EQ(true, + dispatcher_.OnMessageReceived( + ResourceMsg_ReceivedResponse(request_id, head))); + } + + void NotifySetDataBuffer(int request_id, size_t buffer_size) { + base::SharedMemory* shared_memory = new base::SharedMemory(); + ASSERT_FALSE(shared_memory_map_[request_id]); + shared_memory_map_[request_id] = shared_memory; + EXPECT_TRUE(shared_memory->CreateAndMapAnonymous(buffer_size)); + + base::SharedMemoryHandle duplicate_handle; + EXPECT_TRUE(shared_memory->ShareToProcess( + base::Process::Current().handle(), &duplicate_handle)); + EXPECT_TRUE(dispatcher_.OnMessageReceived( + ResourceMsg_SetDataBuffer(request_id, duplicate_handle, + shared_memory->requested_size(), 0))); + } + + void NotifyDataReceived(int request_id, std::string data) { + ASSERT_LE(data.length(), shared_memory_map_[request_id]->requested_size()); + memcpy(shared_memory_map_[request_id]->memory(), data.c_str(), + data.length()); + + EXPECT_TRUE(dispatcher_.OnMessageReceived( + ResourceMsg_DataReceived(request_id, 0, data.length(), data.length()))); + } + + void NotifyDataDownloaded(int request_id, int decoded_length, + int encoded_length) { + EXPECT_TRUE(dispatcher_.OnMessageReceived( + ResourceMsg_DataDownloaded(request_id, decoded_length, + encoded_length))); + } + + void NotifyRequestComplete(int request_id, size_t total_size) { + ResourceMsg_RequestCompleteData request_complete_data; + request_complete_data.error_code = net::OK; + request_complete_data.was_ignored_by_handler = false; + request_complete_data.exists_in_cache = false; + request_complete_data.encoded_data_length = total_size; + EXPECT_TRUE(dispatcher_.OnMessageReceived( + ResourceMsg_RequestComplete(request_id, request_complete_data))); } - protected: - // testing::Test - virtual void SetUp() OVERRIDE { - dispatcher_.reset(new ResourceDispatcher(this)); + ResourceLoaderBridge* CreateBridge() { + return CreateBridgeInternal(false); } - virtual void TearDown() OVERRIDE { - dispatcher_.reset(); + + ResourceLoaderBridge* CreateBridgeForDownloadToFile() { + return CreateBridgeInternal(true); } - ResourceLoaderBridge* CreateBridge() { + ResourceDispatcher* dispatcher() { return &dispatcher_; } + + private: + ResourceLoaderBridge* CreateBridgeInternal(bool download_to_file) { RequestInfo request_info; request_info.method = "GET"; - request_info.url = GURL(test_page_url); - request_info.first_party_for_cookies = GURL(test_page_url); + request_info.url = GURL(kTestPageUrl); + request_info.first_party_for_cookies = GURL(kTestPageUrl); request_info.referrer = GURL(); request_info.headers = std::string(); request_info.load_flags = 0; @@ -174,161 +333,373 @@ class ResourceDispatcherTest : public testing::Test, public IPC::Sender { request_info.request_type = ResourceType::SUB_RESOURCE; request_info.appcache_host_id = appcache::kAppCacheNoHostId; request_info.routing_id = 0; + request_info.download_to_file = download_to_file; RequestExtraData extra_data; request_info.extra_data = &extra_data; - return dispatcher_->CreateBridge(request_info); + return dispatcher_.CreateBridge(request_info); } + // Map of request IDs to shared memory. + std::map<int, base::SharedMemory*> shared_memory_map_; + std::vector<IPC::Message> message_queue_; - static scoped_ptr<ResourceDispatcher> dispatcher_; + ResourceDispatcher dispatcher_; + base::MessageLoop message_loop_; }; -/*static*/ -scoped_ptr<ResourceDispatcher> ResourceDispatcherTest::dispatcher_; - -// Does a simple request and tests that the correct data is received. +// Does a simple request and tests that the correct data is received. Simulates +// two reads. TEST_F(ResourceDispatcherTest, RoundTrip) { - TestRequestCallback callback; + // Number of bytes received in the first read. + const size_t kFirstReceiveSize = 2; + ASSERT_LT(kFirstReceiveSize, strlen(kTestPageContents)); + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); + + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); - bridge->Start(&callback); + NotifyReceivedResponse(id); + EXPECT_EQ(0u, queued_messages()); + EXPECT_TRUE(peer.received_response()); - ProcessMessages(); + NotifySetDataBuffer(id, strlen(kTestPageContents)); + NotifyDataReceived(id, std::string(kTestPageContents, kFirstReceiveSize)); + ConsumeDataReceived_ACK(id); + EXPECT_EQ(0u, queued_messages()); - // FIXME(brettw) when the request complete messages are actually handledo - // and dispatched, uncomment this. - //EXPECT_TRUE(callback.complete()); - //EXPECT_STREQ(test_page_contents, callback.data().c_str()); - //EXPECT_EQ(test_page_contents_len, callback.total_encoded_data_length()); + NotifyDataReceived(id, kTestPageContents + kFirstReceiveSize); + ConsumeDataReceived_ACK(id); + EXPECT_EQ(0u, queued_messages()); + + NotifyRequestComplete(id, strlen(kTestPageContents)); + EXPECT_EQ(kTestPageContents, peer.data()); + EXPECT_TRUE(peer.complete()); + EXPECT_EQ(0u, queued_messages()); } -// Tests that the request IDs are straight when there are multiple requests. +// Tests that the request IDs are straight when there are two interleaving +// requests. TEST_F(ResourceDispatcherTest, MultipleRequests) { - // FIXME + const char kTestPageContents2[] = "Not kTestPageContents"; + + scoped_ptr<ResourceLoaderBridge> bridge1(CreateBridge()); + TestRequestPeer peer1(bridge1.get()); + scoped_ptr<ResourceLoaderBridge> bridge2(CreateBridge()); + TestRequestPeer peer2(bridge2.get()); + + EXPECT_TRUE(bridge1->Start(&peer1)); + int id1 = ConsumeRequestResource(); + EXPECT_TRUE(bridge2->Start(&peer2)); + int id2 = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); + + NotifyReceivedResponse(id1); + EXPECT_TRUE(peer1.received_response()); + EXPECT_FALSE(peer2.received_response()); + NotifyReceivedResponse(id2); + EXPECT_TRUE(peer2.received_response()); + EXPECT_EQ(0u, queued_messages()); + + NotifySetDataBuffer(id2, strlen(kTestPageContents2)); + NotifyDataReceived(id2, kTestPageContents2); + ConsumeDataReceived_ACK(id2); + NotifySetDataBuffer(id1, strlen(kTestPageContents)); + NotifyDataReceived(id1, kTestPageContents); + ConsumeDataReceived_ACK(id1); + EXPECT_EQ(0u, queued_messages()); + + NotifyRequestComplete(id1, strlen(kTestPageContents)); + EXPECT_EQ(kTestPageContents, peer1.data()); + EXPECT_TRUE(peer1.complete()); + EXPECT_FALSE(peer2.complete()); + + NotifyRequestComplete(id2, strlen(kTestPageContents2)); + EXPECT_EQ(kTestPageContents2, peer2.data()); + EXPECT_TRUE(peer2.complete()); + + EXPECT_EQ(0u, queued_messages()); } -// Tests that the cancel method prevents other messages from being received +// Tests that the cancel method prevents other messages from being received. TEST_F(ResourceDispatcherTest, Cancel) { - // FIXME + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); + + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); + + // Cancel the request. + bridge->Cancel(); + ConsumeCancelRequest(id); + + // Any future messages related to the request should be ignored. + NotifyReceivedResponse(id); + NotifySetDataBuffer(id, strlen(kTestPageContents)); + NotifyDataReceived(id, kTestPageContents); + NotifyRequestComplete(id, strlen(kTestPageContents)); + + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ("", peer.data()); + EXPECT_FALSE(peer.received_response()); + EXPECT_FALSE(peer.complete()); } -TEST_F(ResourceDispatcherTest, Cookies) { - // FIXME +// Tests that calling cancel during a callback works as expected. +TEST_F(ResourceDispatcherTest, CancelDuringCallback) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); + peer.set_cancel_on_receive_response(true); + + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); + + NotifyReceivedResponse(id); + EXPECT_TRUE(peer.received_response()); + // Request should have been cancelled. + ConsumeCancelRequest(id); + + // Any future messages related to the request should be ignored. + NotifySetDataBuffer(id, strlen(kTestPageContents)); + NotifyDataReceived(id, kTestPageContents); + NotifyRequestComplete(id, strlen(kTestPageContents)); + + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ("", peer.data()); + EXPECT_FALSE(peer.complete()); } -TEST_F(ResourceDispatcherTest, SerializedPostData) { - // FIXME -} +// Checks that redirects work as expected. +TEST_F(ResourceDispatcherTest, Redirect) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); -// This class provides functionality to validate whether the ResourceDispatcher -// object honors the deferred loading contract correctly, i.e. if deferred -// loading is enabled it should queue up any responses received. If deferred -// loading is enabled/disabled in the context of a dispatched message, other -// queued messages should not be dispatched until deferred load is turned off. -class DeferredResourceLoadingTest : public ResourceDispatcherTest, - public RequestPeer { - public: - DeferredResourceLoadingTest() - : defer_loading_(false) { - } + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); - virtual bool Send(IPC::Message* msg) OVERRIDE { - delete msg; - return true; - } + NotifyReceivedRedirect(id); + ConsumeFollowRedirect(id); + EXPECT_EQ(1, peer.seen_redirects()); - void InitMessages() { - set_defer_loading(true); + NotifyReceivedRedirect(id); + ConsumeFollowRedirect(id); + EXPECT_EQ(2, peer.seen_redirects()); - ResourceResponseHead response_head; - response_head.error_code = net::OK; + NotifyReceivedResponse(id); + EXPECT_TRUE(peer.received_response()); - dispatcher_->OnMessageReceived( - ResourceMsg_ReceivedResponse(0, response_head)); + NotifySetDataBuffer(id, strlen(kTestPageContents)); + NotifyDataReceived(id, kTestPageContents); + ConsumeDataReceived_ACK(id); + + NotifyRequestComplete(id, strlen(kTestPageContents)); + EXPECT_EQ(kTestPageContents, peer.data()); + EXPECT_TRUE(peer.complete()); + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ(2, peer.seen_redirects()); +} - // Duplicate the shared memory handle so both the test and the callee can - // close their copy. - base::SharedMemoryHandle duplicated_handle; - EXPECT_TRUE(shared_handle_.ShareToProcess(base::GetCurrentProcessHandle(), - &duplicated_handle)); +// Tests that that cancelling during a redirect method prevents other messages +// from being received. +TEST_F(ResourceDispatcherTest, CancelDuringRedirect) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); + peer.set_follow_redirects(false); + + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); + + // Redirect the request, which triggers a cancellation. + NotifyReceivedRedirect(id); + ConsumeCancelRequest(id); + EXPECT_EQ(1, peer.seen_redirects()); + EXPECT_EQ(0u, queued_messages()); + + // Any future messages related to the request should be ignored. In practice, + // only the NotifyRequestComplete should be received after this point. + NotifyReceivedRedirect(id); + NotifyReceivedResponse(id); + NotifySetDataBuffer(id, strlen(kTestPageContents)); + NotifyDataReceived(id, kTestPageContents); + NotifyRequestComplete(id, strlen(kTestPageContents)); + + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ("", peer.data()); + EXPECT_FALSE(peer.complete()); + EXPECT_EQ(1, peer.seen_redirects()); +} - dispatcher_->OnMessageReceived( - ResourceMsg_SetDataBuffer(0, duplicated_handle, 100, 0)); - dispatcher_->OnMessageReceived(ResourceMsg_DataReceived(0, 0, 100, 100)); +// Checks that deferring a request delays messages until it's resumed. +TEST_F(ResourceDispatcherTest, Defer) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); + + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); + + bridge->SetDefersLoading(true); + NotifyReceivedResponse(id); + NotifySetDataBuffer(id, strlen(kTestPageContents)); + NotifyDataReceived(id, kTestPageContents); + NotifyRequestComplete(id, strlen(kTestPageContents)); + + // None of the messages should have been processed yet, so no queued messages + // to the browser process, and no data received by the peer. + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ("", peer.data()); + EXPECT_FALSE(peer.complete()); + EXPECT_EQ(0, peer.seen_redirects()); + + // Resuming the request should asynchronously unleash the deferred messages. + bridge->SetDefersLoading(false); + base::RunLoop().RunUntilIdle(); - set_defer_loading(false); - } + ConsumeDataReceived_ACK(id); + EXPECT_EQ(0u, queued_messages()); + EXPECT_TRUE(peer.received_response()); + EXPECT_EQ(kTestPageContents, peer.data()); + EXPECT_TRUE(peer.complete()); +} - // RequestPeer methods. - virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE { - } +// Checks that deferring a request during a redirect delays messages until it's +// resumed. +TEST_F(ResourceDispatcherTest, DeferOnRedirect) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); + peer.set_defer_on_redirect(true); + + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); + + // The request should be deferred during the redirect, including the message + // to follow the redirect. + NotifyReceivedRedirect(id); + NotifyReceivedResponse(id); + NotifySetDataBuffer(id, strlen(kTestPageContents)); + NotifyDataReceived(id, kTestPageContents); + NotifyRequestComplete(id, strlen(kTestPageContents)); + + // None of the messages should have been processed yet, so no queued messages + // to the browser process, and no data received by the peer. + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ("", peer.data()); + EXPECT_FALSE(peer.complete()); + EXPECT_EQ(1, peer.seen_redirects()); + + // Resuming the request should asynchronously unleash the deferred messages. + bridge->SetDefersLoading(false); + base::RunLoop().RunUntilIdle(); - virtual bool OnReceivedRedirect(const GURL& new_url, - const GURL& new_first_party_for_cookies, - const ResourceResponseInfo& info) OVERRIDE { - return true; - } + ConsumeFollowRedirect(id); + ConsumeDataReceived_ACK(id); - virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE { - EXPECT_EQ(defer_loading_, false); - set_defer_loading(true); - } + EXPECT_EQ(0u, queued_messages()); + EXPECT_TRUE(peer.received_response()); + EXPECT_EQ(kTestPageContents, peer.data()); + EXPECT_TRUE(peer.complete()); + EXPECT_EQ(1, peer.seen_redirects()); +} - virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE { - } +// Checks that a deferred request that's cancelled doesn't receive any messages. +TEST_F(ResourceDispatcherTest, CancelDeferredRequest) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + TestRequestPeer peer(bridge.get()); - virtual void OnReceivedData(const char* data, - int data_length, - int encoded_data_length) OVERRIDE { - EXPECT_EQ(defer_loading_, false); - set_defer_loading(false); - } + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); - virtual void OnCompletedRequest( - int error_code, - bool was_ignored_by_handler, - bool stale_copy_in_cache, - const std::string& security_info, - const base::TimeTicks& completion_time, - int64 total_transfer_size) OVERRIDE { - } + bridge->SetDefersLoading(true); + NotifyReceivedRedirect(id); + bridge->Cancel(); + ConsumeCancelRequest(id); - protected: - virtual void SetUp() OVERRIDE { - ResourceDispatcherTest::SetUp(); - EXPECT_TRUE(shared_handle_.CreateAnonymous(100)); - } + NotifyRequestComplete(id, 0); + base::RunLoop().RunUntilIdle(); - virtual void TearDown() OVERRIDE { - shared_handle_.Close(); - ResourceDispatcherTest::TearDown(); - } + // None of the messages should have been processed. + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ("", peer.data()); + EXPECT_FALSE(peer.complete()); + EXPECT_EQ(0, peer.seen_redirects()); +} - private: - void set_defer_loading(bool defer) { - defer_loading_ = defer; - dispatcher_->SetDefersLoading(0, defer); - } +TEST_F(ResourceDispatcherTest, DownloadToFile) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridgeForDownloadToFile()); + TestRequestPeer peer(bridge.get()); + const int kDownloadedIncrement = 100; + const int kEncodedIncrement = 50; + + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); + + NotifyReceivedResponse(id); + EXPECT_EQ(0u, queued_messages()); + EXPECT_TRUE(peer.received_response()); + + int expected_total_downloaded_length = 0; + int expected_total_encoded_length = 0; + for (int i = 0; i < 10; ++i) { + NotifyDataDownloaded(id, kDownloadedIncrement, kEncodedIncrement); + ConsumeDataDownloaded_ACK(id); + expected_total_downloaded_length += kDownloadedIncrement; + expected_total_encoded_length += kEncodedIncrement; + EXPECT_EQ(expected_total_downloaded_length, + peer.total_downloaded_data_length()); + EXPECT_EQ(expected_total_encoded_length, peer.total_encoded_data_length()); + } + + NotifyRequestComplete(id, strlen(kTestPageContents)); + EXPECT_EQ("", peer.data()); + EXPECT_TRUE(peer.complete()); + EXPECT_EQ(0u, queued_messages()); + + bridge.reset(); + ConsumeReleaseDownloadedFile(id); + EXPECT_EQ(0u, queued_messages()); + EXPECT_EQ(expected_total_downloaded_length, + peer.total_downloaded_data_length()); + EXPECT_EQ(expected_total_encoded_length, peer.total_encoded_data_length()); +} - bool defer_loading() const { - return defer_loading_; - } +// Make sure that when a download to file is cancelled, the file is destroyed. +TEST_F(ResourceDispatcherTest, CancelDownloadToFile) { + scoped_ptr<ResourceLoaderBridge> bridge(CreateBridgeForDownloadToFile()); + TestRequestPeer peer(bridge.get()); - bool defer_loading_; - base::SharedMemory shared_handle_; -}; + EXPECT_TRUE(bridge->Start(&peer)); + int id = ConsumeRequestResource(); + EXPECT_EQ(0u, queued_messages()); -TEST_F(DeferredResourceLoadingTest, DeferredLoadTest) { - base::MessageLoopForIO message_loop; + NotifyReceivedResponse(id); + EXPECT_EQ(0u, queued_messages()); + EXPECT_TRUE(peer.received_response()); - scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); + // Cancelling the request deletes the file. + bridge->Cancel(); + ConsumeCancelRequest(id); + ConsumeReleaseDownloadedFile(id); - bridge->Start(this); - InitMessages(); + // Deleting the bridge shouldn't send another message to delete the file. + bridge.reset(); + EXPECT_EQ(0u, queued_messages()); +} - // Dispatch deferred messages. - base::RunLoop().RunUntilIdle(); +TEST_F(ResourceDispatcherTest, Cookies) { + // FIXME +} + +TEST_F(ResourceDispatcherTest, SerializedPostData) { + // FIXME } class TimeConversionTest : public ResourceDispatcherTest, @@ -343,7 +714,7 @@ class TimeConversionTest : public ResourceDispatcherTest, scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge()); bridge->Start(this); - dispatcher_->OnMessageReceived( + dispatcher()->OnMessageReceived( ResourceMsg_ReceivedResponse(0, response_head)); } |