// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include #include "include/base/cef_bind.h" #include "include/cef_file_util.h" #include "include/cef_waitable_event.h" #include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_resource_manager.h" #include "include/wrapper/cef_scoped_temp_dir.h" #include "include/wrapper/cef_stream_resource_handler.h" #include "tests/ceftests/routing_test_handler.h" #include "tests/ceftests/test_util.h" #include "tests/gtest/include/gtest/gtest.h" #include "tests/shared/browser/file_util.h" namespace { std::string CreateMessage(const std::string& name, const std::string& value) { return name + ":" + value; } // The returned contents execute a JavaScript callback containing |message|. std::string CreateContents(const std::string& message) { return "" + message + ""; } void WriteFile(const std::string& path, const std::string& contents) { int contents_size = static_cast(contents.size()); int write_ct = client::file_util::WriteFile(path, contents.data(), contents_size); EXPECT_EQ(contents_size, write_ct); } CefRefPtr CreateContentsResourceHandler( const std::string& message) { const std::string& contents = CreateContents(message); CefRefPtr stream = CefStreamReader::CreateForData( static_cast(const_cast(contents.data())), contents.length()); return new CefStreamResourceHandler("text/html", stream); } const char kDoneMsg[] = "ResourceManagerTestHandler.Done"; const char kNotHandled[] = "NotHandled"; // Browser side. class ResourceManagerTestHandler : public RoutingTestHandler { public: struct State { State() : manager_(new CefResourceManager()), expected_message_ct_(0) {} CefRefPtr manager_; // Set of URLs that will be loaded. std::vector urls_; // Set of messages that were received. std::vector messages_; // If non-zero the test will not complete until the expected number of // messages have been received. size_t expected_message_ct_; }; explicit ResourceManagerTestHandler(State* state) : state_(state), current_url_(0) { EXPECT_TRUE(state_); EXPECT_TRUE(state_->manager_.get()); EXPECT_TRUE(!state_->urls_.empty()); EXPECT_TRUE(state_->messages_.empty()); } void RunTest() override { // Create the browser. CreateBrowser(GetNextURL()); SetTestTimeout(); } cef_return_value_t OnBeforeResourceLoad( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr callback) override { if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) { // Ignore favicon requests. return RV_CANCEL; } return state_->manager_->OnBeforeResourceLoad(browser, frame, request, callback); } CefRefPtr GetResourceHandler( CefRefPtr browser, CefRefPtr frame, CefRefPtr request) override { // The ProviderDoNothing test destroys the manager before the handler. if (state_->manager_) { CefRefPtr handler = state_->manager_->GetResourceHandler(browser, frame, request); if (handler.get()) return handler; } return CreateContentsResourceHandler(CreateMessage(kDoneMsg, kNotHandled)); } bool OnQuery(CefRefPtr browser, CefRefPtr frame, int64 query_id, const CefString& request, bool persistent, CefRefPtr callback) override { state_->messages_.push_back(request); callback->Success(""); CefPostTask(TID_UI, base::Bind(&ResourceManagerTestHandler::Continue, this, browser)); return true; } // Wait a bit before destroying the test. Used with ProviderDoNothing. void DelayedDestroyTest() { CefPostDelayedTask( TID_UI, base::Bind(&ResourceManagerTestHandler::DestroyTest, this), 100); } private: void Continue(CefRefPtr browser) { if (state_->expected_message_ct_ == 0) { // Load each URL sequentially. const std::string& next_url = GetNextURL(); if (next_url.empty()) DestroyTest(); else browser->GetMainFrame()->LoadURL(next_url); } else if (state_->messages_.size() == state_->expected_message_ct_) { DestroyTest(); } } std::string GetNextURL() { if (current_url_ >= state_->urls_.size()) return std::string(); return state_->urls_[current_url_++]; } State* state_; size_t current_url_; IMPLEMENT_REFCOUNTING(ResourceManagerTestHandler); }; } // namespace // Test with no providers. TEST(ResourceManagerTest, NoProviders) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Should get the message returned from GetResourceHandler when the request is // not handled. EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } namespace { // Content provider that tracks execution state. class TestProvider : public CefResourceManager::Provider { public: struct State { TrackCallback got_on_request_; TrackCallback got_on_request_canceled_; TrackCallback got_destruct_; base::Closure destruct_callback_; std::string request_url_; }; explicit TestProvider(State* state) : state_(state) { EXPECT_TRUE(state_); } ~TestProvider() { CEF_REQUIRE_IO_THREAD(); state_->got_destruct_.yes(); if (!state_->destruct_callback_.is_null()) state_->destruct_callback_.Run(); } bool OnRequest(scoped_refptr request) override { CEF_REQUIRE_IO_THREAD(); EXPECT_FALSE(state_->got_on_request_); EXPECT_FALSE(state_->got_on_request_canceled_); state_->got_on_request_.yes(); state_->request_url_ = request->url(); return false; } void OnRequestCanceled( scoped_refptr request) override { CEF_REQUIRE_IO_THREAD(); EXPECT_TRUE(state_->got_on_request_); EXPECT_FALSE(state_->got_on_request_canceled_); state_->got_on_request_canceled_.yes(); EXPECT_STREQ(state_->request_url_.c_str(), request->url().c_str()); } private: State* state_; DISALLOW_COPY_AND_ASSIGN(TestProvider); }; // Helper that blocks on destruction of 1 or more TestProviders. class ProviderDestructHelper { public: explicit ProviderDestructHelper(int expected_count) : current_count_(0) { event_ = CefWaitableEvent::CreateWaitableEvent(true, false); callback_ = base::Bind(&DestructCallback, expected_count, ¤t_count_, event_); } const base::Closure& callback() const { return callback_; } void Wait() { event_->Wait(); } private: static void DestructCallback(int expected_count, int* current_count, CefRefPtr event) { if (++(*current_count) == expected_count) event->Signal(); } int current_count_; CefRefPtr event_; base::Closure callback_; }; // Test that that the URL retrieved via Request::url() is parsed as expected. // Fragment or query components in any order should be removed. void TestUrlParsing(const char* kUrl) { const char kRequestUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state; ProviderDestructHelper destruct_helper(1); provider_state.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider(new TestProvider(&provider_state), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // The provider is called. EXPECT_TRUE(provider_state.got_on_request_); EXPECT_FALSE(provider_state.got_on_request_canceled_); EXPECT_TRUE(provider_state.got_destruct_); // The expected URL is received. EXPECT_STREQ(kRequestUrl, provider_state.request_url_.c_str()); // The request is not handled. EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } } // namespace TEST(ResourceManagerTest, UrlParsingNoQueryOrFragment) { TestUrlParsing("http://test.com/ResourceManagerTest"); } TEST(ResourceManagerTest, UrlParsingWithQuery) { TestUrlParsing("http://test.com/ResourceManagerTest?foo=bar&choo=too"); } TEST(ResourceManagerTest, UrlParsingWithFragment) { TestUrlParsing("http://test.com/ResourceManagerTest#some/fragment"); } TEST(ResourceManagerTest, UrlParsingWithQueryAndFragment) { TestUrlParsing("http://test.com/ResourceManagerTest?foo=bar#some/fragment"); } TEST(ResourceManagerTest, UrlParsingWithFragmentAndQuery) { TestUrlParsing("http://test.com/ResourceManagerTest#some/fragment?foo=bar"); } namespace { const char kProviderId[] = "provider"; // Content provider that performs simple tests. class SimpleTestProvider : public TestProvider { public: enum Mode { NOT_HANDLED, CONTINUE, STOP, REMOVE, REMOVE_ALL, DO_NOTHING, }; SimpleTestProvider(State* state, Mode mode, CefResourceManager* manager) : TestProvider(state), mode_(mode), manager_(manager) {} SimpleTestProvider(State* state, Mode mode, CefResourceManager* manager, base::Closure do_nothing_callback) : TestProvider(state), mode_(mode), manager_(manager), do_nothing_callback_(do_nothing_callback) {} bool OnRequest(scoped_refptr request) override { TestProvider::OnRequest(request); if (mode_ == NOT_HANDLED) return false; else if (mode_ == CONTINUE) request->Continue(nullptr); else if (mode_ == STOP) request->Stop(); else if (mode_ == REMOVE) manager_->RemoveProviders(kProviderId); else if (mode_ == REMOVE_ALL) manager_->RemoveAllProviders(); else if (mode_ == DO_NOTHING) { EXPECT_FALSE(do_nothing_callback_.is_null()); do_nothing_callback_.Run(); do_nothing_callback_.Reset(); } return true; } private: Mode mode_; CefResourceManager* manager_; // Weak reference. base::Closure do_nothing_callback_; DISALLOW_COPY_AND_ASSIGN(SimpleTestProvider); }; } // namespace // Test with multiple providers that do not handle the request. TEST(ResourceManagerTest, ProviderNotHandled) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new SimpleTestProvider(&provider_state1, SimpleTestProvider::NOT_HANDLED, nullptr), 0, std::string()); state.manager_->AddProvider( new SimpleTestProvider(&provider_state2, SimpleTestProvider::NOT_HANDLED, nullptr), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers are called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test with multiple providers that all continue. TEST(ResourceManagerTest, ProviderContinue) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new SimpleTestProvider(&provider_state1, SimpleTestProvider::CONTINUE, nullptr), 0, std::string()); state.manager_->AddProvider( new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE, nullptr), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers are called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test with multiple providers where the first one stops. TEST(ResourceManagerTest, ProviderStop) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new SimpleTestProvider(&provider_state1, SimpleTestProvider::STOP, nullptr), 0, std::string()); state.manager_->AddProvider( new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE, nullptr), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // 1st provider is called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); // 2nd provider is not called because the 1st provider stopped. EXPECT_FALSE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test with multiple providers where the first one removes multiple providers // including itself. TEST(ResourceManagerTest, ProviderRemove) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; TestProvider::State provider_state3; ProviderDestructHelper destruct_helper(3); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); provider_state3.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new SimpleTestProvider(&provider_state1, SimpleTestProvider::REMOVE, state.manager_.get()), 0, kProviderId); state.manager_->AddProvider( new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE, nullptr), 0, kProviderId); state.manager_->AddProvider( new SimpleTestProvider(&provider_state3, SimpleTestProvider::CONTINUE, nullptr), 1, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // 1st provider is called and canceled. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_TRUE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); // 2nd provider is removed with the 1st provider due to sharing the same // identifier. EXPECT_FALSE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); // 3rd provider is called. EXPECT_TRUE(provider_state3.got_on_request_); EXPECT_FALSE(provider_state3.got_on_request_canceled_); EXPECT_TRUE(provider_state3.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test with multiple providers where the first provider removes all. TEST(ResourceManagerTest, ProviderRemoveAll) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; TestProvider::State provider_state3; ProviderDestructHelper destruct_helper(3); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); provider_state3.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new SimpleTestProvider(&provider_state1, SimpleTestProvider::REMOVE_ALL, state.manager_.get()), 0, std::string()); state.manager_->AddProvider( new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE, nullptr), 0, std::string()); state.manager_->AddProvider( new SimpleTestProvider(&provider_state3, SimpleTestProvider::CONTINUE, nullptr), 1, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // 1st provider is called and canceled. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_TRUE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); // 2nd and 3rd providers are not called due to removal. EXPECT_FALSE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_FALSE(provider_state3.got_on_request_); EXPECT_FALSE(provider_state3.got_on_request_canceled_); EXPECT_TRUE(provider_state3.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test with multiple providers that do not continue and will be destroyed when // the manager is destroyed. TEST(ResourceManagerTest, ProviderDoNothing) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); CefRefPtr handler = new ResourceManagerTestHandler(&state); // DelayedDestroyTest will be executed from SimpleTestHandler::OnRequest. state.manager_->AddProvider( new SimpleTestProvider( &provider_state1, SimpleTestProvider::DO_NOTHING, nullptr, base::Bind(&ResourceManagerTestHandler::DelayedDestroyTest, handler)), 0, std::string()); state.manager_->AddProvider( new SimpleTestProvider(&provider_state2, SimpleTestProvider::DO_NOTHING, nullptr), 0, std::string()); handler->ExecuteTest(); // Destroy the resource manager before the handler so that pending requests // are canceled. ResourceManagerTestHandler::GetResourceHandler will be called // after the manager is destroyed. state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); ReleaseAndWaitForDestructor(handler); // Only the first provider is called. It will be canceled when the manager is // destroyed. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_TRUE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_FALSE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); // Nothing completed. EXPECT_EQ(state.messages_.size(), 0U); } // Test AddContentProvider. TEST(ResourceManagerTest, ContentProvider) { const char kUrl1[] = "http://test.com/ResourceManagerTest1"; const char kUrl2[] = "http://test.com/ResourceManagerTest2"; const char kUrl3[] = "http://test.com/ResourceManagerTest3"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl1); state.urls_.push_back(kUrl2); state.urls_.push_back(kUrl3); // Only the first 2 URLs will be handled. state.manager_->AddContentProvider(kUrl1, CreateContents(success1_message), "text/html", 0, std::string()); state.manager_->AddContentProvider(kUrl2, CreateContents(success2_message), "text/html", 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. WaitForIOThread(); // Both providers are called and return the expected results. EXPECT_EQ(state.messages_.size(), 3U); EXPECT_EQ(success1_message, state.messages_[0]); EXPECT_EQ(success2_message, state.messages_[1]); EXPECT_EQ(not_handled_message, state.messages_[2]); } // Test AddDirectoryProvider. TEST(ResourceManagerTest, DirectoryProvider) { const char kUrlBase[] = "http://test.com/ResourceManager"; const char kFile1[] = "File1.html"; const char kFile2[] = "File2.html"; const char kFile3[] = "File3.html"; const char kFile4[] = "File4.html"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& success3_message = CreateMessage(kDoneMsg, "Success3"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrlBase + std::string("/") + kFile1); state.urls_.push_back(kUrlBase + std::string("/") + kFile2); state.urls_.push_back(kUrlBase + std::string("/sub/") + kFile3); state.urls_.push_back(kUrlBase + std::string("/") + kFile4); CefScopedTempDir scoped_dir; EXPECT_TRUE(scoped_dir.CreateUniqueTempDir()); // Write the files to disk. const std::string& temp_dir = scoped_dir.GetPath(); WriteFile(client::file_util::JoinPath(temp_dir, kFile1), CreateContents(success1_message)); WriteFile(client::file_util::JoinPath(temp_dir, kFile2), CreateContents(success2_message)); // Also include a subdirectory. const std::string& sub_dir = client::file_util::JoinPath(temp_dir, "sub"); EXPECT_TRUE(CefCreateDirectory(sub_dir)); WriteFile(client::file_util::JoinPath(sub_dir, kFile3), CreateContents(success3_message)); state.manager_->AddDirectoryProvider(kUrlBase, temp_dir, 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. WaitForIOThread(); EXPECT_TRUE(scoped_dir.Delete()); // The first 3 URLs are handled. EXPECT_EQ(state.messages_.size(), 4U); EXPECT_EQ(success1_message, state.messages_[0]); EXPECT_EQ(success2_message, state.messages_[1]); EXPECT_EQ(success3_message, state.messages_[2]); EXPECT_EQ(not_handled_message, state.messages_[3]); } // Test AddArchiveProvider. TEST(ResourceManagerTest, ArchiveProvider) { const char kUrlBase[] = "http://test.com/ResourceManager"; const char kFile1[] = "File1.html"; const char kFile2[] = "File2.html"; const char kFile3[] = "File3.html"; const char kFile4[] = "File4.html"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& success3_message = CreateMessage(kDoneMsg, "Success3"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrlBase + std::string("/") + kFile1); state.urls_.push_back(kUrlBase + std::string("/") + kFile2); state.urls_.push_back(kUrlBase + std::string("/sub/") + kFile3); state.urls_.push_back(kUrlBase + std::string("/") + kFile4); // Only the first 2 URLs will be handled. CefScopedTempDir scoped_dir; EXPECT_TRUE(scoped_dir.CreateUniqueTempDir()); const std::string& temp_dir = scoped_dir.GetPath(); // Write the files to disk. const std::string& file_dir = client::file_util::JoinPath(temp_dir, "files"); EXPECT_TRUE(CefCreateDirectory(file_dir)); WriteFile(client::file_util::JoinPath(file_dir, kFile1), CreateContents(success1_message)); WriteFile(client::file_util::JoinPath(file_dir, kFile2), CreateContents(success2_message)); // Also include a subdirectory. const std::string& sub_dir = client::file_util::JoinPath(file_dir, "sub"); EXPECT_TRUE(CefCreateDirectory(sub_dir)); WriteFile(client::file_util::JoinPath(sub_dir, kFile3), CreateContents(success3_message)); const std::string& archive_path = client::file_util::JoinPath(temp_dir, "archive.zip"); // Create the archive file. EXPECT_TRUE(CefZipDirectory(file_dir, archive_path, false)); state.manager_->AddArchiveProvider(kUrlBase, archive_path, std::string(), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. WaitForIOThread(); EXPECT_TRUE(scoped_dir.Delete()); // The first 3 URLs are handled. EXPECT_EQ(state.messages_.size(), 4U); EXPECT_EQ(success1_message, state.messages_[0]); EXPECT_EQ(success2_message, state.messages_[1]); EXPECT_EQ(success3_message, state.messages_[2]); EXPECT_EQ(not_handled_message, state.messages_[3]); } namespace { // Content provider that only handles a single request. class OneShotProvider : public CefResourceManager::Provider { public: OneShotProvider(const std::string& content, const base::Closure& destruct_callback) : done_(false), content_(content), destruct_callback_(destruct_callback) { EXPECT_FALSE(content.empty()); } ~OneShotProvider() { CEF_REQUIRE_IO_THREAD(); destruct_callback_.Run(); } bool OnRequest(scoped_refptr request) override { CEF_REQUIRE_IO_THREAD(); if (done_) { // Provider only handles a single request. return false; } done_ = true; CefRefPtr stream = CefStreamReader::CreateForData( static_cast(const_cast(content_.data())), content_.length()); request->Continue(new CefStreamResourceHandler("text/html", stream)); return true; } private: bool done_; std::string content_; base::Closure destruct_callback_; DISALLOW_COPY_AND_ASSIGN(OneShotProvider); }; } // namespace // Test that providers are called in the expected order and return expected // results. TEST(ResourceManagerTest, ProviderOrder) { const char kUrl1[] = "http://test.com/ResourceManagerTest1"; const char kUrl2[] = "http://test.com/ResourceManagerTest2"; const char kUrl3[] = "http://test.com/ResourceManagerTest3"; const char kUrl4[] = "http://test.com/ResourceManagerTest4"; const char kUrl5[] = "http://test.com/ResourceManagerTest5"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& success3_message = CreateMessage(kDoneMsg, "Success3"); const std::string& success4_message = CreateMessage(kDoneMsg, "Success4"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl1); state.urls_.push_back(kUrl2); state.urls_.push_back(kUrl3); state.urls_.push_back(kUrl4); state.urls_.push_back(kUrl5); ProviderDestructHelper destruct_helper(4); // Resulting order should be sequential; success1 .. success4. state.manager_->AddProvider( new OneShotProvider(CreateContents(success2_message), destruct_helper.callback()), 0, std::string()); state.manager_->AddProvider( new OneShotProvider(CreateContents(success1_message), destruct_helper.callback()), -100, std::string()); state.manager_->AddProvider( new OneShotProvider(CreateContents(success4_message), destruct_helper.callback()), 100, std::string()); state.manager_->AddProvider( new OneShotProvider(CreateContents(success3_message), destruct_helper.callback()), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); EXPECT_EQ(state.messages_.size(), 5U); EXPECT_EQ(success1_message, state.messages_[0]); EXPECT_EQ(success2_message, state.messages_[1]); EXPECT_EQ(success3_message, state.messages_[2]); EXPECT_EQ(success4_message, state.messages_[3]); EXPECT_EQ(not_handled_message, state.messages_[4]); } namespace { // Content provider that returns the path component as the result. class EchoProvider : public CefResourceManager::Provider { public: EchoProvider(const std::string& base_url) : base_url_(base_url) { EXPECT_TRUE(!base_url_.empty()); } bool OnRequest(scoped_refptr request) override { CEF_REQUIRE_IO_THREAD(); const std::string& url = request->url(); if (url.find(base_url_) != 0U) { // Not handled by this provider. return false; } const std::string& content = CreateContents(url); // Parse the URL to identify the delay. int delay = atoi(url.substr(base_url_.size()).data()); EXPECT_GE(delay, 0); CefRefPtr stream = CefStreamReader::CreateForData( static_cast(const_cast(content.data())), content.length()); CefPostDelayedTask( TID_IO, base::Bind(&CefResourceManager::Request::Continue, request, new CefStreamResourceHandler("text/html", stream)), delay); return true; } private: std::string base_url_; DISALLOW_COPY_AND_ASSIGN(EchoProvider); }; } // namespace // Test that many requests pending at the same time complete in the expected // order and return correct results. TEST(ResourceManagerTest, ManyRequests) { const char kUrl[] = "http://test.com/ResourceManagerTest"; const char kBaseUrl[] = "http://test.com/ResourceManagerSubTest/"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); state.expected_message_ct_ = 50U; // Build a page with lots of iframes. std::stringstream ss; ss << ""; for (size_t i = 0U; i < state.expected_message_ct_; ++i) { ss << ""; } ss << ""; state.manager_->AddContentProvider(kUrl, ss.str(), "text/html", 0, std::string()); state.manager_->AddProvider(new EchoProvider(kBaseUrl), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. WaitForIOThread(); EXPECT_EQ(state.messages_.size(), state.expected_message_ct_); // Requests should complete in order due to the delay. for (size_t i = 0; i < state.messages_.size(); ++i) { ss.str(""); ss << kBaseUrl << (i * 10); EXPECT_EQ(ss.str(), state.messages_[i]); } } namespace { // Content provider that only handles a single request and then removes itself // from the manager. class OneShotRemovalProvider : public TestProvider { public: OneShotRemovalProvider(State* state, const std::string& content, CefResourceManager* manager, const std::string& identifier, bool remove_before_continue) : TestProvider(state), content_(content), manager_(manager), identifier_(identifier), remove_before_continue_(remove_before_continue) { EXPECT_FALSE(content.empty()); } bool OnRequest(scoped_refptr request) override { TestProvider::OnRequest(request); CefRefPtr stream = CefStreamReader::CreateForData( static_cast(const_cast(content_.data())), content_.length()); if (remove_before_continue_) { // Removing the provider before continuing should trigger a call to // OnRequestCanceled. if (identifier_.empty()) manager_->RemoveAllProviders(); else manager_->RemoveProviders(identifier_); } request->Continue(new CefStreamResourceHandler("text/html", stream)); if (!remove_before_continue_) { // The request has already completed so OnRequestCanceled is not called. if (identifier_.empty()) manager_->RemoveAllProviders(); else manager_->RemoveProviders(identifier_); } return true; } private: std::string content_; CefResourceManager* manager_; // Weak reference. std::string identifier_; bool remove_before_continue_; DISALLOW_COPY_AND_ASSIGN(OneShotRemovalProvider); }; } // namespace // Test that removal of the current provider after continue has the expected // results. TEST(ResourceManagerTest, RemoveProviderAfterContinue) { const char kUrl1[] = "http://test.com/ResourceManagerTest1"; const char kUrl2[] = "http://test.com/ResourceManagerTest2"; const char kUrl3[] = "http://test.com/ResourceManagerTest3"; const char kUrl4[] = "http://test.com/ResourceManagerTest4"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& success3_message = CreateMessage(kDoneMsg, "Success3"); const std::string& success4_message = CreateMessage(kDoneMsg, "Success4"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl1); state.urls_.push_back(kUrl2); state.urls_.push_back(kUrl3); state.urls_.push_back(kUrl4); TestProvider::State provider_state1; TestProvider::State provider_state2; TestProvider::State provider_state3; TestProvider::State provider_state4; ProviderDestructHelper destruct_helper(4); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); provider_state3.destruct_callback_ = destruct_helper.callback(); provider_state4.destruct_callback_ = destruct_helper.callback(); const char kIdentifier1[] = "id1"; const char kIdentifier2[] = "id2"; const char kIdentifier4[] = "id4"; // Resulting order should be sequential; success1 .. success4. state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state2, CreateContents(success2_message), state.manager_.get(), kIdentifier2, false), 0, kIdentifier2); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state1, CreateContents(success1_message), state.manager_.get(), kIdentifier1, false), -100, kIdentifier1); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state4, CreateContents(success4_message), state.manager_.get(), kIdentifier4, false), 100, kIdentifier4); // Will be removed at the same time as #2 and therefore never called. state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state3, CreateContents(success3_message), state.manager_.get(), kIdentifier2, false), 0, kIdentifier2); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers except for 3 (which is removed at the same time as 2 and // therefore never executed) should complete. EXPECT_EQ(state.messages_.size(), 4U); EXPECT_EQ(success1_message, state.messages_[0]); EXPECT_EQ(success2_message, state.messages_[1]); EXPECT_EQ(success4_message, state.messages_[2]); EXPECT_EQ(not_handled_message, state.messages_[3]); EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); // Removed at the same time as 2 and therefore not executed. EXPECT_FALSE(provider_state3.got_on_request_); EXPECT_FALSE(provider_state3.got_on_request_canceled_); EXPECT_TRUE(provider_state3.got_destruct_); EXPECT_TRUE(provider_state4.got_on_request_); EXPECT_FALSE(provider_state4.got_on_request_canceled_); EXPECT_TRUE(provider_state4.got_destruct_); } // Test that removal of the current provider before continue has the expected // results. TEST(ResourceManagerTest, RemoveProviderBeforeContinue) { const char kUrl1[] = "http://test.com/ResourceManagerTest1"; const char kUrl2[] = "http://test.com/ResourceManagerTest2"; const char kUrl3[] = "http://test.com/ResourceManagerTest3"; const char kUrl4[] = "http://test.com/ResourceManagerTest4"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& success3_message = CreateMessage(kDoneMsg, "Success3"); const std::string& success4_message = CreateMessage(kDoneMsg, "Success4"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl1); state.urls_.push_back(kUrl2); state.urls_.push_back(kUrl3); state.urls_.push_back(kUrl4); TestProvider::State provider_state1; TestProvider::State provider_state2; TestProvider::State provider_state3; TestProvider::State provider_state4; ProviderDestructHelper destruct_helper(4); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); provider_state3.destruct_callback_ = destruct_helper.callback(); provider_state4.destruct_callback_ = destruct_helper.callback(); const char kIdentifier1[] = "id1"; const char kIdentifier2[] = "id2"; const char kIdentifier4[] = "id4"; // Resulting order should be sequential; success1 .. success4. state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state2, CreateContents(success2_message), state.manager_.get(), kIdentifier2, true), 0, kIdentifier2); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state1, CreateContents(success1_message), state.manager_.get(), kIdentifier1, true), -100, kIdentifier1); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state4, CreateContents(success4_message), state.manager_.get(), kIdentifier4, true), 100, kIdentifier4); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state3, CreateContents(success3_message), state.manager_.get(), kIdentifier2, true), 0, kIdentifier2); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // No providers should complete. EXPECT_EQ(state.messages_.size(), 4U); EXPECT_EQ(not_handled_message, state.messages_[0]); EXPECT_EQ(not_handled_message, state.messages_[1]); EXPECT_EQ(not_handled_message, state.messages_[2]); EXPECT_EQ(not_handled_message, state.messages_[3]); // All providers except 3 should be called and then canceled. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_TRUE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_TRUE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); // Removed at the same time as 2 and therefore not executed. EXPECT_FALSE(provider_state3.got_on_request_); EXPECT_FALSE(provider_state3.got_on_request_canceled_); EXPECT_TRUE(provider_state3.got_destruct_); EXPECT_TRUE(provider_state4.got_on_request_); EXPECT_TRUE(provider_state4.got_on_request_canceled_); EXPECT_TRUE(provider_state4.got_destruct_); } // Test that removal of all providers after continue has the expected results. TEST(ResourceManagerTest, RemoveAllProvidersAfterContinue) { const char kUrl1[] = "http://test.com/ResourceManagerTest1"; const char kUrl2[] = "http://test.com/ResourceManagerTest2"; const char kUrl3[] = "http://test.com/ResourceManagerTest3"; const char kUrl4[] = "http://test.com/ResourceManagerTest4"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& success3_message = CreateMessage(kDoneMsg, "Success3"); const std::string& success4_message = CreateMessage(kDoneMsg, "Success4"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl1); state.urls_.push_back(kUrl2); state.urls_.push_back(kUrl3); state.urls_.push_back(kUrl4); TestProvider::State provider_state1; TestProvider::State provider_state2; TestProvider::State provider_state3; TestProvider::State provider_state4; ProviderDestructHelper destruct_helper(4); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); provider_state3.destruct_callback_ = destruct_helper.callback(); provider_state4.destruct_callback_ = destruct_helper.callback(); // Resulting order should be sequential; success1 .. success4. state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state2, CreateContents(success2_message), state.manager_.get(), std::string(), false), 0, std::string()); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state1, CreateContents(success1_message), state.manager_.get(), std::string(), false), -100, std::string()); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state4, CreateContents(success4_message), state.manager_.get(), std::string(), false), 100, std::string()); // Will be removed at the same time as #2 and therefore never called. state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state3, CreateContents(success3_message), state.manager_.get(), std::string(), false), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // Only the 1st provider should complete EXPECT_EQ(state.messages_.size(), 4U); EXPECT_EQ(success1_message, state.messages_[0]); EXPECT_EQ(not_handled_message, state.messages_[1]); EXPECT_EQ(not_handled_message, state.messages_[2]); EXPECT_EQ(not_handled_message, state.messages_[3]); EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_FALSE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_FALSE(provider_state3.got_on_request_); EXPECT_FALSE(provider_state3.got_on_request_canceled_); EXPECT_TRUE(provider_state3.got_destruct_); EXPECT_FALSE(provider_state4.got_on_request_); EXPECT_FALSE(provider_state4.got_on_request_canceled_); EXPECT_TRUE(provider_state4.got_destruct_); } // Test that removal of all providers before continue has the expected results. TEST(ResourceManagerTest, RemoveAllProvidersBeforeContinue) { const char kUrl1[] = "http://test.com/ResourceManagerTest1"; const char kUrl2[] = "http://test.com/ResourceManagerTest2"; const char kUrl3[] = "http://test.com/ResourceManagerTest3"; const char kUrl4[] = "http://test.com/ResourceManagerTest4"; const std::string& success1_message = CreateMessage(kDoneMsg, "Success1"); const std::string& success2_message = CreateMessage(kDoneMsg, "Success2"); const std::string& success3_message = CreateMessage(kDoneMsg, "Success3"); const std::string& success4_message = CreateMessage(kDoneMsg, "Success4"); const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled); ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl1); state.urls_.push_back(kUrl2); state.urls_.push_back(kUrl3); state.urls_.push_back(kUrl4); TestProvider::State provider_state1; TestProvider::State provider_state2; TestProvider::State provider_state3; TestProvider::State provider_state4; ProviderDestructHelper destruct_helper(4); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); provider_state3.destruct_callback_ = destruct_helper.callback(); provider_state4.destruct_callback_ = destruct_helper.callback(); // Resulting order should be sequential; success1 .. success4. state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state2, CreateContents(success2_message), state.manager_.get(), std::string(), true), 0, std::string()); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state1, CreateContents(success1_message), state.manager_.get(), std::string(), true), -100, std::string()); state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state4, CreateContents(success4_message), state.manager_.get(), std::string(), true), 100, std::string()); // Will be removed at the same time as #2 and therefore never called. state.manager_->AddProvider( new OneShotRemovalProvider(&provider_state3, CreateContents(success3_message), state.manager_.get(), std::string(), true), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // No providers should complete. EXPECT_EQ(state.messages_.size(), 4U); EXPECT_EQ(not_handled_message, state.messages_[0]); EXPECT_EQ(not_handled_message, state.messages_[1]); EXPECT_EQ(not_handled_message, state.messages_[2]); EXPECT_EQ(not_handled_message, state.messages_[3]); // 1st provider should also be canceled. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_TRUE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_FALSE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_FALSE(provider_state3.got_on_request_); EXPECT_FALSE(provider_state3.got_on_request_canceled_); EXPECT_TRUE(provider_state3.got_destruct_); EXPECT_FALSE(provider_state4.got_on_request_); EXPECT_FALSE(provider_state4.got_on_request_canceled_); EXPECT_TRUE(provider_state4.got_destruct_); } namespace { // Test the URL filter capability. class UrlFilterTestProvider : public TestProvider { public: UrlFilterTestProvider(State* state, const std::string& expected_url, const std::string& expected_url_after_filter) : TestProvider(state), expected_url_(expected_url), expected_url_after_filter_(expected_url_after_filter) {} bool OnRequest(scoped_refptr request) override { TestProvider::OnRequest(request); // Request::url is already filtered. EXPECT_EQ(expected_url_, request->url()); // Explicitly filter the URL again. const std::string& filtered_url = request->url_filter().Run(request->request()->GetURL()); EXPECT_EQ(expected_url_after_filter_, filtered_url); request->Continue(nullptr); return true; } private: std::string expected_url_; std::string expected_url_after_filter_; DISALLOW_COPY_AND_ASSIGN(UrlFilterTestProvider); }; std::string TestUrlFilter(const std::string& url) { return url + "Rewrite"; } // Add to the URL but keep the query component. std::string TestUrlFilterWithQuery(const std::string& url) { size_t pos = url.find('?'); if (pos == std::string::npos) return url; return url.substr(0, pos) + "Rewrite" + url.substr(pos); } // Add to the URL but keep the fragment component. std::string TestUrlFilterWithFragment(const std::string& url) { size_t pos = url.find('#'); if (pos == std::string::npos) return url; return url.substr(0, pos) + "Rewrite" + url.substr(pos); } } // namespace // Test the URL filter capability. TEST(ResourceManagerTest, UrlFilter) { const char kUrl[] = "http://test.com/ResourceManagerTest"; const char kExpectedUrl[] = "http://test.com/ResourceManagerTestRewrite"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); // Set the URL filter. state.manager_->SetUrlFilter(base::Bind(TestUrlFilter)); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new UrlFilterTestProvider(&provider_state1, kExpectedUrl, kExpectedUrl), 0, std::string()); state.manager_->AddProvider( new UrlFilterTestProvider(&provider_state2, kExpectedUrl, kExpectedUrl), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers are called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test the URL filter capability with a query component. TEST(ResourceManagerTest, UrlFilterWithQuery) { const char kUrl[] = "http://test.com/ResourceManagerTest?foo=bar"; const char kExpectedUrl[] = "http://test.com/ResourceManagerTestRewrite"; const char kExpectedUrlAfterFilter[] = "http://test.com/ResourceManagerTestRewrite?foo=bar"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); // Set the URL filter. state.manager_->SetUrlFilter(base::Bind(TestUrlFilterWithQuery)); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new UrlFilterTestProvider(&provider_state1, kExpectedUrl, kExpectedUrlAfterFilter), 0, std::string()); state.manager_->AddProvider( new UrlFilterTestProvider(&provider_state2, kExpectedUrl, kExpectedUrlAfterFilter), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers are called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test the URL filter capability with a fragment component. TEST(ResourceManagerTest, UrlFilterWithFragment) { // Fragment components will not be passed with the request. const char kUrl[] = "http://test.com/ResourceManagerTest#fragment"; const char kExpectedUrl[] = "http://test.com/ResourceManagerTestRewrite"; const char kExpectedUrlAfterFilter[] = "http://test.com/ResourceManagerTestRewrite#fragment"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); // Set the URL filter. state.manager_->SetUrlFilter(base::Bind(TestUrlFilterWithFragment)); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new UrlFilterTestProvider(&provider_state1, kExpectedUrl, kExpectedUrlAfterFilter), 0, std::string()); state.manager_->AddProvider( new UrlFilterTestProvider(&provider_state2, kExpectedUrl, kExpectedUrlAfterFilter), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers are called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } namespace { // Test the mime type resolver capability. class MimeTypeTestProvider : public TestProvider { public: MimeTypeTestProvider(State* state, const std::string& expected_mime_type) : TestProvider(state), expected_mime_type_(expected_mime_type) {} bool OnRequest(scoped_refptr request) override { TestProvider::OnRequest(request); const std::string& mime_type = request->mime_type_resolver().Run(request->url()); EXPECT_EQ(expected_mime_type_, mime_type); request->Continue(nullptr); return true; } private: std::string expected_mime_type_; DISALLOW_COPY_AND_ASSIGN(MimeTypeTestProvider); }; const char kExpectedMimeType[] = "foo/bar"; std::string TestMimeTypeResolver(const std::string& url) { return kExpectedMimeType; } } // namespace // Test the mime type resolver capability. TEST(ResourceManagerTest, MimeTypeResolver) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); // Set the mime type resolver. state.manager_->SetMimeTypeResolver(base::Bind(TestMimeTypeResolver)); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new MimeTypeTestProvider(&provider_state1, kExpectedMimeType), 0, std::string()); state.manager_->AddProvider( new MimeTypeTestProvider(&provider_state2, kExpectedMimeType), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers are called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } namespace { // Content provider that adds another provider before or after the current // provider. class AddingTestProvider : public TestProvider { public: AddingTestProvider(State* state, State* new_state, CefResourceManager* manager, bool before) : TestProvider(state), new_state_(new_state), manager_(manager), before_(before) {} bool OnRequest(scoped_refptr request) override { TestProvider::OnRequest(request); manager_->AddProvider( new SimpleTestProvider(new_state_, SimpleTestProvider::CONTINUE, nullptr), before_ ? -1 : 1, std::string()); request->Continue(nullptr); return true; } private: State* new_state_; CefResourceManager* manager_; // Weak reference. bool before_; DISALLOW_COPY_AND_ASSIGN(AddingTestProvider); }; } // namespace // Test adding a new provider after the current provider. TEST(ResourceManagerTest, AddProviderAfter) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new AddingTestProvider(&provider_state1, &provider_state2, state.manager_.get(), false), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // All providers are called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); EXPECT_TRUE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); } // Test adding a new provider before the current provider. TEST(ResourceManagerTest, AddProviderBefore) { const char kUrl[] = "http://test.com/ResourceManagerTest"; ResourceManagerTestHandler::State state; state.urls_.push_back(kUrl); TestProvider::State provider_state1; TestProvider::State provider_state2; ProviderDestructHelper destruct_helper(2); provider_state1.destruct_callback_ = destruct_helper.callback(); provider_state2.destruct_callback_ = destruct_helper.callback(); state.manager_->AddProvider( new AddingTestProvider(&provider_state1, &provider_state2, state.manager_.get(), true), 0, std::string()); CefRefPtr handler = new ResourceManagerTestHandler(&state); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); state.manager_ = nullptr; // Wait for the manager to be deleted. destruct_helper.Wait(); // 1st provider is called. EXPECT_TRUE(provider_state1.got_on_request_); EXPECT_FALSE(provider_state1.got_on_request_canceled_); EXPECT_TRUE(provider_state1.got_destruct_); // 2nd provider is not called because it was added before the 1st provider. EXPECT_FALSE(provider_state2.got_on_request_); EXPECT_FALSE(provider_state2.got_on_request_canceled_); EXPECT_TRUE(provider_state2.got_destruct_); EXPECT_EQ(state.messages_.size(), 1U); EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]); }