| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/policy/device_management_service.h" |
| |
| #include "chrome/browser/io_thread.h" |
| #include "chrome/browser/net/chrome_net_log.h" |
| #include "chrome/browser/policy/device_management_backend_impl.h" |
| #include "content/browser/browser_thread.h" |
| #include "net/base/cookie_monster.h" |
| #include "net/base/host_resolver.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/ssl_config_service_defaults.h" |
| #include "net/http/http_auth_handler_factory.h" |
| #include "net/http/http_network_layer.h" |
| #include "net/proxy/proxy_service.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_context_getter.h" |
| #include "net/url_request/url_request_status.h" |
| #include "webkit/glue/webkit_glue.h" |
| |
| namespace policy { |
| |
| namespace { |
| |
| // Custom request context implementation that allows to override the user agent, |
| // amongst others. Wraps a baseline request context from which we reuse the |
| // networking components. |
| class DeviceManagementRequestContext : public net::URLRequestContext { |
| public: |
| explicit DeviceManagementRequestContext(net::URLRequestContext* base_context); |
| virtual ~DeviceManagementRequestContext(); |
| |
| private: |
| // Overridden from net::URLRequestContext: |
| virtual const std::string& GetUserAgent(const GURL& url) const; |
| }; |
| |
| DeviceManagementRequestContext::DeviceManagementRequestContext( |
| net::URLRequestContext* base_context) { |
| // Share resolver, proxy service and ssl bits with the baseline context. This |
| // is important so we don't make redundant requests (e.g. when resolving proxy |
| // auto configuration). |
| set_net_log(base_context->net_log()); |
| set_host_resolver(base_context->host_resolver()); |
| set_proxy_service(base_context->proxy_service()); |
| set_ssl_config_service(base_context->ssl_config_service()); |
| |
| // Share the http session. |
| set_http_transaction_factory( |
| new net::HttpNetworkLayer( |
| base_context->http_transaction_factory()->GetSession())); |
| |
| // No cookies, please. |
| set_cookie_store(new net::CookieMonster(NULL, NULL)); |
| |
| // Initialize these to sane values for our purposes. |
| set_accept_language("*"); |
| set_accept_charset("*"); |
| } |
| |
| DeviceManagementRequestContext::~DeviceManagementRequestContext() { |
| delete http_transaction_factory(); |
| } |
| |
| const std::string& DeviceManagementRequestContext::GetUserAgent( |
| const GURL& url) const { |
| return webkit_glue::GetUserAgent(url); |
| } |
| |
| // Request context holder. |
| class DeviceManagementRequestContextGetter |
| : public net::URLRequestContextGetter { |
| public: |
| DeviceManagementRequestContextGetter( |
| net::URLRequestContextGetter* base_context_getter) |
| : base_context_getter_(base_context_getter) {} |
| |
| // Overridden from net::URLRequestContextGetter: |
| virtual net::URLRequestContext* GetURLRequestContext(); |
| virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const; |
| |
| private: |
| scoped_refptr<net::URLRequestContext> context_; |
| scoped_refptr<net::URLRequestContextGetter> base_context_getter_; |
| }; |
| |
| |
| net::URLRequestContext* |
| DeviceManagementRequestContextGetter::GetURLRequestContext() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| if (!context_) { |
| context_ = new DeviceManagementRequestContext( |
| base_context_getter_->GetURLRequestContext()); |
| } |
| |
| return context_.get(); |
| } |
| |
| scoped_refptr<base::MessageLoopProxy> |
| DeviceManagementRequestContextGetter::GetIOMessageLoopProxy() const { |
| return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); |
| } |
| |
| } // namespace |
| |
| DeviceManagementService::~DeviceManagementService() { |
| // All running jobs should have been canceled by now. If not, there are |
| // backend objects still around, which is an error. |
| DCHECK(pending_jobs_.empty()); |
| DCHECK(queued_jobs_.empty()); |
| } |
| |
| DeviceManagementBackend* DeviceManagementService::CreateBackend() { |
| return new DeviceManagementBackendImpl(this); |
| } |
| |
| void DeviceManagementService::Initialize( |
| net::URLRequestContextGetter* request_context_getter) { |
| DCHECK(!request_context_getter_); |
| request_context_getter_ = |
| new DeviceManagementRequestContextGetter(request_context_getter); |
| while (!queued_jobs_.empty()) { |
| StartJob(queued_jobs_.front()); |
| queued_jobs_.pop_front(); |
| } |
| } |
| |
| void DeviceManagementService::Shutdown() { |
| for (JobFetcherMap::iterator job(pending_jobs_.begin()); |
| job != pending_jobs_.end(); |
| ++job) { |
| delete job->first; |
| queued_jobs_.push_back(job->second); |
| } |
| pending_jobs_.clear(); |
| } |
| |
| DeviceManagementService::DeviceManagementService( |
| const std::string& server_url) |
| : server_url_(server_url) { |
| } |
| |
| void DeviceManagementService::AddJob(DeviceManagementJob* job) { |
| if (request_context_getter_.get()) |
| StartJob(job); |
| else |
| queued_jobs_.push_back(job); |
| } |
| |
| void DeviceManagementService::RemoveJob(DeviceManagementJob* job) { |
| for (JobFetcherMap::iterator entry(pending_jobs_.begin()); |
| entry != pending_jobs_.end(); |
| ++entry) { |
| if (entry->second == job) { |
| delete entry->first; |
| pending_jobs_.erase(entry); |
| return; |
| } |
| } |
| |
| const JobQueue::iterator elem = |
| std::find(queued_jobs_.begin(), queued_jobs_.end(), job); |
| if (elem != queued_jobs_.end()) |
| queued_jobs_.erase(elem); |
| } |
| |
| void DeviceManagementService::StartJob(DeviceManagementJob* job) { |
| URLFetcher* fetcher = URLFetcher::Create(0, job->GetURL(server_url_), |
| URLFetcher::POST, this); |
| fetcher->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | |
| net::LOAD_DO_NOT_SAVE_COOKIES | |
| net::LOAD_DISABLE_CACHE); |
| fetcher->set_request_context(request_context_getter_.get()); |
| job->ConfigureRequest(fetcher); |
| pending_jobs_[fetcher] = job; |
| fetcher->Start(); |
| } |
| |
| void DeviceManagementService::OnURLFetchComplete( |
| const URLFetcher* source, |
| const GURL& url, |
| const net::URLRequestStatus& status, |
| int response_code, |
| const ResponseCookies& cookies, |
| const std::string& data) { |
| JobFetcherMap::iterator entry(pending_jobs_.find(source)); |
| if (entry != pending_jobs_.end()) { |
| DeviceManagementJob* job = entry->second; |
| pending_jobs_.erase(entry); |
| job->HandleResponse(status, response_code, cookies, data); |
| } else { |
| NOTREACHED() << "Callback from foreign URL fetcher"; |
| } |
| delete source; |
| } |
| |
| } // namespace policy |