Home | History | Annotate | Download | only in policy
      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/policy/device_management_service.h"
      6 
      7 #include "chrome/browser/io_thread.h"
      8 #include "chrome/browser/net/chrome_net_log.h"
      9 #include "chrome/browser/policy/device_management_backend_impl.h"
     10 #include "content/browser/browser_thread.h"
     11 #include "net/base/cookie_monster.h"
     12 #include "net/base/host_resolver.h"
     13 #include "net/base/load_flags.h"
     14 #include "net/base/ssl_config_service_defaults.h"
     15 #include "net/http/http_auth_handler_factory.h"
     16 #include "net/http/http_network_layer.h"
     17 #include "net/proxy/proxy_service.h"
     18 #include "net/url_request/url_request_context.h"
     19 #include "net/url_request/url_request_context_getter.h"
     20 #include "net/url_request/url_request_status.h"
     21 #include "webkit/glue/webkit_glue.h"
     22 
     23 namespace policy {
     24 
     25 namespace {
     26 
     27 // Custom request context implementation that allows to override the user agent,
     28 // amongst others. Wraps a baseline request context from which we reuse the
     29 // networking components.
     30 class DeviceManagementRequestContext : public net::URLRequestContext {
     31  public:
     32   explicit DeviceManagementRequestContext(net::URLRequestContext* base_context);
     33   virtual ~DeviceManagementRequestContext();
     34 
     35  private:
     36   // Overridden from net::URLRequestContext:
     37   virtual const std::string& GetUserAgent(const GURL& url) const;
     38 };
     39 
     40 DeviceManagementRequestContext::DeviceManagementRequestContext(
     41     net::URLRequestContext* base_context) {
     42   // Share resolver, proxy service and ssl bits with the baseline context. This
     43   // is important so we don't make redundant requests (e.g. when resolving proxy
     44   // auto configuration).
     45   set_net_log(base_context->net_log());
     46   set_host_resolver(base_context->host_resolver());
     47   set_proxy_service(base_context->proxy_service());
     48   set_ssl_config_service(base_context->ssl_config_service());
     49 
     50   // Share the http session.
     51   set_http_transaction_factory(
     52       new net::HttpNetworkLayer(
     53           base_context->http_transaction_factory()->GetSession()));
     54 
     55   // No cookies, please.
     56   set_cookie_store(new net::CookieMonster(NULL, NULL));
     57 
     58   // Initialize these to sane values for our purposes.
     59   set_accept_language("*");
     60   set_accept_charset("*");
     61 }
     62 
     63 DeviceManagementRequestContext::~DeviceManagementRequestContext() {
     64   delete http_transaction_factory();
     65 }
     66 
     67 const std::string& DeviceManagementRequestContext::GetUserAgent(
     68     const GURL& url) const {
     69   return webkit_glue::GetUserAgent(url);
     70 }
     71 
     72 // Request context holder.
     73 class DeviceManagementRequestContextGetter
     74     : public net::URLRequestContextGetter {
     75  public:
     76   DeviceManagementRequestContextGetter(
     77       net::URLRequestContextGetter* base_context_getter)
     78       : base_context_getter_(base_context_getter) {}
     79 
     80   // Overridden from net::URLRequestContextGetter:
     81   virtual net::URLRequestContext* GetURLRequestContext();
     82   virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const;
     83 
     84  private:
     85   scoped_refptr<net::URLRequestContext> context_;
     86   scoped_refptr<net::URLRequestContextGetter> base_context_getter_;
     87 };
     88 
     89 
     90 net::URLRequestContext*
     91 DeviceManagementRequestContextGetter::GetURLRequestContext() {
     92   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     93   if (!context_) {
     94     context_ = new DeviceManagementRequestContext(
     95         base_context_getter_->GetURLRequestContext());
     96   }
     97 
     98   return context_.get();
     99 }
    100 
    101 scoped_refptr<base::MessageLoopProxy>
    102 DeviceManagementRequestContextGetter::GetIOMessageLoopProxy() const {
    103   return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
    104 }
    105 
    106 }  // namespace
    107 
    108 DeviceManagementService::~DeviceManagementService() {
    109   // All running jobs should have been canceled by now. If not, there are
    110   // backend objects still around, which is an error.
    111   DCHECK(pending_jobs_.empty());
    112   DCHECK(queued_jobs_.empty());
    113 }
    114 
    115 DeviceManagementBackend* DeviceManagementService::CreateBackend() {
    116   return new DeviceManagementBackendImpl(this);
    117 }
    118 
    119 void DeviceManagementService::Initialize(
    120     net::URLRequestContextGetter* request_context_getter) {
    121   DCHECK(!request_context_getter_);
    122   request_context_getter_ =
    123       new DeviceManagementRequestContextGetter(request_context_getter);
    124   while (!queued_jobs_.empty()) {
    125     StartJob(queued_jobs_.front());
    126     queued_jobs_.pop_front();
    127   }
    128 }
    129 
    130 void DeviceManagementService::Shutdown() {
    131   for (JobFetcherMap::iterator job(pending_jobs_.begin());
    132        job != pending_jobs_.end();
    133        ++job) {
    134     delete job->first;
    135     queued_jobs_.push_back(job->second);
    136   }
    137   pending_jobs_.clear();
    138 }
    139 
    140 DeviceManagementService::DeviceManagementService(
    141     const std::string& server_url)
    142     : server_url_(server_url) {
    143 }
    144 
    145 void DeviceManagementService::AddJob(DeviceManagementJob* job) {
    146   if (request_context_getter_.get())
    147     StartJob(job);
    148   else
    149     queued_jobs_.push_back(job);
    150 }
    151 
    152 void DeviceManagementService::RemoveJob(DeviceManagementJob* job) {
    153   for (JobFetcherMap::iterator entry(pending_jobs_.begin());
    154        entry != pending_jobs_.end();
    155        ++entry) {
    156     if (entry->second == job) {
    157       delete entry->first;
    158       pending_jobs_.erase(entry);
    159       return;
    160     }
    161   }
    162 
    163   const JobQueue::iterator elem =
    164       std::find(queued_jobs_.begin(), queued_jobs_.end(), job);
    165   if (elem != queued_jobs_.end())
    166     queued_jobs_.erase(elem);
    167 }
    168 
    169 void DeviceManagementService::StartJob(DeviceManagementJob* job) {
    170   URLFetcher* fetcher = URLFetcher::Create(0, job->GetURL(server_url_),
    171                                            URLFetcher::POST, this);
    172   fetcher->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
    173                           net::LOAD_DO_NOT_SAVE_COOKIES |
    174                           net::LOAD_DISABLE_CACHE);
    175   fetcher->set_request_context(request_context_getter_.get());
    176   job->ConfigureRequest(fetcher);
    177   pending_jobs_[fetcher] = job;
    178   fetcher->Start();
    179 }
    180 
    181 void DeviceManagementService::OnURLFetchComplete(
    182     const URLFetcher* source,
    183     const GURL& url,
    184     const net::URLRequestStatus& status,
    185     int response_code,
    186     const ResponseCookies& cookies,
    187     const std::string& data) {
    188   JobFetcherMap::iterator entry(pending_jobs_.find(source));
    189   if (entry != pending_jobs_.end()) {
    190     DeviceManagementJob* job = entry->second;
    191     pending_jobs_.erase(entry);
    192     job->HandleResponse(status, response_code, cookies, data);
    193   } else {
    194     NOTREACHED() << "Callback from foreign URL fetcher";
    195   }
    196   delete source;
    197 }
    198 
    199 }  // namespace policy
    200