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