blob: c595a4ec0f43dfada2f446619ab59136e56d69ca [file] [log] [blame]
// 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_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