Home | History | Annotate | Download | only in net
      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:
     29   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:
     48   explicit FactoryForMain(const ProfileIOData* profile_io_data)
     49       : profile_io_data_(profile_io_data) {}
     50 
     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:
     62   explicit FactoryForExtensions(const ProfileIOData* profile_io_data)
     63       : profile_io_data_(profile_io_data) {}
     64 
     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:
     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 
     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:
     99   explicit FactoryForMedia(const ProfileIOData* profile_io_data)
    100       : profile_io_data_(profile_io_data) {
    101   }
    102 
    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 
    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 
    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.
    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 
    168 void ChromeURLRequestContextGetter::ReleaseURLRequestContext() {
    169   DCHECK(url_request_context_);
    170   url_request_context_ = NULL;
    171 }
    172 
    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>
    198 ChromeURLRequestContextGetter::GetIOMessageLoopProxy() const {
    199   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
    200 }
    201 
    202 // static
    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*
    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*
    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*
    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*
    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*
    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*
    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 
    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.
    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 
    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 
    338 void ChromeURLRequestContextGetter::OnAcceptLanguageChange(
    339     const std::string& accept_language) {
    340   GetIOContext()->OnAcceptLanguageChange(accept_language);
    341 }
    342 
    343 void ChromeURLRequestContextGetter::OnDefaultCharsetChange(
    344     const std::string& default_charset) {
    345   GetIOContext()->OnDefaultCharsetChange(default_charset);
    346 }
    347 
    348 void ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange(
    349     bool clear_site_data) {
    350   GetURLRequestContext()->cookie_store()->GetCookieMonster()->
    351       SetClearPersistentStoreOnExit(clear_site_data);
    352 }
    353 
    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 
    366 ChromeURLRequestContext::ChromeURLRequestContext()
    367     : is_incognito_(false) {
    368   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    369 }
    370 
    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*
    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 
    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 
    422 const std::string& ChromeURLRequestContext::GetUserAgent(
    423     const GURL& url) const {
    424   return webkit_glue::GetUserAgent(url);
    425 }
    426 
    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 
    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