// Copyright (c) 2012 The Chromium 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 "net/url_request/url_fetcher_impl.h" #include #include #include "base/bind.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/message_loop/message_loop_proxy.h" #include "base/path_service.h" #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "build/build_config.h" #include "crypto/nss_util.h" #include "net/base/network_change_notifier.h" #include "net/dns/mock_host_resolver.h" #include "net/http/http_response_headers.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_test_util.h" #include "net/url_request/url_request_throttler_manager.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(USE_NSS) || defined(OS_IOS) #include "net/ocsp/nss_ocsp.h" #endif namespace net { using base::Time; using base::TimeDelta; // TODO(eroman): Add a regression test for http://crbug.com/40505. namespace { // TODO(akalin): Move all the test data to somewhere under net/. const base::FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("net/data/url_fetcher_impl_unittest"); const char kTestServerFilePrefix[] = "files/"; class ThrottlingTestURLRequestContext : public TestURLRequestContext { public: ThrottlingTestURLRequestContext() : TestURLRequestContext(true) { set_throttler_manager(&throttler_manager_); Init(); DCHECK(throttler_manager() != NULL); } private: URLRequestThrottlerManager throttler_manager_; }; class ThrottlingTestURLRequestContextGetter : public TestURLRequestContextGetter { public: ThrottlingTestURLRequestContextGetter( base::MessageLoopProxy* io_message_loop_proxy, TestURLRequestContext* request_context) : TestURLRequestContextGetter(io_message_loop_proxy), context_(request_context) { } // TestURLRequestContextGetter: TestURLRequestContext* GetURLRequestContext() override { return context_; } protected: ~ThrottlingTestURLRequestContextGetter() override {} TestURLRequestContext* const context_; }; } // namespace class URLFetcherTest : public testing::Test, public URLFetcherDelegate { public: URLFetcherTest() : fetcher_(NULL) {} static int GetNumFetcherCores() { return URLFetcherImpl::GetNumFetcherCores(); } // Creates a URLFetcher, using the program's main thread to do IO. virtual void CreateFetcher(const GURL& url); // URLFetcherDelegate: // Subclasses that override this should either call this function or // CleanupAfterFetchComplete() at the end of their processing, depending on // whether they want to check for a non-empty HTTP 200 response or not. void OnURLFetchComplete(const URLFetcher* source) override; // Deletes |fetcher| and terminates the message loop. void CleanupAfterFetchComplete(); scoped_refptr io_message_loop_proxy() { return io_message_loop_proxy_; } TestURLRequestContext* request_context() { return context_.get(); } protected: // testing::Test: void SetUp() override { testing::Test::SetUp(); context_.reset(new ThrottlingTestURLRequestContext()); io_message_loop_proxy_ = base::MessageLoopProxy::current(); #if defined(USE_NSS) || defined(OS_IOS) crypto::EnsureNSSInit(); EnsureNSSHttpIOInit(); #endif } void TearDown() override { #if defined(USE_NSS) || defined(OS_IOS) ShutdownNSSHttpIO(); #endif } // URLFetcher is designed to run on the main UI thread, but in our tests // we assume that the current thread is the IO thread where the URLFetcher // dispatches its requests to. When we wish to simulate being used from // a UI thread, we dispatch a worker thread to do so. scoped_refptr io_message_loop_proxy_; URLFetcherImpl* fetcher_; scoped_ptr context_; }; // A test fixture that uses a MockHostResolver, so that name resolutions can // be manipulated by the tests to keep connections in the resolving state. class URLFetcherMockDnsTest : public URLFetcherTest { public: // testing::Test: void SetUp() override; // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; protected: GURL test_url_; scoped_ptr test_server_; MockHostResolver resolver_; scoped_ptr completed_fetcher_; }; void URLFetcherTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->Start(); } void URLFetcherTest::OnURLFetchComplete(const URLFetcher* source) { EXPECT_TRUE(source->GetStatus().is_success()); EXPECT_EQ(200, source->GetResponseCode()); // HTTP OK std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_FALSE(data.empty()); CleanupAfterFetchComplete(); } void URLFetcherTest::CleanupAfterFetchComplete() { delete fetcher_; // Have to delete this here and not in the destructor, // because the destructor won't necessarily run on the // same thread that CreateFetcher() did. io_message_loop_proxy()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); // If the current message loop is not the IO loop, it will be shut down when // the main loop returns and this thread subsequently goes out of scope. } void URLFetcherMockDnsTest::SetUp() { URLFetcherTest::SetUp(); resolver_.set_ondemand_mode(true); resolver_.rules()->AddRule("example.com", "127.0.0.1"); context_.reset(new TestURLRequestContext(true)); context_->set_host_resolver(&resolver_); context_->Init(); test_server_.reset(new SpawnedTestServer(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot))); ASSERT_TRUE(test_server_->Start()); // test_server_.GetURL() returns a URL with 127.0.0.1 (kLocalhost), that is // immediately resolved by the MockHostResolver. Use a hostname instead to // trigger an async resolve. test_url_ = GURL( base::StringPrintf("http://example.com:%d/defaultresponse", test_server_->host_port_pair().port())); ASSERT_TRUE(test_url_.is_valid()); } void URLFetcherMockDnsTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); } void URLFetcherMockDnsTest::OnURLFetchComplete(const URLFetcher* source) { io_message_loop_proxy()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); ASSERT_EQ(fetcher_, source); EXPECT_EQ(test_url_, source->GetOriginalURL()); completed_fetcher_.reset(fetcher_); } namespace { // Version of URLFetcherTest that does a POST instead class URLFetcherPostTest : public URLFetcherTest { public: // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; }; // Version of URLFetcherTest that does a POST of a file using // SetUploadDataStream class URLFetcherPostFileTest : public URLFetcherTest { public: URLFetcherPostFileTest(); void SetUploadRange(uint64 range_offset, uint64 range_length) { range_offset_ = range_offset; range_length_ = range_length; } // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; private: base::FilePath path_; uint64 range_offset_; uint64 range_length_; }; // Version of URLFetcherTest that does a POST instead with empty upload body class URLFetcherEmptyPostTest : public URLFetcherTest { public: // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; }; // Version of URLFetcherTest that tests download progress reports. class URLFetcherDownloadProgressTest : public URLFetcherTest { public: URLFetcherDownloadProgressTest() : previous_progress_(0), expected_total_(0) { } // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchDownloadProgress(const URLFetcher* source, int64 current, int64 total) override; protected: // Download progress returned by the previous callback. int64 previous_progress_; // Size of the file being downloaded, known in advance (provided by each test // case). int64 expected_total_; }; // Version of URLFetcherTest that tests progress reports at cancellation. class URLFetcherDownloadProgressCancelTest : public URLFetcherTest { public: // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; void OnURLFetchDownloadProgress(const URLFetcher* source, int64 current, int64 total) override; protected: bool cancelled_; }; // Version of URLFetcherTest that tests upload progress reports. class URLFetcherUploadProgressTest : public URLFetcherTest { public: // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchUploadProgress(const URLFetcher* source, int64 current, int64 total) override; protected: int64 previous_progress_; std::string chunk_; int64 number_of_chunks_added_; }; // Version of URLFetcherTest that tests headers. class URLFetcherHeadersTest : public URLFetcherTest { public: // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; }; // Version of URLFetcherTest that tests SocketAddress. class URLFetcherSocketAddressTest : public URLFetcherTest { public: // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; protected: std::string expected_host_; uint16 expected_port_; }; // Version of URLFetcherTest that tests stopping on a redirect. class URLFetcherStopOnRedirectTest : public URLFetcherTest { public: URLFetcherStopOnRedirectTest(); ~URLFetcherStopOnRedirectTest() override; // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; protected: // The URL we should be redirected to. static const char* kRedirectTarget; bool callback_called_; // Set to true in OnURLFetchComplete(). }; // Version of URLFetcherTest that tests overload protection. class URLFetcherProtectTest : public URLFetcherTest { public: // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; private: Time start_time_; }; // Version of URLFetcherTest that tests overload protection, when responses // passed through. class URLFetcherProtectTestPassedThrough : public URLFetcherTest { public: // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; private: Time start_time_; }; // Version of URLFetcherTest that tests bad HTTPS requests. class URLFetcherBadHTTPSTest : public URLFetcherTest { public: URLFetcherBadHTTPSTest(); // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; private: base::FilePath cert_dir_; }; // Version of URLFetcherTest that tests request cancellation on shutdown. class URLFetcherCancelTest : public URLFetcherTest { public: // URLFetcherTest: void CreateFetcher(const GURL& url) override; // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; void CancelRequest(); }; // Version of TestURLRequestContext that posts a Quit task to the IO // thread once it is deleted. class CancelTestURLRequestContext : public ThrottlingTestURLRequestContext { public: explicit CancelTestURLRequestContext() { } private: ~CancelTestURLRequestContext() override { // The d'tor should execute in the IO thread. Post the quit task to the // current thread. base::MessageLoop::current()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } }; class CancelTestURLRequestContextGetter : public TestURLRequestContextGetter { public: CancelTestURLRequestContextGetter( base::MessageLoopProxy* io_message_loop_proxy, const GURL& throttle_for_url) : TestURLRequestContextGetter(io_message_loop_proxy), io_message_loop_proxy_(io_message_loop_proxy), context_created_(false, false), throttle_for_url_(throttle_for_url) { } // TestURLRequestContextGetter: TestURLRequestContext* GetURLRequestContext() override { if (!context_.get()) { context_.reset(new CancelTestURLRequestContext()); DCHECK(context_->throttler_manager()); // Registers an entry for test url. The backoff time is calculated by: // new_backoff = 2.0 * old_backoff + 0 // The initial backoff is 2 seconds and maximum backoff is 4 seconds. // Maximum retries allowed is set to 2. scoped_refptr entry( new URLRequestThrottlerEntry(context_->throttler_manager(), std::string(), 200, 3, 2000, 2.0, 0.0, 4000)); context_->throttler_manager() ->OverrideEntryForTests(throttle_for_url_, entry.get()); context_created_.Signal(); } return context_.get(); } virtual scoped_refptr GetIOMessageLoopProxy() const { return io_message_loop_proxy_; } void WaitForContextCreation() { context_created_.Wait(); } protected: ~CancelTestURLRequestContextGetter() override {} private: scoped_ptr context_; scoped_refptr io_message_loop_proxy_; base::WaitableEvent context_created_; GURL throttle_for_url_; }; // Version of URLFetcherTest that tests retying the same request twice. class URLFetcherMultipleAttemptTest : public URLFetcherTest { public: // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; private: std::string data_; }; class URLFetcherFileTest : public URLFetcherTest { public: URLFetcherFileTest() : take_ownership_of_file_(false), expected_file_error_(OK) {} void CreateFetcherForFile(const GURL& url, const base::FilePath& file_path); void CreateFetcherForTempFile(const GURL& url); // URLFetcherDelegate: void OnURLFetchComplete(const URLFetcher* source) override; protected: base::FilePath expected_file_; base::FilePath file_path_; // Set by the test. Used in OnURLFetchComplete() to decide if // the URLFetcher should own the temp file, so that we can test // disowning prevents the file from being deleted. bool take_ownership_of_file_; // Expected file error code for the test. OK when expecting success. int expected_file_error_; }; void URLFetcherPostTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::POST, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->SetUploadData("application/x-www-form-urlencoded", "bobsyeruncle"); fetcher_->Start(); } void URLFetcherPostTest::OnURLFetchComplete(const URLFetcher* source) { std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_EQ(std::string("bobsyeruncle"), data); URLFetcherTest::OnURLFetchComplete(source); } URLFetcherPostFileTest::URLFetcherPostFileTest() : range_offset_(0), range_length_(kuint64max) { PathService::Get(base::DIR_SOURCE_ROOT, &path_); path_ = path_.Append(FILE_PATH_LITERAL("net")); path_ = path_.Append(FILE_PATH_LITERAL("data")); path_ = path_.Append(FILE_PATH_LITERAL("url_request_unittest")); path_ = path_.Append(FILE_PATH_LITERAL("BullRunSpeech.txt")); } void URLFetcherPostFileTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::POST, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->SetUploadFilePath("application/x-www-form-urlencoded", path_, range_offset_, range_length_, base::MessageLoopProxy::current()); fetcher_->Start(); } void URLFetcherPostFileTest::OnURLFetchComplete(const URLFetcher* source) { std::string expected; ASSERT_TRUE(base::ReadFileToString(path_, &expected)); ASSERT_LE(range_offset_, expected.size()); uint64 expected_size = std::min(range_length_, expected.size() - range_offset_); std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_EQ(expected.substr(range_offset_, expected_size), data); URLFetcherTest::OnURLFetchComplete(source); } void URLFetcherEmptyPostTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::POST, this); fetcher_->SetRequestContext(new TestURLRequestContextGetter( io_message_loop_proxy())); fetcher_->SetUploadData("text/plain", std::string()); fetcher_->Start(); } void URLFetcherEmptyPostTest::OnURLFetchComplete(const URLFetcher* source) { EXPECT_TRUE(source->GetStatus().is_success()); EXPECT_EQ(200, source->GetResponseCode()); // HTTP OK std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_TRUE(data.empty()); CleanupAfterFetchComplete(); // Do not call the super class method URLFetcherTest::OnURLFetchComplete, // since it expects a non-empty response. } void URLFetcherDownloadProgressTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->Start(); } void URLFetcherDownloadProgressTest::OnURLFetchDownloadProgress( const URLFetcher* source, int64 progress, int64 total) { // Increasing between 0 and total. EXPECT_LE(0, progress); EXPECT_GE(total, progress); EXPECT_LE(previous_progress_, progress); EXPECT_EQ(expected_total_, total); previous_progress_ = progress; } void URLFetcherDownloadProgressCancelTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); cancelled_ = false; fetcher_->Start(); } void URLFetcherDownloadProgressCancelTest::OnURLFetchDownloadProgress( const URLFetcher* source, int64 current, int64 total) { EXPECT_FALSE(cancelled_); if (!cancelled_) { cancelled_ = true; CleanupAfterFetchComplete(); } } void URLFetcherDownloadProgressCancelTest::OnURLFetchComplete( const URLFetcher* source) { // Should have been cancelled. ADD_FAILURE(); CleanupAfterFetchComplete(); } void URLFetcherUploadProgressTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::POST, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); previous_progress_ = 0; // Large enough data to require more than one read from UploadDataStream. chunk_.assign(1<<16, 'a'); // Use chunked upload to wait for a timer event of progress notification. fetcher_->SetChunkedUpload("application/x-www-form-urlencoded"); fetcher_->Start(); number_of_chunks_added_ = 1; fetcher_->AppendChunkToUpload(chunk_, false); } void URLFetcherUploadProgressTest::OnURLFetchUploadProgress( const URLFetcher* source, int64 current, int64 total) { // Increasing between 0 and total. EXPECT_LE(0, current); EXPECT_GE(static_cast(chunk_.size()) * number_of_chunks_added_, current); EXPECT_LE(previous_progress_, current); previous_progress_ = current; EXPECT_EQ(-1, total); if (number_of_chunks_added_ < 2) { number_of_chunks_added_ += 1; fetcher_->AppendChunkToUpload(chunk_, true); } } void URLFetcherHeadersTest::OnURLFetchComplete( const URLFetcher* source) { std::string header; EXPECT_TRUE(source->GetResponseHeaders()->GetNormalizedHeader("cache-control", &header)); EXPECT_EQ("private", header); URLFetcherTest::OnURLFetchComplete(source); } void URLFetcherSocketAddressTest::OnURLFetchComplete( const URLFetcher* source) { EXPECT_EQ("127.0.0.1", source->GetSocketAddress().host()); EXPECT_EQ(expected_port_, source->GetSocketAddress().port()); URLFetcherTest::OnURLFetchComplete(source); } // static const char* URLFetcherStopOnRedirectTest::kRedirectTarget = "http://redirect.target.com"; URLFetcherStopOnRedirectTest::URLFetcherStopOnRedirectTest() : callback_called_(false) { } URLFetcherStopOnRedirectTest::~URLFetcherStopOnRedirectTest() { } void URLFetcherStopOnRedirectTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->SetStopOnRedirect(true); fetcher_->Start(); } void URLFetcherStopOnRedirectTest::OnURLFetchComplete( const URLFetcher* source) { callback_called_ = true; EXPECT_EQ(GURL(kRedirectTarget), source->GetURL()); EXPECT_EQ(URLRequestStatus::CANCELED, source->GetStatus().status()); EXPECT_EQ(ERR_ABORTED, source->GetStatus().error()); EXPECT_EQ(301, source->GetResponseCode()); CleanupAfterFetchComplete(); } void URLFetcherProtectTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); start_time_ = Time::Now(); fetcher_->SetMaxRetriesOn5xx(11); fetcher_->Start(); } void URLFetcherProtectTest::OnURLFetchComplete(const URLFetcher* source) { const TimeDelta one_second = TimeDelta::FromMilliseconds(1000); if (source->GetResponseCode() >= 500) { // Now running ServerUnavailable test. // It takes more than 1 second to finish all 11 requests. EXPECT_TRUE(Time::Now() - start_time_ >= one_second); EXPECT_TRUE(source->GetStatus().is_success()); std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_FALSE(data.empty()); CleanupAfterFetchComplete(); } else { // Now running Overload test. static int count = 0; count++; if (count < 20) { fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->Start(); } else { // We have already sent 20 requests continuously. And we expect that // it takes more than 1 second due to the overload protection settings. EXPECT_TRUE(Time::Now() - start_time_ >= one_second); URLFetcherTest::OnURLFetchComplete(source); } } } void URLFetcherProtectTestPassedThrough::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->SetAutomaticallyRetryOn5xx(false); start_time_ = Time::Now(); fetcher_->SetMaxRetriesOn5xx(11); fetcher_->Start(); } void URLFetcherProtectTestPassedThrough::OnURLFetchComplete( const URLFetcher* source) { const TimeDelta one_minute = TimeDelta::FromMilliseconds(60000); if (source->GetResponseCode() >= 500) { // Now running ServerUnavailable test. // It should get here on the first attempt, so almost immediately and // *not* to attempt to execute all 11 requests (2.5 minutes). EXPECT_TRUE(Time::Now() - start_time_ < one_minute); EXPECT_TRUE(source->GetStatus().is_success()); // Check that suggested back off time is bigger than 0. EXPECT_GT(fetcher_->GetBackoffDelay().InMicroseconds(), 0); std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_FALSE(data.empty()); } else { // We should not get here! ADD_FAILURE(); } CleanupAfterFetchComplete(); } URLFetcherBadHTTPSTest::URLFetcherBadHTTPSTest() { PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_); cert_dir_ = cert_dir_.AppendASCII("chrome"); cert_dir_ = cert_dir_.AppendASCII("test"); cert_dir_ = cert_dir_.AppendASCII("data"); cert_dir_ = cert_dir_.AppendASCII("ssl"); cert_dir_ = cert_dir_.AppendASCII("certificates"); } // The "server certificate expired" error should result in automatic // cancellation of the request by // URLRequest::Delegate::OnSSLCertificateError. void URLFetcherBadHTTPSTest::OnURLFetchComplete( const URLFetcher* source) { // This part is different from URLFetcherTest::OnURLFetchComplete // because this test expects the request to be cancelled. EXPECT_EQ(URLRequestStatus::CANCELED, source->GetStatus().status()); EXPECT_EQ(ERR_ABORTED, source->GetStatus().error()); EXPECT_EQ(-1, source->GetResponseCode()); EXPECT_TRUE(source->GetCookies().empty()); std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_TRUE(data.empty()); CleanupAfterFetchComplete(); } void URLFetcherCancelTest::CreateFetcher(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); CancelTestURLRequestContextGetter* context_getter = new CancelTestURLRequestContextGetter(io_message_loop_proxy().get(), url); fetcher_->SetRequestContext(context_getter); fetcher_->SetMaxRetriesOn5xx(2); fetcher_->Start(); // We need to wait for the creation of the URLRequestContext, since we // rely on it being destroyed as a signal to end the test. context_getter->WaitForContextCreation(); CancelRequest(); } void URLFetcherCancelTest::OnURLFetchComplete( const URLFetcher* source) { // We should have cancelled the request before completion. ADD_FAILURE(); CleanupAfterFetchComplete(); } void URLFetcherCancelTest::CancelRequest() { delete fetcher_; // The URLFetcher's test context will post a Quit task once it is // deleted. So if this test simply hangs, it means cancellation // did not work. } void URLFetcherMultipleAttemptTest::OnURLFetchComplete( const URLFetcher* source) { EXPECT_TRUE(source->GetStatus().is_success()); EXPECT_EQ(200, source->GetResponseCode()); // HTTP OK std::string data; EXPECT_TRUE(source->GetResponseAsString(&data)); EXPECT_FALSE(data.empty()); if (!data.empty() && data_.empty()) { data_ = data; fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); fetcher_->Start(); } else { EXPECT_EQ(data, data_); CleanupAfterFetchComplete(); } } void URLFetcherFileTest::CreateFetcherForFile(const GURL& url, const base::FilePath& file_path) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); // Use the IO message loop to do the file operations in this test. fetcher_->SaveResponseToFileAtPath(file_path, io_message_loop_proxy()); fetcher_->Start(); } void URLFetcherFileTest::CreateFetcherForTempFile(const GURL& url) { fetcher_ = new URLFetcherImpl(url, URLFetcher::GET, this); fetcher_->SetRequestContext(new ThrottlingTestURLRequestContextGetter( io_message_loop_proxy().get(), request_context())); // Use the IO message loop to do the file operations in this test. fetcher_->SaveResponseToTemporaryFile(io_message_loop_proxy()); fetcher_->Start(); } void URLFetcherFileTest::OnURLFetchComplete(const URLFetcher* source) { if (expected_file_error_ == OK) { EXPECT_TRUE(source->GetStatus().is_success()); EXPECT_EQ(OK, source->GetStatus().error()); EXPECT_EQ(200, source->GetResponseCode()); EXPECT_TRUE(source->GetResponseAsFilePath( take_ownership_of_file_, &file_path_)); EXPECT_TRUE(base::ContentsEqual(expected_file_, file_path_)); } else { EXPECT_FALSE(source->GetStatus().is_success()); EXPECT_EQ(expected_file_error_, source->GetStatus().error()); } CleanupAfterFetchComplete(); } TEST_F(URLFetcherTest, SameThreadsTest) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Create the fetcher on the main thread. Since IO will happen on the main // thread, this will test URLFetcher's ability to do everything on one // thread. CreateFetcher(test_server.GetURL("defaultresponse")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherTest, DifferentThreadsTest) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Create a separate thread that will create the URLFetcher. The current // (main) thread will do the IO, and when the fetch is complete it will // terminate the main thread's message loop; then the other thread's // message loop will be shut down automatically as the thread goes out of // scope. base::Thread t("URLFetcher test thread"); ASSERT_TRUE(t.Start()); t.message_loop()->PostTask( FROM_HERE, base::Bind(&URLFetcherTest::CreateFetcher, base::Unretained(this), test_server.GetURL("defaultresponse"))); base::MessageLoop::current()->Run(); } void CancelAllOnIO() { EXPECT_EQ(1, URLFetcherTest::GetNumFetcherCores()); URLFetcherImpl::CancelAll(); EXPECT_EQ(0, URLFetcherTest::GetNumFetcherCores()); } // Tests to make sure CancelAll() will successfully cancel existing URLFetchers. TEST_F(URLFetcherTest, CancelAll) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); EXPECT_EQ(0, GetNumFetcherCores()); CreateFetcher(test_server.GetURL("defaultresponse")); io_message_loop_proxy()->PostTaskAndReply( FROM_HERE, base::Bind(&CancelAllOnIO), base::MessageLoop::QuitClosure()); base::MessageLoop::current()->Run(); EXPECT_EQ(0, GetNumFetcherCores()); delete fetcher_; } TEST_F(URLFetcherMockDnsTest, DontRetryOnNetworkChangedByDefault) { EXPECT_EQ(0, GetNumFetcherCores()); EXPECT_FALSE(resolver_.has_pending_requests()); // This posts a task to start the fetcher. CreateFetcher(test_url_); fetcher_->Start(); EXPECT_EQ(0, GetNumFetcherCores()); base::MessageLoop::current()->RunUntilIdle(); // The fetcher is now running, but is pending the host resolve. EXPECT_EQ(1, GetNumFetcherCores()); EXPECT_TRUE(resolver_.has_pending_requests()); ASSERT_FALSE(completed_fetcher_); // A network change notification aborts the connect job. NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ(0, GetNumFetcherCores()); EXPECT_FALSE(resolver_.has_pending_requests()); ASSERT_TRUE(completed_fetcher_); // And the owner of the fetcher gets the ERR_NETWORK_CHANGED error. EXPECT_EQ(ERR_NETWORK_CHANGED, completed_fetcher_->GetStatus().error()); } TEST_F(URLFetcherMockDnsTest, RetryOnNetworkChangedAndFail) { EXPECT_EQ(0, GetNumFetcherCores()); EXPECT_FALSE(resolver_.has_pending_requests()); // This posts a task to start the fetcher. CreateFetcher(test_url_); fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); fetcher_->Start(); EXPECT_EQ(0, GetNumFetcherCores()); base::MessageLoop::current()->RunUntilIdle(); // The fetcher is now running, but is pending the host resolve. EXPECT_EQ(1, GetNumFetcherCores()); EXPECT_TRUE(resolver_.has_pending_requests()); ASSERT_FALSE(completed_fetcher_); // Make it fail 3 times. for (int i = 0; i < 3; ++i) { // A network change notification aborts the connect job. NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); base::MessageLoop::current()->RunUntilIdle(); // But the fetcher retries automatically. EXPECT_EQ(1, GetNumFetcherCores()); EXPECT_TRUE(resolver_.has_pending_requests()); ASSERT_FALSE(completed_fetcher_); } // A 4th failure doesn't trigger another retry, and propagates the error // to the owner of the fetcher. NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ(0, GetNumFetcherCores()); EXPECT_FALSE(resolver_.has_pending_requests()); ASSERT_TRUE(completed_fetcher_); // And the owner of the fetcher gets the ERR_NETWORK_CHANGED error. EXPECT_EQ(ERR_NETWORK_CHANGED, completed_fetcher_->GetStatus().error()); } TEST_F(URLFetcherMockDnsTest, RetryOnNetworkChangedAndSucceed) { EXPECT_EQ(0, GetNumFetcherCores()); EXPECT_FALSE(resolver_.has_pending_requests()); // This posts a task to start the fetcher. CreateFetcher(test_url_); fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); fetcher_->Start(); EXPECT_EQ(0, GetNumFetcherCores()); base::MessageLoop::current()->RunUntilIdle(); // The fetcher is now running, but is pending the host resolve. EXPECT_EQ(1, GetNumFetcherCores()); EXPECT_TRUE(resolver_.has_pending_requests()); ASSERT_FALSE(completed_fetcher_); // Make it fail 3 times. for (int i = 0; i < 3; ++i) { // A network change notification aborts the connect job. NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); base::MessageLoop::current()->RunUntilIdle(); // But the fetcher retries automatically. EXPECT_EQ(1, GetNumFetcherCores()); EXPECT_TRUE(resolver_.has_pending_requests()); ASSERT_FALSE(completed_fetcher_); } // Now let it succeed by resolving the pending request. resolver_.ResolveAllPending(); base::MessageLoop::current()->Run(); // URLFetcherMockDnsTest::OnURLFetchComplete() will quit the loop. EXPECT_EQ(0, GetNumFetcherCores()); EXPECT_FALSE(resolver_.has_pending_requests()); ASSERT_TRUE(completed_fetcher_); // This time the request succeeded. EXPECT_EQ(OK, completed_fetcher_->GetStatus().error()); EXPECT_EQ(200, completed_fetcher_->GetResponseCode()); } TEST_F(URLFetcherPostTest, Basic) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); CreateFetcher(test_server.GetURL("echo")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherPostFileTest, Basic) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); CreateFetcher(test_server.GetURL("echo")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherPostFileTest, Range) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); SetUploadRange(30, 100); CreateFetcher(test_server.GetURL("echo")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherEmptyPostTest, Basic) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); CreateFetcher(test_server.GetURL("echo")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherUploadProgressTest, Basic) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); CreateFetcher(test_server.GetURL("echo")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherDownloadProgressTest, Basic) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Get a file large enough to require more than one read into // URLFetcher::Core's IOBuffer. static const char kFileToFetch[] = "animate1.gif"; // Hardcoded file size - it cannot be easily fetched when a remote http server // is used for testing. static const int64 kFileSize = 19021; expected_total_ = kFileSize; CreateFetcher(test_server.GetURL( std::string(kTestServerFilePrefix) + kFileToFetch)); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherDownloadProgressCancelTest, CancelWhileProgressReport) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Get a file large enough to require more than one read into // URLFetcher::Core's IOBuffer. static const char kFileToFetch[] = "animate1.gif"; CreateFetcher(test_server.GetURL( std::string(kTestServerFilePrefix) + kFileToFetch)); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherHeadersTest, Headers) { SpawnedTestServer test_server( SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))); ASSERT_TRUE(test_server.Start()); CreateFetcher(test_server.GetURL("files/with-headers.html")); base::MessageLoop::current()->Run(); // The actual tests are in the URLFetcherHeadersTest fixture. } TEST_F(URLFetcherSocketAddressTest, SocketAddress) { SpawnedTestServer test_server( SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))); ASSERT_TRUE(test_server.Start()); expected_port_ = test_server.host_port_pair().port(); // Reusing "with-headers.html" but doesn't really matter. CreateFetcher(test_server.GetURL("files/with-headers.html")); base::MessageLoop::current()->Run(); // The actual tests are in the URLFetcherSocketAddressTest fixture. } TEST_F(URLFetcherStopOnRedirectTest, StopOnRedirect) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); CreateFetcher( test_server.GetURL(std::string("server-redirect?") + kRedirectTarget)); base::MessageLoop::current()->Run(); EXPECT_TRUE(callback_called_); } TEST_F(URLFetcherProtectTest, Overload) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); GURL url(test_server.GetURL("defaultresponse")); // Registers an entry for test url. It only allows 3 requests to be sent // in 200 milliseconds. scoped_refptr entry( new URLRequestThrottlerEntry(request_context()->throttler_manager(), std::string(), 200, 3, 1, 2.0, 0.0, 256)); request_context()->throttler_manager() ->OverrideEntryForTests(url, entry.get()); CreateFetcher(url); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherProtectTest, ServerUnavailable) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); GURL url(test_server.GetURL("files/server-unavailable.html")); // Registers an entry for test url. The backoff time is calculated by: // new_backoff = 2.0 * old_backoff + 0 // and maximum backoff time is 256 milliseconds. // Maximum retries allowed is set to 11. scoped_refptr entry( new URLRequestThrottlerEntry(request_context()->throttler_manager(), std::string(), 200, 3, 1, 2.0, 0.0, 256)); request_context()->throttler_manager() ->OverrideEntryForTests(url, entry.get()); CreateFetcher(url); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherProtectTestPassedThrough, ServerUnavailablePropagateResponse) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); GURL url(test_server.GetURL("files/server-unavailable.html")); // Registers an entry for test url. The backoff time is calculated by: // new_backoff = 2.0 * old_backoff + 0 // and maximum backoff time is 150000 milliseconds. // Maximum retries allowed is set to 11. scoped_refptr entry( new URLRequestThrottlerEntry(request_context()->throttler_manager(), std::string(), 200, 3, 100, 2.0, 0.0, 150000)); // Total time if *not* for not doing automatic backoff would be 150s. // In reality it should be "as soon as server responds". request_context()->throttler_manager() ->OverrideEntryForTests(url, entry.get()); CreateFetcher(url); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherBadHTTPSTest, BadHTTPSTest) { SpawnedTestServer::SSLOptions ssl_options( SpawnedTestServer::SSLOptions::CERT_EXPIRED); SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); CreateFetcher(test_server.GetURL("defaultresponse")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherCancelTest, ReleasesContext) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); GURL url(test_server.GetURL("files/server-unavailable.html")); // Create a separate thread that will create the URLFetcher. The current // (main) thread will do the IO, and when the fetch is complete it will // terminate the main thread's message loop; then the other thread's // message loop will be shut down automatically as the thread goes out of // scope. base::Thread t("URLFetcher test thread"); ASSERT_TRUE(t.Start()); t.message_loop()->PostTask( FROM_HERE, base::Bind(&URLFetcherCancelTest::CreateFetcher, base::Unretained(this), url)); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherCancelTest, CancelWhileDelayedStartTaskPending) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); GURL url(test_server.GetURL("files/server-unavailable.html")); // Register an entry for test url. // Using a sliding window of 4 seconds, and max of 1 request, under a fast // run we expect to have a 4 second delay when posting the Start task. scoped_refptr entry( new URLRequestThrottlerEntry(request_context()->throttler_manager(), std::string(), 4000, 1, 2000, 2.0, 0.0, 4000)); request_context()->throttler_manager() ->OverrideEntryForTests(url, entry.get()); // Fake that a request has just started. entry->ReserveSendingTimeForNextRequest(base::TimeTicks()); // The next request we try to send will be delayed by ~4 seconds. // The slower the test runs, the less the delay will be (since it takes the // time difference from now). base::Thread t("URLFetcher test thread"); ASSERT_TRUE(t.Start()); t.message_loop()->PostTask( FROM_HERE, base::Bind(&URLFetcherTest::CreateFetcher, base::Unretained(this), url)); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherMultipleAttemptTest, SameData) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Create the fetcher on the main thread. Since IO will happen on the main // thread, this will test URLFetcher's ability to do everything on one // thread. CreateFetcher(test_server.GetURL("defaultresponse")); base::MessageLoop::current()->Run(); } TEST_F(URLFetcherFileTest, SmallGet) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); // Get a small file. static const char kFileToFetch[] = "simple.html"; expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); CreateFetcherForFile( test_server.GetURL(std::string(kTestServerFilePrefix) + kFileToFetch), temp_dir.path().AppendASCII(kFileToFetch)); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). ASSERT_FALSE(base::PathExists(file_path_)) << file_path_.value() << " not removed."; } TEST_F(URLFetcherFileTest, LargeGet) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); // Get a file large enough to require more than one read into // URLFetcher::Core's IOBuffer. static const char kFileToFetch[] = "animate1.gif"; expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); CreateFetcherForFile( test_server.GetURL(std::string(kTestServerFilePrefix) + kFileToFetch), temp_dir.path().AppendASCII(kFileToFetch)); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). } TEST_F(URLFetcherFileTest, SavedOutputFileOwnerhisp) { // If the caller takes the ownership of the output file, the file should // persist even after URLFetcher is gone. If not, the file must be deleted. const bool kTake[] = {false, true}; for (size_t i = 0; i < arraysize(kTake); ++i) { take_ownership_of_file_ = kTake[i]; SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); // Get a small file. static const char kFileToFetch[] = "simple.html"; expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); CreateFetcherForFile( test_server.GetURL(std::string(kTestServerFilePrefix) + kFileToFetch), temp_dir.path().AppendASCII(kFileToFetch)); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). base::MessageLoop::current()->RunUntilIdle(); ASSERT_EQ(kTake[i], base::PathExists(file_path_)) << "FilePath: " << file_path_.value(); } } TEST_F(URLFetcherFileTest, OverwriteExistingFile) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); // Create a file before trying to fetch. static const char kFileToFetch[] = "simple.html"; std::string data(10000, '?'); // Meant to be larger than simple.html. file_path_ = temp_dir.path().AppendASCII(kFileToFetch); ASSERT_EQ(static_cast(data.size()), base::WriteFile(file_path_, data.data(), data.size())); ASSERT_TRUE(base::PathExists(file_path_)); expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); ASSERT_FALSE(base::ContentsEqual(file_path_, expected_file_)); // Get a small file. CreateFetcherForFile( test_server.GetURL(std::string(kTestServerFilePrefix) + kFileToFetch), file_path_); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). } TEST_F(URLFetcherFileTest, TryToOverwriteDirectory) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); // Create a directory before trying to fetch. static const char kFileToFetch[] = "simple.html"; file_path_ = temp_dir.path().AppendASCII(kFileToFetch); ASSERT_TRUE(base::CreateDirectory(file_path_)); ASSERT_TRUE(base::PathExists(file_path_)); // Get a small file. expected_file_error_ = ERR_ACCESS_DENIED; expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); CreateFetcherForFile( test_server.GetURL(std::string(kTestServerFilePrefix) + kFileToFetch), file_path_); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). base::MessageLoop::current()->RunUntilIdle(); } TEST_F(URLFetcherFileTest, SmallGetToTempFile) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Get a small file. static const char kFileToFetch[] = "simple.html"; expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); CreateFetcherForTempFile( test_server.GetURL(std::string(kTestServerFilePrefix) + kFileToFetch)); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). ASSERT_FALSE(base::PathExists(file_path_)) << file_path_.value() << " not removed."; } TEST_F(URLFetcherFileTest, LargeGetToTempFile) { SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Get a file large enough to require more than one read into // URLFetcher::Core's IOBuffer. static const char kFileToFetch[] = "animate1.gif"; expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); CreateFetcherForTempFile(test_server.GetURL( std::string(kTestServerFilePrefix) + kFileToFetch)); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). } TEST_F(URLFetcherFileTest, SavedOutputTempFileOwnerhisp) { // If the caller takes the ownership of the temp file, the file should persist // even after URLFetcher is gone. If not, the file must be deleted. const bool kTake[] = {false, true}; for (size_t i = 0; i < arraysize(kTake); ++i) { take_ownership_of_file_ = kTake[i]; SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTP, SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot)); ASSERT_TRUE(test_server.Start()); // Get a small file. static const char kFileToFetch[] = "simple.html"; expected_file_ = test_server.GetDocumentRoot().AppendASCII(kFileToFetch); CreateFetcherForTempFile(test_server.GetURL( std::string(kTestServerFilePrefix) + kFileToFetch)); base::MessageLoop::current()->Run(); // OnURLFetchComplete() will Quit(). base::MessageLoop::current()->RunUntilIdle(); ASSERT_EQ(kTake[i], base::PathExists(file_path_)) << "FilePath: " << file_path_.value(); } } } // namespace } // namespace net