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