1 // Copyright (c) 2011 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/message_loop.h"
8 #include "base/message_loop_proxy.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/io_thread.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_io_data.h"
13 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h"
14 #include "chrome/common/pref_names.h"
15 #include "content/browser/browser_thread.h"
16 #include "content/common/notification_service.h"
17 #include "net/base/cookie_store.h"
18 #include "net/ftp/ftp_transaction_factory.h"
19 #include "net/http/http_transaction_factory.h"
20 #include "net/http/http_util.h"
21 #include "webkit/glue/webkit_glue.h"
22
23 #if defined(USE_NSS)
24 #include "net/ocsp/nss_ocsp.h"
25 #endif
26
27 class ChromeURLRequestContextFactory {
28 public:
ChromeURLRequestContextFactory()29 ChromeURLRequestContextFactory() {}
~ChromeURLRequestContextFactory()30 virtual ~ChromeURLRequestContextFactory() {}
31
32 // Called to create a new instance (will only be called once).
33 virtual scoped_refptr<ChromeURLRequestContext> Create() = 0;
34
35 protected:
36 DISALLOW_COPY_AND_ASSIGN(ChromeURLRequestContextFactory);
37 };
38
39 namespace {
40
41 // ----------------------------------------------------------------------------
42 // Helper factories
43 // ----------------------------------------------------------------------------
44
45 // Factory that creates the main ChromeURLRequestContext.
46 class FactoryForMain : public ChromeURLRequestContextFactory {
47 public:
FactoryForMain(const ProfileIOData * profile_io_data)48 explicit FactoryForMain(const ProfileIOData* profile_io_data)
49 : profile_io_data_(profile_io_data) {}
50
Create()51 virtual scoped_refptr<ChromeURLRequestContext> Create() {
52 return profile_io_data_->GetMainRequestContext();
53 }
54
55 private:
56 const scoped_refptr<const ProfileIOData> profile_io_data_;
57 };
58
59 // Factory that creates the ChromeURLRequestContext for extensions.
60 class FactoryForExtensions : public ChromeURLRequestContextFactory {
61 public:
FactoryForExtensions(const ProfileIOData * profile_io_data)62 explicit FactoryForExtensions(const ProfileIOData* profile_io_data)
63 : profile_io_data_(profile_io_data) {}
64
Create()65 virtual scoped_refptr<ChromeURLRequestContext> Create() {
66 return profile_io_data_->GetExtensionsRequestContext();
67 }
68
69 private:
70 const scoped_refptr<const ProfileIOData> profile_io_data_;
71 };
72
73 // Factory that creates the ChromeURLRequestContext for a given isolated app.
74 class FactoryForIsolatedApp : public ChromeURLRequestContextFactory {
75 public:
FactoryForIsolatedApp(const ProfileIOData * profile_io_data,const std::string & app_id,ChromeURLRequestContextGetter * main_context)76 FactoryForIsolatedApp(const ProfileIOData* profile_io_data,
77 const std::string& app_id,
78 ChromeURLRequestContextGetter* main_context)
79 : profile_io_data_(profile_io_data),
80 app_id_(app_id),
81 main_request_context_getter_(main_context) {}
82
Create()83 virtual scoped_refptr<ChromeURLRequestContext> Create() {
84 // We will copy most of the state from the main request context.
85 return profile_io_data_->GetIsolatedAppRequestContext(
86 main_request_context_getter_->GetIOContext(), app_id_);
87 }
88
89 private:
90 const scoped_refptr<const ProfileIOData> profile_io_data_;
91 const std::string app_id_;
92 scoped_refptr<ChromeURLRequestContextGetter>
93 main_request_context_getter_;
94 };
95
96 // Factory that creates the ChromeURLRequestContext for media.
97 class FactoryForMedia : public ChromeURLRequestContextFactory {
98 public:
FactoryForMedia(const ProfileIOData * profile_io_data)99 explicit FactoryForMedia(const ProfileIOData* profile_io_data)
100 : profile_io_data_(profile_io_data) {
101 }
102
Create()103 virtual scoped_refptr<ChromeURLRequestContext> Create() {
104 return profile_io_data_->GetMediaRequestContext();
105 }
106
107 private:
108 const scoped_refptr<const ProfileIOData> profile_io_data_;
109 };
110
111 } // namespace
112
113 // ----------------------------------------------------------------------------
114 // ChromeURLRequestContextGetter
115 // ----------------------------------------------------------------------------
116
ChromeURLRequestContextGetter(Profile * profile,ChromeURLRequestContextFactory * factory)117 ChromeURLRequestContextGetter::ChromeURLRequestContextGetter(
118 Profile* profile,
119 ChromeURLRequestContextFactory* factory)
120 : io_thread_(g_browser_process->io_thread()),
121 factory_(factory),
122 url_request_context_(NULL) {
123 DCHECK(factory);
124 DCHECK(profile);
125 RegisterPrefsObserver(profile);
126 }
127
~ChromeURLRequestContextGetter()128 ChromeURLRequestContextGetter::~ChromeURLRequestContextGetter() {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
130
131 DCHECK(registrar_.IsEmpty()) << "Probably didn't call CleanupOnUIThread";
132
133 // Either we already transformed the factory into a net::URLRequestContext, or
134 // we still have a pending factory.
135 DCHECK((factory_.get() && !url_request_context_.get()) ||
136 (!factory_.get() && url_request_context_.get()));
137
138 if (url_request_context_)
139 io_thread_->UnregisterURLRequestContextGetter(this);
140
141 // The scoped_refptr / scoped_ptr destructors take care of releasing
142 // |factory_| and |url_request_context_| now.
143 }
144
145 // Lazily create a ChromeURLRequestContext using our factory.
GetURLRequestContext()146 net::URLRequestContext* ChromeURLRequestContextGetter::GetURLRequestContext() {
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
148
149 if (!url_request_context_) {
150 DCHECK(factory_.get());
151 url_request_context_ = factory_->Create();
152 if (is_main()) {
153 url_request_context_->set_is_main(true);
154 #if defined(USE_NSS)
155 // TODO(ukai): find a better way to set the net::URLRequestContext for
156 // OCSP.
157 net::SetURLRequestContextForOCSP(url_request_context_);
158 #endif
159 }
160
161 factory_.reset();
162 io_thread_->RegisterURLRequestContextGetter(this);
163 }
164
165 return url_request_context_;
166 }
167
ReleaseURLRequestContext()168 void ChromeURLRequestContextGetter::ReleaseURLRequestContext() {
169 DCHECK(url_request_context_);
170 url_request_context_ = NULL;
171 }
172
DONTUSEME_GetCookieStore()173 net::CookieStore* ChromeURLRequestContextGetter::DONTUSEME_GetCookieStore() {
174 // If we are running on the IO thread this is real easy.
175 if (BrowserThread::CurrentlyOn(BrowserThread::IO))
176 return GetURLRequestContext()->cookie_store();
177
178 // If we aren't running on the IO thread, we cannot call
179 // GetURLRequestContext(). Instead we will post a task to the IO loop
180 // and wait for it to complete.
181
182 base::WaitableEvent completion(false, false);
183 net::CookieStore* result = NULL;
184
185 BrowserThread::PostTask(
186 BrowserThread::IO, FROM_HERE,
187 NewRunnableMethod(this,
188 &ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper,
189 &completion,
190 &result));
191
192 completion.Wait();
193 DCHECK(result);
194 return result;
195 }
196
197 scoped_refptr<base::MessageLoopProxy>
GetIOMessageLoopProxy() const198 ChromeURLRequestContextGetter::GetIOMessageLoopProxy() const {
199 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
200 }
201
202 // static
CreateOriginal(Profile * profile,const ProfileIOData * profile_io_data)203 ChromeURLRequestContextGetter* ChromeURLRequestContextGetter::CreateOriginal(
204 Profile* profile,
205 const ProfileIOData* profile_io_data) {
206 DCHECK(!profile->IsOffTheRecord());
207 return new ChromeURLRequestContextGetter(
208 profile,
209 new FactoryForMain(profile_io_data));
210 }
211
212 // static
213 ChromeURLRequestContextGetter*
CreateOriginalForMedia(Profile * profile,const ProfileIOData * profile_io_data)214 ChromeURLRequestContextGetter::CreateOriginalForMedia(
215 Profile* profile, const ProfileIOData* profile_io_data) {
216 DCHECK(!profile->IsOffTheRecord());
217 return new ChromeURLRequestContextGetter(
218 profile,
219 new FactoryForMedia(profile_io_data));
220 }
221
222 // static
223 ChromeURLRequestContextGetter*
CreateOriginalForExtensions(Profile * profile,const ProfileIOData * profile_io_data)224 ChromeURLRequestContextGetter::CreateOriginalForExtensions(
225 Profile* profile, const ProfileIOData* profile_io_data) {
226 DCHECK(!profile->IsOffTheRecord());
227 return new ChromeURLRequestContextGetter(
228 profile,
229 new FactoryForExtensions(profile_io_data));
230 }
231
232 // static
233 ChromeURLRequestContextGetter*
CreateOriginalForIsolatedApp(Profile * profile,const ProfileIOData * profile_io_data,const std::string & app_id)234 ChromeURLRequestContextGetter::CreateOriginalForIsolatedApp(
235 Profile* profile,
236 const ProfileIOData* profile_io_data,
237 const std::string& app_id) {
238 DCHECK(!profile->IsOffTheRecord());
239 ChromeURLRequestContextGetter* main_context =
240 static_cast<ChromeURLRequestContextGetter*>(profile->GetRequestContext());
241 return new ChromeURLRequestContextGetter(
242 profile,
243 new FactoryForIsolatedApp(profile_io_data, app_id, main_context));
244 }
245
246 // static
247 ChromeURLRequestContextGetter*
CreateOffTheRecord(Profile * profile,const ProfileIOData * profile_io_data)248 ChromeURLRequestContextGetter::CreateOffTheRecord(
249 Profile* profile, const ProfileIOData* profile_io_data) {
250 DCHECK(profile->IsOffTheRecord());
251 return new ChromeURLRequestContextGetter(
252 profile, new FactoryForMain(profile_io_data));
253 }
254
255 // static
256 ChromeURLRequestContextGetter*
CreateOffTheRecordForExtensions(Profile * profile,const ProfileIOData * profile_io_data)257 ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(
258 Profile* profile, const ProfileIOData* profile_io_data) {
259 DCHECK(profile->IsOffTheRecord());
260 return new ChromeURLRequestContextGetter(
261 profile, new FactoryForExtensions(profile_io_data));
262 }
263
264 // static
265 ChromeURLRequestContextGetter*
CreateOffTheRecordForIsolatedApp(Profile * profile,const ProfileIOData * profile_io_data,const std::string & app_id)266 ChromeURLRequestContextGetter::CreateOffTheRecordForIsolatedApp(
267 Profile* profile,
268 const ProfileIOData* profile_io_data,
269 const std::string& app_id) {
270 DCHECK(profile->IsOffTheRecord());
271 ChromeURLRequestContextGetter* main_context =
272 static_cast<ChromeURLRequestContextGetter*>(profile->GetRequestContext());
273 return new ChromeURLRequestContextGetter(
274 profile,
275 new FactoryForIsolatedApp(profile_io_data, app_id, main_context));
276 }
277
CleanupOnUIThread()278 void ChromeURLRequestContextGetter::CleanupOnUIThread() {
279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
280 // Unregister for pref notifications.
281 DCHECK(!registrar_.IsEmpty()) << "Called more than once!";
282 registrar_.RemoveAll();
283 }
284
285 // NotificationObserver implementation.
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)286 void ChromeURLRequestContextGetter::Observe(
287 NotificationType type,
288 const NotificationSource& source,
289 const NotificationDetails& details) {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291
292 if (NotificationType::PREF_CHANGED == type) {
293 std::string* pref_name_in = Details<std::string>(details).ptr();
294 PrefService* prefs = Source<PrefService>(source).ptr();
295 DCHECK(pref_name_in && prefs);
296 if (*pref_name_in == prefs::kAcceptLanguages) {
297 std::string accept_language =
298 prefs->GetString(prefs::kAcceptLanguages);
299 BrowserThread::PostTask(
300 BrowserThread::IO, FROM_HERE,
301 NewRunnableMethod(
302 this,
303 &ChromeURLRequestContextGetter::OnAcceptLanguageChange,
304 accept_language));
305 } else if (*pref_name_in == prefs::kDefaultCharset) {
306 std::string default_charset =
307 prefs->GetString(prefs::kDefaultCharset);
308 BrowserThread::PostTask(
309 BrowserThread::IO, FROM_HERE,
310 NewRunnableMethod(
311 this,
312 &ChromeURLRequestContextGetter::OnDefaultCharsetChange,
313 default_charset));
314 } else if (*pref_name_in == prefs::kClearSiteDataOnExit) {
315 bool clear_site_data =
316 prefs->GetBoolean(prefs::kClearSiteDataOnExit);
317 BrowserThread::PostTask(
318 BrowserThread::IO, FROM_HERE,
319 NewRunnableMethod(
320 this,
321 &ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange,
322 clear_site_data));
323 }
324 } else {
325 NOTREACHED();
326 }
327 }
328
RegisterPrefsObserver(Profile * profile)329 void ChromeURLRequestContextGetter::RegisterPrefsObserver(Profile* profile) {
330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
331
332 registrar_.Init(profile->GetPrefs());
333 registrar_.Add(prefs::kAcceptLanguages, this);
334 registrar_.Add(prefs::kDefaultCharset, this);
335 registrar_.Add(prefs::kClearSiteDataOnExit, this);
336 }
337
OnAcceptLanguageChange(const std::string & accept_language)338 void ChromeURLRequestContextGetter::OnAcceptLanguageChange(
339 const std::string& accept_language) {
340 GetIOContext()->OnAcceptLanguageChange(accept_language);
341 }
342
OnDefaultCharsetChange(const std::string & default_charset)343 void ChromeURLRequestContextGetter::OnDefaultCharsetChange(
344 const std::string& default_charset) {
345 GetIOContext()->OnDefaultCharsetChange(default_charset);
346 }
347
OnClearSiteDataOnExitChange(bool clear_site_data)348 void ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange(
349 bool clear_site_data) {
350 GetURLRequestContext()->cookie_store()->GetCookieMonster()->
351 SetClearPersistentStoreOnExit(clear_site_data);
352 }
353
GetCookieStoreAsyncHelper(base::WaitableEvent * completion,net::CookieStore ** result)354 void ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper(
355 base::WaitableEvent* completion,
356 net::CookieStore** result) {
357 // Note that CookieStore is refcounted, yet we do not add a reference.
358 *result = GetURLRequestContext()->cookie_store();
359 completion->Signal();
360 }
361
362 // ----------------------------------------------------------------------------
363 // ChromeURLRequestContext
364 // ----------------------------------------------------------------------------
365
ChromeURLRequestContext()366 ChromeURLRequestContext::ChromeURLRequestContext()
367 : is_incognito_(false) {
368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
369 }
370
CopyFrom(ChromeURLRequestContext * other)371 void ChromeURLRequestContext::CopyFrom(ChromeURLRequestContext* other) {
372 URLRequestContext::CopyFrom(other);
373
374 // Copy ChromeURLRequestContext parameters.
375 set_user_script_dir_path(other->user_script_dir_path());
376 set_appcache_service(other->appcache_service());
377 set_host_content_settings_map(other->host_content_settings_map());
378 set_host_zoom_map(other->host_zoom_map_);
379 set_blob_storage_context(other->blob_storage_context());
380 set_file_system_context(other->file_system_context());
381 set_extension_info_map(other->extension_info_map_);
382 set_prerender_manager(other->prerender_manager());
383 // ChromeURLDataManagerBackend is unique per context.
384 set_is_incognito(other->is_incognito());
385 }
386
387 ChromeURLDataManagerBackend*
GetChromeURLDataManagerBackend()388 ChromeURLRequestContext::GetChromeURLDataManagerBackend() {
389 if (!chrome_url_data_manager_backend_.get())
390 chrome_url_data_manager_backend_.reset(new ChromeURLDataManagerBackend());
391 return chrome_url_data_manager_backend_.get();
392 }
393
~ChromeURLRequestContext()394 ChromeURLRequestContext::~ChromeURLRequestContext() {
395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
396
397 if (appcache_service_.get() && appcache_service_->request_context() == this)
398 appcache_service_->set_request_context(NULL);
399
400 #if defined(USE_NSS)
401 if (is_main()) {
402 net::URLRequestContext* ocsp_context = net::GetURLRequestContextForOCSP();
403 if (ocsp_context) {
404 DCHECK_EQ(this, ocsp_context);
405 // We are releasing the net::URLRequestContext used by OCSP handlers.
406 net::SetURLRequestContextForOCSP(NULL);
407 }
408 }
409 #endif
410
411 NotificationService::current()->Notify(
412 NotificationType::URL_REQUEST_CONTEXT_RELEASED,
413 Source<net::URLRequestContext>(this),
414 NotificationService::NoDetails());
415
416 // cookie_policy_'s lifetime is auto-managed by chrome_cookie_policy_. We
417 // null this out here to avoid a dangling reference to chrome_cookie_policy_
418 // when ~net::URLRequestContext runs.
419 set_cookie_policy(NULL);
420 }
421
GetUserAgent(const GURL & url) const422 const std::string& ChromeURLRequestContext::GetUserAgent(
423 const GURL& url) const {
424 return webkit_glue::GetUserAgent(url);
425 }
426
OnAcceptLanguageChange(const std::string & accept_language)427 void ChromeURLRequestContext::OnAcceptLanguageChange(
428 const std::string& accept_language) {
429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
430 set_accept_language(
431 net::HttpUtil::GenerateAcceptLanguageHeader(accept_language));
432 }
433
OnDefaultCharsetChange(const std::string & default_charset)434 void ChromeURLRequestContext::OnDefaultCharsetChange(
435 const std::string& default_charset) {
436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
437 set_referrer_charset(default_charset);
438 set_accept_charset(
439 net::HttpUtil::GenerateAcceptCharsetHeader(default_charset));
440 }
441