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 "chrome/browser/net/chrome_url_request_context_getter.h"
6
7#include "base/bind.h"
8#include "base/compiler_specific.h"
9#include "base/message_loop/message_loop.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/io_thread.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/profiles/profile_io_data.h"
15#include "chrome/browser/profiles/storage_partition_descriptor.h"
16#include "content/public/browser/browser_thread.h"
17#include "net/cookies/cookie_store.h"
18
19using content::BrowserThread;
20
21class ChromeURLRequestContextFactory {
22 public:
23  ChromeURLRequestContextFactory() {}
24  virtual ~ChromeURLRequestContextFactory() {}
25
26  // Called to create a new instance (will only be called once).
27  virtual net::URLRequestContext* Create() = 0;
28
29 protected:
30  DISALLOW_COPY_AND_ASSIGN(ChromeURLRequestContextFactory);
31};
32
33namespace {
34
35// ----------------------------------------------------------------------------
36// Helper factories
37// ----------------------------------------------------------------------------
38
39// Factory that creates the main URLRequestContext.
40class FactoryForMain : public ChromeURLRequestContextFactory {
41 public:
42  FactoryForMain(
43      const ProfileIOData* profile_io_data,
44      content::ProtocolHandlerMap* protocol_handlers,
45      content::URLRequestInterceptorScopedVector request_interceptors)
46      : profile_io_data_(profile_io_data),
47        request_interceptors_(request_interceptors.Pass()) {
48    std::swap(protocol_handlers_, *protocol_handlers);
49  }
50
51  virtual net::URLRequestContext* Create() OVERRIDE {
52    profile_io_data_->Init(&protocol_handlers_, request_interceptors_.Pass());
53    return profile_io_data_->GetMainRequestContext();
54  }
55
56 private:
57  const ProfileIOData* const profile_io_data_;
58  content::ProtocolHandlerMap protocol_handlers_;
59  content::URLRequestInterceptorScopedVector request_interceptors_;
60};
61
62// Factory that creates the URLRequestContext for extensions.
63class FactoryForExtensions : public ChromeURLRequestContextFactory {
64 public:
65  explicit FactoryForExtensions(const ProfileIOData* profile_io_data)
66      : profile_io_data_(profile_io_data) {}
67
68  virtual net::URLRequestContext* Create() OVERRIDE {
69    return profile_io_data_->GetExtensionsRequestContext();
70  }
71
72 private:
73  const ProfileIOData* const profile_io_data_;
74};
75
76// Factory that creates the URLRequestContext for a given isolated app.
77class FactoryForIsolatedApp : public ChromeURLRequestContextFactory {
78 public:
79  FactoryForIsolatedApp(
80      const ProfileIOData* profile_io_data,
81      const StoragePartitionDescriptor& partition_descriptor,
82      ChromeURLRequestContextGetter* main_context,
83      scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
84          protocol_handler_interceptor,
85      content::ProtocolHandlerMap* protocol_handlers,
86      content::URLRequestInterceptorScopedVector request_interceptors)
87      : profile_io_data_(profile_io_data),
88        partition_descriptor_(partition_descriptor),
89        main_request_context_getter_(main_context),
90        protocol_handler_interceptor_(protocol_handler_interceptor.Pass()),
91        request_interceptors_(request_interceptors.Pass()) {
92    std::swap(protocol_handlers_, *protocol_handlers);
93  }
94
95  virtual net::URLRequestContext* Create() OVERRIDE {
96    // We will copy most of the state from the main request context.
97    //
98    // Note that this factory is one-shot.  After Create() is called once, the
99    // factory is actually destroyed. Thus it is safe to destructively pass
100    // state onwards.
101    return profile_io_data_->GetIsolatedAppRequestContext(
102        main_request_context_getter_->GetURLRequestContext(),
103        partition_descriptor_,
104        protocol_handler_interceptor_.Pass(),
105        &protocol_handlers_,
106        request_interceptors_.Pass());
107  }
108
109 private:
110  const ProfileIOData* const profile_io_data_;
111  const StoragePartitionDescriptor partition_descriptor_;
112  scoped_refptr<ChromeURLRequestContextGetter>
113      main_request_context_getter_;
114  scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
115      protocol_handler_interceptor_;
116  content::ProtocolHandlerMap protocol_handlers_;
117  content::URLRequestInterceptorScopedVector request_interceptors_;
118};
119
120// Factory that creates the media URLRequestContext for a given isolated
121// app.  The media context is based on the corresponding isolated app's context.
122class FactoryForIsolatedMedia : public ChromeURLRequestContextFactory {
123 public:
124  FactoryForIsolatedMedia(
125      const ProfileIOData* profile_io_data,
126      const StoragePartitionDescriptor& partition_descriptor,
127      ChromeURLRequestContextGetter* app_context)
128    : profile_io_data_(profile_io_data),
129      partition_descriptor_(partition_descriptor),
130      app_context_getter_(app_context) {}
131
132  virtual net::URLRequestContext* Create() OVERRIDE {
133    // We will copy most of the state from the corresopnding app's
134    // request context. We expect to have the same lifetime as
135    // the associated |app_context_getter_| so we can just reuse
136    // all its backing objects, including the
137    // |protocol_handler_interceptor|.  This is why the API
138    // looks different from FactoryForIsolatedApp's.
139    return profile_io_data_->GetIsolatedMediaRequestContext(
140        app_context_getter_->GetURLRequestContext(), partition_descriptor_);
141  }
142
143 private:
144  const ProfileIOData* const profile_io_data_;
145  const StoragePartitionDescriptor partition_descriptor_;
146  scoped_refptr<ChromeURLRequestContextGetter> app_context_getter_;
147};
148
149// Factory that creates the URLRequestContext for media.
150class FactoryForMedia : public ChromeURLRequestContextFactory {
151 public:
152  explicit FactoryForMedia(const ProfileIOData* profile_io_data)
153      : profile_io_data_(profile_io_data) {
154  }
155
156  virtual net::URLRequestContext* Create() OVERRIDE {
157    return profile_io_data_->GetMediaRequestContext();
158  }
159
160 private:
161  const ProfileIOData* const profile_io_data_;
162};
163
164}  // namespace
165
166// ----------------------------------------------------------------------------
167// ChromeURLRequestContextGetter
168// ----------------------------------------------------------------------------
169
170ChromeURLRequestContextGetter::ChromeURLRequestContextGetter(
171    ChromeURLRequestContextFactory* factory)
172    : factory_(factory),
173      url_request_context_(NULL) {
174  DCHECK(factory);
175}
176
177ChromeURLRequestContextGetter::~ChromeURLRequestContextGetter() {}
178
179// Lazily create a URLRequestContext using our factory.
180net::URLRequestContext*
181ChromeURLRequestContextGetter::GetURLRequestContext() {
182  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
183
184  if (factory_.get()) {
185    DCHECK(!url_request_context_);
186    url_request_context_ = factory_->Create();
187    factory_.reset();
188  }
189
190  // Context reference is valid, unless we're trying to use the
191  // URLRequestContextGetter after the Profile has already been deleted.
192  CHECK(url_request_context_);
193
194  return url_request_context_;
195}
196
197void ChromeURLRequestContextGetter::Invalidate() {
198  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
199  factory_.reset();
200  url_request_context_ = NULL;
201}
202
203scoped_refptr<base::SingleThreadTaskRunner>
204ChromeURLRequestContextGetter::GetNetworkTaskRunner() const {
205  return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
206}
207
208// static
209ChromeURLRequestContextGetter* ChromeURLRequestContextGetter::Create(
210    Profile* profile,
211    const ProfileIOData* profile_io_data,
212    content::ProtocolHandlerMap* protocol_handlers,
213    content::URLRequestInterceptorScopedVector request_interceptors) {
214  return new ChromeURLRequestContextGetter(new FactoryForMain(
215      profile_io_data, protocol_handlers, request_interceptors.Pass()));
216}
217
218// static
219ChromeURLRequestContextGetter*
220ChromeURLRequestContextGetter::CreateForMedia(
221    Profile* profile, const ProfileIOData* profile_io_data) {
222  return new ChromeURLRequestContextGetter(
223      new FactoryForMedia(profile_io_data));
224}
225
226// static
227ChromeURLRequestContextGetter*
228ChromeURLRequestContextGetter::CreateForExtensions(
229    Profile* profile, const ProfileIOData* profile_io_data) {
230  return new ChromeURLRequestContextGetter(
231      new FactoryForExtensions(profile_io_data));
232}
233
234// static
235ChromeURLRequestContextGetter*
236ChromeURLRequestContextGetter::CreateForIsolatedApp(
237    Profile* profile,
238    const ProfileIOData* profile_io_data,
239    const StoragePartitionDescriptor& partition_descriptor,
240    scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
241        protocol_handler_interceptor,
242    content::ProtocolHandlerMap* protocol_handlers,
243    content::URLRequestInterceptorScopedVector request_interceptors) {
244  ChromeURLRequestContextGetter* main_context =
245      static_cast<ChromeURLRequestContextGetter*>(profile->GetRequestContext());
246  return new ChromeURLRequestContextGetter(
247      new FactoryForIsolatedApp(profile_io_data,
248                                partition_descriptor,
249                                main_context,
250                                protocol_handler_interceptor.Pass(),
251                                protocol_handlers,
252                                request_interceptors.Pass()));
253}
254
255// static
256ChromeURLRequestContextGetter*
257ChromeURLRequestContextGetter::CreateForIsolatedMedia(
258    Profile* profile,
259    ChromeURLRequestContextGetter* app_context,
260    const ProfileIOData* profile_io_data,
261    const StoragePartitionDescriptor& partition_descriptor) {
262  return new ChromeURLRequestContextGetter(
263      new FactoryForIsolatedMedia(
264          profile_io_data, partition_descriptor, app_context));
265}
266