• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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