diff options
Diffstat (limited to 'chromium/net/url_request/url_request_test_util.cc')
-rw-r--r-- | chromium/net/url_request/url_request_test_util.cc | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/chromium/net/url_request/url_request_test_util.cc b/chromium/net/url_request/url_request_test_util.cc new file mode 100644 index 00000000000..8b209f9c6dc --- /dev/null +++ b/chromium/net/url_request/url_request_test_util.cc @@ -0,0 +1,607 @@ +// 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_request_test_util.h" + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/threading/thread.h" +#include "base/threading/worker_pool.h" +#include "net/base/host_port_pair.h" +#include "net/cert/cert_verifier.h" +#include "net/dns/mock_host_resolver.h" +#include "net/http/http_network_session.h" +#include "net/http/http_server_properties_impl.h" +#include "net/http/transport_security_state.h" +#include "net/ssl/default_server_bound_cert_store.h" +#include "net/ssl/server_bound_cert_service.h" +#include "net/url_request/static_http_user_agent_settings.h" +#include "net/url_request/url_request_job_factory_impl.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +// These constants put the NetworkDelegate events of TestNetworkDelegate +// into an order. They are used in conjunction with +// |TestNetworkDelegate::next_states_| to check that we do not send +// events in the wrong order. +const int kStageBeforeURLRequest = 1 << 0; +const int kStageBeforeSendHeaders = 1 << 1; +const int kStageSendHeaders = 1 << 2; +const int kStageHeadersReceived = 1 << 3; +const int kStageAuthRequired = 1 << 4; +const int kStageBeforeRedirect = 1 << 5; +const int kStageResponseStarted = 1 << 6; +const int kStageCompletedSuccess = 1 << 7; +const int kStageCompletedError = 1 << 8; +const int kStageURLRequestDestroyed = 1 << 9; +const int kStageDestruction = 1 << 10; + +} // namespace + +TestURLRequestContext::TestURLRequestContext() + : initialized_(false), + client_socket_factory_(NULL), + context_storage_(this) { + Init(); +} + +TestURLRequestContext::TestURLRequestContext(bool delay_initialization) + : initialized_(false), + client_socket_factory_(NULL), + context_storage_(this) { + if (!delay_initialization) + Init(); +} + +TestURLRequestContext::~TestURLRequestContext() { + DCHECK(initialized_); +} + +void TestURLRequestContext::Init() { + DCHECK(!initialized_); + initialized_ = true; + + if (!host_resolver()) + context_storage_.set_host_resolver( + scoped_ptr<HostResolver>(new MockCachingHostResolver())); + if (!proxy_service()) + context_storage_.set_proxy_service(ProxyService::CreateDirect()); + if (!cert_verifier()) + context_storage_.set_cert_verifier(CertVerifier::CreateDefault()); + if (!transport_security_state()) + context_storage_.set_transport_security_state(new TransportSecurityState); + if (!ssl_config_service()) + context_storage_.set_ssl_config_service(new SSLConfigServiceDefaults); + if (!http_auth_handler_factory()) { + context_storage_.set_http_auth_handler_factory( + HttpAuthHandlerFactory::CreateDefault(host_resolver())); + } + if (!http_server_properties()) { + context_storage_.set_http_server_properties( + scoped_ptr<HttpServerProperties>(new HttpServerPropertiesImpl())); + } + if (!transport_security_state()) { + context_storage_.set_transport_security_state( + new TransportSecurityState()); + } + if (http_transaction_factory()) { + // Make sure we haven't been passed an object we're not going to use. + EXPECT_FALSE(client_socket_factory_); + } else { + HttpNetworkSession::Params params; + params.client_socket_factory = client_socket_factory(); + params.host_resolver = host_resolver(); + params.cert_verifier = cert_verifier(); + params.transport_security_state = transport_security_state(); + params.proxy_service = proxy_service(); + params.ssl_config_service = ssl_config_service(); + params.http_auth_handler_factory = http_auth_handler_factory(); + params.network_delegate = network_delegate(); + params.http_server_properties = http_server_properties(); + params.net_log = net_log(); + context_storage_.set_http_transaction_factory(new HttpCache( + new HttpNetworkSession(params), + HttpCache::DefaultBackend::InMemory(0))); + } + // In-memory cookie store. + if (!cookie_store()) + context_storage_.set_cookie_store(new CookieMonster(NULL, NULL)); + // In-memory origin bound cert service. + if (!server_bound_cert_service()) { + context_storage_.set_server_bound_cert_service( + new ServerBoundCertService( + new DefaultServerBoundCertStore(NULL), + base::WorkerPool::GetTaskRunner(true))); + } + if (!http_user_agent_settings()) { + context_storage_.set_http_user_agent_settings( + new StaticHttpUserAgentSettings("en-us,fr", EmptyString())); + } + if (!job_factory()) + context_storage_.set_job_factory(new URLRequestJobFactoryImpl); +} + +TestURLRequest::TestURLRequest(const GURL& url, + Delegate* delegate, + TestURLRequestContext* context, + NetworkDelegate* network_delegate) + : URLRequest(url, delegate, context, network_delegate) { +} + +TestURLRequest::~TestURLRequest() { +} + +TestURLRequestContextGetter::TestURLRequestContextGetter( + const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner) + : network_task_runner_(network_task_runner) { + DCHECK(network_task_runner_.get()); +} + +TestURLRequestContextGetter::TestURLRequestContextGetter( + const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner, + scoped_ptr<TestURLRequestContext> context) + : network_task_runner_(network_task_runner), context_(context.Pass()) { + DCHECK(network_task_runner_.get()); +} + +TestURLRequestContextGetter::~TestURLRequestContextGetter() {} + +TestURLRequestContext* TestURLRequestContextGetter::GetURLRequestContext() { + if (!context_.get()) + context_.reset(new TestURLRequestContext); + return context_.get(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +TestURLRequestContextGetter::GetNetworkTaskRunner() const { + return network_task_runner_; +} + +TestDelegate::TestDelegate() + : cancel_in_rr_(false), + cancel_in_rs_(false), + cancel_in_rd_(false), + cancel_in_rd_pending_(false), + quit_on_complete_(true), + quit_on_redirect_(false), + allow_certificate_errors_(false), + response_started_count_(0), + received_bytes_count_(0), + received_redirect_count_(0), + received_data_before_response_(false), + request_failed_(false), + have_certificate_errors_(false), + certificate_errors_are_fatal_(false), + auth_required_(false), + have_full_request_headers_(false), + buf_(new IOBuffer(kBufferSize)) { +} + +TestDelegate::~TestDelegate() {} + +void TestDelegate::ClearFullRequestHeaders() { + full_request_headers_.Clear(); + have_full_request_headers_ = false; +} + +void TestDelegate::OnReceivedRedirect(URLRequest* request, + const GURL& new_url, + bool* defer_redirect) { + EXPECT_TRUE(request->is_redirecting()); + + have_full_request_headers_ = + request->GetFullRequestHeaders(&full_request_headers_); + + received_redirect_count_++; + if (quit_on_redirect_) { + *defer_redirect = true; + base::MessageLoop::current()->PostTask(FROM_HERE, + base::MessageLoop::QuitClosure()); + } else if (cancel_in_rr_) { + request->Cancel(); + } +} + +void TestDelegate::OnAuthRequired(URLRequest* request, + AuthChallengeInfo* auth_info) { + auth_required_ = true; + if (!credentials_.Empty()) { + request->SetAuth(credentials_); + } else { + request->CancelAuth(); + } +} + +void TestDelegate::OnSSLCertificateError(URLRequest* request, + const SSLInfo& ssl_info, + bool fatal) { + // The caller can control whether it needs all SSL requests to go through, + // independent of any possible errors, or whether it wants SSL errors to + // cancel the request. + have_certificate_errors_ = true; + certificate_errors_are_fatal_ = fatal; + if (allow_certificate_errors_) + request->ContinueDespiteLastError(); + else + request->Cancel(); +} + +void TestDelegate::OnResponseStarted(URLRequest* request) { + // It doesn't make sense for the request to have IO pending at this point. + DCHECK(!request->status().is_io_pending()); + EXPECT_FALSE(request->is_redirecting()); + + have_full_request_headers_ = + request->GetFullRequestHeaders(&full_request_headers_); + + response_started_count_++; + if (cancel_in_rs_) { + request->Cancel(); + OnResponseCompleted(request); + } else if (!request->status().is_success()) { + DCHECK(request->status().status() == URLRequestStatus::FAILED || + request->status().status() == URLRequestStatus::CANCELED); + request_failed_ = true; + OnResponseCompleted(request); + } else { + // Initiate the first read. + int bytes_read = 0; + if (request->Read(buf_.get(), kBufferSize, &bytes_read)) + OnReadCompleted(request, bytes_read); + else if (!request->status().is_io_pending()) + OnResponseCompleted(request); + } +} + +void TestDelegate::OnReadCompleted(URLRequest* request, int bytes_read) { + // It doesn't make sense for the request to have IO pending at this point. + DCHECK(!request->status().is_io_pending()); + + if (response_started_count_ == 0) + received_data_before_response_ = true; + + if (cancel_in_rd_) + request->Cancel(); + + if (bytes_read >= 0) { + // There is data to read. + received_bytes_count_ += bytes_read; + + // consume the data + data_received_.append(buf_->data(), bytes_read); + } + + // If it was not end of stream, request to read more. + if (request->status().is_success() && bytes_read > 0) { + bytes_read = 0; + while (request->Read(buf_.get(), kBufferSize, &bytes_read)) { + if (bytes_read > 0) { + data_received_.append(buf_->data(), bytes_read); + received_bytes_count_ += bytes_read; + } else { + break; + } + } + } + if (!request->status().is_io_pending()) + OnResponseCompleted(request); + else if (cancel_in_rd_pending_) + request->Cancel(); +} + +void TestDelegate::OnResponseCompleted(URLRequest* request) { + if (quit_on_complete_) + base::MessageLoop::current()->PostTask(FROM_HERE, + base::MessageLoop::QuitClosure()); +} + +TestNetworkDelegate::TestNetworkDelegate() + : last_error_(0), + error_count_(0), + created_requests_(0), + destroyed_requests_(0), + completed_requests_(0), + cookie_options_bit_mask_(0), + blocked_get_cookies_count_(0), + blocked_set_cookie_count_(0), + set_cookie_count_(0), + has_load_timing_info_before_redirect_(false), + has_load_timing_info_before_auth_(false) { +} + +TestNetworkDelegate::~TestNetworkDelegate() { + for (std::map<int, int>::iterator i = next_states_.begin(); + i != next_states_.end(); ++i) { + event_order_[i->first] += "~TestNetworkDelegate\n"; + EXPECT_TRUE(i->second & kStageDestruction) << event_order_[i->first]; + } +} + +bool TestNetworkDelegate::GetLoadTimingInfoBeforeRedirect( + LoadTimingInfo* load_timing_info_before_redirect) const { + *load_timing_info_before_redirect = load_timing_info_before_redirect_; + return has_load_timing_info_before_redirect_; +} + +bool TestNetworkDelegate::GetLoadTimingInfoBeforeAuth( + LoadTimingInfo* load_timing_info_before_auth) const { + *load_timing_info_before_auth = load_timing_info_before_auth_; + return has_load_timing_info_before_auth_; +} + +void TestNetworkDelegate::InitRequestStatesIfNew(int request_id) { + if (next_states_.find(request_id) == next_states_.end()) { + next_states_[request_id] = kStageBeforeURLRequest; + event_order_[request_id] = ""; + } +} + +int TestNetworkDelegate::OnBeforeURLRequest( + URLRequest* request, + const CompletionCallback& callback, + GURL* new_url ) { + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnBeforeURLRequest\n"; + EXPECT_TRUE(next_states_[req_id] & kStageBeforeURLRequest) << + event_order_[req_id]; + next_states_[req_id] = + kStageBeforeSendHeaders | + kStageResponseStarted | // data: URLs do not trigger sending headers + kStageBeforeRedirect | // a delegate can trigger a redirection + kStageCompletedError | // request canceled by delegate + kStageAuthRequired; // Auth can come next for FTP requests + created_requests_++; + return OK; +} + +int TestNetworkDelegate::OnBeforeSendHeaders( + URLRequest* request, + const CompletionCallback& callback, + HttpRequestHeaders* headers) { + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnBeforeSendHeaders\n"; + EXPECT_TRUE(next_states_[req_id] & kStageBeforeSendHeaders) << + event_order_[req_id]; + next_states_[req_id] = + kStageSendHeaders | + kStageCompletedError; // request canceled by delegate + + return OK; +} + +void TestNetworkDelegate::OnSendHeaders( + URLRequest* request, + const HttpRequestHeaders& headers) { + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnSendHeaders\n"; + EXPECT_TRUE(next_states_[req_id] & kStageSendHeaders) << + event_order_[req_id]; + next_states_[req_id] = + kStageHeadersReceived | + kStageCompletedError; +} + +int TestNetworkDelegate::OnHeadersReceived( + URLRequest* request, + const CompletionCallback& callback, + const HttpResponseHeaders* original_response_headers, + scoped_refptr<HttpResponseHeaders>* override_response_headers) { + int req_id = request->identifier(); + event_order_[req_id] += "OnHeadersReceived\n"; + InitRequestStatesIfNew(req_id); + EXPECT_TRUE(next_states_[req_id] & kStageHeadersReceived) << + event_order_[req_id]; + next_states_[req_id] = + kStageBeforeRedirect | + kStageResponseStarted | + kStageAuthRequired | + kStageCompletedError; // e.g. proxy resolution problem + + // Basic authentication sends a second request from the URLRequestHttpJob + // layer before the URLRequest reports that a response has started. + next_states_[req_id] |= kStageBeforeSendHeaders; + + return OK; +} + +void TestNetworkDelegate::OnBeforeRedirect(URLRequest* request, + const GURL& new_location) { + load_timing_info_before_redirect_ = LoadTimingInfo(); + request->GetLoadTimingInfo(&load_timing_info_before_redirect_); + has_load_timing_info_before_redirect_ = true; + EXPECT_FALSE(load_timing_info_before_redirect_.request_start_time.is_null()); + EXPECT_FALSE(load_timing_info_before_redirect_.request_start.is_null()); + + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnBeforeRedirect\n"; + EXPECT_TRUE(next_states_[req_id] & kStageBeforeRedirect) << + event_order_[req_id]; + next_states_[req_id] = + kStageBeforeURLRequest | // HTTP redirects trigger this. + kStageBeforeSendHeaders | // Redirects from the network delegate do not + // trigger onBeforeURLRequest. + kStageCompletedError; + + // A redirect can lead to a file or a data URL. In this case, we do not send + // headers. + next_states_[req_id] |= kStageResponseStarted; +} + +void TestNetworkDelegate::OnResponseStarted(URLRequest* request) { + LoadTimingInfo load_timing_info; + request->GetLoadTimingInfo(&load_timing_info); + EXPECT_FALSE(load_timing_info.request_start_time.is_null()); + EXPECT_FALSE(load_timing_info.request_start.is_null()); + + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnResponseStarted\n"; + EXPECT_TRUE(next_states_[req_id] & kStageResponseStarted) << + event_order_[req_id]; + next_states_[req_id] = kStageCompletedSuccess | kStageCompletedError; + if (request->status().status() == URLRequestStatus::FAILED) { + error_count_++; + last_error_ = request->status().error(); + } +} + +void TestNetworkDelegate::OnRawBytesRead(const URLRequest& request, + int bytes_read) { +} + +void TestNetworkDelegate::OnCompleted(URLRequest* request, bool started) { + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnCompleted\n"; + // Expect "Success -> (next_states_ & kStageCompletedSuccess)" + // is logically identical to + // Expect "!(Success) || (next_states_ & kStageCompletedSuccess)" + EXPECT_TRUE(!request->status().is_success() || + (next_states_[req_id] & kStageCompletedSuccess)) << + event_order_[req_id]; + EXPECT_TRUE(request->status().is_success() || + (next_states_[req_id] & kStageCompletedError)) << + event_order_[req_id]; + next_states_[req_id] = kStageURLRequestDestroyed; + completed_requests_++; + if (request->status().status() == URLRequestStatus::FAILED) { + error_count_++; + last_error_ = request->status().error(); + } +} + +void TestNetworkDelegate::OnURLRequestDestroyed(URLRequest* request) { + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnURLRequestDestroyed\n"; + EXPECT_TRUE(next_states_[req_id] & kStageURLRequestDestroyed) << + event_order_[req_id]; + next_states_[req_id] = kStageDestruction; + destroyed_requests_++; +} + +void TestNetworkDelegate::OnPACScriptError(int line_number, + const base::string16& error) { +} + +NetworkDelegate::AuthRequiredResponse TestNetworkDelegate::OnAuthRequired( + URLRequest* request, + const AuthChallengeInfo& auth_info, + const AuthCallback& callback, + AuthCredentials* credentials) { + load_timing_info_before_auth_ = LoadTimingInfo(); + request->GetLoadTimingInfo(&load_timing_info_before_auth_); + has_load_timing_info_before_auth_ = true; + EXPECT_FALSE(load_timing_info_before_auth_.request_start_time.is_null()); + EXPECT_FALSE(load_timing_info_before_auth_.request_start.is_null()); + + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnAuthRequired\n"; + EXPECT_TRUE(next_states_[req_id] & kStageAuthRequired) << + event_order_[req_id]; + next_states_[req_id] = kStageBeforeSendHeaders | + kStageAuthRequired | // For example, proxy auth followed by server auth. + kStageHeadersReceived | // Request canceled by delegate simulates empty + // response. + kStageResponseStarted | // data: URLs do not trigger sending headers + kStageBeforeRedirect | // a delegate can trigger a redirection + kStageCompletedError; // request cancelled before callback + return NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION; +} + +bool TestNetworkDelegate::OnCanGetCookies(const URLRequest& request, + const CookieList& cookie_list) { + bool allow = true; + if (cookie_options_bit_mask_ & NO_GET_COOKIES) + allow = false; + + if (!allow) { + blocked_get_cookies_count_++; + } + + return allow; +} + +bool TestNetworkDelegate::OnCanSetCookie(const URLRequest& request, + const std::string& cookie_line, + CookieOptions* options) { + bool allow = true; + if (cookie_options_bit_mask_ & NO_SET_COOKIE) + allow = false; + + if (!allow) { + blocked_set_cookie_count_++; + } else { + set_cookie_count_++; + } + + return allow; +} + +bool TestNetworkDelegate::OnCanAccessFile(const URLRequest& request, + const base::FilePath& path) const { + return true; +} + +bool TestNetworkDelegate::OnCanThrottleRequest( + const URLRequest& request) const { + return true; +} + +int TestNetworkDelegate::OnBeforeSocketStreamConnect( + SocketStream* socket, + const CompletionCallback& callback) { + return OK; +} + +void TestNetworkDelegate::OnRequestWaitStateChange( + const URLRequest& request, + RequestWaitState state) { +} + +// static +std::string ScopedCustomUrlRequestTestHttpHost::value_("127.0.0.1"); + +ScopedCustomUrlRequestTestHttpHost::ScopedCustomUrlRequestTestHttpHost( + const std::string& new_value) + : old_value_(value_), + new_value_(new_value) { + value_ = new_value_; +} + +ScopedCustomUrlRequestTestHttpHost::~ScopedCustomUrlRequestTestHttpHost() { + DCHECK_EQ(value_, new_value_); + value_ = old_value_; +} + +// static +const std::string& ScopedCustomUrlRequestTestHttpHost::value() { + return value_; +} + +TestJobInterceptor::TestJobInterceptor() : main_intercept_job_(NULL) { +} + +URLRequestJob* TestJobInterceptor::MaybeCreateJob( + URLRequest* request, + NetworkDelegate* network_delegate) const { + URLRequestJob* job = main_intercept_job_; + main_intercept_job_ = NULL; + return job; +} + +void TestJobInterceptor::set_main_intercept_job(URLRequestJob* job) { + main_intercept_job_ = job; +} + +} // namespace net |