| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/policy/core/common/cloud/device_management_service.h" | 5 #include "components/policy/core/common/cloud/device_management_service.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 namespace policy { | 27 namespace policy { |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 | 30 |
| 31 const char kPostContentType[] = "application/protobuf"; | 31 const char kPostContentType[] = "application/protobuf"; |
| 32 | 32 |
| 33 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth="; | 33 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth="; |
| 34 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token="; | 34 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token="; |
| 35 | 35 |
| 36 // Number of times to retry on ERR_NETWORK_CHANGED errors. | 36 // Number of times to retry on ERR_NETWORK_CHANGED errors. |
| 37 const int kMaxNetworkChangedRetries = 3; | 37 const int kMaxRetries = 3; |
| 38 | 38 |
| 39 // HTTP Error Codes of the DM Server with their concrete meanings in the context | 39 // HTTP Error Codes of the DM Server with their concrete meanings in the context |
| 40 // of the DM Server communication. | 40 // of the DM Server communication. |
| 41 const int kSuccess = 200; | 41 const int kSuccess = 200; |
| 42 const int kInvalidArgument = 400; | 42 const int kInvalidArgument = 400; |
| 43 const int kInvalidAuthCookieOrDMToken = 401; | 43 const int kInvalidAuthCookieOrDMToken = 401; |
| 44 const int kMissingLicenses = 402; | 44 const int kMissingLicenses = 402; |
| 45 const int kDeviceManagementNotAllowed = 403; | 45 const int kDeviceManagementNotAllowed = 403; |
| 46 const int kInvalidURL = 404; // This error is not coming from the GFE. | 46 const int kInvalidURL = 404; // This error is not coming from the GFE. |
| 47 const int kInvalidSerialNumber = 405; | 47 const int kInvalidSerialNumber = 405; |
| 48 const int kDomainMismatch = 406; | 48 const int kDomainMismatch = 406; |
| 49 const int kDeviceIdConflict = 409; | 49 const int kDeviceIdConflict = 409; |
| 50 const int kDeviceNotFound = 410; | 50 const int kDeviceNotFound = 410; |
| 51 const int kPendingApproval = 412; | 51 const int kPendingApproval = 412; |
| 52 const int kInternalServerError = 500; | 52 const int kInternalServerError = 500; |
| 53 const int kServiceUnavailable = 503; | 53 const int kServiceUnavailable = 503; |
| 54 const int kPolicyNotFound = 902; | 54 const int kPolicyNotFound = 902; |
| 55 const int kDeprovisioned = 903; | 55 const int kDeprovisioned = 903; |
| 56 | 56 |
| 57 // Delay after first unsuccessful upload attempt. After each additional failure, |
| 58 // the delay increases exponentially. Can be changed for testing to prevent |
| 59 // timeouts. |
| 60 long g_retry_delay_ms = 10000; |
| 61 |
| 57 bool IsProxyError(const net::URLRequestStatus status) { | 62 bool IsProxyError(const net::URLRequestStatus status) { |
| 58 switch (status.error()) { | 63 switch (status.error()) { |
| 59 case net::ERR_PROXY_CONNECTION_FAILED: | 64 case net::ERR_PROXY_CONNECTION_FAILED: |
| 60 case net::ERR_TUNNEL_CONNECTION_FAILED: | 65 case net::ERR_TUNNEL_CONNECTION_FAILED: |
| 61 case net::ERR_PROXY_AUTH_UNSUPPORTED: | 66 case net::ERR_PROXY_AUTH_UNSUPPORTED: |
| 62 case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE: | 67 case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE: |
| 63 case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED: | 68 case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED: |
| 64 case net::ERR_PROXY_CERTIFICATE_INVALID: | 69 case net::ERR_PROXY_CERTIFICATE_INVALID: |
| 65 case net::ERR_SOCKS_CONNECTION_FAILED: | 70 case net::ERR_SOCKS_CONNECTION_FAILED: |
| 66 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: | 71 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: |
| 67 return true; | 72 return true; |
| 68 } | 73 } |
| 69 return false; | 74 return false; |
| 70 } | 75 } |
| 71 | 76 |
| 77 bool IsConnectionError(const net::URLRequestStatus status) { |
| 78 switch (status.error()) { |
| 79 case net::ERR_NETWORK_CHANGED: |
| 80 case net::ERR_NAME_NOT_RESOLVED: |
| 81 case net::ERR_INTERNET_DISCONNECTED: |
| 82 case net::ERR_ADDRESS_UNREACHABLE: |
| 83 case net::ERR_CONNECTION_TIMED_OUT: |
| 84 case net::ERR_NAME_RESOLUTION_FAILED: |
| 85 return true; |
| 86 } |
| 87 return false; |
| 88 } |
| 89 |
| 72 bool IsProtobufMimeType(const net::URLFetcher* fetcher) { | 90 bool IsProtobufMimeType(const net::URLFetcher* fetcher) { |
| 73 return fetcher->GetResponseHeaders()->HasHeaderValue( | 91 return fetcher->GetResponseHeaders()->HasHeaderValue( |
| 74 "content-type", "application/x-protobuffer"); | 92 "content-type", "application/x-protobuffer"); |
| 75 } | 93 } |
| 76 | 94 |
| 77 bool FailedWithProxy(const net::URLFetcher* fetcher) { | 95 bool FailedWithProxy(const net::URLFetcher* fetcher) { |
| 78 if ((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0) { | 96 if ((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0) { |
| 79 // The request didn't use a proxy. | 97 // The request didn't use a proxy. |
| 80 return false; | 98 return false; |
| 81 } | 99 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 void ConfigureRequest(net::URLFetcher* fetcher); | 178 void ConfigureRequest(net::URLFetcher* fetcher); |
| 161 | 179 |
| 162 // Returns true if this job should be retried. |fetcher| has just completed, | 180 // Returns true if this job should be retried. |fetcher| has just completed, |
| 163 // and can be inspected to determine if the request failed and should be | 181 // and can be inspected to determine if the request failed and should be |
| 164 // retried. | 182 // retried. |
| 165 bool ShouldRetry(const net::URLFetcher* fetcher); | 183 bool ShouldRetry(const net::URLFetcher* fetcher); |
| 166 | 184 |
| 167 // Invoked right before retrying this job. | 185 // Invoked right before retrying this job. |
| 168 void PrepareRetry(); | 186 void PrepareRetry(); |
| 169 | 187 |
| 188 // Number of times that this job has been retried due to connection errors. |
| 189 int retries_count() { return retries_count_; } |
| 190 |
| 170 protected: | 191 protected: |
| 171 // DeviceManagementRequestJob: | 192 // DeviceManagementRequestJob: |
| 172 void Run() override; | 193 void Run() override; |
| 173 | 194 |
| 174 private: | 195 private: |
| 175 // Invokes the callback with the given error code. | 196 // Invokes the callback with the given error code. |
| 176 void ReportError(DeviceManagementStatus code); | 197 void ReportError(DeviceManagementStatus code); |
| 177 | 198 |
| 178 // Pointer to the service this job is associated with. | 199 // Pointer to the service this job is associated with. |
| 179 DeviceManagementService* service_; | 200 DeviceManagementService* service_; |
| 180 | 201 |
| 181 // Whether the BYPASS_PROXY flag should be set by ConfigureRequest(). | 202 // Whether the BYPASS_PROXY flag should be set by ConfigureRequest(). |
| 182 bool bypass_proxy_; | 203 bool bypass_proxy_; |
| 183 | 204 |
| 184 // Number of times that this job has been retried due to ERR_NETWORK_CHANGED. | 205 // Number of times that this job has been retried due to connection errors. |
| 185 int retries_count_; | 206 int retries_count_; |
| 186 | 207 |
| 187 // The request context to use for this job. | 208 // The request context to use for this job. |
| 188 scoped_refptr<net::URLRequestContextGetter> request_context_; | 209 scoped_refptr<net::URLRequestContextGetter> request_context_; |
| 189 | 210 |
| 190 DISALLOW_COPY_AND_ASSIGN(DeviceManagementRequestJobImpl); | 211 DISALLOW_COPY_AND_ASSIGN(DeviceManagementRequestJobImpl); |
| 191 }; | 212 }; |
| 192 | 213 |
| 193 DeviceManagementRequestJobImpl::DeviceManagementRequestJobImpl( | 214 DeviceManagementRequestJobImpl::DeviceManagementRequestJobImpl( |
| 194 JobType type, | 215 JobType type, |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 bool DeviceManagementRequestJobImpl::ShouldRetry( | 346 bool DeviceManagementRequestJobImpl::ShouldRetry( |
| 326 const net::URLFetcher* fetcher) { | 347 const net::URLFetcher* fetcher) { |
| 327 if (FailedWithProxy(fetcher) && !bypass_proxy_) { | 348 if (FailedWithProxy(fetcher) && !bypass_proxy_) { |
| 328 // Retry the job if it failed due to a broken proxy, by bypassing the | 349 // Retry the job if it failed due to a broken proxy, by bypassing the |
| 329 // proxy on the next try. | 350 // proxy on the next try. |
| 330 bypass_proxy_ = true; | 351 bypass_proxy_ = true; |
| 331 return true; | 352 return true; |
| 332 } | 353 } |
| 333 | 354 |
| 334 // Early device policy fetches on ChromeOS and Auto-Enrollment checks are | 355 // Early device policy fetches on ChromeOS and Auto-Enrollment checks are |
| 335 // often interrupted during ChromeOS startup when network change notifications | 356 // often interrupted during ChromeOS startup when network is not yet ready. |
| 336 // are sent. Allowing the fetcher to retry once after that is enough to | 357 // Allowing the fetcher to retry once after that is enough to recover; allow |
| 337 // recover; allow it to retry up to 3 times just in case. | 358 // it to retry up to 3 times just in case. |
| 338 if (fetcher->GetStatus().error() == net::ERR_NETWORK_CHANGED && | 359 if (IsConnectionError(fetcher->GetStatus()) && retries_count_ < kMaxRetries) { |
| 339 retries_count_ < kMaxNetworkChangedRetries) { | |
| 340 ++retries_count_; | 360 ++retries_count_; |
| 341 return true; | 361 return true; |
| 342 } | 362 } |
| 343 | 363 |
| 344 // The request didn't fail, or the limit of retry attempts has been reached; | 364 // The request didn't fail, or the limit of retry attempts has been reached; |
| 345 // forward the result to the job owner. | 365 // forward the result to the job owner. |
| 346 return false; | 366 return false; |
| 347 } | 367 } |
| 348 | 368 |
| 349 void DeviceManagementRequestJobImpl::PrepareRetry() { | 369 void DeviceManagementRequestJobImpl::PrepareRetry() { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 | 429 |
| 410 DeviceManagementService::~DeviceManagementService() { | 430 DeviceManagementService::~DeviceManagementService() { |
| 411 // All running jobs should have been cancelled by now. | 431 // All running jobs should have been cancelled by now. |
| 412 DCHECK(pending_jobs_.empty()); | 432 DCHECK(pending_jobs_.empty()); |
| 413 DCHECK(queued_jobs_.empty()); | 433 DCHECK(queued_jobs_.empty()); |
| 414 } | 434 } |
| 415 | 435 |
| 416 DeviceManagementRequestJob* DeviceManagementService::CreateJob( | 436 DeviceManagementRequestJob* DeviceManagementService::CreateJob( |
| 417 DeviceManagementRequestJob::JobType type, | 437 DeviceManagementRequestJob::JobType type, |
| 418 const scoped_refptr<net::URLRequestContextGetter>& request_context) { | 438 const scoped_refptr<net::URLRequestContextGetter>& request_context) { |
| 439 DCHECK(thread_checker_.CalledOnValidThread()); |
| 440 |
| 419 return new DeviceManagementRequestJobImpl( | 441 return new DeviceManagementRequestJobImpl( |
| 420 type, | 442 type, |
| 421 configuration_->GetAgentParameter(), | 443 configuration_->GetAgentParameter(), |
| 422 configuration_->GetPlatformParameter(), | 444 configuration_->GetPlatformParameter(), |
| 423 this, | 445 this, |
| 424 request_context); | 446 request_context); |
| 425 } | 447 } |
| 426 | 448 |
| 427 void DeviceManagementService::ScheduleInitialization( | 449 void DeviceManagementService::ScheduleInitialization( |
| 428 int64_t delay_milliseconds) { | 450 int64_t delay_milliseconds) { |
| 451 DCHECK(thread_checker_.CalledOnValidThread()); |
| 452 |
| 429 if (initialized_) | 453 if (initialized_) |
| 430 return; | 454 return; |
| 431 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 455 task_runner_->PostDelayedTask( |
| 432 FROM_HERE, base::Bind(&DeviceManagementService::Initialize, | 456 FROM_HERE, base::Bind(&DeviceManagementService::Initialize, |
| 433 weak_ptr_factory_.GetWeakPtr()), | 457 weak_ptr_factory_.GetWeakPtr()), |
| 434 base::TimeDelta::FromMilliseconds(delay_milliseconds)); | 458 base::TimeDelta::FromMilliseconds(delay_milliseconds)); |
| 435 } | 459 } |
| 436 | 460 |
| 437 void DeviceManagementService::Initialize() { | 461 void DeviceManagementService::Initialize() { |
| 462 DCHECK(thread_checker_.CalledOnValidThread()); |
| 438 if (initialized_) | 463 if (initialized_) |
| 439 return; | 464 return; |
| 440 initialized_ = true; | 465 initialized_ = true; |
| 441 | 466 |
| 442 while (!queued_jobs_.empty()) { | 467 while (!queued_jobs_.empty()) { |
| 443 StartJob(queued_jobs_.front()); | 468 StartJob(queued_jobs_.front()); |
| 444 queued_jobs_.pop_front(); | 469 queued_jobs_.pop_front(); |
| 445 } | 470 } |
| 446 } | 471 } |
| 447 | 472 |
| 448 void DeviceManagementService::Shutdown() { | 473 void DeviceManagementService::Shutdown() { |
| 474 DCHECK(thread_checker_.CalledOnValidThread()); |
| 475 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 449 for (JobFetcherMap::iterator job(pending_jobs_.begin()); | 476 for (JobFetcherMap::iterator job(pending_jobs_.begin()); |
| 450 job != pending_jobs_.end(); | 477 job != pending_jobs_.end(); |
| 451 ++job) { | 478 ++job) { |
| 452 delete job->first; | 479 delete job->first; |
| 453 queued_jobs_.push_back(job->second); | 480 queued_jobs_.push_back(job->second); |
| 454 } | 481 } |
| 455 pending_jobs_.clear(); | 482 pending_jobs_.clear(); |
| 456 } | 483 } |
| 457 | 484 |
| 458 DeviceManagementService::DeviceManagementService( | 485 DeviceManagementService::DeviceManagementService( |
| 459 std::unique_ptr<Configuration> configuration) | 486 std::unique_ptr<Configuration> configuration) |
| 460 : configuration_(std::move(configuration)), | 487 : configuration_(std::move(configuration)), |
| 461 initialized_(false), | 488 initialized_(false), |
| 489 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 462 weak_ptr_factory_(this) { | 490 weak_ptr_factory_(this) { |
| 463 DCHECK(configuration_); | 491 DCHECK(configuration_); |
| 464 } | 492 } |
| 465 | 493 |
| 466 void DeviceManagementService::StartJob(DeviceManagementRequestJobImpl* job) { | 494 void DeviceManagementService::StartJob(DeviceManagementRequestJobImpl* job) { |
| 495 DCHECK(thread_checker_.CalledOnValidThread()); |
| 496 |
| 467 std::string server_url = GetServerUrl(); | 497 std::string server_url = GetServerUrl(); |
| 468 net::URLFetcher* fetcher = | 498 net::URLFetcher* fetcher = |
| 469 net::URLFetcher::Create(kURLFetcherID, job->GetURL(server_url), | 499 net::URLFetcher::Create(kURLFetcherID, job->GetURL(server_url), |
| 470 net::URLFetcher::POST, this).release(); | 500 net::URLFetcher::POST, this).release(); |
| 471 data_use_measurement::DataUseUserData::AttachToFetcher( | 501 data_use_measurement::DataUseUserData::AttachToFetcher( |
| 472 fetcher, data_use_measurement::DataUseUserData::POLICY); | 502 fetcher, data_use_measurement::DataUseUserData::POLICY); |
| 473 job->ConfigureRequest(fetcher); | 503 job->ConfigureRequest(fetcher); |
| 474 pending_jobs_[fetcher] = job; | 504 pending_jobs_[fetcher] = job; |
| 475 fetcher->Start(); | 505 fetcher->Start(); |
| 476 } | 506 } |
| 477 | 507 |
| 478 std::string DeviceManagementService::GetServerUrl() { | 508 std::string DeviceManagementService::GetServerUrl() { |
| 509 DCHECK(thread_checker_.CalledOnValidThread()); |
| 479 return configuration_->GetServerUrl(); | 510 return configuration_->GetServerUrl(); |
| 480 } | 511 } |
| 481 | 512 |
| 513 // static |
| 514 void DeviceManagementService::SetRetryDelayForTesting(long retry_delay_ms) { |
| 515 CHECK_GE(retry_delay_ms, 0); |
| 516 g_retry_delay_ms = retry_delay_ms; |
| 517 } |
| 518 |
| 482 void DeviceManagementService::OnURLFetchComplete( | 519 void DeviceManagementService::OnURLFetchComplete( |
| 483 const net::URLFetcher* source) { | 520 const net::URLFetcher* source) { |
| 484 JobFetcherMap::iterator entry(pending_jobs_.find(source)); | 521 JobFetcherMap::iterator entry(pending_jobs_.find(source)); |
| 485 if (entry == pending_jobs_.end()) { | 522 if (entry == pending_jobs_.end()) { |
| 486 NOTREACHED() << "Callback from foreign URL fetcher"; | 523 NOTREACHED() << "Callback from foreign URL fetcher"; |
| 487 return; | 524 return; |
| 488 } | 525 } |
| 489 | 526 |
| 490 DeviceManagementRequestJobImpl* job = entry->second; | 527 DeviceManagementRequestJobImpl* job = entry->second; |
| 491 pending_jobs_.erase(entry); | 528 pending_jobs_.erase(entry); |
| 492 | 529 |
| 493 if (job->ShouldRetry(source)) { | 530 if (job->ShouldRetry(source)) { |
| 494 VLOG(1) << "Retrying dmserver request."; | |
| 495 job->PrepareRetry(); | 531 job->PrepareRetry(); |
| 496 StartJob(job); | 532 int delay = g_retry_delay_ms << (job->retries_count() - 1); |
| 533 LOG(WARNING) << "Dmserver request failed, retrying in " << delay / 1000 |
| 534 << "s."; |
| 535 task_runner_->PostDelayedTask( |
| 536 FROM_HERE, base::Bind(&DeviceManagementService::StartJob, |
| 537 weak_ptr_factory_.GetWeakPtr(), job), |
| 538 base::TimeDelta::FromMilliseconds(delay)); |
| 497 } else { | 539 } else { |
| 498 std::string data; | 540 std::string data; |
| 499 source->GetResponseAsString(&data); | 541 source->GetResponseAsString(&data); |
| 500 job->HandleResponse(source->GetStatus(), source->GetResponseCode(), | 542 job->HandleResponse(source->GetStatus(), source->GetResponseCode(), |
| 501 source->GetCookies(), data); | 543 source->GetCookies(), data); |
| 502 } | 544 } |
| 503 delete source; | 545 delete source; |
| 504 } | 546 } |
| 505 | 547 |
| 506 void DeviceManagementService::AddJob(DeviceManagementRequestJobImpl* job) { | 548 void DeviceManagementService::AddJob(DeviceManagementRequestJobImpl* job) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 521 } | 563 } |
| 522 } | 564 } |
| 523 | 565 |
| 524 const JobQueue::iterator elem = | 566 const JobQueue::iterator elem = |
| 525 std::find(queued_jobs_.begin(), queued_jobs_.end(), job); | 567 std::find(queued_jobs_.begin(), queued_jobs_.end(), job); |
| 526 if (elem != queued_jobs_.end()) | 568 if (elem != queued_jobs_.end()) |
| 527 queued_jobs_.erase(elem); | 569 queued_jobs_.erase(elem); |
| 528 } | 570 } |
| 529 | 571 |
| 530 } // namespace policy | 572 } // namespace policy |
| OLD | NEW |