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