Chromium Code Reviews| 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 "chrome/browser/policy/device_management_service.h" | 5 #include "chrome/browser/policy/device_management_service.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/compiler_specific.h" | |
| 8 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 9 #include "base/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
| 11 #include "base/stringprintf.h" | |
| 12 #include "base/sys_info.h" | |
| 10 #include "chrome/browser/browser_process.h" | 13 #include "chrome/browser/browser_process.h" |
| 11 #include "chrome/browser/net/chrome_net_log.h" | 14 #include "chrome/browser/net/chrome_net_log.h" |
| 12 #include "chrome/browser/policy/device_management_backend.h" | 15 #include "chrome/browser/policy/device_management_backend.h" |
| 13 #include "chrome/browser/policy/device_management_backend_impl.h" | 16 #include "chrome/browser/policy/device_management_backend_impl.h" |
| 17 #include "chrome/common/chrome_version_info.h" | |
| 14 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 15 #include "content/public/common/content_client.h" | 19 #include "content/public/common/content_client.h" |
| 16 #include "content/public/common/url_fetcher.h" | 20 #include "content/public/common/url_fetcher.h" |
| 21 #include "content/public/common/url_fetcher.h" | |
|
Joao da Silva
2012/01/02 16:14:43
Nit: don't include twice
Mattias Nissler (ping if slow)
2012/01/02 17:53:23
Done.
| |
| 17 #include "net/base/cookie_monster.h" | 22 #include "net/base/cookie_monster.h" |
| 23 #include "net/base/escape.h" | |
| 18 #include "net/base/host_resolver.h" | 24 #include "net/base/host_resolver.h" |
| 19 #include "net/base/load_flags.h" | 25 #include "net/base/load_flags.h" |
| 20 #include "net/base/net_errors.h" | 26 #include "net/base/net_errors.h" |
| 21 #include "net/base/ssl_config_service_defaults.h" | 27 #include "net/base/ssl_config_service_defaults.h" |
| 22 #include "net/http/http_network_layer.h" | 28 #include "net/http/http_network_layer.h" |
| 23 #include "net/http/http_response_headers.h" | 29 #include "net/http/http_response_headers.h" |
| 24 #include "net/proxy/proxy_service.h" | 30 #include "net/proxy/proxy_service.h" |
| 25 #include "net/url_request/url_request_context.h" | 31 #include "net/url_request/url_request_context.h" |
| 26 #include "net/url_request/url_request_context_getter.h" | 32 #include "net/url_request/url_request_context_getter.h" |
| 27 #include "net/url_request/url_request_status.h" | 33 #include "net/url_request/url_request_status.h" |
| 34 #include "net/url_request/url_request_status.h" | |
|
Joao da Silva
2012/01/02 16:14:43
Nit: don't include twice
Mattias Nissler (ping if slow)
2012/01/02 17:53:23
Done.
| |
| 35 | |
| 36 #if defined(OS_CHROMEOS) | |
| 37 #include "chrome/browser/chromeos/system/statistics_provider.h" | |
| 38 #endif | |
| 28 | 39 |
| 29 using content::BrowserThread; | 40 using content::BrowserThread; |
| 30 | 41 |
| 31 namespace em = enterprise_management; | 42 namespace em = enterprise_management; |
| 32 | 43 |
| 33 namespace policy { | 44 namespace policy { |
| 34 | 45 |
| 35 namespace { | 46 namespace { |
| 36 | 47 |
| 48 const char kValueAgent[] = "%s %s(%s)"; | |
| 49 const char kValuePlatform[] = "%s|%s|%s"; | |
| 50 | |
| 51 const char kPostContentType[] = "application/protobuf"; | |
| 52 | |
| 53 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth="; | |
| 54 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token="; | |
| 55 | |
| 56 // HTTP Error Codes of the DM Server with their concrete meanings in the context | |
| 57 // of the DM Server communication. | |
| 58 const int kSuccess = 200; | |
| 59 const int kInvalidArgument = 400; | |
| 60 const int kInvalidAuthCookieOrDMToken = 401; | |
| 61 const int kDeviceManagementNotAllowed = 403; | |
| 62 const int kInvalidURL = 404; // This error is not coming from the GFE. | |
| 63 const int kInvalidSerialNumber = 405; | |
| 64 const int kDeviceIdConflict = 409; | |
| 65 const int kDeviceNotFound = 410; | |
| 66 const int kPendingApproval = 412; | |
| 67 const int kInternalServerError = 500; | |
| 68 const int kServiceUnavailable = 503; | |
| 69 const int kPolicyNotFound = 902; // This error is not sent as HTTP status code. | |
| 70 | |
| 71 // TODO(pastarmovj): Legacy error codes are here for compatibility only. They | |
| 72 // should be removed once the DM Server has been updated. | |
| 73 const int kPendingApprovalLegacy = 491; | |
| 74 const int kDeviceNotFoundLegacy = 901; | |
| 75 | |
| 76 #if defined(OS_CHROMEOS) | |
| 77 // Machine info keys. | |
| 78 const char kMachineInfoHWClass[] = "hardware_class"; | |
| 79 const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD"; | |
| 80 #endif | |
| 81 | |
| 37 bool IsProxyError(const net::URLRequestStatus status) { | 82 bool IsProxyError(const net::URLRequestStatus status) { |
| 38 switch (status.error()) { | 83 switch (status.error()) { |
| 39 case net::ERR_PROXY_CONNECTION_FAILED: | 84 case net::ERR_PROXY_CONNECTION_FAILED: |
| 40 case net::ERR_TUNNEL_CONNECTION_FAILED: | 85 case net::ERR_TUNNEL_CONNECTION_FAILED: |
| 41 case net::ERR_PROXY_AUTH_UNSUPPORTED: | 86 case net::ERR_PROXY_AUTH_UNSUPPORTED: |
| 42 case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE: | 87 case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE: |
| 43 case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED: | 88 case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED: |
| 44 case net::ERR_PROXY_CERTIFICATE_INVALID: | 89 case net::ERR_PROXY_CERTIFICATE_INVALID: |
| 45 case net::ERR_SOCKS_CONNECTION_FAILED: | 90 case net::ERR_SOCKS_CONNECTION_FAILED: |
| 46 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: | 91 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: |
| 47 return true; | 92 return true; |
| 48 } | 93 } |
| 49 return false; | 94 return false; |
| 50 } | 95 } |
| 51 | 96 |
| 52 bool IsProtobufMimeType(const content::URLFetcher* source) { | 97 bool IsProtobufMimeType(const content::URLFetcher* source) { |
| 53 return source->GetResponseHeaders()->HasHeaderValue( | 98 return source->GetResponseHeaders()->HasHeaderValue( |
| 54 "content-type", "application/x-protobuffer"); | 99 "content-type", "application/x-protobuffer"); |
| 55 } | 100 } |
| 56 | 101 |
| 102 const char* UserAffiliationToString(UserAffiliation affiliation) { | |
| 103 switch (affiliation) { | |
| 104 case USER_AFFILIATION_MANAGED: | |
| 105 return dm_protocol::kValueUserAffiliationManaged; | |
| 106 case USER_AFFILIATION_NONE: | |
| 107 return dm_protocol::kValueUserAffiliationNone; | |
| 108 } | |
| 109 NOTREACHED() << "Invalid user affiliation " << affiliation; | |
| 110 return dm_protocol::kValueUserAffiliationNone; | |
| 111 } | |
| 112 | |
| 113 const char* JobTypeToRequestType(DeviceManagementRequestJob::JobType type) { | |
| 114 switch (type) { | |
| 115 case DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT: | |
| 116 return dm_protocol::kValueRequestAutoEnrollment; | |
| 117 case DeviceManagementRequestJob::TYPE_REGISTRATION: | |
| 118 return dm_protocol::kValueRequestRegister; | |
| 119 case DeviceManagementRequestJob::TYPE_POLICY_FETCH: | |
| 120 return dm_protocol::kValueRequestPolicy; | |
| 121 case DeviceManagementRequestJob::TYPE_UNREGISTRATION: | |
| 122 return dm_protocol::kValueRequestUnregister; | |
| 123 } | |
| 124 NOTREACHED() << "Invalid job type " << type; | |
| 125 return ""; | |
| 126 } | |
| 127 | |
| 128 const std::string& GetAgentString() { | |
| 129 CR_DEFINE_STATIC_LOCAL(std::string, agent, ()); | |
| 130 if (!agent.empty()) | |
| 131 return agent; | |
| 132 | |
| 133 chrome::VersionInfo version_info; | |
| 134 agent = base::StringPrintf(kValueAgent, | |
| 135 version_info.Name().c_str(), | |
| 136 version_info.Version().c_str(), | |
| 137 version_info.LastChange().c_str()); | |
| 138 return agent; | |
| 139 } | |
| 140 | |
| 141 const std::string& GetPlatformString() { | |
| 142 CR_DEFINE_STATIC_LOCAL(std::string, platform, ()); | |
| 143 if (!platform.empty()) | |
| 144 return platform; | |
| 145 | |
| 146 std::string os_name(base::SysInfo::OperatingSystemName()); | |
| 147 std::string os_hardware(base::SysInfo::CPUArchitecture()); | |
| 148 | |
| 149 #if defined(OS_CHROMEOS) | |
| 150 chromeos::system::StatisticsProvider* provider = | |
| 151 chromeos::system::StatisticsProvider::GetInstance(); | |
| 152 | |
| 153 std::string hwclass; | |
| 154 std::string board; | |
| 155 if (!provider->GetMachineStatistic(kMachineInfoHWClass, &hwclass) || | |
| 156 !provider->GetMachineStatistic(kMachineInfoBoard, &board)) { | |
| 157 LOG(ERROR) << "Failed to get machine information"; | |
| 158 } | |
| 159 os_name += ",CrOS," + board; | |
| 160 os_hardware += "," + hwclass; | |
| 161 #endif | |
| 162 | |
| 163 std::string os_version("-"); | |
| 164 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) | |
| 165 int32 os_major_version = 0; | |
| 166 int32 os_minor_version = 0; | |
| 167 int32 os_bugfix_version = 0; | |
| 168 base::SysInfo::OperatingSystemVersionNumbers(&os_major_version, | |
| 169 &os_minor_version, | |
| 170 &os_bugfix_version); | |
| 171 os_version = base::StringPrintf("%d.%d.%d", | |
| 172 os_major_version, | |
| 173 os_minor_version, | |
| 174 os_bugfix_version); | |
| 175 #endif | |
| 176 | |
| 177 platform = base::StringPrintf(kValuePlatform, | |
| 178 os_name.c_str(), | |
| 179 os_hardware.c_str(), | |
| 180 os_version.c_str()); | |
| 181 return platform; | |
| 182 } | |
| 183 | |
| 57 // Custom request context implementation that allows to override the user agent, | 184 // Custom request context implementation that allows to override the user agent, |
| 58 // amongst others. Wraps a baseline request context from which we reuse the | 185 // amongst others. Wraps a baseline request context from which we reuse the |
| 59 // networking components. | 186 // networking components. |
| 60 class DeviceManagementRequestContext : public net::URLRequestContext { | 187 class DeviceManagementRequestContext : public net::URLRequestContext { |
| 61 public: | 188 public: |
| 62 explicit DeviceManagementRequestContext(net::URLRequestContext* base_context); | 189 explicit DeviceManagementRequestContext(net::URLRequestContext* base_context); |
| 63 virtual ~DeviceManagementRequestContext(); | 190 virtual ~DeviceManagementRequestContext(); |
| 64 | 191 |
| 65 private: | 192 private: |
| 66 // Overridden from net::URLRequestContext: | 193 // Overridden from net::URLRequestContext: |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 129 return context_.get(); | 256 return context_.get(); |
| 130 } | 257 } |
| 131 | 258 |
| 132 scoped_refptr<base::MessageLoopProxy> | 259 scoped_refptr<base::MessageLoopProxy> |
| 133 DeviceManagementRequestContextGetter::GetIOMessageLoopProxy() const { | 260 DeviceManagementRequestContextGetter::GetIOMessageLoopProxy() const { |
| 134 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); | 261 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); |
| 135 } | 262 } |
| 136 | 263 |
| 137 } // namespace | 264 } // namespace |
| 138 | 265 |
| 266 // Request job implementation used with DeviceManagementService. | |
| 267 class DeviceManagementRequestJobImpl : public DeviceManagementRequestJob { | |
| 268 public: | |
| 269 DeviceManagementRequestJobImpl(JobType type, | |
| 270 DeviceManagementService* service); | |
| 271 virtual ~DeviceManagementRequestJobImpl(); | |
| 272 | |
| 273 // Handles the URL request response. | |
| 274 void HandleResponse(const net::URLRequestStatus& status, | |
| 275 int response_code, | |
| 276 const net::ResponseCookies& cookies, | |
| 277 const std::string& data); | |
| 278 | |
| 279 // Gets the URL to contact. | |
| 280 GURL GetURL(const std::string& server_url); | |
| 281 | |
| 282 // Configures the fetcher, setting up payload and headers. | |
| 283 void ConfigureRequest(content::URLFetcher* fetcher); | |
| 284 | |
| 285 protected: | |
| 286 // DeviceManagementRequestJob: | |
| 287 virtual void Run() OVERRIDE; | |
| 288 | |
| 289 private: | |
| 290 // Invokes the callback with the given error code. | |
| 291 void ReportError(DeviceManagementStatus code); | |
| 292 | |
| 293 // Pointer to the service this job is associated with. | |
| 294 DeviceManagementService* service_; | |
| 295 | |
| 296 DISALLOW_COPY_AND_ASSIGN(DeviceManagementRequestJobImpl); | |
| 297 }; | |
| 298 | |
| 299 DeviceManagementRequestJobImpl::DeviceManagementRequestJobImpl( | |
| 300 JobType type, | |
| 301 DeviceManagementService* service) | |
| 302 : DeviceManagementRequestJob(type), | |
| 303 service_(service) {} | |
| 304 | |
| 305 DeviceManagementRequestJobImpl::~DeviceManagementRequestJobImpl() { | |
| 306 service_->RemoveJob(this); | |
| 307 } | |
| 308 | |
| 309 void DeviceManagementRequestJobImpl::Run() { | |
| 310 service_->AddJob(this); | |
| 311 } | |
| 312 | |
| 313 void DeviceManagementRequestJobImpl::HandleResponse( | |
| 314 const net::URLRequestStatus& status, | |
| 315 int response_code, | |
| 316 const net::ResponseCookies& cookies, | |
| 317 const std::string& data) { | |
| 318 if (status.status() != net::URLRequestStatus::SUCCESS) { | |
| 319 ReportError(DM_STATUS_REQUEST_FAILED); | |
| 320 return; | |
| 321 } | |
| 322 | |
| 323 switch (response_code) { | |
| 324 case kSuccess: { | |
| 325 em::DeviceManagementResponse response; | |
| 326 if (!response.ParseFromString(data)) { | |
| 327 ReportError(DM_STATUS_RESPONSE_DECODING_ERROR); | |
| 328 return; | |
| 329 } | |
| 330 callback_.Run(DM_STATUS_SUCCESS, response); | |
| 331 return; | |
| 332 } | |
| 333 case kInvalidArgument: { | |
| 334 ReportError(DM_STATUS_REQUEST_INVALID); | |
| 335 return; | |
| 336 } | |
| 337 case kInvalidAuthCookieOrDMToken: { | |
| 338 ReportError(DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID); | |
| 339 return; | |
| 340 } | |
| 341 case kDeviceManagementNotAllowed: { | |
| 342 ReportError(DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED); | |
| 343 return; | |
| 344 } | |
| 345 case kPendingApprovalLegacy: | |
| 346 case kPendingApproval: { | |
| 347 ReportError(DM_STATUS_SERVICE_ACTIVATION_PENDING); | |
| 348 return; | |
| 349 } | |
| 350 case kInvalidURL: | |
| 351 case kInternalServerError: | |
| 352 case kServiceUnavailable: { | |
| 353 ReportError(DM_STATUS_TEMPORARY_UNAVAILABLE); | |
| 354 return; | |
| 355 } | |
| 356 case kDeviceNotFoundLegacy: | |
| 357 case kDeviceNotFound: { | |
| 358 ReportError(DM_STATUS_SERVICE_DEVICE_NOT_FOUND); | |
| 359 return; | |
| 360 } | |
| 361 case kPolicyNotFound: { | |
| 362 ReportError(DM_STATUS_SERVICE_POLICY_NOT_FOUND); | |
| 363 break; | |
|
Joao da Silva
2012/01/02 16:14:43
Some cases return and some break; please use the s
Mattias Nissler (ping if slow)
2012/01/02 17:53:23
Switched break to return. I don't mind either way
| |
| 364 } | |
| 365 case kInvalidSerialNumber: { | |
| 366 ReportError(DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER); | |
| 367 break; | |
| 368 } | |
| 369 case kDeviceIdConflict: { | |
| 370 ReportError(DM_STATUS_SERVICE_DEVICE_ID_CONFLICT); | |
| 371 break; | |
| 372 } | |
| 373 default: { | |
| 374 VLOG(1) << "Unexpected HTTP status in response from DMServer : " | |
| 375 << response_code << "."; | |
| 376 // Handle all unknown 5xx HTTP error codes as temporary and any other | |
| 377 // unknown error as one that needs more time to recover. | |
| 378 if (response_code >= 500 && response_code <= 599) | |
| 379 ReportError(DM_STATUS_TEMPORARY_UNAVAILABLE); | |
| 380 else | |
| 381 ReportError(DM_STATUS_HTTP_STATUS_ERROR); | |
| 382 return; | |
| 383 } | |
| 384 } | |
| 385 } | |
| 386 | |
| 387 GURL DeviceManagementRequestJobImpl::GetURL( | |
| 388 const std::string& server_url) { | |
| 389 std::string result(server_url); | |
| 390 result += '?'; | |
| 391 for (ParameterMap::const_iterator entry(query_params_.begin()); | |
| 392 entry != query_params_.end(); | |
| 393 ++entry) { | |
| 394 if (entry != query_params_.begin()) | |
| 395 result += '&'; | |
| 396 result += net::EscapeQueryParamValue(entry->first, true); | |
| 397 result += '='; | |
| 398 result += net::EscapeQueryParamValue(entry->second, true); | |
| 399 } | |
| 400 return GURL(result); | |
| 401 } | |
| 402 | |
| 403 void DeviceManagementRequestJobImpl::ConfigureRequest( | |
| 404 content::URLFetcher* fetcher) { | |
| 405 std::string payload; | |
| 406 CHECK(request_.SerializeToString(&payload)); | |
| 407 fetcher->SetUploadData(kPostContentType, payload); | |
| 408 std::string extra_headers; | |
| 409 if (!gaia_token_.empty()) | |
| 410 extra_headers += kServiceTokenAuthHeader + gaia_token_ + "\n"; | |
| 411 if (!dm_token_.empty()) | |
| 412 extra_headers += kDMTokenAuthHeader + dm_token_ + "\n"; | |
| 413 fetcher->SetExtraRequestHeaders(extra_headers); | |
| 414 } | |
| 415 | |
| 416 void DeviceManagementRequestJobImpl::ReportError(DeviceManagementStatus code) { | |
| 417 em::DeviceManagementResponse dummy_response; | |
| 418 callback_.Run(code, dummy_response); | |
| 419 } | |
| 420 | |
| 421 DeviceManagementRequestJob::~DeviceManagementRequestJob() {} | |
| 422 | |
| 423 void DeviceManagementRequestJob::SetGaiaToken(const std::string& gaia_token) { | |
| 424 gaia_token_ = gaia_token; | |
| 425 } | |
| 426 | |
| 427 void DeviceManagementRequestJob::SetOAuthToken(const std::string& oauth_token) { | |
| 428 query_params_[dm_protocol::kParamOAuthToken] = oauth_token; | |
| 429 } | |
| 430 | |
| 431 void DeviceManagementRequestJob::SetUserAffiliation( | |
| 432 UserAffiliation user_affiliation) { | |
| 433 query_params_[dm_protocol::kParamUserAffiliation] = | |
| 434 UserAffiliationToString(user_affiliation); | |
| 435 } | |
| 436 | |
| 437 void DeviceManagementRequestJob::SetDMToken(const std::string& dm_token) { | |
| 438 dm_token_ = dm_token; | |
| 439 } | |
| 440 | |
| 441 void DeviceManagementRequestJob::SetClientID(const std::string& client_id) { | |
| 442 query_params_[dm_protocol::kParamDeviceID] = client_id; | |
| 443 } | |
| 444 | |
| 445 em::DeviceManagementRequest* DeviceManagementRequestJob::GetRequest() { | |
| 446 return &request_; | |
| 447 } | |
| 448 | |
| 449 DeviceManagementRequestJob::DeviceManagementRequestJob(JobType type) { | |
| 450 query_params_[dm_protocol::kParamRequest] = JobTypeToRequestType(type); | |
| 451 query_params_[dm_protocol::kParamDeviceType] = dm_protocol::kValueDeviceType; | |
| 452 query_params_[dm_protocol::kParamAppType] = dm_protocol::kValueAppType; | |
| 453 query_params_[dm_protocol::kParamAgent] = GetAgentString(); | |
| 454 query_params_[dm_protocol::kParamPlatform] = GetPlatformString(); | |
| 455 } | |
| 456 | |
| 457 void DeviceManagementRequestJob::Start(const Callback& callback) { | |
| 458 callback_ = callback; | |
| 459 Run(); | |
| 460 } | |
| 461 | |
| 139 DeviceManagementService::~DeviceManagementService() { | 462 DeviceManagementService::~DeviceManagementService() { |
| 140 // All running jobs should have been cancelled by now. If not, there are | 463 // All running jobs should have been cancelled by now. |
| 141 // backend objects still around, which is an error. | |
| 142 DCHECK(pending_jobs_.empty()); | 464 DCHECK(pending_jobs_.empty()); |
| 143 DCHECK(queued_jobs_.empty()); | 465 DCHECK(queued_jobs_.empty()); |
| 144 } | 466 } |
| 145 | 467 |
| 146 DeviceManagementBackend* DeviceManagementService::CreateBackend() { | 468 DeviceManagementBackend* DeviceManagementService::CreateBackend() { |
| 147 return new DeviceManagementBackendImpl(this); | 469 return new DeviceManagementBackendImpl(this); |
| 148 } | 470 } |
| 149 | 471 |
| 472 DeviceManagementRequestJob* DeviceManagementService::CreateJob( | |
| 473 DeviceManagementRequestJob::JobType type) { | |
| 474 return new DeviceManagementRequestJobImpl(type, this); | |
| 475 } | |
| 476 | |
| 150 void DeviceManagementService::ScheduleInitialization(int64 delay_milliseconds) { | 477 void DeviceManagementService::ScheduleInitialization(int64 delay_milliseconds) { |
| 151 if (initialized_) | 478 if (initialized_) |
| 152 return; | 479 return; |
| 153 MessageLoop::current()->PostDelayedTask( | 480 MessageLoop::current()->PostDelayedTask( |
| 154 FROM_HERE, | 481 FROM_HERE, |
| 155 base::Bind(&DeviceManagementService::Initialize, | 482 base::Bind(&DeviceManagementService::Initialize, |
| 156 weak_ptr_factory_.GetWeakPtr()), | 483 weak_ptr_factory_.GetWeakPtr()), |
| 157 delay_milliseconds); | 484 delay_milliseconds); |
| 158 } | 485 } |
| 159 | 486 |
| 160 void DeviceManagementService::Initialize() { | 487 void DeviceManagementService::Initialize() { |
| 161 if (initialized_) | 488 if (initialized_) |
| 162 return; | 489 return; |
| 163 DCHECK(!request_context_getter_); | 490 DCHECK(!request_context_getter_); |
| 164 request_context_getter_ = new DeviceManagementRequestContextGetter( | 491 request_context_getter_ = new DeviceManagementRequestContextGetter( |
| 165 g_browser_process->system_request_context()); | 492 g_browser_process->system_request_context()); |
| 166 initialized_ = true; | 493 initialized_ = true; |
| 167 | 494 |
| 168 while (!queued_jobs_.empty()) { | 495 while (!queued_jobs_.empty()) { |
| 169 StartJob(queued_jobs_.front(), false); | 496 StartJob(queued_jobs_.front(), false); |
| 170 queued_jobs_.pop_front(); | 497 queued_jobs_.pop_front(); |
| 171 } | 498 } |
| 172 } | 499 } |
| 173 | 500 |
| 174 void DeviceManagementService::Shutdown() { | 501 void DeviceManagementService::Shutdown() { |
| 175 for (JobFetcherMap::iterator job(pending_jobs_.begin()); | 502 for (JobFetcherMap::iterator job(pending_jobs_.begin()); |
| 176 job != pending_jobs_.end(); | 503 job != pending_jobs_.end(); |
| 177 ++job) { | 504 ++job) { |
| 178 delete job->first; | |
|
Joao da Silva
2012/01/02 16:14:43
Why? It seems that the outstanding URLFetcher will
Mattias Nissler (ping if slow)
2012/01/02 17:53:23
Must have deleted this by accident when making the
| |
| 179 queued_jobs_.push_back(job->second); | 505 queued_jobs_.push_back(job->second); |
| 180 } | 506 } |
| 181 pending_jobs_.clear(); | 507 pending_jobs_.clear(); |
| 182 } | 508 } |
| 183 | 509 |
| 184 DeviceManagementService::DeviceManagementService( | 510 DeviceManagementService::DeviceManagementService( |
| 185 const std::string& server_url) | 511 const std::string& server_url) |
| 186 : server_url_(server_url), | 512 : server_url_(server_url), |
| 187 initialized_(false), | 513 initialized_(false), |
| 188 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 514 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
| 189 } | 515 } |
| 190 | 516 |
| 191 void DeviceManagementService::AddJob(DeviceManagementJob* job) { | 517 void DeviceManagementService::StartJob(DeviceManagementRequestJobImpl* job, |
| 192 if (initialized_) | |
| 193 StartJob(job, false); | |
| 194 else | |
| 195 queued_jobs_.push_back(job); | |
| 196 } | |
| 197 | |
| 198 void DeviceManagementService::RemoveJob(DeviceManagementJob* job) { | |
| 199 for (JobFetcherMap::iterator entry(pending_jobs_.begin()); | |
| 200 entry != pending_jobs_.end(); | |
| 201 ++entry) { | |
| 202 if (entry->second == job) { | |
| 203 delete entry->first; | |
| 204 pending_jobs_.erase(entry); | |
| 205 return; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 const JobQueue::iterator elem = | |
| 210 std::find(queued_jobs_.begin(), queued_jobs_.end(), job); | |
| 211 if (elem != queued_jobs_.end()) | |
| 212 queued_jobs_.erase(elem); | |
| 213 } | |
| 214 | |
| 215 void DeviceManagementService::StartJob(DeviceManagementJob* job, | |
| 216 bool bypass_proxy) { | 518 bool bypass_proxy) { |
| 217 content::URLFetcher* fetcher = content::URLFetcher::Create( | 519 content::URLFetcher* fetcher = content::URLFetcher::Create( |
| 218 0, job->GetURL(server_url_), content::URLFetcher::POST, this); | 520 0, job->GetURL(server_url_), content::URLFetcher::POST, this); |
| 219 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 521 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 220 net::LOAD_DO_NOT_SAVE_COOKIES | | 522 net::LOAD_DO_NOT_SAVE_COOKIES | |
| 221 net::LOAD_DISABLE_CACHE | | 523 net::LOAD_DISABLE_CACHE | |
| 222 (bypass_proxy ? net::LOAD_BYPASS_PROXY : 0)); | 524 (bypass_proxy ? net::LOAD_BYPASS_PROXY : 0)); |
| 223 fetcher->SetRequestContext(request_context_getter_.get()); | 525 fetcher->SetRequestContext(request_context_getter_.get()); |
| 224 job->ConfigureRequest(fetcher); | 526 job->ConfigureRequest(fetcher); |
| 225 pending_jobs_[fetcher] = job; | 527 pending_jobs_[fetcher] = job; |
| 226 fetcher->Start(); | 528 fetcher->Start(); |
| 227 } | 529 } |
| 228 | 530 |
| 229 void DeviceManagementService::OnURLFetchComplete( | 531 void DeviceManagementService::OnURLFetchComplete( |
| 230 const content::URLFetcher* source) { | 532 const content::URLFetcher* source) { |
| 231 JobFetcherMap::iterator entry(pending_jobs_.find(source)); | 533 JobFetcherMap::iterator entry(pending_jobs_.find(source)); |
| 232 if (entry != pending_jobs_.end()) { | 534 if (entry == pending_jobs_.end()) { |
| 233 DeviceManagementJob* job = entry->second; | 535 NOTREACHED() << "Callback from foreign URL fetcher"; |
| 234 pending_jobs_.erase(entry); | 536 return; |
| 537 } | |
| 235 | 538 |
| 236 // Retry the job if it failed due to a broken proxy, by bypassing the | 539 DeviceManagementRequestJobImpl* job = entry->second; |
| 237 // proxy on the next try. Don't retry if this URLFetcher already bypassed | 540 pending_jobs_.erase(entry); |
| 238 // the proxy. | 541 |
| 239 bool retry = false; | 542 // Retry the job if it failed due to a broken proxy, by bypassing the |
| 240 if ((source->GetLoadFlags() & net::LOAD_BYPASS_PROXY) == 0) { | 543 // proxy on the next try. Don't retry if this URLFetcher already bypassed |
| 241 if (!source->GetStatus().is_success() && | 544 // the proxy. |
| 242 IsProxyError(source->GetStatus())) { | 545 bool retry = false; |
| 243 LOG(WARNING) << "Proxy failed while contacting dmserver."; | 546 if ((source->GetLoadFlags() & net::LOAD_BYPASS_PROXY) == 0) { |
| 244 retry = true; | 547 if (!source->GetStatus().is_success() && |
| 245 } else if (source->GetStatus().is_success() && | 548 IsProxyError(source->GetStatus())) { |
| 246 source->WasFetchedViaProxy() && | 549 LOG(WARNING) << "Proxy failed while contacting dmserver."; |
| 247 !IsProtobufMimeType(source)) { | 550 retry = true; |
| 248 // The proxy server can be misconfigured but pointing to an existing | 551 } else if (source->GetStatus().is_success() && |
| 249 // server that replies to requests. Try to recover if a successful | 552 source->WasFetchedViaProxy() && |
| 250 // request that went through a proxy returns an unexpected mime type. | 553 !IsProtobufMimeType(source)) { |
| 251 LOG(WARNING) << "Got bad mime-type in response from dmserver that was " | 554 // The proxy server can be misconfigured but pointing to an existing |
| 252 << "fetched via a proxy."; | 555 // server that replies to requests. Try to recover if a successful |
| 253 retry = true; | 556 // request that went through a proxy returns an unexpected mime type. |
| 254 } | 557 LOG(WARNING) << "Got bad mime-type in response from dmserver that was " |
| 558 << "fetched via a proxy."; | |
| 559 retry = true; | |
| 255 } | 560 } |
| 561 } | |
| 256 | 562 |
| 257 if (retry) { | 563 if (retry) { |
| 258 LOG(WARNING) << "Retrying dmserver request without using a proxy."; | 564 LOG(WARNING) << "Retrying dmserver request without using a proxy."; |
| 259 StartJob(job, true); | 565 StartJob(job, true); |
| 260 } else { | |
| 261 std::string data; | |
| 262 source->GetResponseAsString(&data); | |
| 263 job->HandleResponse(source->GetStatus(), source->GetResponseCode(), | |
| 264 source->GetCookies(), data); | |
| 265 } | |
| 266 } else { | 566 } else { |
| 267 NOTREACHED() << "Callback from foreign URL fetcher"; | 567 std::string data; |
| 568 source->GetResponseAsString(&data); | |
| 569 job->HandleResponse(source->GetStatus(), source->GetResponseCode(), | |
| 570 source->GetCookies(), data); | |
| 268 } | 571 } |
| 269 delete source; | 572 delete source; |
| 270 } | 573 } |
| 271 | 574 |
| 575 void DeviceManagementService::AddJob(DeviceManagementRequestJobImpl* job) { | |
| 576 if (initialized_) | |
| 577 StartJob(job, false); | |
| 578 else | |
| 579 queued_jobs_.push_back(job); | |
| 580 } | |
| 581 | |
| 582 void DeviceManagementService::RemoveJob(DeviceManagementRequestJobImpl* job) { | |
| 583 for (JobFetcherMap::iterator entry(pending_jobs_.begin()); | |
| 584 entry != pending_jobs_.end(); | |
| 585 ++entry) { | |
| 586 if (entry->second == job) { | |
| 587 pending_jobs_.erase(entry); | |
|
Joao da Silva
2012/01/02 16:14:43
If the job is removed, shouldn't its URLFetcher be
Mattias Nissler (ping if slow)
2012/01/02 17:53:23
You are absolutely right. Done.
| |
| 588 return; | |
| 589 } | |
| 590 } | |
| 591 | |
| 592 const JobQueue::iterator elem = | |
| 593 std::find(queued_jobs_.begin(), queued_jobs_.end(), job); | |
| 594 if (elem != queued_jobs_.end()) | |
| 595 queued_jobs_.erase(elem); | |
| 596 } | |
| 597 | |
| 272 } // namespace policy | 598 } // namespace policy |
| OLD | NEW |