1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chromecast/shell/browser/url_request_context_factory.h" 6 7 #include "base/command_line.h" 8 #include "base/files/file_path.h" 9 #include "base/macros.h" 10 #include "base/path_service.h" 11 #include "base/threading/worker_pool.h" 12 #include "chromecast/shell/browser/cast_http_user_agent_settings.h" 13 #include "content/public/browser/browser_context.h" 14 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/cookie_store_factory.h" 16 #include "content/public/common/content_switches.h" 17 #include "content/public/common/url_constants.h" 18 #include "net/cert/cert_verifier.h" 19 #include "net/cookies/cookie_store.h" 20 #include "net/dns/host_resolver.h" 21 #include "net/http/http_auth_handler_factory.h" 22 #include "net/http/http_cache.h" 23 #include "net/http/http_network_layer.h" 24 #include "net/http/http_server_properties_impl.h" 25 #include "net/http/http_stream_factory.h" 26 #include "net/ocsp/nss_ocsp.h" 27 #include "net/proxy/proxy_service.h" 28 #include "net/socket/next_proto.h" 29 #include "net/ssl/channel_id_service.h" 30 #include "net/ssl/default_channel_id_store.h" 31 #include "net/ssl/ssl_config_service_defaults.h" 32 #include "net/url_request/data_protocol_handler.h" 33 #include "net/url_request/file_protocol_handler.h" 34 #include "net/url_request/url_request_context.h" 35 #include "net/url_request/url_request_context_getter.h" 36 #include "net/url_request/url_request_intercepting_job_factory.h" 37 #include "net/url_request/url_request_job_factory_impl.h" 38 39 namespace chromecast { 40 namespace shell { 41 42 namespace { 43 44 const char kCookieStoreFile[] = "Cookies"; 45 46 } // namespace 47 48 // Private classes to expose URLRequestContextGetter that call back to the 49 // URLRequestContextFactory to create the URLRequestContext on demand. 50 // 51 // The URLRequestContextFactory::URLRequestContextGetter class is used for both 52 // the system and media URLRequestCotnexts. 53 class URLRequestContextFactory::URLRequestContextGetter 54 : public net::URLRequestContextGetter { 55 public: 56 URLRequestContextGetter(URLRequestContextFactory* factory, bool is_media) 57 : is_media_(is_media), 58 factory_(factory) { 59 } 60 61 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { 62 if (!request_context_) { 63 if (is_media_) { 64 request_context_.reset(factory_->CreateMediaRequestContext()); 65 } else { 66 request_context_.reset(factory_->CreateSystemRequestContext()); 67 #if defined(USE_NSS) 68 // Set request context used by NSS for Crl requests. 69 net::SetURLRequestContextForNSSHttpIO(request_context_.get()); 70 #endif // defined(USE_NSS) 71 } 72 } 73 return request_context_.get(); 74 } 75 76 virtual scoped_refptr<base::SingleThreadTaskRunner> 77 GetNetworkTaskRunner() const OVERRIDE { 78 return content::BrowserThread::GetMessageLoopProxyForThread( 79 content::BrowserThread::IO); 80 } 81 82 private: 83 virtual ~URLRequestContextGetter() {} 84 85 const bool is_media_; 86 URLRequestContextFactory* const factory_; 87 scoped_ptr<net::URLRequestContext> request_context_; 88 89 DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter); 90 }; 91 92 // The URLRequestContextFactory::MainURLRequestContextGetter class is used for 93 // the main URLRequestContext. 94 class URLRequestContextFactory::MainURLRequestContextGetter 95 : public net::URLRequestContextGetter { 96 public: 97 MainURLRequestContextGetter( 98 URLRequestContextFactory* factory, 99 content::BrowserContext* browser_context, 100 content::ProtocolHandlerMap* protocol_handlers, 101 content::URLRequestInterceptorScopedVector request_interceptors) 102 : browser_context_(browser_context), 103 factory_(factory), 104 request_interceptors_(request_interceptors.Pass()) { 105 std::swap(protocol_handlers_, *protocol_handlers); 106 } 107 108 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { 109 if (!request_context_) { 110 request_context_.reset(factory_->CreateMainRequestContext( 111 browser_context_, &protocol_handlers_, request_interceptors_.Pass())); 112 protocol_handlers_.clear(); 113 } 114 return request_context_.get(); 115 } 116 117 virtual scoped_refptr<base::SingleThreadTaskRunner> 118 GetNetworkTaskRunner() const OVERRIDE { 119 return content::BrowserThread::GetMessageLoopProxyForThread( 120 content::BrowserThread::IO); 121 } 122 123 private: 124 virtual ~MainURLRequestContextGetter() {} 125 126 content::BrowserContext* const browser_context_; 127 URLRequestContextFactory* const factory_; 128 content::ProtocolHandlerMap protocol_handlers_; 129 content::URLRequestInterceptorScopedVector request_interceptors_; 130 scoped_ptr<net::URLRequestContext> request_context_; 131 132 DISALLOW_COPY_AND_ASSIGN(MainURLRequestContextGetter); 133 }; 134 135 URLRequestContextFactory::URLRequestContextFactory() 136 : system_dependencies_initialized_(false), 137 main_dependencies_initialized_(false), 138 media_dependencies_initialized_(false) { 139 } 140 141 URLRequestContextFactory::~URLRequestContextFactory() { 142 } 143 144 void URLRequestContextFactory::InitializeOnUIThread() { 145 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 146 // Cast http user agent settings must be initialized in UI thread 147 // because it registers itself to pref notification observer which is not 148 // thread safe. 149 http_user_agent_settings_.reset(new CastHttpUserAgentSettings()); 150 151 // Proxy config service should be initialized in UI thread, since 152 // ProxyConfigServiceDelegate on Android expects UI thread. 153 proxy_config_service_.reset(net::ProxyService::CreateSystemProxyConfigService( 154 content::BrowserThread::GetMessageLoopProxyForThread( 155 content::BrowserThread::IO), 156 content::BrowserThread::GetMessageLoopProxyForThread( 157 content::BrowserThread::FILE))); 158 } 159 160 net::URLRequestContextGetter* URLRequestContextFactory::CreateMainGetter( 161 content::BrowserContext* browser_context, 162 content::ProtocolHandlerMap* protocol_handlers, 163 content::URLRequestInterceptorScopedVector request_interceptors) { 164 DCHECK(!main_getter_.get()) 165 << "Main URLRequestContextGetter already initialized"; 166 main_getter_ = new MainURLRequestContextGetter(this, 167 browser_context, 168 protocol_handlers, 169 request_interceptors.Pass()); 170 return main_getter_.get(); 171 } 172 173 net::URLRequestContextGetter* URLRequestContextFactory::GetMainGetter() { 174 CHECK(main_getter_.get()); 175 return main_getter_.get(); 176 } 177 178 net::URLRequestContextGetter* URLRequestContextFactory::GetSystemGetter() { 179 if (!system_getter_.get()) { 180 system_getter_ = new URLRequestContextGetter(this, false); 181 } 182 return system_getter_.get(); 183 } 184 185 net::URLRequestContextGetter* URLRequestContextFactory::GetMediaGetter() { 186 if (!media_getter_.get()) { 187 media_getter_ = new URLRequestContextGetter(this, true); 188 } 189 return media_getter_.get(); 190 } 191 192 void URLRequestContextFactory::InitializeSystemContextDependencies() { 193 if (system_dependencies_initialized_) 194 return; 195 196 host_resolver_ = net::HostResolver::CreateDefaultResolver(NULL); 197 198 // TODO(lcwu): http://crbug.com/392352. For performance and security reasons, 199 // a persistent (on-disk) HttpServerProperties and ChannelIDService might be 200 // desirable in the future. 201 channel_id_service_.reset( 202 new net::ChannelIDService(new net::DefaultChannelIDStore(NULL), 203 base::WorkerPool::GetTaskRunner(true))); 204 205 cert_verifier_.reset(net::CertVerifier::CreateDefault()); 206 207 ssl_config_service_ = new net::SSLConfigServiceDefaults; 208 209 transport_security_state_.reset(new net::TransportSecurityState()); 210 http_auth_handler_factory_.reset( 211 net::HttpAuthHandlerFactory::CreateDefault(host_resolver_.get())); 212 213 http_server_properties_.reset(new net::HttpServerPropertiesImpl); 214 215 proxy_service_.reset(net::ProxyService::CreateUsingSystemProxyResolver( 216 proxy_config_service_.release(), 0, NULL)); 217 system_dependencies_initialized_ = true; 218 } 219 220 void URLRequestContextFactory::InitializeMainContextDependencies( 221 net::HttpTransactionFactory* transaction_factory, 222 content::ProtocolHandlerMap* protocol_handlers, 223 content::URLRequestInterceptorScopedVector request_interceptors) { 224 if (main_dependencies_initialized_) 225 return; 226 227 main_transaction_factory_.reset(transaction_factory); 228 scoped_ptr<net::URLRequestJobFactoryImpl> job_factory( 229 new net::URLRequestJobFactoryImpl()); 230 // Keep ProtocolHandlers added in sync with 231 // CastContentBrowserClient::IsHandledURL(). 232 bool set_protocol = false; 233 for (content::ProtocolHandlerMap::iterator it = protocol_handlers->begin(); 234 it != protocol_handlers->end(); 235 ++it) { 236 set_protocol = job_factory->SetProtocolHandler( 237 it->first, it->second.release()); 238 DCHECK(set_protocol); 239 } 240 set_protocol = job_factory->SetProtocolHandler( 241 url::kDataScheme, 242 new net::DataProtocolHandler); 243 DCHECK(set_protocol); 244 #if defined(OS_ANDROID) 245 set_protocol = job_factory->SetProtocolHandler( 246 url::kFileScheme, 247 new net::FileProtocolHandler( 248 content::BrowserThread::GetBlockingPool()-> 249 GetTaskRunnerWithShutdownBehavior( 250 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))); 251 DCHECK(set_protocol); 252 #endif // defined(OS_ANDROID) 253 254 // Set up interceptors in the reverse order. 255 scoped_ptr<net::URLRequestJobFactory> top_job_factory = 256 job_factory.PassAs<net::URLRequestJobFactory>(); 257 for (content::URLRequestInterceptorScopedVector::reverse_iterator i = 258 request_interceptors.rbegin(); 259 i != request_interceptors.rend(); 260 ++i) { 261 top_job_factory.reset(new net::URLRequestInterceptingJobFactory( 262 top_job_factory.Pass(), make_scoped_ptr(*i))); 263 } 264 request_interceptors.weak_clear(); 265 266 main_job_factory_.reset(top_job_factory.release()); 267 268 main_dependencies_initialized_ = true; 269 } 270 271 void URLRequestContextFactory::InitializeMediaContextDependencies( 272 net::HttpTransactionFactory* transaction_factory) { 273 if (media_dependencies_initialized_) 274 return; 275 276 media_transaction_factory_.reset(transaction_factory); 277 media_dependencies_initialized_ = true; 278 } 279 280 void URLRequestContextFactory::PopulateNetworkSessionParams( 281 bool ignore_certificate_errors, 282 net::HttpNetworkSession::Params* params) { 283 params->host_resolver = host_resolver_.get(); 284 params->cert_verifier = cert_verifier_.get(); 285 params->channel_id_service = channel_id_service_.get(); 286 params->ssl_config_service = ssl_config_service_.get(); 287 params->transport_security_state = transport_security_state_.get(); 288 params->http_auth_handler_factory = http_auth_handler_factory_.get(); 289 params->http_server_properties = http_server_properties_->GetWeakPtr(); 290 params->ignore_certificate_errors = ignore_certificate_errors; 291 params->proxy_service = proxy_service_.get(); 292 293 // TODO(lcwu): http://crbug.com/329681. Remove this once spdy is enabled 294 // by default at the content level. 295 params->next_protos = net::NextProtosSpdy31(); 296 params->use_alternate_protocols = true; 297 } 298 299 net::URLRequestContext* URLRequestContextFactory::CreateSystemRequestContext() { 300 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 301 InitializeSystemContextDependencies(); 302 net::HttpNetworkSession::Params system_params; 303 PopulateNetworkSessionParams(false, &system_params); 304 system_transaction_factory_.reset(new net::HttpNetworkLayer( 305 new net::HttpNetworkSession(system_params))); 306 system_job_factory_.reset(new net::URLRequestJobFactoryImpl()); 307 308 net::URLRequestContext* system_context = new net::URLRequestContext(); 309 system_context->set_host_resolver(host_resolver_.get()); 310 system_context->set_channel_id_service(channel_id_service_.get()); 311 system_context->set_cert_verifier(cert_verifier_.get()); 312 system_context->set_proxy_service(proxy_service_.get()); 313 system_context->set_ssl_config_service(ssl_config_service_.get()); 314 system_context->set_transport_security_state( 315 transport_security_state_.get()); 316 system_context->set_http_auth_handler_factory( 317 http_auth_handler_factory_.get()); 318 system_context->set_http_server_properties( 319 http_server_properties_->GetWeakPtr()); 320 system_context->set_http_transaction_factory( 321 system_transaction_factory_.get()); 322 system_context->set_http_user_agent_settings( 323 http_user_agent_settings_.get()); 324 system_context->set_job_factory(system_job_factory_.get()); 325 system_context->set_cookie_store( 326 content::CreateCookieStore(content::CookieStoreConfig())); 327 return system_context; 328 } 329 330 net::URLRequestContext* URLRequestContextFactory::CreateMediaRequestContext() { 331 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 332 DCHECK(main_getter_.get()) 333 << "Getting MediaRequestContext before MainRequestContext"; 334 net::URLRequestContext* main_context = main_getter_->GetURLRequestContext(); 335 336 // Set non caching backend. 337 net::HttpNetworkSession* main_session = 338 main_transaction_factory_->GetSession(); 339 InitializeMediaContextDependencies( 340 new net::HttpNetworkLayer(main_session)); 341 342 net::URLRequestContext* media_context = new net::URLRequestContext(); 343 media_context->CopyFrom(main_context); 344 media_context->set_http_transaction_factory( 345 media_transaction_factory_.get()); 346 return media_context; 347 } 348 349 net::URLRequestContext* URLRequestContextFactory::CreateMainRequestContext( 350 content::BrowserContext* browser_context, 351 content::ProtocolHandlerMap* protocol_handlers, 352 content::URLRequestInterceptorScopedVector request_interceptors) { 353 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 354 InitializeSystemContextDependencies(); 355 356 net::HttpCache::BackendFactory* main_backend = 357 net::HttpCache::DefaultBackend::InMemory(16 * 1024 * 1024); 358 359 bool ignore_certificate_errors = false; 360 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 361 if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors)) { 362 ignore_certificate_errors = true; 363 } 364 net::HttpNetworkSession::Params network_session_params; 365 PopulateNetworkSessionParams(ignore_certificate_errors, 366 &network_session_params); 367 InitializeMainContextDependencies( 368 new net::HttpCache(network_session_params, main_backend), 369 protocol_handlers, 370 request_interceptors.Pass()); 371 372 content::CookieStoreConfig cookie_config( 373 browser_context->GetPath().Append(kCookieStoreFile), 374 content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, 375 NULL, NULL); 376 cookie_config.background_task_runner = 377 scoped_refptr<base::SequencedTaskRunner>(); 378 scoped_refptr<net::CookieStore> cookie_store = 379 content::CreateCookieStore(cookie_config); 380 381 net::URLRequestContext* main_context = new net::URLRequestContext(); 382 main_context->set_host_resolver(host_resolver_.get()); 383 main_context->set_channel_id_service(channel_id_service_.get()); 384 main_context->set_cert_verifier(cert_verifier_.get()); 385 main_context->set_proxy_service(proxy_service_.get()); 386 main_context->set_ssl_config_service(ssl_config_service_.get()); 387 main_context->set_transport_security_state(transport_security_state_.get()); 388 main_context->set_http_auth_handler_factory( 389 http_auth_handler_factory_.get()); 390 main_context->set_http_server_properties( 391 http_server_properties_->GetWeakPtr()); 392 main_context->set_cookie_store(cookie_store.get()); 393 main_context->set_http_user_agent_settings( 394 http_user_agent_settings_.get()); 395 396 main_context->set_http_transaction_factory( 397 main_transaction_factory_.get()); 398 main_context->set_job_factory(main_job_factory_.get()); 399 return main_context; 400 } 401 402 } // namespace shell 403 } // namespace chromecast 404