15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/device_management_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
119ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
12b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/url_request/url_request_context_getter.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace em = enterprise_management;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPostContentType[] = "application/protobuf";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth=";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token=";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Number of times to retry on ERR_NETWORK_CHANGED errors.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaxNetworkChangedRetries = 3;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTTP Error Codes of the DM Server with their concrete meanings in the context
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the DM Server communication.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSuccess = 200;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInvalidArgument = 400;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInvalidAuthCookieOrDMToken = 401;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMissingLicenses = 402;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDeviceManagementNotAllowed = 403;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInvalidURL = 404;  // This error is not coming from the GFE.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInvalidSerialNumber = 405;
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst int kDomainMismatch = 406;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDeviceIdConflict = 409;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDeviceNotFound = 410;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kPendingApproval = 412;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInternalServerError = 500;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kServiceUnavailable = 503;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kPolicyNotFound = 902;
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kDeprovisioned = 903;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsProxyError(const net::URLRequestStatus status) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (status.error()) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_PROXY_CONNECTION_FAILED:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_TUNNEL_CONNECTION_FAILED:
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_PROXY_AUTH_UNSUPPORTED:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED:
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_PROXY_CERTIFICATE_INVALID:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_SOCKS_CONNECTION_FAILED:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsProtobufMimeType(const net::URLFetcher* fetcher) {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return fetcher->GetResponseHeaders()->HasHeaderValue(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "content-type", "application/x-protobuffer");
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FailedWithProxy(const net::URLFetcher* fetcher) {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0) {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The request didn't use a proxy.
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!fetcher->GetStatus().is_success() &&
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      IsProxyError(fetcher->GetStatus())) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Proxy failed while contacting dmserver.";
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (fetcher->GetStatus().is_success() &&
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fetcher->GetResponseCode() == kSuccess &&
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fetcher->WasFetchedViaProxy() &&
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !IsProtobufMimeType(fetcher)) {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The proxy server can be misconfigured but pointing to an existing
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // server that replies to requests. Try to recover if a successful
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // request that went through a proxy returns an unexpected mime type.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Got bad mime-type in response from dmserver that was "
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << "fetched via a proxy.";
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* UserAffiliationToString(UserAffiliation affiliation) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (affiliation) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case USER_AFFILIATION_MANAGED:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return dm_protocol::kValueUserAffiliationManaged;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case USER_AFFILIATION_NONE:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return dm_protocol::kValueUserAffiliationNone;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Invalid user affiliation " << affiliation;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dm_protocol::kValueUserAffiliationNone;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* JobTypeToRequestType(DeviceManagementRequestJob::JobType type) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return dm_protocol::kValueRequestAutoEnrollment;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DeviceManagementRequestJob::TYPE_REGISTRATION:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return dm_protocol::kValueRequestRegister;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DeviceManagementRequestJob::TYPE_POLICY_FETCH:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return dm_protocol::kValueRequestPolicy;
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH:
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return dm_protocol::kValueRequestApiAuthorization;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case DeviceManagementRequestJob::TYPE_UNREGISTRATION:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return dm_protocol::kValueRequestUnregister;
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE:
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return dm_protocol::kValueRequestUploadCertificate;
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL:
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return dm_protocol::kValueRequestDeviceStateRetrieval;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Invalid job type " << type;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return "";
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Request job implementation used with DeviceManagementService.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DeviceManagementRequestJobImpl : public DeviceManagementRequestJob {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DeviceManagementRequestJobImpl(
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      JobType type,
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& agent_parameter,
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& platform_parameter,
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      DeviceManagementService* service,
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const scoped_refptr<net::URLRequestContextGetter>& request_context);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~DeviceManagementRequestJobImpl();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handles the URL request response.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void HandleResponse(const net::URLRequestStatus& status,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      int response_code,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const net::ResponseCookies& cookies,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const std::string& data);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Gets the URL to contact.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL GetURL(const std::string& server_url);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Configures the fetcher, setting up payload and headers.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ConfigureRequest(net::URLFetcher* fetcher);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns true if this job should be retried. |fetcher| has just completed,
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and can be inspected to determine if the request failed and should be
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // retried.
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool ShouldRetry(const net::URLFetcher* fetcher);
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Invoked right before retrying this job.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void PrepareRetry();
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DeviceManagementRequestJob:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() OVERRIDE;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invokes the callback with the given error code.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReportError(DeviceManagementStatus code);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pointer to the service this job is associated with.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeviceManagementService* service_;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Whether the BYPASS_PROXY flag should be set by ConfigureRequest().
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bypass_proxy_;
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Number of times that this job has been retried due to ERR_NETWORK_CHANGED.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int retries_count_;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The request context to use for this job.
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<net::URLRequestContextGetter> request_context_;
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DeviceManagementRequestJobImpl);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeviceManagementRequestJobImpl::DeviceManagementRequestJobImpl(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JobType type,
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& agent_parameter,
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& platform_parameter,
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DeviceManagementService* service,
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<net::URLRequestContextGetter>& request_context)
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : DeviceManagementRequestJob(type, agent_parameter, platform_parameter),
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      service_(service),
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bypass_proxy_(false),
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      retries_count_(0),
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      request_context_(request_context) {
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeviceManagementRequestJobImpl::~DeviceManagementRequestJobImpl() {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_->RemoveJob(this);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJobImpl::Run() {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_->AddJob(this);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJobImpl::HandleResponse(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequestStatus& status,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int response_code,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::ResponseCookies& cookies,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.status() != net::URLRequestStatus::SUCCESS) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "DMServer request failed, status: " << status.status()
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << ", error: " << status.error();
218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    em::DeviceManagementResponse dummy_response;
219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    callback_.Run(DM_STATUS_REQUEST_FAILED, status.error(), dummy_response);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response_code != kSuccess)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "DMServer sent an error response: " << response_code;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (response_code) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kSuccess: {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      em::DeviceManagementResponse response;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!response.ParseFromString(data)) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ReportError(DM_STATUS_RESPONSE_DECODING_ERROR);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
233b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      callback_.Run(DM_STATUS_SUCCESS, net::OK, response);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kInvalidArgument:
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_REQUEST_INVALID);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kInvalidAuthCookieOrDMToken:
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kMissingLicenses:
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_MISSING_LICENSES);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kDeviceManagementNotAllowed:
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPendingApproval:
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_ACTIVATION_PENDING);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kInvalidURL:
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kInternalServerError:
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kServiceUnavailable:
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_TEMPORARY_UNAVAILABLE);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kDeviceNotFound:
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_DEVICE_NOT_FOUND);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kPolicyNotFound:
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_POLICY_NOT_FOUND);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kInvalidSerialNumber:
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
265effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case kDomainMismatch:
266effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ReportError(DM_STATUS_SERVICE_DOMAIN_MISMATCH);
267effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return;
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case kDeprovisioned:
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_DEPROVISIONED);
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kDeviceIdConflict:
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportError(DM_STATUS_SERVICE_DEVICE_ID_CONFLICT);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Handle all unknown 5xx HTTP error codes as temporary and any other
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // unknown error as one that needs more time to recover.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (response_code >= 500 && response_code <= 599)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ReportError(DM_STATUS_TEMPORARY_UNAVAILABLE);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ReportError(DM_STATUS_HTTP_STATUS_ERROR);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL DeviceManagementRequestJobImpl::GetURL(
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& server_url) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string result(server_url);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result += '?';
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ParameterMap::const_iterator entry(query_params_.begin());
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       entry != query_params_.end();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++entry) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry != query_params_.begin())
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result += '&';
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result += net::EscapeQueryParamValue(entry->first, true);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result += '=';
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result += net::EscapeQueryParamValue(entry->second, true);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GURL(result);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJobImpl::ConfigureRequest(
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLFetcher* fetcher) {
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(dcheng): It might make sense to make this take a const
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // scoped_refptr<T>& too eventually.
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  fetcher->SetRequestContext(request_context_.get());
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        net::LOAD_DO_NOT_SAVE_COOKIES |
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        net::LOAD_DISABLE_CACHE |
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        (bypass_proxy_ ? net::LOAD_BYPASS_PROXY : 0));
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string payload;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(request_.SerializeToString(&payload));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher->SetUploadData(kPostContentType, payload);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string extra_headers;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_token_.empty())
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra_headers += kServiceTokenAuthHeader + gaia_token_ + "\n";
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dm_token_.empty())
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra_headers += kDMTokenAuthHeader + dm_token_ + "\n";
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher->SetExtraRequestHeaders(extra_headers);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DeviceManagementRequestJobImpl::ShouldRetry(
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const net::URLFetcher* fetcher) {
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FailedWithProxy(fetcher) && !bypass_proxy_) {
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Retry the job if it failed due to a broken proxy, by bypassing the
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // proxy on the next try.
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bypass_proxy_ = true;
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Early device policy fetches on ChromeOS and Auto-Enrollment checks are
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // often interrupted during ChromeOS startup when network change notifications
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // are sent. Allowing the fetcher to retry once after that is enough to
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // recover; allow it to retry up to 3 times just in case.
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (fetcher->GetStatus().error() == net::ERR_NETWORK_CHANGED &&
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      retries_count_ < kMaxNetworkChangedRetries) {
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++retries_count_;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The request didn't fail, or the limit of retry attempts has been reached;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // forward the result to the job owner.
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DeviceManagementRequestJobImpl::PrepareRetry() {
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!retry_callback_.is_null())
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    retry_callback_.Run(this);
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJobImpl::ReportError(DeviceManagementStatus code) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  em::DeviceManagementResponse dummy_response;
352b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  callback_.Run(code, net::OK, dummy_response);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeviceManagementRequestJob::~DeviceManagementRequestJob() {}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJob::SetGaiaToken(const std::string& gaia_token) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gaia_token_ = gaia_token;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJob::SetOAuthToken(const std::string& oauth_token) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddParameter(dm_protocol::kParamOAuthToken, oauth_token);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJob::SetUserAffiliation(
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UserAffiliation user_affiliation) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddParameter(dm_protocol::kParamUserAffiliation,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               UserAffiliationToString(user_affiliation));
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJob::SetDMToken(const std::string& dm_token) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dm_token_ = dm_token;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJob::SetClientID(const std::string& client_id) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddParameter(dm_protocol::kParamDeviceID, client_id);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)em::DeviceManagementRequest* DeviceManagementRequestJob::GetRequest() {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &request_;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DeviceManagementRequestJob::DeviceManagementRequestJob(
3844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    JobType type,
3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& agent_parameter,
3864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& platform_parameter) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddParameter(dm_protocol::kParamRequest, JobTypeToRequestType(type));
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddParameter(dm_protocol::kParamDeviceType, dm_protocol::kValueDeviceType);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddParameter(dm_protocol::kParamAppType, dm_protocol::kValueAppType);
3904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddParameter(dm_protocol::kParamAgent, agent_parameter);
3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddParameter(dm_protocol::kParamPlatform, platform_parameter);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DeviceManagementRequestJob::SetRetryCallback(
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const RetryCallback& retry_callback) {
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  retry_callback_ = retry_callback;
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJob::Start(const Callback& callback) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_ = callback;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Run();
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementRequestJob::AddParameter(const std::string& name,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              const std::string& value) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query_params_.push_back(std::make_pair(name, value));
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A random value that other fetchers won't likely use.
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int DeviceManagementService::kURLFetcherID = 0xde71ce1d;
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeviceManagementService::~DeviceManagementService() {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All running jobs should have been cancelled by now.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pending_jobs_.empty());
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(queued_jobs_.empty());
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeviceManagementRequestJob* DeviceManagementService::CreateJob(
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DeviceManagementRequestJob::JobType type,
4201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<net::URLRequestContextGetter>& request_context) {
4214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return new DeviceManagementRequestJobImpl(
4224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      type,
4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      configuration_->GetAgentParameter(),
4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      configuration_->GetPlatformParameter(),
425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      this,
426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      request_context);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementService::ScheduleInitialization(int64 delay_milliseconds) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized_)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
43290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DeviceManagementService::Initialize,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()),
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(delay_milliseconds));
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementService::Initialize() {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized_)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialized_ = true;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!queued_jobs_.empty()) {
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartJob(queued_jobs_.front());
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    queued_jobs_.pop_front();
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementService::Shutdown() {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (JobFetcherMap::iterator job(pending_jobs_.begin());
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       job != pending_jobs_.end();
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++job) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete job->first;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    queued_jobs_.push_back(job->second);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_jobs_.clear();
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DeviceManagementService::DeviceManagementService(
461a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_ptr<Configuration> configuration)
4624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : configuration_(configuration.Pass()),
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      initialized_(false),
464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(configuration_);
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DeviceManagementService::StartJob(DeviceManagementRequestJobImpl* job) {
469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string server_url = GetServerUrl();
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::URLFetcher* fetcher = net::URLFetcher::Create(
4714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      kURLFetcherID, job->GetURL(server_url), net::URLFetcher::POST, this);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job->ConfigureRequest(fetcher);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_jobs_[fetcher] = job;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher->Start();
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::string DeviceManagementService::GetServerUrl() {
478a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return configuration_->GetServerUrl();
479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementService::OnURLFetchComplete(
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JobFetcherMap::iterator entry(pending_jobs_.find(source));
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry == pending_jobs_.end()) {
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Callback from foreign URL fetcher";
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeviceManagementRequestJobImpl* job = entry->second;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_jobs_.erase(entry);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (job->ShouldRetry(source)) {
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(1) << "Retrying dmserver request.";
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    job->PrepareRetry();
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartJob(job);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string data;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    source->GetResponseAsString(&data);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    job->HandleResponse(source->GetStatus(), source->GetResponseCode(),
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        source->GetCookies(), data);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete source;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementService::AddJob(DeviceManagementRequestJobImpl* job) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized_)
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartJob(job);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    queued_jobs_.push_back(job);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeviceManagementService::RemoveJob(DeviceManagementRequestJobImpl* job) {
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (JobFetcherMap::iterator entry(pending_jobs_.begin());
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       entry != pending_jobs_.end();
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++entry) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->second == job) {
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete entry->first;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_jobs_.erase(entry);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const JobQueue::iterator elem =
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(queued_jobs_.begin(), queued_jobs_.end(), job);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (elem != queued_jobs_.end())
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    queued_jobs_.erase(elem);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
530