blob: b13d2682bcbf0b46914bdf87547474f03ed7afbb [file] [log] [blame]
// Copyright (c) 2010 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.
#ifndef NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
#define NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_
#pragma once
#include <stdlib.h>
#include <sstream>
#include <string>
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "base/string16.h"
#include "base/threading/thread.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "net/base/cert_verifier.h"
#include "net/base/cookie_monster.h"
#include "net/base/cookie_policy.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/disk_cache/disk_cache.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_layer.h"
#include "net/test/test_server.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/proxy/proxy_service.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "googleurl/src/url_util.h"
using base::TimeDelta;
//-----------------------------------------------------------------------------
class TestCookiePolicy : public net::CookiePolicy {
public:
enum Options {
NO_GET_COOKIES = 1 << 0,
NO_SET_COOKIE = 1 << 1,
ASYNC = 1 << 2,
FORCE_SESSION = 1 << 3,
};
explicit TestCookiePolicy(int options_bit_mask)
: ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
options_(options_bit_mask),
callback_(NULL) {
}
virtual int CanGetCookies(const GURL& url, const GURL& first_party,
net::CompletionCallback* callback) {
if ((options_ & ASYNC) && callback) {
callback_ = callback;
MessageLoop::current()->PostTask(FROM_HERE,
method_factory_.NewRunnableMethod(
&TestCookiePolicy::DoGetCookiesPolicy, url, first_party));
return net::ERR_IO_PENDING;
}
if (options_ & NO_GET_COOKIES)
return net::ERR_ACCESS_DENIED;
return net::OK;
}
virtual int CanSetCookie(const GURL& url, const GURL& first_party,
const std::string& cookie_line,
net::CompletionCallback* callback) {
if ((options_ & ASYNC) && callback) {
callback_ = callback;
MessageLoop::current()->PostTask(FROM_HERE,
method_factory_.NewRunnableMethod(
&TestCookiePolicy::DoSetCookiePolicy, url, first_party,
cookie_line));
return net::ERR_IO_PENDING;
}
if (options_ & NO_SET_COOKIE)
return net::ERR_ACCESS_DENIED;
if (options_ & FORCE_SESSION)
return net::OK_FOR_SESSION_ONLY;
return net::OK;
}
private:
void DoGetCookiesPolicy(const GURL& url, const GURL& first_party) {
int policy = CanGetCookies(url, first_party, NULL);
DCHECK(callback_);
net::CompletionCallback* callback = callback_;
callback_ = NULL;
callback->Run(policy);
}
void DoSetCookiePolicy(const GURL& url, const GURL& first_party,
const std::string& cookie_line) {
int policy = CanSetCookie(url, first_party, cookie_line, NULL);
DCHECK(callback_);
net::CompletionCallback* callback = callback_;
callback_ = NULL;
callback->Run(policy);
}
ScopedRunnableMethodFactory<TestCookiePolicy> method_factory_;
int options_;
net::CompletionCallback* callback_;
};
//-----------------------------------------------------------------------------
class TestURLRequestContext : public URLRequestContext {
public:
TestURLRequestContext() {
host_resolver_ =
net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
NULL, NULL);
proxy_service_ = net::ProxyService::CreateDirect();
Init();
}
explicit TestURLRequestContext(const std::string& proxy) {
host_resolver_ =
net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
NULL, NULL);
net::ProxyConfig proxy_config;
proxy_config.proxy_rules().ParseFromString(proxy);
proxy_service_ = net::ProxyService::CreateFixed(proxy_config);
Init();
}
void set_cookie_policy(net::CookiePolicy* policy) {
cookie_policy_ = policy;
}
protected:
virtual ~TestURLRequestContext() {
delete ftp_transaction_factory_;
delete http_transaction_factory_;
delete http_auth_handler_factory_;
delete cert_verifier_;
delete host_resolver_;
}
private:
void Init() {
cert_verifier_ = new net::CertVerifier;
ftp_transaction_factory_ = new net::FtpNetworkLayer(host_resolver_);
ssl_config_service_ = new net::SSLConfigServiceDefaults;
http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault(
host_resolver_);
http_transaction_factory_ = new net::HttpCache(
net::HttpNetworkLayer::CreateFactory(host_resolver_,
cert_verifier_,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
proxy_service_,
ssl_config_service_,
http_auth_handler_factory_,
network_delegate_,
NULL),
net::HttpCache::DefaultBackend::InMemory(0));
// In-memory cookie store.
cookie_store_ = new net::CookieMonster(NULL, NULL);
accept_language_ = "en-us,fr";
accept_charset_ = "iso-8859-1,*,utf-8";
}
};
//-----------------------------------------------------------------------------
class TestURLRequest : public net::URLRequest {
public:
TestURLRequest(const GURL& url, Delegate* delegate)
: net::URLRequest(url, delegate) {
set_context(new TestURLRequestContext());
}
};
//-----------------------------------------------------------------------------
class TestDelegate : public net::URLRequest::Delegate {
public:
TestDelegate()
: cancel_in_rr_(false),
cancel_in_rs_(false),
cancel_in_rd_(false),
cancel_in_rd_pending_(false),
cancel_in_getcookiesblocked_(false),
cancel_in_setcookieblocked_(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),
blocked_get_cookies_count_(0),
blocked_set_cookie_count_(0),
set_cookie_count_(0),
received_data_before_response_(false),
request_failed_(false),
have_certificate_errors_(false),
buf_(new net::IOBuffer(kBufferSize)) {
}
virtual void OnReceivedRedirect(net::URLRequest* request, const GURL& new_url,
bool* defer_redirect) {
received_redirect_count_++;
if (quit_on_redirect_) {
*defer_redirect = true;
MessageLoop::current()->Quit();
} else if (cancel_in_rr_) {
request->Cancel();
}
}
virtual void OnResponseStarted(net::URLRequest* request) {
// It doesn't make sense for the request to have IO pending at this point.
DCHECK(!request->status().is_io_pending());
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_, kBufferSize, &bytes_read))
OnReadCompleted(request, bytes_read);
else if (!request->status().is_io_pending())
OnResponseCompleted(request);
}
}
virtual void OnReadCompleted(net::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_, 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();
}
virtual void OnResponseCompleted(net::URLRequest* request) {
if (quit_on_complete_)
MessageLoop::current()->Quit();
}
void OnAuthRequired(net::URLRequest* request,
net::AuthChallengeInfo* auth_info) {
if (!username_.empty() || !password_.empty()) {
request->SetAuth(username_, password_);
} else {
request->CancelAuth();
}
}
virtual void OnSSLCertificateError(net::URLRequest* request,
int cert_error,
net::X509Certificate* cert) {
// 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;
if (allow_certificate_errors_)
request->ContinueDespiteLastError();
else
request->Cancel();
}
virtual void OnGetCookies(net::URLRequest* request, bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_get_cookies_count_++;
if (cancel_in_getcookiesblocked_)
request->Cancel();
}
}
virtual void OnSetCookie(net::URLRequest* request,
const std::string& cookie_line,
const net::CookieOptions& options,
bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_set_cookie_count_++;
if (cancel_in_setcookieblocked_)
request->Cancel();
} else {
set_cookie_count_++;
}
}
void set_cancel_in_received_redirect(bool val) { cancel_in_rr_ = val; }
void set_cancel_in_response_started(bool val) { cancel_in_rs_ = val; }
void set_cancel_in_received_data(bool val) { cancel_in_rd_ = val; }
void set_cancel_in_received_data_pending(bool val) {
cancel_in_rd_pending_ = val;
}
void set_cancel_in_get_cookies_blocked(bool val) {
cancel_in_getcookiesblocked_ = val;
}
void set_cancel_in_set_cookie_blocked(bool val) {
cancel_in_setcookieblocked_ = val;
}
void set_quit_on_complete(bool val) { quit_on_complete_ = val; }
void set_quit_on_redirect(bool val) { quit_on_redirect_ = val; }
void set_allow_certificate_errors(bool val) {
allow_certificate_errors_ = val;
}
void set_username(const string16& u) { username_ = u; }
void set_password(const string16& p) { password_ = p; }
// query state
const std::string& data_received() const { return data_received_; }
int bytes_received() const { return static_cast<int>(data_received_.size()); }
int response_started_count() const { return response_started_count_; }
int received_redirect_count() const { return received_redirect_count_; }
int blocked_get_cookies_count() const { return blocked_get_cookies_count_; }
int blocked_set_cookie_count() const { return blocked_set_cookie_count_; }
int set_cookie_count() const { return set_cookie_count_; }
bool received_data_before_response() const {
return received_data_before_response_;
}
bool request_failed() const { return request_failed_; }
bool have_certificate_errors() const { return have_certificate_errors_; }
private:
static const int kBufferSize = 4096;
// options for controlling behavior
bool cancel_in_rr_;
bool cancel_in_rs_;
bool cancel_in_rd_;
bool cancel_in_rd_pending_;
bool cancel_in_getcookiesblocked_;
bool cancel_in_setcookieblocked_;
bool quit_on_complete_;
bool quit_on_redirect_;
bool allow_certificate_errors_;
string16 username_;
string16 password_;
// tracks status of callbacks
int response_started_count_;
int received_bytes_count_;
int received_redirect_count_;
int blocked_get_cookies_count_;
int blocked_set_cookie_count_;
int set_cookie_count_;
bool received_data_before_response_;
bool request_failed_;
bool have_certificate_errors_;
std::string data_received_;
// our read buffer
scoped_refptr<net::IOBuffer> buf_;
};
#endif // NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_