| // 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/test_url_fetcher_factory.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/compiler_specific.h" | 
 | #include "base/files/file_util.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "base/message_loop/message_loop.h" | 
 | #include "base/threading/thread_restrictions.h" | 
 | #include "net/base/host_port_pair.h" | 
 | #include "net/base/io_buffer.h" | 
 | #include "net/base/net_errors.h" | 
 | #include "net/http/http_response_headers.h" | 
 | #include "net/url_request/url_fetcher_delegate.h" | 
 | #include "net/url_request/url_fetcher_impl.h" | 
 | #include "net/url_request/url_fetcher_response_writer.h" | 
 | #include "net/url_request/url_request_status.h" | 
 |  | 
 | namespace net { | 
 |  | 
 | ScopedURLFetcherFactory::ScopedURLFetcherFactory( | 
 |     URLFetcherFactory* factory) { | 
 |   DCHECK(!URLFetcherImpl::factory()); | 
 |   URLFetcherImpl::set_factory(factory); | 
 | } | 
 |  | 
 | ScopedURLFetcherFactory::~ScopedURLFetcherFactory() { | 
 |   DCHECK(URLFetcherImpl::factory()); | 
 |   URLFetcherImpl::set_factory(NULL); | 
 | } | 
 |  | 
 | TestURLFetcher::TestURLFetcher(int id, | 
 |                                const GURL& url, | 
 |                                URLFetcherDelegate* d) | 
 |     : owner_(NULL), | 
 |       id_(id), | 
 |       original_url_(url), | 
 |       delegate_(d), | 
 |       delegate_for_tests_(NULL), | 
 |       did_receive_last_chunk_(false), | 
 |       fake_load_flags_(0), | 
 |       fake_response_code_(-1), | 
 |       fake_response_destination_(STRING), | 
 |       fake_was_fetched_via_proxy_(false), | 
 |       fake_max_retries_(0) { | 
 | } | 
 |  | 
 | TestURLFetcher::~TestURLFetcher() { | 
 |   if (delegate_for_tests_) | 
 |     delegate_for_tests_->OnRequestEnd(id_); | 
 |   if (owner_) | 
 |     owner_->RemoveFetcherFromMap(id_); | 
 | } | 
 |  | 
 | void TestURLFetcher::SetUploadData(const std::string& upload_content_type, | 
 |                                    const std::string& upload_content) { | 
 |   upload_content_type_ = upload_content_type; | 
 |   upload_data_ = upload_content; | 
 | } | 
 |  | 
 | void TestURLFetcher::SetUploadFilePath( | 
 |     const std::string& upload_content_type, | 
 |     const base::FilePath& file_path, | 
 |     uint64 range_offset, | 
 |     uint64 range_length, | 
 |     scoped_refptr<base::TaskRunner> file_task_runner) { | 
 |   upload_file_path_ = file_path; | 
 | } | 
 |  | 
 | void TestURLFetcher::SetChunkedUpload(const std::string& upload_content_type) { | 
 | } | 
 |  | 
 | void TestURLFetcher::AppendChunkToUpload(const std::string& data, | 
 |                                          bool is_last_chunk) { | 
 |   DCHECK(!did_receive_last_chunk_); | 
 |   did_receive_last_chunk_ = is_last_chunk; | 
 |   chunks_.push_back(data); | 
 |   if (delegate_for_tests_) | 
 |     delegate_for_tests_->OnChunkUpload(id_); | 
 | } | 
 |  | 
 | void TestURLFetcher::SetLoadFlags(int load_flags) { | 
 |   fake_load_flags_= load_flags; | 
 | } | 
 |  | 
 | int TestURLFetcher::GetLoadFlags() const { | 
 |   return fake_load_flags_; | 
 | } | 
 |  | 
 | void TestURLFetcher::SetReferrer(const std::string& referrer) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SetReferrerPolicy( | 
 |     URLRequest::ReferrerPolicy referrer_policy) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SetExtraRequestHeaders( | 
 |     const std::string& extra_request_headers) { | 
 |   fake_extra_request_headers_.Clear(); | 
 |   fake_extra_request_headers_.AddHeadersFromString(extra_request_headers); | 
 | } | 
 |  | 
 | void TestURLFetcher::AddExtraRequestHeader(const std::string& header_line) { | 
 |   fake_extra_request_headers_.AddHeaderFromString(header_line); | 
 | } | 
 |  | 
 | void TestURLFetcher::SetRequestContext( | 
 |     URLRequestContextGetter* request_context_getter) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SetFirstPartyForCookies( | 
 |     const GURL& first_party_for_cookies) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SetURLRequestUserData( | 
 |     const void* key, | 
 |     const CreateDataCallback& create_data_callback) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SetStopOnRedirect(bool stop_on_redirect) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SetAutomaticallyRetryOn5xx(bool retry) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SetMaxRetriesOn5xx(int max_retries) { | 
 |   fake_max_retries_ = max_retries; | 
 | } | 
 |  | 
 | int TestURLFetcher::GetMaxRetriesOn5xx() const { | 
 |   return fake_max_retries_; | 
 | } | 
 |  | 
 | base::TimeDelta TestURLFetcher::GetBackoffDelay() const { | 
 |   return fake_backoff_delay_; | 
 | } | 
 |  | 
 | void TestURLFetcher::SetAutomaticallyRetryOnNetworkChanges(int max_retries) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SaveResponseToFileAtPath( | 
 |     const base::FilePath& file_path, | 
 |     scoped_refptr<base::SequencedTaskRunner> file_task_runner) { | 
 |   SetResponseFilePath(file_path); | 
 |   // Asynchronous IO is not supported, so file_task_runner is ignored. | 
 |   base::ThreadRestrictions::ScopedAllowIO allow_io; | 
 |   const size_t written_bytes = base::WriteFile( | 
 |       file_path, fake_response_string_.c_str(), fake_response_string_.size()); | 
 |   DCHECK_EQ(written_bytes, fake_response_string_.size()); | 
 | } | 
 |  | 
 | void TestURLFetcher::SaveResponseToTemporaryFile( | 
 |     scoped_refptr<base::SequencedTaskRunner> file_task_runner) { | 
 | } | 
 |  | 
 | void TestURLFetcher::SaveResponseWithWriter( | 
 |     scoped_ptr<URLFetcherResponseWriter> response_writer) { | 
 |   // In class URLFetcherCore this method is called by all three: | 
 |   // GetResponseAsString() / SaveResponseToFileAtPath() / | 
 |   // SaveResponseToTemporaryFile(). But here (in TestURLFetcher), this method | 
 |   // is never used by any of these three methods. So, file writing is expected | 
 |   // to be done in SaveResponseToFileAtPath(), and this method supports only | 
 |   // URLFetcherStringWriter (for testing of this method only). | 
 |   if (fake_response_destination_ == STRING) { | 
 |     response_writer_ = response_writer.Pass(); | 
 |     int response = response_writer_->Initialize(CompletionCallback()); | 
 |     // The TestURLFetcher doesn't handle asynchronous writes. | 
 |     DCHECK_EQ(OK, response); | 
 |  | 
 |     scoped_refptr<IOBuffer> buffer(new StringIOBuffer(fake_response_string_)); | 
 |     response = response_writer_->Write(buffer.get(), | 
 |                                        fake_response_string_.size(), | 
 |                                        CompletionCallback()); | 
 |     DCHECK_EQ(static_cast<int>(fake_response_string_.size()), response); | 
 |     response = response_writer_->Finish(CompletionCallback()); | 
 |     DCHECK_EQ(OK, response); | 
 |   } else if (fake_response_destination_ == TEMP_FILE) { | 
 |     // SaveResponseToFileAtPath() should be called instead of this method to | 
 |     // save file. Asynchronous file writing using URLFetcherFileWriter is not | 
 |     // supported. | 
 |     NOTIMPLEMENTED(); | 
 |   } else { | 
 |     NOTREACHED(); | 
 |   } | 
 | } | 
 |  | 
 | HttpResponseHeaders* TestURLFetcher::GetResponseHeaders() const { | 
 |   return fake_response_headers_.get(); | 
 | } | 
 |  | 
 | HostPortPair TestURLFetcher::GetSocketAddress() const { | 
 |   NOTIMPLEMENTED(); | 
 |   return HostPortPair(); | 
 | } | 
 |  | 
 | bool TestURLFetcher::WasFetchedViaProxy() const { | 
 |   return fake_was_fetched_via_proxy_; | 
 | } | 
 |  | 
 | void TestURLFetcher::Start() { | 
 |   // Overriden to do nothing. It is assumed the caller will notify the delegate. | 
 |   if (delegate_for_tests_) | 
 |     delegate_for_tests_->OnRequestStart(id_); | 
 | } | 
 |  | 
 | const GURL& TestURLFetcher::GetOriginalURL() const { | 
 |   return original_url_; | 
 | } | 
 |  | 
 | const GURL& TestURLFetcher::GetURL() const { | 
 |   return fake_url_; | 
 | } | 
 |  | 
 | const URLRequestStatus& TestURLFetcher::GetStatus() const { | 
 |   return fake_status_; | 
 | } | 
 |  | 
 | int TestURLFetcher::GetResponseCode() const { | 
 |   return fake_response_code_; | 
 | } | 
 |  | 
 | const ResponseCookies& TestURLFetcher::GetCookies() const { | 
 |   return fake_cookies_; | 
 | } | 
 |  | 
 | void TestURLFetcher::ReceivedContentWasMalformed() { | 
 | } | 
 |  | 
 | bool TestURLFetcher::GetResponseAsString( | 
 |     std::string* out_response_string) const { | 
 |   if (fake_response_destination_ != STRING) | 
 |     return false; | 
 |  | 
 |   *out_response_string = fake_response_string_; | 
 |   return true; | 
 | } | 
 |  | 
 | bool TestURLFetcher::GetResponseAsFilePath( | 
 |     bool take_ownership, base::FilePath* out_response_path) const { | 
 |   if (fake_response_destination_ != TEMP_FILE) | 
 |     return false; | 
 |  | 
 |   *out_response_path = fake_response_file_path_; | 
 |   return true; | 
 | } | 
 |  | 
 | void TestURLFetcher::GetExtraRequestHeaders( | 
 |     HttpRequestHeaders* headers) const { | 
 |   *headers = fake_extra_request_headers_; | 
 | } | 
 |  | 
 | void TestURLFetcher::set_status(const URLRequestStatus& status) { | 
 |   fake_status_ = status; | 
 | } | 
 |  | 
 | void TestURLFetcher::set_was_fetched_via_proxy(bool flag) { | 
 |   fake_was_fetched_via_proxy_ = flag; | 
 | } | 
 |  | 
 | void TestURLFetcher::set_response_headers( | 
 |     scoped_refptr<HttpResponseHeaders> headers) { | 
 |   fake_response_headers_ = headers; | 
 | } | 
 |  | 
 | void TestURLFetcher::set_backoff_delay(base::TimeDelta backoff_delay) { | 
 |   fake_backoff_delay_ = backoff_delay; | 
 | } | 
 |  | 
 | void TestURLFetcher::SetDelegateForTests(DelegateForTests* delegate_for_tests) { | 
 |   delegate_for_tests_ = delegate_for_tests; | 
 | } | 
 |  | 
 | void TestURLFetcher::SetResponseString(const std::string& response) { | 
 |   fake_response_destination_ = STRING; | 
 |   fake_response_string_ = response; | 
 | } | 
 |  | 
 | void TestURLFetcher::SetResponseFilePath(const base::FilePath& path) { | 
 |   fake_response_destination_ = TEMP_FILE; | 
 |   fake_response_file_path_ = path; | 
 | } | 
 |  | 
 | TestURLFetcherFactory::TestURLFetcherFactory() | 
 |     : ScopedURLFetcherFactory(this), | 
 |       delegate_for_tests_(NULL), | 
 |       remove_fetcher_on_delete_(false) { | 
 | } | 
 |  | 
 | TestURLFetcherFactory::~TestURLFetcherFactory() {} | 
 |  | 
 | URLFetcher* TestURLFetcherFactory::CreateURLFetcher( | 
 |     int id, | 
 |     const GURL& url, | 
 |     URLFetcher::RequestType request_type, | 
 |     URLFetcherDelegate* d) { | 
 |   TestURLFetcher* fetcher = new TestURLFetcher(id, url, d); | 
 |   if (remove_fetcher_on_delete_) | 
 |     fetcher->set_owner(this); | 
 |   fetcher->SetDelegateForTests(delegate_for_tests_); | 
 |   fetchers_[id] = fetcher; | 
 |   return fetcher; | 
 | } | 
 |  | 
 | TestURLFetcher* TestURLFetcherFactory::GetFetcherByID(int id) const { | 
 |   Fetchers::const_iterator i = fetchers_.find(id); | 
 |   return i == fetchers_.end() ? NULL : i->second; | 
 | } | 
 |  | 
 | void TestURLFetcherFactory::RemoveFetcherFromMap(int id) { | 
 |   Fetchers::iterator i = fetchers_.find(id); | 
 |   DCHECK(i != fetchers_.end()); | 
 |   fetchers_.erase(i); | 
 | } | 
 |  | 
 | void TestURLFetcherFactory::SetDelegateForTests( | 
 |     TestURLFetcherDelegateForTests* delegate_for_tests) { | 
 |   delegate_for_tests_ = delegate_for_tests; | 
 | } | 
 |  | 
 | FakeURLFetcher::FakeURLFetcher(const GURL& url, | 
 |                                URLFetcherDelegate* d, | 
 |                                const std::string& response_data, | 
 |                                HttpStatusCode response_code, | 
 |                                URLRequestStatus::Status status) | 
 |     : TestURLFetcher(0, url, d), | 
 |       weak_factory_(this) { | 
 |   Error error = OK; | 
 |   switch(status) { | 
 |     case URLRequestStatus::SUCCESS: | 
 |       // |error| is initialized to OK. | 
 |       break; | 
 |     case URLRequestStatus::IO_PENDING: | 
 |       error = ERR_IO_PENDING; | 
 |       break; | 
 |     case URLRequestStatus::CANCELED: | 
 |       error = ERR_ABORTED; | 
 |       break; | 
 |     case URLRequestStatus::FAILED: | 
 |       error = ERR_FAILED; | 
 |       break; | 
 |   } | 
 |   set_status(URLRequestStatus(status, error)); | 
 |   set_response_code(response_code); | 
 |   SetResponseString(response_data); | 
 | } | 
 |  | 
 | FakeURLFetcher::~FakeURLFetcher() {} | 
 |  | 
 | void FakeURLFetcher::Start() { | 
 |   base::MessageLoop::current()->PostTask( | 
 |       FROM_HERE, | 
 |       base::Bind(&FakeURLFetcher::RunDelegate, weak_factory_.GetWeakPtr())); | 
 | } | 
 |  | 
 | void FakeURLFetcher::RunDelegate() { | 
 |   delegate()->OnURLFetchComplete(this); | 
 | } | 
 |  | 
 | const GURL& FakeURLFetcher::GetURL() const { | 
 |   return TestURLFetcher::GetOriginalURL(); | 
 | } | 
 |  | 
 | FakeURLFetcherFactory::FakeURLFetcherFactory( | 
 |     URLFetcherFactory* default_factory) | 
 |     : ScopedURLFetcherFactory(this), | 
 |       creator_(base::Bind(&DefaultFakeURLFetcherCreator)), | 
 |       default_factory_(default_factory) { | 
 | } | 
 |  | 
 | FakeURLFetcherFactory::FakeURLFetcherFactory( | 
 |     URLFetcherFactory* default_factory, | 
 |     const FakeURLFetcherCreator& creator) | 
 |     : ScopedURLFetcherFactory(this), | 
 |       creator_(creator), | 
 |       default_factory_(default_factory) { | 
 | } | 
 |  | 
 | scoped_ptr<FakeURLFetcher> FakeURLFetcherFactory::DefaultFakeURLFetcherCreator( | 
 |       const GURL& url, | 
 |       URLFetcherDelegate* delegate, | 
 |       const std::string& response_data, | 
 |       HttpStatusCode response_code, | 
 |       URLRequestStatus::Status status) { | 
 |   return scoped_ptr<FakeURLFetcher>( | 
 |       new FakeURLFetcher(url, delegate, response_data, response_code, status)); | 
 | } | 
 |  | 
 | FakeURLFetcherFactory::~FakeURLFetcherFactory() {} | 
 |  | 
 | URLFetcher* FakeURLFetcherFactory::CreateURLFetcher( | 
 |     int id, | 
 |     const GURL& url, | 
 |     URLFetcher::RequestType request_type, | 
 |     URLFetcherDelegate* d) { | 
 |   FakeResponseMap::const_iterator it = fake_responses_.find(url); | 
 |   if (it == fake_responses_.end()) { | 
 |     if (default_factory_ == NULL) { | 
 |       // If we don't have a baked response for that URL we return NULL. | 
 |       DLOG(ERROR) << "No baked response for URL: " << url.spec(); | 
 |       return NULL; | 
 |     } else { | 
 |       return default_factory_->CreateURLFetcher(id, url, request_type, d); | 
 |     } | 
 |   } | 
 |  | 
 |   scoped_ptr<FakeURLFetcher> fake_fetcher = | 
 |       creator_.Run(url, d, it->second.response_data, | 
 |                    it->second.response_code, it->second.status); | 
 |   // TODO: Make URLFetcherFactory::CreateURLFetcher return a scoped_ptr | 
 |   return fake_fetcher.release(); | 
 | } | 
 |  | 
 | void FakeURLFetcherFactory::SetFakeResponse( | 
 |     const GURL& url, | 
 |     const std::string& response_data, | 
 |     HttpStatusCode response_code, | 
 |     URLRequestStatus::Status status) { | 
 |   // Overwrite existing URL if it already exists. | 
 |   FakeURLResponse response; | 
 |   response.response_data = response_data; | 
 |   response.response_code = response_code; | 
 |   response.status = status; | 
 |   fake_responses_[url] = response; | 
 | } | 
 |  | 
 | void FakeURLFetcherFactory::ClearFakeResponses() { | 
 |   fake_responses_.clear(); | 
 | } | 
 |  | 
 | URLFetcherImplFactory::URLFetcherImplFactory() {} | 
 |  | 
 | URLFetcherImplFactory::~URLFetcherImplFactory() {} | 
 |  | 
 | URLFetcher* URLFetcherImplFactory::CreateURLFetcher( | 
 |     int id, | 
 |     const GURL& url, | 
 |     URLFetcher::RequestType request_type, | 
 |     URLFetcherDelegate* d) { | 
 |   return new URLFetcherImpl(url, request_type, d); | 
 | } | 
 |  | 
 | }  // namespace net |