OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/policy/device_management_service.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/compiler_specific.h" | |
11 #include "base/message_loop.h" | |
12 #include "base/message_loop_proxy.h" | |
13 #include "base/stringprintf.h" | |
14 #include "base/sys_info.h" | |
15 #include "chrome/browser/browser_process.h" | |
16 #include "chrome/browser/net/basic_http_user_agent_settings.h" | |
17 #include "chrome/browser/net/chrome_net_log.h" | |
18 #include "chrome/common/chrome_version_info.h" | |
19 #include "content/public/browser/browser_thread.h" | |
20 #include "content/public/common/content_client.h" | |
21 #include "googleurl/src/gurl.h" | |
22 #include "net/base/escape.h" | |
23 #include "net/base/host_resolver.h" | |
24 #include "net/base/load_flags.h" | |
25 #include "net/base/net_errors.h" | |
26 #include "net/base/ssl_config_service_defaults.h" | |
27 #include "net/cookies/cookie_monster.h" | |
28 #include "net/http/http_network_layer.h" | |
29 #include "net/http/http_response_headers.h" | |
30 #include "net/proxy/proxy_service.h" | |
31 #include "net/url_request/url_fetcher.h" | |
32 #include "net/url_request/url_request_context.h" | |
33 #include "net/url_request/url_request_context_getter.h" | |
34 #include "net/url_request/url_request_status.h" | |
35 | |
36 #if defined(OS_CHROMEOS) | |
37 #include "chrome/browser/chromeos/system/statistics_provider.h" | |
38 #endif | |
39 | |
40 using content::BrowserThread; | |
41 | |
42 namespace em = enterprise_management; | |
43 | |
44 namespace policy { | |
45 | |
46 namespace { | |
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 // Number of times to retry on ERR_NETWORK_CHANGED errors. | |
57 const int kMaxNetworkChangedRetries = 3; | |
58 | |
59 // HTTP Error Codes of the DM Server with their concrete meanings in the context | |
60 // of the DM Server communication. | |
61 const int kSuccess = 200; | |
62 const int kInvalidArgument = 400; | |
63 const int kInvalidAuthCookieOrDMToken = 401; | |
64 const int kMissingLicenses = 402; | |
65 const int kDeviceManagementNotAllowed = 403; | |
66 const int kInvalidURL = 404; // This error is not coming from the GFE. | |
67 const int kInvalidSerialNumber = 405; | |
68 const int kDeviceIdConflict = 409; | |
69 const int kDeviceNotFound = 410; | |
70 const int kPendingApproval = 412; | |
71 const int kInternalServerError = 500; | |
72 const int kServiceUnavailable = 503; | |
73 const int kPolicyNotFound = 902; // This error is not sent as HTTP status code. | |
74 | |
75 #if defined(OS_CHROMEOS) | |
76 // Machine info keys. | |
77 const char kMachineInfoHWClass[] = "hardware_class"; | |
78 const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD"; | |
79 #endif | |
80 | |
81 bool IsProxyError(const net::URLRequestStatus status) { | |
82 switch (status.error()) { | |
83 case net::ERR_PROXY_CONNECTION_FAILED: | |
84 case net::ERR_TUNNEL_CONNECTION_FAILED: | |
85 case net::ERR_PROXY_AUTH_UNSUPPORTED: | |
86 case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE: | |
87 case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED: | |
88 case net::ERR_PROXY_CERTIFICATE_INVALID: | |
89 case net::ERR_SOCKS_CONNECTION_FAILED: | |
90 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: | |
91 return true; | |
92 } | |
93 return false; | |
94 } | |
95 | |
96 bool IsProtobufMimeType(const net::URLFetcher* fetcher) { | |
97 return fetcher->GetResponseHeaders()->HasHeaderValue( | |
98 "content-type", "application/x-protobuffer"); | |
99 } | |
100 | |
101 bool FailedWithProxy(const net::URLFetcher* fetcher) { | |
102 if ((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0) { | |
103 // The request didn't use a proxy. | |
104 return false; | |
105 } | |
106 | |
107 if (!fetcher->GetStatus().is_success() && | |
108 IsProxyError(fetcher->GetStatus())) { | |
109 LOG(WARNING) << "Proxy failed while contacting dmserver."; | |
110 return true; | |
111 } | |
112 | |
113 if (fetcher->GetStatus().is_success() && | |
114 fetcher->GetResponseCode() == kSuccess && | |
115 fetcher->WasFetchedViaProxy() && | |
116 !IsProtobufMimeType(fetcher)) { | |
117 // The proxy server can be misconfigured but pointing to an existing | |
118 // server that replies to requests. Try to recover if a successful | |
119 // request that went through a proxy returns an unexpected mime type. | |
120 LOG(WARNING) << "Got bad mime-type in response from dmserver that was " | |
121 << "fetched via a proxy."; | |
122 return true; | |
123 } | |
124 | |
125 return false; | |
126 } | |
127 | |
128 const char* UserAffiliationToString(UserAffiliation affiliation) { | |
129 switch (affiliation) { | |
130 case USER_AFFILIATION_MANAGED: | |
131 return dm_protocol::kValueUserAffiliationManaged; | |
132 case USER_AFFILIATION_NONE: | |
133 return dm_protocol::kValueUserAffiliationNone; | |
134 } | |
135 NOTREACHED() << "Invalid user affiliation " << affiliation; | |
136 return dm_protocol::kValueUserAffiliationNone; | |
137 } | |
138 | |
139 const char* JobTypeToRequestType(DeviceManagementRequestJob::JobType type) { | |
140 switch (type) { | |
141 case DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT: | |
142 return dm_protocol::kValueRequestAutoEnrollment; | |
143 case DeviceManagementRequestJob::TYPE_REGISTRATION: | |
144 return dm_protocol::kValueRequestRegister; | |
145 case DeviceManagementRequestJob::TYPE_POLICY_FETCH: | |
146 return dm_protocol::kValueRequestPolicy; | |
147 case DeviceManagementRequestJob::TYPE_UNREGISTRATION: | |
148 return dm_protocol::kValueRequestUnregister; | |
149 } | |
150 NOTREACHED() << "Invalid job type " << type; | |
151 return ""; | |
152 } | |
153 | |
154 const std::string& GetAgentString() { | |
155 CR_DEFINE_STATIC_LOCAL(std::string, agent, ()); | |
156 if (!agent.empty()) | |
157 return agent; | |
158 | |
159 chrome::VersionInfo version_info; | |
160 agent = base::StringPrintf(kValueAgent, | |
161 version_info.Name().c_str(), | |
162 version_info.Version().c_str(), | |
163 version_info.LastChange().c_str()); | |
164 return agent; | |
165 } | |
166 | |
167 const std::string& GetPlatformString() { | |
168 CR_DEFINE_STATIC_LOCAL(std::string, platform, ()); | |
169 if (!platform.empty()) | |
170 return platform; | |
171 | |
172 std::string os_name(base::SysInfo::OperatingSystemName()); | |
173 std::string os_hardware(base::SysInfo::OperatingSystemArchitecture()); | |
174 | |
175 #if defined(OS_CHROMEOS) | |
176 chromeos::system::StatisticsProvider* provider = | |
177 chromeos::system::StatisticsProvider::GetInstance(); | |
178 | |
179 std::string hwclass; | |
180 std::string board; | |
181 if (!provider->GetMachineStatistic(kMachineInfoHWClass, &hwclass) || | |
182 !provider->GetMachineStatistic(kMachineInfoBoard, &board)) { | |
183 LOG(ERROR) << "Failed to get machine information"; | |
184 } | |
185 os_name += ",CrOS," + board; | |
186 os_hardware += "," + hwclass; | |
187 #endif | |
188 | |
189 std::string os_version("-"); | |
190 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) | |
191 int32 os_major_version = 0; | |
192 int32 os_minor_version = 0; | |
193 int32 os_bugfix_version = 0; | |
194 base::SysInfo::OperatingSystemVersionNumbers(&os_major_version, | |
195 &os_minor_version, | |
196 &os_bugfix_version); | |
197 os_version = base::StringPrintf("%d.%d.%d", | |
198 os_major_version, | |
199 os_minor_version, | |
200 os_bugfix_version); | |
201 #endif | |
202 | |
203 platform = base::StringPrintf(kValuePlatform, | |
204 os_name.c_str(), | |
205 os_hardware.c_str(), | |
206 os_version.c_str()); | |
207 return platform; | |
208 } | |
209 | |
210 // Custom request context implementation that allows to override the user agent, | |
211 // amongst others. Wraps a baseline request context from which we reuse the | |
212 // networking components. | |
213 class DeviceManagementRequestContext : public net::URLRequestContext { | |
214 public: | |
215 explicit DeviceManagementRequestContext(net::URLRequestContext* base_context); | |
216 virtual ~DeviceManagementRequestContext(); | |
217 | |
218 private: | |
219 BasicHttpUserAgentSettings basic_http_user_agent_settings_; | |
220 }; | |
221 | |
222 DeviceManagementRequestContext::DeviceManagementRequestContext( | |
223 net::URLRequestContext* base_context) | |
224 // Use sane Accept-Language and Accept-Charset values for our purposes. | |
225 : basic_http_user_agent_settings_("*", "*") { | |
226 // Share resolver, proxy service and ssl bits with the baseline context. This | |
227 // is important so we don't make redundant requests (e.g. when resolving proxy | |
228 // auto configuration). | |
229 set_net_log(base_context->net_log()); | |
230 set_host_resolver(base_context->host_resolver()); | |
231 set_proxy_service(base_context->proxy_service()); | |
232 set_ssl_config_service(base_context->ssl_config_service()); | |
233 | |
234 // Share the http session. | |
235 set_http_transaction_factory( | |
236 new net::HttpNetworkLayer( | |
237 base_context->http_transaction_factory()->GetSession())); | |
238 | |
239 // No cookies, please. | |
240 set_cookie_store(new net::CookieMonster(NULL, NULL)); | |
241 | |
242 set_http_user_agent_settings(&basic_http_user_agent_settings_); | |
243 } | |
244 | |
245 DeviceManagementRequestContext::~DeviceManagementRequestContext() { | |
246 delete http_transaction_factory(); | |
247 } | |
248 | |
249 // Request context holder. | |
250 class DeviceManagementRequestContextGetter | |
251 : public net::URLRequestContextGetter { | |
252 public: | |
253 explicit DeviceManagementRequestContextGetter( | |
254 net::URLRequestContextGetter* base_context_getter) | |
255 : base_context_getter_(base_context_getter) {} | |
256 | |
257 // Overridden from net::URLRequestContextGetter: | |
258 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE; | |
259 virtual scoped_refptr<base::SingleThreadTaskRunner> | |
260 GetNetworkTaskRunner() const OVERRIDE; | |
261 | |
262 protected: | |
263 virtual ~DeviceManagementRequestContextGetter() {} | |
264 | |
265 private: | |
266 scoped_ptr<net::URLRequestContext> context_; | |
267 scoped_refptr<net::URLRequestContextGetter> base_context_getter_; | |
268 }; | |
269 | |
270 | |
271 net::URLRequestContext* | |
272 DeviceManagementRequestContextGetter::GetURLRequestContext() { | |
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
274 if (!context_.get()) { | |
275 context_.reset(new DeviceManagementRequestContext( | |
276 base_context_getter_->GetURLRequestContext())); | |
277 } | |
278 | |
279 return context_.get(); | |
280 } | |
281 | |
282 scoped_refptr<base::SingleThreadTaskRunner> | |
283 DeviceManagementRequestContextGetter::GetNetworkTaskRunner() const { | |
284 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); | |
285 } | |
286 | |
287 } // namespace | |
288 | |
289 // Request job implementation used with DeviceManagementService. | |
290 class DeviceManagementRequestJobImpl : public DeviceManagementRequestJob { | |
291 public: | |
292 DeviceManagementRequestJobImpl(JobType type, | |
293 DeviceManagementService* service); | |
294 virtual ~DeviceManagementRequestJobImpl(); | |
295 | |
296 // Handles the URL request response. | |
297 void HandleResponse(const net::URLRequestStatus& status, | |
298 int response_code, | |
299 const net::ResponseCookies& cookies, | |
300 const std::string& data); | |
301 | |
302 // Gets the URL to contact. | |
303 GURL GetURL(const std::string& server_url); | |
304 | |
305 // Configures the fetcher, setting up payload and headers. | |
306 void ConfigureRequest(net::URLFetcher* fetcher); | |
307 | |
308 // Returns true if this job should be retried. |fetcher| has just completed, | |
309 // and can be inspected to determine if the request failed and should be | |
310 // retried. | |
311 bool ShouldRetry(const net::URLFetcher* fetcher); | |
312 | |
313 // Invoked right before retrying this job. | |
314 void PrepareRetry(); | |
315 | |
316 protected: | |
317 // DeviceManagementRequestJob: | |
318 virtual void Run() OVERRIDE; | |
319 | |
320 private: | |
321 // Invokes the callback with the given error code. | |
322 void ReportError(DeviceManagementStatus code); | |
323 | |
324 // Pointer to the service this job is associated with. | |
325 DeviceManagementService* service_; | |
326 | |
327 // Whether the BYPASS_PROXY flag should be set by ConfigureRequest(). | |
328 bool bypass_proxy_; | |
329 | |
330 // Number of times that this job has been retried due to ERR_NETWORK_CHANGED. | |
331 int retries_count_; | |
332 | |
333 DISALLOW_COPY_AND_ASSIGN(DeviceManagementRequestJobImpl); | |
334 }; | |
335 | |
336 DeviceManagementRequestJobImpl::DeviceManagementRequestJobImpl( | |
337 JobType type, | |
338 DeviceManagementService* service) | |
339 : DeviceManagementRequestJob(type), | |
340 service_(service), | |
341 bypass_proxy_(false), | |
342 retries_count_(0) {} | |
343 | |
344 DeviceManagementRequestJobImpl::~DeviceManagementRequestJobImpl() { | |
345 service_->RemoveJob(this); | |
346 } | |
347 | |
348 void DeviceManagementRequestJobImpl::Run() { | |
349 service_->AddJob(this); | |
350 } | |
351 | |
352 void DeviceManagementRequestJobImpl::HandleResponse( | |
353 const net::URLRequestStatus& status, | |
354 int response_code, | |
355 const net::ResponseCookies& cookies, | |
356 const std::string& data) { | |
357 if (status.status() != net::URLRequestStatus::SUCCESS) { | |
358 LOG(WARNING) << "DMServer request failed, status: " << status.status() | |
359 << ", error: " << status.error(); | |
360 ReportError(DM_STATUS_REQUEST_FAILED); | |
361 return; | |
362 } | |
363 | |
364 if (response_code != kSuccess) | |
365 LOG(WARNING) << "DMServer sent an error response: " << response_code; | |
366 | |
367 switch (response_code) { | |
368 case kSuccess: { | |
369 em::DeviceManagementResponse response; | |
370 if (!response.ParseFromString(data)) { | |
371 ReportError(DM_STATUS_RESPONSE_DECODING_ERROR); | |
372 return; | |
373 } | |
374 callback_.Run(DM_STATUS_SUCCESS, response); | |
375 return; | |
376 } | |
377 case kInvalidArgument: | |
378 ReportError(DM_STATUS_REQUEST_INVALID); | |
379 return; | |
380 case kInvalidAuthCookieOrDMToken: | |
381 ReportError(DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID); | |
382 return; | |
383 case kMissingLicenses: | |
384 ReportError(DM_STATUS_SERVICE_MISSING_LICENSES); | |
385 return; | |
386 case kDeviceManagementNotAllowed: | |
387 ReportError(DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED); | |
388 return; | |
389 case kPendingApproval: | |
390 ReportError(DM_STATUS_SERVICE_ACTIVATION_PENDING); | |
391 return; | |
392 case kInvalidURL: | |
393 case kInternalServerError: | |
394 case kServiceUnavailable: | |
395 ReportError(DM_STATUS_TEMPORARY_UNAVAILABLE); | |
396 return; | |
397 case kDeviceNotFound: | |
398 ReportError(DM_STATUS_SERVICE_DEVICE_NOT_FOUND); | |
399 return; | |
400 case kPolicyNotFound: | |
401 ReportError(DM_STATUS_SERVICE_POLICY_NOT_FOUND); | |
402 return; | |
403 case kInvalidSerialNumber: | |
404 ReportError(DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER); | |
405 return; | |
406 case kDeviceIdConflict: | |
407 ReportError(DM_STATUS_SERVICE_DEVICE_ID_CONFLICT); | |
408 return; | |
409 default: | |
410 // Handle all unknown 5xx HTTP error codes as temporary and any other | |
411 // unknown error as one that needs more time to recover. | |
412 if (response_code >= 500 && response_code <= 599) | |
413 ReportError(DM_STATUS_TEMPORARY_UNAVAILABLE); | |
414 else | |
415 ReportError(DM_STATUS_HTTP_STATUS_ERROR); | |
416 return; | |
417 } | |
418 } | |
419 | |
420 GURL DeviceManagementRequestJobImpl::GetURL( | |
421 const std::string& server_url) { | |
422 std::string result(server_url); | |
423 result += '?'; | |
424 for (ParameterMap::const_iterator entry(query_params_.begin()); | |
425 entry != query_params_.end(); | |
426 ++entry) { | |
427 if (entry != query_params_.begin()) | |
428 result += '&'; | |
429 result += net::EscapeQueryParamValue(entry->first, true); | |
430 result += '='; | |
431 result += net::EscapeQueryParamValue(entry->second, true); | |
432 } | |
433 return GURL(result); | |
434 } | |
435 | |
436 void DeviceManagementRequestJobImpl::ConfigureRequest( | |
437 net::URLFetcher* fetcher) { | |
438 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | |
439 net::LOAD_DO_NOT_SAVE_COOKIES | | |
440 net::LOAD_DISABLE_CACHE | | |
441 (bypass_proxy_ ? net::LOAD_BYPASS_PROXY : 0)); | |
442 std::string payload; | |
443 CHECK(request_.SerializeToString(&payload)); | |
444 fetcher->SetUploadData(kPostContentType, payload); | |
445 std::string extra_headers; | |
446 if (!gaia_token_.empty()) | |
447 extra_headers += kServiceTokenAuthHeader + gaia_token_ + "\n"; | |
448 if (!dm_token_.empty()) | |
449 extra_headers += kDMTokenAuthHeader + dm_token_ + "\n"; | |
450 fetcher->SetExtraRequestHeaders(extra_headers); | |
451 } | |
452 | |
453 bool DeviceManagementRequestJobImpl::ShouldRetry( | |
454 const net::URLFetcher* fetcher) { | |
455 if (FailedWithProxy(fetcher) && !bypass_proxy_) { | |
456 // Retry the job if it failed due to a broken proxy, by bypassing the | |
457 // proxy on the next try. | |
458 bypass_proxy_ = true; | |
459 return true; | |
460 } | |
461 | |
462 // Early device policy fetches on ChromeOS and Auto-Enrollment checks are | |
463 // often interrupted during ChromeOS startup when network change notifications | |
464 // are sent. Allowing the fetcher to retry once after that is enough to | |
465 // recover; allow it to retry up to 3 times just in case. | |
466 if (fetcher->GetStatus().error() == net::ERR_NETWORK_CHANGED && | |
467 retries_count_ < kMaxNetworkChangedRetries) { | |
468 ++retries_count_; | |
469 return true; | |
470 } | |
471 | |
472 // The request didn't fail, or the limit of retry attempts has been reached; | |
473 // forward the result to the job owner. | |
474 return false; | |
475 } | |
476 | |
477 void DeviceManagementRequestJobImpl::PrepareRetry() { | |
478 if (!retry_callback_.is_null()) | |
479 retry_callback_.Run(this); | |
480 } | |
481 | |
482 void DeviceManagementRequestJobImpl::ReportError(DeviceManagementStatus code) { | |
483 em::DeviceManagementResponse dummy_response; | |
484 callback_.Run(code, dummy_response); | |
485 } | |
486 | |
487 DeviceManagementRequestJob::~DeviceManagementRequestJob() {} | |
488 | |
489 void DeviceManagementRequestJob::SetGaiaToken(const std::string& gaia_token) { | |
490 gaia_token_ = gaia_token; | |
491 } | |
492 | |
493 void DeviceManagementRequestJob::SetOAuthToken(const std::string& oauth_token) { | |
494 AddParameter(dm_protocol::kParamOAuthToken, oauth_token); | |
495 } | |
496 | |
497 void DeviceManagementRequestJob::SetUserAffiliation( | |
498 UserAffiliation user_affiliation) { | |
499 AddParameter(dm_protocol::kParamUserAffiliation, | |
500 UserAffiliationToString(user_affiliation)); | |
501 } | |
502 | |
503 void DeviceManagementRequestJob::SetDMToken(const std::string& dm_token) { | |
504 dm_token_ = dm_token; | |
505 } | |
506 | |
507 void DeviceManagementRequestJob::SetClientID(const std::string& client_id) { | |
508 AddParameter(dm_protocol::kParamDeviceID, client_id); | |
509 } | |
510 | |
511 em::DeviceManagementRequest* DeviceManagementRequestJob::GetRequest() { | |
512 return &request_; | |
513 } | |
514 | |
515 DeviceManagementRequestJob::DeviceManagementRequestJob(JobType type) { | |
516 AddParameter(dm_protocol::kParamRequest, JobTypeToRequestType(type)); | |
517 AddParameter(dm_protocol::kParamDeviceType, dm_protocol::kValueDeviceType); | |
518 AddParameter(dm_protocol::kParamAppType, dm_protocol::kValueAppType); | |
519 AddParameter(dm_protocol::kParamAgent, GetAgentString()); | |
520 AddParameter(dm_protocol::kParamPlatform, GetPlatformString()); | |
521 } | |
522 | |
523 void DeviceManagementRequestJob::SetRetryCallback( | |
524 const RetryCallback& retry_callback) { | |
525 retry_callback_ = retry_callback; | |
526 } | |
527 | |
528 void DeviceManagementRequestJob::Start(const Callback& callback) { | |
529 callback_ = callback; | |
530 Run(); | |
531 } | |
532 | |
533 void DeviceManagementRequestJob::AddParameter(const std::string& name, | |
534 const std::string& value) { | |
535 query_params_.push_back(std::make_pair(name, value)); | |
536 } | |
537 | |
538 // A random value that other fetchers won't likely use. | |
539 const int DeviceManagementService::kURLFetcherID = 0xde71ce1d; | |
540 | |
541 DeviceManagementService::~DeviceManagementService() { | |
542 // All running jobs should have been cancelled by now. | |
543 DCHECK(pending_jobs_.empty()); | |
544 DCHECK(queued_jobs_.empty()); | |
545 } | |
546 | |
547 DeviceManagementRequestJob* DeviceManagementService::CreateJob( | |
548 DeviceManagementRequestJob::JobType type) { | |
549 return new DeviceManagementRequestJobImpl(type, this); | |
550 } | |
551 | |
552 void DeviceManagementService::ScheduleInitialization(int64 delay_milliseconds) { | |
553 if (initialized_) | |
554 return; | |
555 MessageLoop::current()->PostDelayedTask( | |
556 FROM_HERE, | |
557 base::Bind(&DeviceManagementService::Initialize, | |
558 weak_ptr_factory_.GetWeakPtr()), | |
559 base::TimeDelta::FromMilliseconds(delay_milliseconds)); | |
560 } | |
561 | |
562 void DeviceManagementService::Initialize() { | |
563 if (initialized_) | |
564 return; | |
565 DCHECK(!request_context_getter_); | |
566 request_context_getter_ = new DeviceManagementRequestContextGetter( | |
567 g_browser_process->system_request_context()); | |
568 initialized_ = true; | |
569 | |
570 while (!queued_jobs_.empty()) { | |
571 StartJob(queued_jobs_.front()); | |
572 queued_jobs_.pop_front(); | |
573 } | |
574 } | |
575 | |
576 void DeviceManagementService::Shutdown() { | |
577 for (JobFetcherMap::iterator job(pending_jobs_.begin()); | |
578 job != pending_jobs_.end(); | |
579 ++job) { | |
580 delete job->first; | |
581 queued_jobs_.push_back(job->second); | |
582 } | |
583 pending_jobs_.clear(); | |
584 } | |
585 | |
586 DeviceManagementService::DeviceManagementService( | |
587 const std::string& server_url) | |
588 : server_url_(server_url), | |
589 initialized_(false), | |
590 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
591 } | |
592 | |
593 void DeviceManagementService::StartJob(DeviceManagementRequestJobImpl* job) { | |
594 net::URLFetcher* fetcher = net::URLFetcher::Create( | |
595 kURLFetcherID, job->GetURL(server_url_), net::URLFetcher::POST, this); | |
596 fetcher->SetRequestContext(request_context_getter_.get()); | |
597 job->ConfigureRequest(fetcher); | |
598 pending_jobs_[fetcher] = job; | |
599 fetcher->Start(); | |
600 } | |
601 | |
602 void DeviceManagementService::OnURLFetchComplete( | |
603 const net::URLFetcher* source) { | |
604 JobFetcherMap::iterator entry(pending_jobs_.find(source)); | |
605 if (entry == pending_jobs_.end()) { | |
606 NOTREACHED() << "Callback from foreign URL fetcher"; | |
607 return; | |
608 } | |
609 | |
610 DeviceManagementRequestJobImpl* job = entry->second; | |
611 pending_jobs_.erase(entry); | |
612 | |
613 if (job->ShouldRetry(source)) { | |
614 VLOG(1) << "Retrying dmserver request."; | |
615 job->PrepareRetry(); | |
616 StartJob(job); | |
617 } else { | |
618 std::string data; | |
619 source->GetResponseAsString(&data); | |
620 job->HandleResponse(source->GetStatus(), source->GetResponseCode(), | |
621 source->GetCookies(), data); | |
622 } | |
623 delete source; | |
624 } | |
625 | |
626 void DeviceManagementService::AddJob(DeviceManagementRequestJobImpl* job) { | |
627 if (initialized_) | |
628 StartJob(job); | |
629 else | |
630 queued_jobs_.push_back(job); | |
631 } | |
632 | |
633 void DeviceManagementService::RemoveJob(DeviceManagementRequestJobImpl* job) { | |
634 for (JobFetcherMap::iterator entry(pending_jobs_.begin()); | |
635 entry != pending_jobs_.end(); | |
636 ++entry) { | |
637 if (entry->second == job) { | |
638 delete entry->first; | |
639 pending_jobs_.erase(entry); | |
640 return; | |
641 } | |
642 } | |
643 | |
644 const JobQueue::iterator elem = | |
645 std::find(queued_jobs_.begin(), queued_jobs_.end(), job); | |
646 if (elem != queued_jobs_.end()) | |
647 queued_jobs_.erase(elem); | |
648 } | |
649 | |
650 } // namespace policy | |
OLD | NEW |