| Index: chrome/browser/policy/device_management_service.cc
 | 
| diff --git a/chrome/browser/policy/device_management_service.cc b/chrome/browser/policy/device_management_service.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..632c68c657ec72f11331fdb5ee69228a85708bf9
 | 
| --- /dev/null
 | 
| +++ b/chrome/browser/policy/device_management_service.cc
 | 
| @@ -0,0 +1,619 @@
 | 
| +// Copyright (c) 2010 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 <utility>
 | 
| +#include <set>
 | 
| +#include <vector>
 | 
| +
 | 
| +#include "base/command_line.h"
 | 
| +#include "base/lazy_instance.h"
 | 
| +#include "base/stl_util-inl.h"
 | 
| +#include "base/stringprintf.h"
 | 
| +#include "chrome/browser/browser_thread.h"
 | 
| +#include "chrome/common/chrome_switches.h"
 | 
| +#include "chrome/common/net/url_request_context_getter.h"
 | 
| +#include "net/base/cookie_monster.h"
 | 
| +#include "net/base/escape.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_status.h"
 | 
| +#include "chrome/browser/browser_process.h"
 | 
| +#include "chrome/browser/io_thread.h"
 | 
| +#include "chrome/browser/net/chrome_net_log.h"
 | 
| +#include "chrome/browser/profile.h"
 | 
| +#include "chrome/common/chrome_switches.h"
 | 
| +#include "chrome/common/chrome_version_info.h"
 | 
| +
 | 
| +namespace policy {
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +// Name constants for URL query parameters.
 | 
| +const char kServiceParamRequest[] = "request";
 | 
| +const char kServiceParamDeviceType[] = "devicetype";
 | 
| +const char kServiceParamDeviceID[] = "deviceid";
 | 
| +const char kServiceParamAgent[] = "agent";
 | 
| +
 | 
| +// String constants for the device type and agent we report to the service.
 | 
| +const char kServiceValueDeviceType[] = "Chrome";
 | 
| +const char kServiceValueAgent[] =
 | 
| +    "%s enterprise management client version %s (%s)";
 | 
| +
 | 
| +const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth=";
 | 
| +const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token=";
 | 
| +
 | 
| +// Helper class for URL query parameter encoding/decoding.
 | 
| +class URLQueryParameters {
 | 
| + public:
 | 
| +  URLQueryParameters() {}
 | 
| +
 | 
| +  // Add a query parameter.
 | 
| +  void Put(const std::string& name, const std::string& value);
 | 
| +
 | 
| +  // Produce the query string, taking care of properly encoding and assembling
 | 
| +  // the names and values.
 | 
| +  std::string Encode();
 | 
| +
 | 
| + private:
 | 
| +  typedef std::vector<std::pair<std::string, std::string> > ParameterMap;
 | 
| +  ParameterMap params_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(URLQueryParameters);
 | 
| +};
 | 
| +
 | 
| +void URLQueryParameters::Put(const std::string& name,
 | 
| +                             const std::string& value) {
 | 
| +  params_.push_back(std::make_pair(name, value));
 | 
| +}
 | 
| +
 | 
| +std::string URLQueryParameters::Encode() {
 | 
| +  std::string result;
 | 
| +  for (ParameterMap::const_iterator entry(params_.begin());
 | 
| +       entry != params_.end();
 | 
| +       ++entry) {
 | 
| +    if (entry != params_.begin())
 | 
| +      result += '&';
 | 
| +    result += EscapeUrlEncodedData(entry->first);
 | 
| +    result += '=';
 | 
| +    result += EscapeUrlEncodedData(entry->second);
 | 
| +  }
 | 
| +  return result;
 | 
| +}
 | 
| +
 | 
| +// 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 DeviceManagementBackendRequestContext : public URLRequestContext {
 | 
| + public:
 | 
| +  explicit DeviceManagementBackendRequestContext(
 | 
| +      URLRequestContext* base_context);
 | 
| +  virtual ~DeviceManagementBackendRequestContext();
 | 
| +
 | 
| + private:
 | 
| +  virtual const std::string& GetUserAgent(const GURL& url) const;
 | 
| +
 | 
| +  std::string user_agent_;
 | 
| +};
 | 
| +
 | 
| +DeviceManagementBackendRequestContext::DeviceManagementBackendRequestContext(
 | 
| +    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).
 | 
| +  net_log_ = base_context->net_log();
 | 
| +  host_resolver_ = base_context->host_resolver();
 | 
| +  proxy_service_ = base_context->proxy_service();
 | 
| +  ssl_config_service_ = base_context->ssl_config_service();
 | 
| +
 | 
| +  // Share the http session.
 | 
| +  http_transaction_factory_ = net::HttpNetworkLayer::CreateFactory(
 | 
| +      base_context->http_transaction_factory()->GetSession());
 | 
| +
 | 
| +  // No cookies, please.
 | 
| +  cookie_store_ = new net::CookieMonster(NULL, NULL);
 | 
| +
 | 
| +  // Initialize these to sane values for our purposes.
 | 
| +  user_agent_ = DeviceManagementService::GetAgentString();
 | 
| +  accept_language_ = "*";
 | 
| +  accept_charset_ = "*";
 | 
| +}
 | 
| +
 | 
| +DeviceManagementBackendRequestContext
 | 
| +    ::~DeviceManagementBackendRequestContext() {
 | 
| +  delete http_transaction_factory_;
 | 
| +  delete http_auth_handler_factory_;
 | 
| +}
 | 
| +
 | 
| +const std::string&
 | 
| +DeviceManagementBackendRequestContext::GetUserAgent(const GURL& url) const {
 | 
| +  return user_agent_;
 | 
| +}
 | 
| +
 | 
| +// Request context holder.
 | 
| +class DeviceManagementBackendRequestContextGetter
 | 
| +    : public URLRequestContextGetter {
 | 
| + public:
 | 
| +  DeviceManagementBackendRequestContextGetter(
 | 
| +      URLRequestContextGetter* base_context_getter)
 | 
| +      : base_context_getter_(base_context_getter) {}
 | 
| +
 | 
| +  // URLRequestContextGetter overrides.
 | 
| +  virtual URLRequestContext* GetURLRequestContext();
 | 
| +  virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const;
 | 
| +
 | 
| + private:
 | 
| +  scoped_refptr<URLRequestContext> context_;
 | 
| +  scoped_refptr<URLRequestContextGetter> base_context_getter_;
 | 
| +};
 | 
| +
 | 
| +
 | 
| +URLRequestContext*
 | 
| +DeviceManagementBackendRequestContextGetter::GetURLRequestContext() {
 | 
| +  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 | 
| +  if (!context_) {
 | 
| +    context_ = new DeviceManagementBackendRequestContext(
 | 
| +        base_context_getter_->GetURLRequestContext());
 | 
| +  }
 | 
| +
 | 
| +  return context_.get();
 | 
| +}
 | 
| +
 | 
| +scoped_refptr<base::MessageLoopProxy>
 | 
| +DeviceManagementBackendRequestContextGetter::GetIOMessageLoopProxy() const {
 | 
| +  return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +// A wrapper that implements the actual backend interface. This is separate from
 | 
| +// DeviceManagementService so the consumer can cancel all pending requests by
 | 
| +// destroying the backend object.
 | 
| +class DeviceManagementBackendProxy : public DeviceManagementBackend {
 | 
| + public:
 | 
| +  explicit DeviceManagementBackendProxy(DeviceManagementService* service);
 | 
| +  virtual ~DeviceManagementBackendProxy();
 | 
| +
 | 
| +  // Called by the DeviceManagementJob dtor so we can clean up.
 | 
| +  void JobDone(DeviceManagementJob* job);
 | 
| +
 | 
| + private:
 | 
| +  typedef std::set<DeviceManagementJob*> JobSet;
 | 
| +
 | 
| +  // Add a job to the pending job set and register it with the service (if
 | 
| +  // available).
 | 
| +  void AddJob(DeviceManagementJob* job);
 | 
| +
 | 
| +  // DeviceManagementBackend overrides.
 | 
| +  virtual void ProcessRegisterRequest(
 | 
| +      const std::string& auth_token,
 | 
| +      const std::string& device_id,
 | 
| +      const em::DeviceRegisterRequest& request,
 | 
| +      DeviceRegisterResponseDelegate* response_delegate);
 | 
| +  virtual void ProcessUnregisterRequest(
 | 
| +      const std::string& device_management_token,
 | 
| +      const em::DeviceUnregisterRequest& request,
 | 
| +      DeviceUnregisterResponseDelegate* response_delegate);
 | 
| +  virtual void ProcessPolicyRequest(
 | 
| +      const std::string& device_management_token,
 | 
| +      const em::DevicePolicyRequest& request,
 | 
| +      DevicePolicyResponseDelegate* response_delegate);
 | 
| +
 | 
| +  // Keeps track of the jobs currently in flight.
 | 
| +  JobSet pending_jobs_;
 | 
| +
 | 
| +  DeviceManagementService* service_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(DeviceManagementBackendProxy);
 | 
| +};
 | 
| +
 | 
| +// Represents a job run by the service. This contains the common code,
 | 
| +// subclasses provide custom code for actual register, unregister, and policy
 | 
| +// jobs.
 | 
| +class DeviceManagementJob {
 | 
| + public:
 | 
| +  virtual ~DeviceManagementJob() {
 | 
| +    proxy_->JobDone(this);
 | 
| +  }
 | 
| +
 | 
| +  // Handles the URL request response.
 | 
| +  void HandleResponse(const URLRequestStatus& status,
 | 
| +                      int response_code,
 | 
| +                      const ResponseCookies& cookies,
 | 
| +                      const std::string& data);
 | 
| +
 | 
| +  // Gets the URL to contact.
 | 
| +  GURL GetURL(const std::string& server_url);
 | 
| +
 | 
| +  // Configures the fetcher, setting up payload and headers.
 | 
| +  void ConfigureRequest(URLFetcher* fetcher);
 | 
| +
 | 
| + protected:
 | 
| +  // Constructs a device management job running for the given proxy.
 | 
| +  DeviceManagementJob(DeviceManagementBackendProxy* proxy,
 | 
| +                      const std::string& request_type)
 | 
| +      : proxy_(proxy) {
 | 
| +    query_params_.Put(kServiceParamRequest, request_type);
 | 
| +    query_params_.Put(kServiceParamDeviceType, kServiceValueDeviceType);
 | 
| +    query_params_.Put(kServiceParamAgent,
 | 
| +                      DeviceManagementService::GetAgentString());
 | 
| +  }
 | 
| +
 | 
| +  void SetQueryParam(const std::string& name, const std::string& value) {
 | 
| +    query_params_.Put(name, value);
 | 
| +  }
 | 
| +
 | 
| +  void SetAuthToken(const std::string& auth_token) {
 | 
| +    auth_token_ = auth_token;
 | 
| +  }
 | 
| +
 | 
| +  void SetDeviceManagementToken(const std::string& device_management_token) {
 | 
| +    device_management_token_ = device_management_token;
 | 
| +  }
 | 
| +
 | 
| +  void SetDeviceID(const std::string& device_id) {
 | 
| +    query_params_.Put(kServiceParamDeviceID, device_id);
 | 
| +  }
 | 
| +
 | 
| +  void SetPayload(const em::DeviceManagementRequest& request) {
 | 
| +    if (!request.SerializeToString(&payload_)) {
 | 
| +      NOTREACHED();
 | 
| +      LOG(ERROR) << "Failed to serialize request.";
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  // Implemented by subclasses to handle decoded responses and errors.
 | 
| +  virtual void ProcessResponse(
 | 
| +      const em::DeviceManagementResponse& response) = 0;
 | 
| +  virtual void ProcessError(DeviceManagementBackend::ErrorCode error) = 0;
 | 
| +
 | 
| +  // The proxy this job is handling a request for.
 | 
| +  DeviceManagementBackendProxy* proxy_;
 | 
| +
 | 
| +  // Query parameters.
 | 
| +  URLQueryParameters query_params_;
 | 
| +
 | 
| +  // Auth token (if applicaple).
 | 
| +  std::string auth_token_;
 | 
| +
 | 
| +  // Device management token (if applicable).
 | 
| +  std::string device_management_token_;
 | 
| +
 | 
| +  // The payload.
 | 
| +  std::string payload_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(DeviceManagementJob);
 | 
| +};
 | 
| +
 | 
| +void DeviceManagementJob::HandleResponse(const URLRequestStatus& status,
 | 
| +                                         int response_code,
 | 
| +                                         const ResponseCookies& cookies,
 | 
| +                                         const std::string& data) {
 | 
| +  // Delete ourselves when this is done.
 | 
| +  scoped_ptr<DeviceManagementJob> scoped_killer(this);
 | 
| +
 | 
| +  if (status.status() != URLRequestStatus::SUCCESS) {
 | 
| +    ProcessError(DeviceManagementBackend::kErrorRequestFailed);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  if (response_code != 200) {
 | 
| +    ProcessError(DeviceManagementBackend::kErrorHttpStatus);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  em::DeviceManagementResponse response;
 | 
| +  if (!response.ParseFromString(data)) {
 | 
| +    ProcessError(DeviceManagementBackend::kErrorResponseDecoding);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  // Check service error code.
 | 
| +  switch (response.error()) {
 | 
| +    case em::DeviceManagementResponse::SUCCESS:
 | 
| +      break;
 | 
| +    case em::DeviceManagementResponse::DEVICE_MANAGEMENT_NOT_SUPPORTED:
 | 
| +      ProcessError(
 | 
| +          DeviceManagementBackend::kErrorServiceManagementNotSupported);
 | 
| +      return;
 | 
| +    case em::DeviceManagementResponse::DEVICE_NOT_FOUND:
 | 
| +      ProcessError(DeviceManagementBackend::kErrorServiceDeviceNotFound);
 | 
| +      return;
 | 
| +    case em::DeviceManagementResponse::DEVICE_MANAGEMENT_TOKEN_INVALID:
 | 
| +      ProcessError(
 | 
| +          DeviceManagementBackend::kErrorServiceManagementTokenInvalid);
 | 
| +      return;
 | 
| +    case em::DeviceManagementResponse::ACTIVATION_PENDING:
 | 
| +      ProcessError(DeviceManagementBackend::kErrorServiceActivationPending);
 | 
| +      return;
 | 
| +    default:
 | 
| +      // This should be caught by the protobuf decoder.
 | 
| +      NOTREACHED();
 | 
| +      ProcessError(DeviceManagementBackend::kErrorResponseDecoding);
 | 
| +      return;
 | 
| +  }
 | 
| +
 | 
| +  ProcessResponse(response);
 | 
| +}
 | 
| +
 | 
| +GURL DeviceManagementJob::GetURL(const std::string& server_url) {
 | 
| +  return GURL(server_url + '?' + query_params_.Encode());
 | 
| +}
 | 
| +
 | 
| +void DeviceManagementJob::ConfigureRequest(URLFetcher* fetcher) {
 | 
| +  fetcher->set_upload_data("application/octet-stream", payload_);
 | 
| +  std::string extra_headers;
 | 
| +  if (!auth_token_.empty())
 | 
| +    extra_headers += kServiceTokenAuthHeader + auth_token_ + "\n";
 | 
| +  if (!device_management_token_.empty())
 | 
| +    extra_headers += kDMTokenAuthHeader + device_management_token_ + "\n";
 | 
| +  fetcher->set_extra_request_headers(extra_headers);
 | 
| +}
 | 
| +
 | 
| +// Handles device registration jobs.
 | 
| +class DeviceManagementRegisterJob : public DeviceManagementJob {
 | 
| + public:
 | 
| +  DeviceManagementRegisterJob(
 | 
| +      DeviceManagementBackendProxy* proxy,
 | 
| +      const std::string& auth_token,
 | 
| +      const std::string& device_id,
 | 
| +      const em::DeviceRegisterRequest& request,
 | 
| +      DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate);
 | 
| +  virtual ~DeviceManagementRegisterJob() {}
 | 
| +
 | 
| + private:
 | 
| +  // DeviceManagementJob overrides.
 | 
| +  virtual void ProcessError(DeviceManagementBackend::ErrorCode error) {
 | 
| +    delegate_->OnError(error);
 | 
| +  }
 | 
| +  virtual void ProcessResponse(const em::DeviceManagementResponse& response) {
 | 
| +    delegate_->HandleRegisterResponse(response.register_response());
 | 
| +  }
 | 
| +
 | 
| +  DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(DeviceManagementRegisterJob);
 | 
| +};
 | 
| +
 | 
| +DeviceManagementRegisterJob::DeviceManagementRegisterJob(
 | 
| +    DeviceManagementBackendProxy* proxy,
 | 
| +    const std::string& auth_token,
 | 
| +    const std::string& device_id,
 | 
| +    const em::DeviceRegisterRequest& request,
 | 
| +    DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate)
 | 
| +    : DeviceManagementJob(proxy, "register"),
 | 
| +      delegate_(delegate) {
 | 
| +  SetDeviceID(device_id);
 | 
| +  SetAuthToken(auth_token);
 | 
| +  em::DeviceManagementRequest request_wrapper;
 | 
| +  request_wrapper.mutable_register_request()->CopyFrom(request);
 | 
| +  SetPayload(request_wrapper);
 | 
| +}
 | 
| +
 | 
| +// Handles device unregistration jobs.
 | 
| +class DeviceManagementUnregisterJob : public DeviceManagementJob {
 | 
| + public:
 | 
| +  DeviceManagementUnregisterJob(
 | 
| +      DeviceManagementBackendProxy* proxy,
 | 
| +      const std::string& device_management_token,
 | 
| +      const em::DeviceUnregisterRequest& request,
 | 
| +      DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate);
 | 
| +  virtual ~DeviceManagementUnregisterJob() {}
 | 
| +
 | 
| + private:
 | 
| +  // DeviceManagementJob overrides.
 | 
| +  virtual void ProcessError(DeviceManagementBackend::ErrorCode error) {
 | 
| +    delegate_->OnError(error);
 | 
| +  }
 | 
| +  virtual void ProcessResponse(const em::DeviceManagementResponse& response) {
 | 
| +    delegate_->HandleUnregisterResponse(response.unregister_response());
 | 
| +  }
 | 
| +
 | 
| +  DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(DeviceManagementUnregisterJob);
 | 
| +};
 | 
| +
 | 
| +DeviceManagementUnregisterJob::DeviceManagementUnregisterJob(
 | 
| +    DeviceManagementBackendProxy* proxy,
 | 
| +    const std::string& device_management_token,
 | 
| +    const em::DeviceUnregisterRequest& request,
 | 
| +    DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate)
 | 
| +    : DeviceManagementJob(proxy, "unregister"),
 | 
| +      delegate_(delegate) {
 | 
| +  SetDeviceManagementToken(device_management_token);
 | 
| +  em::DeviceManagementRequest request_wrapper;
 | 
| +  request_wrapper.mutable_unregister_request()->CopyFrom(request);
 | 
| +  SetPayload(request_wrapper);
 | 
| +}
 | 
| +
 | 
| +// Handles policy request jobs.
 | 
| +class DeviceManagementPolicyJob : public DeviceManagementJob {
 | 
| + public:
 | 
| +  DeviceManagementPolicyJob(
 | 
| +      DeviceManagementBackendProxy* proxy,
 | 
| +      const std::string& device_management_token,
 | 
| +      const em::DevicePolicyRequest& request,
 | 
| +      DeviceManagementBackend::DevicePolicyResponseDelegate* delegate);
 | 
| +  virtual ~DeviceManagementPolicyJob() {}
 | 
| +
 | 
| + private:
 | 
| +  // DeviceManagementJob overrides.
 | 
| +  virtual void ProcessError(DeviceManagementBackend::ErrorCode error) {
 | 
| +    delegate_->OnError(error);
 | 
| +  }
 | 
| +  virtual void ProcessResponse(const em::DeviceManagementResponse& response) {
 | 
| +    delegate_->HandlePolicyResponse(response.policy_response());
 | 
| +  }
 | 
| +
 | 
| +  DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(DeviceManagementPolicyJob);
 | 
| +};
 | 
| +
 | 
| +DeviceManagementPolicyJob::DeviceManagementPolicyJob(
 | 
| +    DeviceManagementBackendProxy* proxy,
 | 
| +    const std::string& device_management_token,
 | 
| +    const em::DevicePolicyRequest& request,
 | 
| +    DeviceManagementBackend::DevicePolicyResponseDelegate* delegate)
 | 
| +    : DeviceManagementJob(proxy, "policy"),
 | 
| +      delegate_(delegate) {
 | 
| +  SetDeviceManagementToken(device_management_token);
 | 
| +  em::DeviceManagementRequest request_wrapper;
 | 
| +  request_wrapper.mutable_policy_request()->CopyFrom(request);
 | 
| +  SetPayload(request_wrapper);
 | 
| +}
 | 
| +
 | 
| +DeviceManagementBackendProxy::DeviceManagementBackendProxy(
 | 
| +    DeviceManagementService* service)
 | 
| +    : service_(service) {
 | 
| +}
 | 
| +
 | 
| +DeviceManagementBackendProxy::~DeviceManagementBackendProxy() {
 | 
| +  // Swap to a helper, so we don't interfere with the unregistration on delete.
 | 
| +  JobSet to_be_deleted;
 | 
| +  to_be_deleted.swap(pending_jobs_);
 | 
| +  for (JobSet::iterator job(to_be_deleted.begin());
 | 
| +       job != to_be_deleted.end();
 | 
| +       ++job) {
 | 
| +    service_->RemoveJob(*job);
 | 
| +    delete *job;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void DeviceManagementBackendProxy::JobDone(DeviceManagementJob* job) {
 | 
| +  pending_jobs_.erase(job);
 | 
| +}
 | 
| +
 | 
| +void DeviceManagementBackendProxy::AddJob(DeviceManagementJob* job) {
 | 
| +  pending_jobs_.insert(job);
 | 
| +  service_->AddJob(job);
 | 
| +}
 | 
| +
 | 
| +void DeviceManagementBackendProxy::ProcessRegisterRequest(
 | 
| +    const std::string& auth_token,
 | 
| +    const std::string& device_id,
 | 
| +    const em::DeviceRegisterRequest& request,
 | 
| +    DeviceRegisterResponseDelegate* delegate) {
 | 
| +  AddJob(new DeviceManagementRegisterJob(this, auth_token, device_id, request,
 | 
| +                                         delegate));
 | 
| +}
 | 
| +
 | 
| +void DeviceManagementBackendProxy::ProcessUnregisterRequest(
 | 
| +    const std::string& device_management_token,
 | 
| +    const em::DeviceUnregisterRequest& request,
 | 
| +    DeviceUnregisterResponseDelegate* delegate) {
 | 
| +  AddJob(new DeviceManagementUnregisterJob(this, device_management_token,
 | 
| +                                           request, delegate));
 | 
| +}
 | 
| +
 | 
| +void DeviceManagementBackendProxy::ProcessPolicyRequest(
 | 
| +    const std::string& device_management_token,
 | 
| +    const em::DevicePolicyRequest& request,
 | 
| +    DevicePolicyResponseDelegate* delegate) {
 | 
| +  AddJob(new DeviceManagementPolicyJob(this, device_management_token, request,
 | 
| +                                       delegate));
 | 
| +}
 | 
| +
 | 
| +DeviceManagementService::~DeviceManagementService() {
 | 
| +  // All running jobs should have been canceled by now. If not, there are proxy
 | 
| +  // objects still around, which is an error.
 | 
| +  DCHECK(pending_jobs_.empty());
 | 
| +  DCHECK(queued_jobs_.empty());
 | 
| +}
 | 
| +
 | 
| +DeviceManagementBackend* DeviceManagementService::CreateBackend() {
 | 
| +  return new DeviceManagementBackendProxy(this);
 | 
| +}
 | 
| +
 | 
| +void DeviceManagementService::Initialize(
 | 
| +    URLRequestContextGetter* request_context_getter) {
 | 
| +  DCHECK(!request_context_getter_);
 | 
| +  request_context_getter_ = 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);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +std::string DeviceManagementService::GetAgentString() {
 | 
| +  chrome::VersionInfo version_info;
 | 
| +  return base::StringPrintf(kServiceValueAgent,
 | 
| +                            version_info.Name().c_str(),
 | 
| +                            version_info.Version().c_str(),
 | 
| +                            version_info.LastChange().c_str());
 | 
| +}
 | 
| +
 | 
| +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);
 | 
| +      break;
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +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 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;
 | 
| +    job->HandleResponse(status, response_code, cookies, data);
 | 
| +    pending_jobs_.erase(entry);
 | 
| +  } else {
 | 
| +    NOTREACHED() << "Callback from foreign URL fetcher";
 | 
| +  }
 | 
| +  delete source;
 | 
| +}
 | 
| +
 | 
| +}  // namespace policy
 | 
| 
 |