blob: a1db712311ea715a100f5bd5de6eb71a13df1217 [file] [log] [blame]
// Copyright 2014 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 "chromecast/shell/browser/url_request_context_factory.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/threading/worker_pool.h"
#include "chromecast/shell/browser/cast_http_user_agent_settings.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "net/cert/cert_verifier.h"
#include "net/cookies/cookie_store.h"
#include "net/dns/host_resolver.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_stream_factory.h"
#include "net/ocsp/nss_ocsp.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/next_proto.h"
#include "net/ssl/default_server_bound_cert_store.h"
#include "net/ssl/server_bound_cert_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_intercepting_job_factory.h"
#include "net/url_request/url_request_job_factory_impl.h"
namespace chromecast {
namespace shell {
namespace {
const char kCookieStoreFile[] = "Cookies";
} // namespace
// Private classes to expose URLRequestContextGetter that call back to the
// URLRequestContextFactory to create the URLRequestContext on demand.
//
// The URLRequestContextFactory::URLRequestContextGetter class is used for both
// the system and media URLRequestCotnexts.
class URLRequestContextFactory::URLRequestContextGetter
: public net::URLRequestContextGetter {
public:
URLRequestContextGetter(URLRequestContextFactory* factory, bool is_media)
: is_media_(is_media),
factory_(factory) {
}
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
if (!request_context_) {
if (is_media_) {
request_context_.reset(factory_->CreateMediaRequestContext());
} else {
request_context_.reset(factory_->CreateSystemRequestContext());
// Set request context used by NSS for Crl requests.
net::SetURLRequestContextForNSSHttpIO(request_context_.get());
}
}
return request_context_.get();
}
virtual scoped_refptr<base::SingleThreadTaskRunner>
GetNetworkTaskRunner() const OVERRIDE {
return content::BrowserThread::GetMessageLoopProxyForThread(
content::BrowserThread::IO);
}
private:
virtual ~URLRequestContextGetter() {}
const bool is_media_;
URLRequestContextFactory* const factory_;
scoped_ptr<net::URLRequestContext> request_context_;
DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);
};
// The URLRequestContextFactory::MainURLRequestContextGetter class is used for
// the main URLRequestContext.
class URLRequestContextFactory::MainURLRequestContextGetter
: public net::URLRequestContextGetter {
public:
MainURLRequestContextGetter(
URLRequestContextFactory* factory,
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector request_interceptors)
: browser_context_(browser_context),
factory_(factory),
request_interceptors_(request_interceptors.Pass()) {
std::swap(protocol_handlers_, *protocol_handlers);
}
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
if (!request_context_) {
request_context_.reset(factory_->CreateMainRequestContext(
browser_context_, &protocol_handlers_, request_interceptors_.Pass()));
protocol_handlers_.clear();
}
return request_context_.get();
}
virtual scoped_refptr<base::SingleThreadTaskRunner>
GetNetworkTaskRunner() const OVERRIDE {
return content::BrowserThread::GetMessageLoopProxyForThread(
content::BrowserThread::IO);
}
private:
virtual ~MainURLRequestContextGetter() {}
content::BrowserContext* const browser_context_;
URLRequestContextFactory* const factory_;
content::ProtocolHandlerMap protocol_handlers_;
content::URLRequestInterceptorScopedVector request_interceptors_;
scoped_ptr<net::URLRequestContext> request_context_;
DISALLOW_COPY_AND_ASSIGN(MainURLRequestContextGetter);
};
URLRequestContextFactory::URLRequestContextFactory()
: system_dependencies_initialized_(false),
main_dependencies_initialized_(false),
media_dependencies_initialized_(false) {
}
URLRequestContextFactory::~URLRequestContextFactory() {
}
void URLRequestContextFactory::InitializeOnUIThread() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Cast http user agent settings must be initialized in UI thread
// because it registers itself to pref notification observer which is not
// thread safe.
http_user_agent_settings_.reset(new CastHttpUserAgentSettings());
}
net::URLRequestContextGetter* URLRequestContextFactory::CreateMainGetter(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector request_interceptors) {
DCHECK(!main_getter_) << "Main URLRequestContextGetter already initialized";
main_getter_ = new MainURLRequestContextGetter(this,
browser_context,
protocol_handlers,
request_interceptors.Pass());
return main_getter_.get();
}
net::URLRequestContextGetter* URLRequestContextFactory::GetMainGetter() {
CHECK(main_getter_);
return main_getter_.get();
}
net::URLRequestContextGetter* URLRequestContextFactory::GetSystemGetter() {
if (!system_getter_) {
system_getter_ = new URLRequestContextGetter(this, false);
}
return system_getter_.get();
}
net::URLRequestContextGetter* URLRequestContextFactory::GetMediaGetter() {
if (!media_getter_) {
media_getter_ = new URLRequestContextGetter(this, true);
}
return media_getter_.get();
}
void URLRequestContextFactory::InitializeSystemContextDependencies() {
if (system_dependencies_initialized_)
return;
host_resolver_ = net::HostResolver::CreateDefaultResolver(NULL);
// TODO(lcwu): http://crbug.com/392352. For performance and security reasons,
// a persistent (on-disk) HttpServerProperties and ServerBoundCertService
// might be desirable in the future.
server_bound_cert_service_.reset(new net::ServerBoundCertService(
new net::DefaultServerBoundCertStore(NULL),
base::WorkerPool::GetTaskRunner(true)));
cert_verifier_.reset(net::CertVerifier::CreateDefault());
ssl_config_service_ = new net::SSLConfigServiceDefaults;
transport_security_state_.reset(new net::TransportSecurityState());
http_auth_handler_factory_.reset(
net::HttpAuthHandlerFactory::CreateDefault(host_resolver_.get()));
http_server_properties_.reset(new net::HttpServerPropertiesImpl);
proxy_service_.reset(net::ProxyService::CreateUsingSystemProxyResolver(
net::ProxyService::CreateSystemProxyConfigService(
content::BrowserThread::GetMessageLoopProxyForThread(
content::BrowserThread::IO).get(),
content::BrowserThread::UnsafeGetMessageLoopForThread(
content::BrowserThread::FILE)),
0,
NULL));
system_dependencies_initialized_ = true;
}
void URLRequestContextFactory::InitializeMainContextDependencies(
net::HttpTransactionFactory* transaction_factory,
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector request_interceptors) {
if (main_dependencies_initialized_)
return;
main_transaction_factory_.reset(transaction_factory);
scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
new net::URLRequestJobFactoryImpl());
// Keep ProtocolHandlers added in sync with
// CastContentBrowserClient::IsHandledURL().
bool set_protocol = false;
for (content::ProtocolHandlerMap::iterator it = protocol_handlers->begin();
it != protocol_handlers->end();
++it) {
set_protocol = job_factory->SetProtocolHandler(
it->first, it->second.release());
DCHECK(set_protocol);
}
set_protocol = job_factory->SetProtocolHandler(
url::kDataScheme,
new net::DataProtocolHandler);
DCHECK(set_protocol);
// Set up interceptors in the reverse order.
scoped_ptr<net::URLRequestJobFactory> top_job_factory =
job_factory.PassAs<net::URLRequestJobFactory>();
for (content::URLRequestInterceptorScopedVector::reverse_iterator i =
request_interceptors.rbegin();
i != request_interceptors.rend();
++i) {
top_job_factory.reset(new net::URLRequestInterceptingJobFactory(
top_job_factory.Pass(), make_scoped_ptr(*i)));
}
request_interceptors.weak_clear();
main_job_factory_.reset(top_job_factory.release());
main_dependencies_initialized_ = true;
}
void URLRequestContextFactory::InitializeMediaContextDependencies(
net::HttpTransactionFactory* transaction_factory) {
if (media_dependencies_initialized_)
return;
media_transaction_factory_.reset(transaction_factory);
media_dependencies_initialized_ = true;
}
void URLRequestContextFactory::PopulateNetworkSessionParams(
bool ignore_certificate_errors,
net::HttpNetworkSession::Params* params) {
params->host_resolver = host_resolver_.get();
params->cert_verifier = cert_verifier_.get();
params->server_bound_cert_service = server_bound_cert_service_.get();
params->ssl_config_service = ssl_config_service_.get();
params->transport_security_state = transport_security_state_.get();
params->http_auth_handler_factory = http_auth_handler_factory_.get();
params->http_server_properties = http_server_properties_->GetWeakPtr();
params->ignore_certificate_errors = ignore_certificate_errors;
params->proxy_service = proxy_service_.get();
// TODO(lcwu): http://crbug.com/329681. Remove this once spdy is enabled
// by default at the content level.
params->next_protos = net::NextProtosSpdy31();
params->use_alternate_protocols = true;
}
net::URLRequestContext* URLRequestContextFactory::CreateSystemRequestContext() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
InitializeSystemContextDependencies();
net::HttpNetworkSession::Params system_params;
PopulateNetworkSessionParams(false, &system_params);
system_transaction_factory_.reset(new net::HttpNetworkLayer(
new net::HttpNetworkSession(system_params)));
net::URLRequestContext* system_context = new net::URLRequestContext();
system_context->set_host_resolver(host_resolver_.get());
system_context->set_server_bound_cert_service(
server_bound_cert_service_.get());
system_context->set_cert_verifier(cert_verifier_.get());
system_context->set_proxy_service(proxy_service_.get());
system_context->set_ssl_config_service(ssl_config_service_.get());
system_context->set_transport_security_state(
transport_security_state_.get());
system_context->set_http_auth_handler_factory(
http_auth_handler_factory_.get());
system_context->set_http_server_properties(
http_server_properties_->GetWeakPtr());
system_context->set_http_transaction_factory(
system_transaction_factory_.get());
system_context->set_http_user_agent_settings(
http_user_agent_settings_.get());
system_context->set_cookie_store(
content::CreateCookieStore(content::CookieStoreConfig()));
return system_context;
}
net::URLRequestContext* URLRequestContextFactory::CreateMediaRequestContext() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
DCHECK(main_getter_)
<< "Getting MediaRequestContext before MainRequestContext";
net::URLRequestContext* main_context = main_getter_->GetURLRequestContext();
// Set non caching backend.
net::HttpNetworkSession* main_session =
main_transaction_factory_->GetSession();
InitializeMediaContextDependencies(
new net::HttpNetworkLayer(main_session));
net::URLRequestContext* media_context = new net::URLRequestContext();
media_context->CopyFrom(main_context);
media_context->set_http_transaction_factory(
media_transaction_factory_.get());
return media_context;
}
net::URLRequestContext* URLRequestContextFactory::CreateMainRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector request_interceptors) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
InitializeSystemContextDependencies();
net::HttpCache::BackendFactory* main_backend =
net::HttpCache::DefaultBackend::InMemory(16 * 1024 * 1024);
bool ignore_certificate_errors = false;
CommandLine* cmd_line = CommandLine::ForCurrentProcess();
if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors)) {
ignore_certificate_errors = true;
}
net::HttpNetworkSession::Params network_session_params;
PopulateNetworkSessionParams(ignore_certificate_errors,
&network_session_params);
InitializeMainContextDependencies(
new net::HttpCache(network_session_params, main_backend),
protocol_handlers,
request_interceptors.Pass());
content::CookieStoreConfig cookie_config(
browser_context->GetPath().Append(kCookieStoreFile),
content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES,
NULL, NULL);
cookie_config.background_task_runner =
scoped_refptr<base::SequencedTaskRunner>();
scoped_refptr<net::CookieStore> cookie_store =
content::CreateCookieStore(cookie_config);
net::URLRequestContext* main_context = new net::URLRequestContext();
main_context->set_host_resolver(host_resolver_.get());
main_context->set_server_bound_cert_service(
server_bound_cert_service_.get());
main_context->set_cert_verifier(cert_verifier_.get());
main_context->set_proxy_service(proxy_service_.get());
main_context->set_ssl_config_service(ssl_config_service_.get());
main_context->set_transport_security_state(transport_security_state_.get());
main_context->set_http_auth_handler_factory(
http_auth_handler_factory_.get());
main_context->set_http_server_properties(
http_server_properties_->GetWeakPtr());
main_context->set_cookie_store(cookie_store.get());
main_context->set_http_user_agent_settings(
http_user_agent_settings_.get());
main_context->set_http_transaction_factory(
main_transaction_factory_.get());
main_context->set_job_factory(main_job_factory_.get());
return main_context;
}
} // namespace shell
} // namespace chromecast