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
39namespace chromecast {
40namespace shell {
41
42namespace {
43
44const 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.
53class 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.
94class 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
135URLRequestContextFactory::URLRequestContextFactory()
136    : system_dependencies_initialized_(false),
137      main_dependencies_initialized_(false),
138      media_dependencies_initialized_(false) {
139}
140
141URLRequestContextFactory::~URLRequestContextFactory() {
142}
143
144void 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
160net::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
173net::URLRequestContextGetter* URLRequestContextFactory::GetMainGetter() {
174  CHECK(main_getter_.get());
175  return main_getter_.get();
176}
177
178net::URLRequestContextGetter* URLRequestContextFactory::GetSystemGetter() {
179  if (!system_getter_.get()) {
180    system_getter_ = new URLRequestContextGetter(this, false);
181  }
182  return system_getter_.get();
183}
184
185net::URLRequestContextGetter* URLRequestContextFactory::GetMediaGetter() {
186  if (!media_getter_.get()) {
187    media_getter_ = new URLRequestContextGetter(this, true);
188  }
189  return media_getter_.get();
190}
191
192void 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
220void 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
271void 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
280void 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
299net::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
330net::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
349net::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