Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Unified Diff: content/browser/loader/resource_dispatcher_host_unittest.cc

Issue 82273002: Fix various issues in RedirectToFileResourceHandler. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rename test fixture Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 6f7a8e238daccffe358f57835dfe9cb8fca83609..02993df8796cea85b27b38580f492cf79f31af79 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -4,7 +4,9 @@
#include <vector>
+#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
@@ -32,6 +34,7 @@
#include "content/public/common/process_type.h"
#include "content/public/common/resource_response.h"
#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/test_content_browser_client.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
@@ -46,10 +49,13 @@
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/common/appcache/appcache_interfaces.h"
+#include "webkit/common/blob/shareable_file_reference.h"
// TODO(eroman): Write unit tests for SafeBrowsing that exercise
// SafeBrowsingResourceHandler.
+using webkit_blob::ShareableFileReference;
+
namespace content {
namespace {
@@ -86,6 +92,7 @@ static int RequestIDForMessage(const IPC::Message& msg) {
case ResourceMsg_ReceivedRedirect::ID:
case ResourceMsg_SetDataBuffer::ID:
case ResourceMsg_DataReceived::ID:
+ case ResourceMsg_DataDownloaded::ID:
case ResourceMsg_RequestComplete::ID: {
bool result = PickleIterator(msg).ReadInt(&request_id);
DCHECK(result);
@@ -181,6 +188,7 @@ class ForwardingFilter : public ResourceMessageFilter {
base::Unretained(this))),
dest_(dest),
resource_context_(resource_context) {
+ ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id());
set_peer_pid_for_testing(base::GetCurrentProcId());
}
@@ -559,32 +567,47 @@ class TestResourceDispatcherHostDelegate
scoped_ptr<base::SupportsUserData::Data> user_data_;
};
+// Waits for a ShareableFileReference to be released.
+class ShareableFileReleaseWaiter {
+ public:
+ ShareableFileReleaseWaiter(const base::FilePath& path) {
+ scoped_refptr<ShareableFileReference> file =
+ ShareableFileReference::Get(path);
+ file->AddFinalReleaseCallback(
+ base::Bind(&ShareableFileReleaseWaiter::Released,
+ base::Unretained(this)));
+ }
+
+ void Wait() {
+ loop_.Run();
+ }
+
+ private:
+ void Released(const base::FilePath& path) {
+ loop_.Quit();
+ }
+
+ base::RunLoop loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShareableFileReleaseWaiter);
+};
+
class ResourceDispatcherHostTest : public testing::Test,
public IPC::Sender {
public:
ResourceDispatcherHostTest()
- : ui_thread_(BrowserThread::UI, &message_loop_),
- file_thread_(BrowserThread::FILE_USER_BLOCKING, &message_loop_),
- cache_thread_(BrowserThread::CACHE, &message_loop_),
- io_thread_(BrowserThread::IO, &message_loop_),
+ : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
old_factory_(NULL),
send_data_received_acks_(false) {
browser_context_.reset(new TestBrowserContext());
BrowserContext::EnsureResourceContextInitialized(browser_context_.get());
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
ResourceContext* resource_context = browser_context_->GetResourceContext();
filter_ = new ForwardingFilter(this, resource_context);
resource_context->GetRequestContext()->set_network_delegate(
&network_delegate_);
}
- virtual ~ResourceDispatcherHostTest() {
- for (std::set<int>::iterator it = child_ids_.begin();
- it != child_ids_.end(); ++it) {
- host_.CancelRequestsForProcess(*it);
- }
- }
-
// IPC::Sender implementation
virtual bool Send(IPC::Message* msg) OVERRIDE {
accum_.AddMessage(*msg);
@@ -594,13 +617,18 @@ class ResourceDispatcherHostTest : public testing::Test,
GenerateDataReceivedACK(*msg);
}
+ if (wait_for_request_complete_loop_ &&
+ msg->type() == ResourceMsg_RequestComplete::ID) {
+ wait_for_request_complete_loop_->Quit();
+ }
+
delete msg;
return true;
}
protected:
// testing::Test
- virtual void SetUp() {
+ virtual void SetUp() OVERRIDE {
DCHECK(!test_fixture_);
test_fixture_ = this;
ChildProcessSecurityPolicyImpl::GetInstance()->Add(0);
@@ -626,6 +654,11 @@ class ResourceDispatcherHostTest : public testing::Test,
DCHECK(test_fixture_ == this);
test_fixture_ = NULL;
+ for (std::set<int>::iterator it = child_ids_.begin();
+ it != child_ids_.end(); ++it) {
+ host_.CancelRequestsForProcess(*it);
+ }
+
host_.Shutdown();
ChildProcessSecurityPolicyImpl::GetInstance()->Remove(0);
@@ -638,7 +671,7 @@ class ResourceDispatcherHostTest : public testing::Test,
WorkerServiceImpl::GetInstance()->PerformTeardownForTesting();
browser_context_.reset();
- message_loop_.RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// Creates a request using the current test object as the filter and
@@ -774,11 +807,14 @@ class ResourceDispatcherHostTest : public testing::Test,
return old_filter;
}
- base::MessageLoopForIO message_loop_;
- BrowserThreadImpl ui_thread_;
- BrowserThreadImpl file_thread_;
- BrowserThreadImpl cache_thread_;
- BrowserThreadImpl io_thread_;
+ void WaitForRequestComplete() {
+ DCHECK(!wait_for_request_complete_loop_);
+ wait_for_request_complete_loop_.reset(new base::RunLoop);
+ wait_for_request_complete_loop_->Run();
+ wait_for_request_complete_loop_.reset();
+ }
+
+ content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<TestBrowserContext> browser_context_;
scoped_refptr<ForwardingFilter> filter_;
net::TestNetworkDelegate network_delegate_;
@@ -790,6 +826,7 @@ class ResourceDispatcherHostTest : public testing::Test,
net::URLRequest::ProtocolFactory* old_factory_;
bool send_data_received_acks_;
std::set<int> child_ids_;
+ scoped_ptr<base::RunLoop> wait_for_request_complete_loop_;
static ResourceDispatcherHostTest* test_fixture_;
static bool delay_start_;
static bool delay_complete_;
@@ -2712,4 +2749,161 @@ TEST_F(ResourceDispatcherHostTest, DataReceivedUnexpectedACKs) {
}
}
+// Tests the dispatcher host's temporary file management.
+TEST_F(ResourceDispatcherHostTest, RegisterDownloadedTempFile) {
+ const int kRequestID = 1;
+
+ // Create a temporary file.
+ base::FilePath file_path;
+ ASSERT_TRUE(base::CreateTemporaryFile(&file_path));
+ scoped_refptr<ShareableFileReference> deletable_file =
+ ShareableFileReference::GetOrCreate(
+ file_path,
+ ShareableFileReference::DELETE_ON_FINAL_RELEASE,
+ BrowserThread::GetMessageLoopProxyForThread(
+ BrowserThread::FILE).get());
+
+ // Not readable.
+ EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), file_path));
+
+ // Register it for a resource request.
+ host_.RegisterDownloadedTempFile(filter_->child_id(), kRequestID, file_path);
+
+ // Should be readable now.
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), file_path));
+
+ // The child releases from the request.
+ bool msg_was_ok = true;
+ ResourceHostMsg_ReleaseDownloadedFile release_msg(kRequestID);
+ host_.OnMessageReceived(release_msg, filter_, &msg_was_ok);
+ ASSERT_TRUE(msg_was_ok);
+
+ // Still readable because there is another reference to the file. (The child
+ // may take additional blob references.)
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), file_path));
+
+ // Release extra references and wait for the file to be deleted. (This relies
+ // on the delete happening on the FILE thread which is mapped to main thread
+ // in this test.)
+ deletable_file = NULL;
+ base::RunLoop().RunUntilIdle();
+
+ // The file is no longer readable to the child and has been deleted.
+ EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), file_path));
+ EXPECT_FALSE(base::PathExists(file_path));
+}
+
+// Tests that temporary files held on behalf of child processes are released
+// when the child process dies.
+TEST_F(ResourceDispatcherHostTest, ReleaseTemporiesOnProcessExit) {
+ const int kRequestID = 1;
+
+ // Create a temporary file.
+ base::FilePath file_path;
+ ASSERT_TRUE(base::CreateTemporaryFile(&file_path));
+ scoped_refptr<ShareableFileReference> deletable_file =
+ ShareableFileReference::GetOrCreate(
+ file_path,
+ ShareableFileReference::DELETE_ON_FINAL_RELEASE,
+ BrowserThread::GetMessageLoopProxyForThread(
+ BrowserThread::FILE).get());
+
+ // Register it for a resource request.
+ host_.RegisterDownloadedTempFile(filter_->child_id(), kRequestID, file_path);
+ deletable_file = NULL;
+
+ // Should be readable now.
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), file_path));
+
+ // Let the process die.
+ filter_->OnChannelClosing();
+ base::RunLoop().RunUntilIdle();
+
+ // The file is no longer readable to the child and has been deleted.
+ EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), file_path));
+ EXPECT_FALSE(base::PathExists(file_path));
+}
+
+TEST_F(ResourceDispatcherHostTest, DownloadToFile) {
+ // Make a request which downloads to file.
+ ResourceHostMsg_Request request = CreateResourceRequest(
+ "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1());
+ request.download_to_file = true;
+ ResourceHostMsg_RequestResource request_msg(0, 1, request);
+ bool msg_was_ok;
+ host_.OnMessageReceived(request_msg, filter_, &msg_was_ok);
+ ASSERT_TRUE(msg_was_ok);
+
+ // Running the message loop until idle does not work because
+ // RedirectToFileResourceHandler posts things to base::WorkerPool. Instead,
+ // wait for the ResourceMsg_RequestComplete to go out. Then run the event loop
+ // until idle so the loader is gone.
+ WaitForRequestComplete();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, host_.pending_requests());
+
+ ResourceIPCAccumulator::ClassifiedMessages msgs;
+ accum_.GetClassifiedMessages(&msgs);
+
+ ASSERT_EQ(1U, msgs.size());
+ const std::vector<IPC::Message>& messages = msgs[0];
+
+ // The request should contain the following messages:
+ // ReceivedResponse (indicates headers received and filename)
+ // DataDownloaded* (bytes downloaded and total length)
+ // RequestComplete (request is done)
+
+ // ReceivedResponse
+ ResourceResponseHead response_head;
+ GetResponseHead(messages, &response_head);
+ ASSERT_FALSE(response_head.download_file_path.empty());
+
+ // DataDownloaded
+ size_t total_len = 0;
+ for (size_t i = 1; i < messages.size() - 1; i++) {
+ ASSERT_EQ(ResourceMsg_DataDownloaded::ID, messages[i].type());
+ PickleIterator iter(messages[i]);
+ int request_id, data_len;
+ ASSERT_TRUE(IPC::ReadParam(&messages[i], &iter, &request_id));
+ ASSERT_TRUE(IPC::ReadParam(&messages[i], &iter, &data_len));
+ total_len += data_len;
+ }
+ EXPECT_EQ(net::URLRequestTestJob::test_data_1().size(), total_len);
+
+ // RequestComplete
+ CheckRequestCompleteErrorCode(messages.back(), net::OK);
+
+ // Verify that the data ended up in the temporary file.
+ std::string contents;
+ ASSERT_TRUE(base::ReadFileToString(response_head.download_file_path,
+ &contents));
+ EXPECT_EQ(net::URLRequestTestJob::test_data_1(), contents);
+
+ // The file should be readable by the child.
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), response_head.download_file_path));
+
+ // When the renderer releases the file, it should be deleted. Again,
+ // RunUntilIdle doesn't work because base::WorkerPool is involved.
+ ShareableFileReleaseWaiter waiter(response_head.download_file_path);
+ ResourceHostMsg_ReleaseDownloadedFile release_msg(1);
+ host_.OnMessageReceived(release_msg, filter_, &msg_was_ok);
+ ASSERT_TRUE(msg_was_ok);
+ waiter.Wait();
+ // The release callback runs before the delete is scheduled, so pump the
+ // message loop for the delete itself. (This relies on the delete happening on
+ // the FILE thread which is mapped to main thread in this test.)
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(base::PathExists(response_head.download_file_path));
+ EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+ filter_->child_id(), response_head.download_file_path));
+}
+
} // namespace content
« no previous file with comments | « content/browser/loader/resource_dispatcher_host_impl.cc ('k') | content/browser/loader/resource_loader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698