OLD | NEW |
| (Empty) |
1 // Copyright 2007-2010 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 // | |
16 // The download manager uses the network request to download the remote file. | |
17 // Once the download is complete, the download manager stores the file in | |
18 // the package cache, then it copies the file out to a location specified | |
19 // by the caller. | |
20 | |
21 // TODO(omaha): the path where to copy the file is hardcoded. Change the | |
22 // class interface to allow the path as a parameter. | |
23 | |
24 #include "omaha/goopdate/download_manager.h" | |
25 #include <algorithm> | |
26 #include <vector> | |
27 #include "omaha/base/debug.h" | |
28 #include "omaha/base/error.h" | |
29 #include "omaha/base/file.h" | |
30 #include "omaha/base/logging.h" | |
31 #include "omaha/base/path.h" | |
32 #include "omaha/base/scoped_impersonation.h" | |
33 #include "omaha/base/safe_format.h" | |
34 #include "omaha/base/string.h" | |
35 #include "omaha/base/synchronized.h" | |
36 #include "omaha/base/user_rights.h" | |
37 #include "omaha/base/utils.h" | |
38 #include "omaha/common/config_manager.h" | |
39 #include "omaha/common/const_goopdate.h" | |
40 #include "omaha/goopdate/model.h" | |
41 #include "omaha/goopdate/package_cache.h" | |
42 #include "omaha/goopdate/server_resource.h" | |
43 #include "omaha/goopdate/string_formatter.h" | |
44 #include "omaha/goopdate/worker_metrics.h" | |
45 #include "omaha/goopdate/worker_utils.h" | |
46 #include "omaha/net/bits_request.h" | |
47 #include "omaha/net/http_client.h" | |
48 #include "omaha/net/network_request.h" | |
49 #include "omaha/net/net_utils.h" | |
50 #include "omaha/net/simple_request.h" | |
51 | |
52 namespace omaha { | |
53 | |
54 namespace { | |
55 | |
56 // Creates and initializes an instance of the NetworkRequest for the | |
57 // DownloadManager to use. Defines the fallback chain: BITS, WinHttp. | |
58 HRESULT CreateNetworkRequest(NetworkRequest** network_request_ptr) { | |
59 NetworkConfig* network_config = NULL; | |
60 NetworkConfigManager& network_manager = NetworkConfigManager::Instance(); | |
61 HRESULT hr = network_manager.GetUserNetworkConfig(&network_config); | |
62 if (FAILED(hr)) { | |
63 return hr; | |
64 } | |
65 const NetworkConfig::Session& session(network_config->session()); | |
66 NetworkRequest* network_request(new NetworkRequest(session)); | |
67 | |
68 // TODO(omaha): provide a mechanism for different timeout values in | |
69 // silent and interactive downloads. | |
70 | |
71 // BITS transfers files only when the job owner is logged on. If the process | |
72 // "Run As" another user, an empty BITS job gets created in suspended state | |
73 // but there is no way to manipulate the job, nor cancel it. | |
74 bool is_logged_on = false; | |
75 hr = UserRights::UserIsLoggedOnInteractively(&is_logged_on); | |
76 if (SUCCEEDED(hr) && is_logged_on) { | |
77 BitsRequest* bits_request(new BitsRequest); | |
78 bits_request->set_minimum_retry_delay(kSecPerMin); | |
79 bits_request->set_no_progress_timeout(5 * kSecPerMin); | |
80 network_request->AddHttpRequest(bits_request); | |
81 } | |
82 | |
83 network_request->AddHttpRequest(new SimpleRequest); | |
84 | |
85 network_request->set_num_retries(3); | |
86 *network_request_ptr = network_request; | |
87 return S_OK; | |
88 } | |
89 | |
90 // TODO(omaha): Unit test this method. | |
91 HRESULT ValidateSize(const CString& file_path, uint64 expected_size) { | |
92 CORE_LOG(L3, (_T("[ValidateSize][%s][%lld]"), file_path, expected_size)); | |
93 ASSERT1(File::Exists(file_path)); | |
94 ASSERT1(expected_size != 0); | |
95 ASSERT(expected_size <= UINT_MAX, | |
96 (_T("TODO(omaha): Add uint64 support to GetFileSizeUnopen()."))); | |
97 | |
98 uint32 file_size(0); | |
99 HRESULT hr = File::GetFileSizeUnopen(file_path, &file_size); | |
100 ASSERT1(SUCCEEDED(hr)); | |
101 if (FAILED(hr)) { | |
102 return hr; | |
103 } | |
104 | |
105 if (0 == file_size) { | |
106 return GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO; | |
107 } else if (file_size < expected_size) { | |
108 return GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER; | |
109 } else if (file_size > expected_size) { | |
110 return GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER; | |
111 } | |
112 | |
113 ASSERT1(file_size == expected_size); | |
114 return S_OK; | |
115 } | |
116 | |
117 } // namespace | |
118 | |
119 DownloadManager::DownloadManager(bool is_machine) | |
120 : lock_(NULL), is_machine_(false) { | |
121 CORE_LOG(L3, (_T("[DownloadManager::DownloadManager]"))); | |
122 | |
123 omaha::interlocked_exchange_pointer(&lock_, | |
124 static_cast<Lockable*>(new LLock)); | |
125 __mutexScope(lock()); | |
126 | |
127 is_machine_ = is_machine; | |
128 | |
129 package_cache_root_ = | |
130 is_machine ? | |
131 ConfigManager::Instance()->GetMachineSecureDownloadStorageDir() : | |
132 ConfigManager::Instance()->GetUserDownloadStorageDir(); | |
133 | |
134 CORE_LOG(L3, (_T("[package_cache_root][%s]"), package_cache_root())); | |
135 | |
136 package_cache_.reset(new PackageCache); | |
137 } | |
138 | |
139 DownloadManager::~DownloadManager() { | |
140 CORE_LOG(L3, (_T("[DownloadManager::~DownloadManager]"))); | |
141 | |
142 ASSERT1(!IsBusy()); | |
143 | |
144 delete &lock(); | |
145 omaha::interlocked_exchange_pointer(&lock_, static_cast<Lockable*>(NULL)); | |
146 } | |
147 | |
148 const Lockable& DownloadManager::lock() const { | |
149 return *omaha::interlocked_exchange_pointer(&lock_, lock_); | |
150 } | |
151 | |
152 bool DownloadManager::is_machine() const { | |
153 __mutexScope(lock()); | |
154 return is_machine_; | |
155 } | |
156 | |
157 CString DownloadManager::package_cache_root() const { | |
158 __mutexScope(lock()); | |
159 return package_cache_root_; | |
160 } | |
161 | |
162 PackageCache* DownloadManager::package_cache() { | |
163 __mutexScope(lock()); | |
164 return package_cache_.get(); | |
165 } | |
166 | |
167 const PackageCache* DownloadManager::package_cache() const { | |
168 __mutexScope(lock()); | |
169 return package_cache_.get(); | |
170 } | |
171 | |
172 HRESULT DownloadManager::Initialize() { | |
173 HRESULT hr = package_cache()->Initialize(package_cache_root()); | |
174 if (FAILED(hr)) { | |
175 CORE_LOG(LE, (_T("[failed to initialize the package cache]0x%08x]"), hr)); | |
176 return hr; | |
177 } | |
178 | |
179 hr = package_cache()->PurgeOldPackagesIfNecessary(); | |
180 if (FAILED(hr)) { | |
181 CORE_LOG(LW, (_T("[PurgeOldPackagesIfNecessary failed][0x%08x]"), hr)); | |
182 } | |
183 | |
184 return S_OK; | |
185 } | |
186 | |
187 CString DownloadManager::GetMessageForError(const ErrorContext& error_context, | |
188 const CString& language) { | |
189 CString message; | |
190 StringFormatter formatter(language); | |
191 | |
192 switch (error_context.error_code) { | |
193 case SIGS_E_INVALID_SIGNATURE: | |
194 case GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO: | |
195 case GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER: | |
196 case GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER: | |
197 VERIFY1(SUCCEEDED(formatter.LoadString(IDS_DOWNLOAD_HASH_MISMATCH, | |
198 &message))); | |
199 break; | |
200 case GOOPDATEDOWNLOAD_E_CACHING_FAILED: | |
201 VERIFY1(SUCCEEDED(formatter.FormatMessage( | |
202 &message, IDS_CACHING_ERROR, error_context.extra_code1, &message))); | |
203 break; | |
204 default: | |
205 if (!worker_utils::FormatMessageForNetworkError(error_context.error_code, | |
206 language, | |
207 &message)) { | |
208 VERIFY1(SUCCEEDED(formatter.LoadString(IDS_DOWNLOAD_ERROR, &message))); | |
209 } | |
210 break; | |
211 } | |
212 | |
213 ASSERT1(!message.IsEmpty()); | |
214 return message; | |
215 } | |
216 | |
217 HRESULT DownloadManager::DownloadApp(App* app) { | |
218 CORE_LOG(L3, (_T("[DownloadManager::DownloadApp][0x%p]"), app)); | |
219 ASSERT1(app); | |
220 | |
221 // TODO(omaha3): Maybe rename these to include "app_". Maybe add package | |
222 // metrics too. | |
223 ++metric_worker_download_total; | |
224 | |
225 // We assume the number of packages does not change after download is started. | |
226 // TODO(omaha3): Could be a problem if we allow installers to request more | |
227 // packages (http://b/1969071), but we will have lots of other problems then. | |
228 AppVersion* app_version = app->working_version(); | |
229 const size_t num_packages = app_version->GetNumberOfPackages(); | |
230 | |
231 State* state = NULL; | |
232 HRESULT hr = CreateStateForApp(app, &state); | |
233 if (FAILED(hr)) { | |
234 CORE_LOG(LE, (_T("[CreateStateForApp failed][0x%08x]"), hr)); | |
235 return hr; | |
236 } | |
237 | |
238 app->Downloading(); | |
239 | |
240 CString message; | |
241 hr = S_OK; | |
242 | |
243 for (size_t i = 0; i < num_packages; ++i) { | |
244 Package* package(app_version->GetPackage(i)); | |
245 hr = DoDownloadPackage(package, state); | |
246 if (FAILED(hr)) { | |
247 CORE_LOG(LE, (_T("[DoDownloadPackage failed][%s][%s][0x%08x][%Iu]"), | |
248 app->display_name(), package->filename(), hr, i)); | |
249 message = GetMessageForError(ErrorContext(hr, error_extra_code1()), | |
250 app->app_bundle()->display_language()); | |
251 break; | |
252 } | |
253 } | |
254 | |
255 if (SUCCEEDED(hr)) { | |
256 app->DownloadComplete(); | |
257 | |
258 // TODO(omaha3): Extract and apply differential update if necessary. | |
259 | |
260 app->MarkReadyToInstall(); | |
261 } else { | |
262 app->Error(ErrorContext(hr, error_extra_code1()), message); | |
263 } | |
264 | |
265 if (SUCCEEDED(hr)) { | |
266 ++metric_worker_download_succeeded; | |
267 } | |
268 | |
269 VERIFY1(SUCCEEDED(DeleteStateForApp(app))); | |
270 | |
271 return hr; | |
272 } | |
273 | |
274 HRESULT DownloadManager::DownloadPackage(Package* package) { | |
275 CORE_LOG(L3, (_T("[DownloadManager::DownloadPackage][0x%p]"), package)); | |
276 ASSERT1(package); | |
277 | |
278 UNREFERENCED_PARAMETER(package); | |
279 | |
280 // TODO(omaha): implement in terms of DoDownloadPackage. | |
281 | |
282 return E_NOTIMPL; | |
283 } | |
284 | |
285 HRESULT DownloadManager::GetPackage(const Package* package, | |
286 const CString& dir) const { | |
287 const CString app_id(package->app_version()->app()->app_guid_string()); | |
288 const CString version(package->app_version()->version()); | |
289 const CString package_name(package->filename()); | |
290 | |
291 const PackageCache::Key key(app_id, version, package_name); | |
292 | |
293 CORE_LOG(L3, (_T("[DownloadManager::GetPackage][%s]"), key.ToString())); | |
294 | |
295 const CString dest_file(ConcatenatePath(dir, package_name)); | |
296 CORE_LOG(L3, (_T("[destination file is '%s']"), dest_file)); | |
297 | |
298 const CString hash(package->expected_hash()); | |
299 HRESULT hr = package_cache()->Get(key, dest_file, hash); | |
300 if (FAILED(hr)) { | |
301 CORE_LOG(LE, (_T("[failed to get from cache][0x%08x]"), hr)); | |
302 return hr; | |
303 } | |
304 | |
305 return S_OK; | |
306 } | |
307 | |
308 bool DownloadManager::IsPackageAvailable(const Package* package) const { | |
309 const CString app_id(package->app_version()->app()->app_guid_string()); | |
310 const CString version(package->app_version()->version()); | |
311 const CString package_name(package->filename()); | |
312 | |
313 const PackageCache::Key key(app_id, version, package_name); | |
314 | |
315 CORE_LOG(L3, (_T("[DownloadManager::IsPackageAvailable][%s]"), | |
316 key.ToString())); | |
317 | |
318 const CString hash(package->expected_hash()); | |
319 return package_cache()->IsCached(key, hash); | |
320 } | |
321 | |
322 // Attempts a package download by trying the fallback urls. It does not | |
323 // retry the download if the file validation fails. | |
324 // Assumes the packages are not created or destroyed while method is running. | |
325 HRESULT DownloadManager::DoDownloadPackage(Package* package, State* state) { | |
326 ASSERT1(package); | |
327 ASSERT1(state); | |
328 | |
329 App* app = package->app_version()->app(); | |
330 const CString app_id(app->app_guid_string()); | |
331 const CString version(package->app_version()->version()); | |
332 const CString package_name(package->filename()); | |
333 | |
334 const ConfigManager& cm = *ConfigManager::Instance(); | |
335 // TODO(omaha): Since we don't currently have is_manual, check the least | |
336 // restrictive case of true. It would be nice if we had is_manual. We'll see. | |
337 ASSERT(SUCCEEDED(app->CheckGroupPolicy()), | |
338 (_T("Downloading package app for disallowed app."))); | |
339 | |
340 if (app_id.IsEmpty() || package_name.IsEmpty()) { | |
341 return E_INVALIDARG; | |
342 } | |
343 | |
344 PackageCache::Key key(app_id, version, package_name); | |
345 | |
346 CORE_LOG(L3, (_T("[DownloadManager::DoDownloadPackage][%s]"), | |
347 key.ToString())); | |
348 | |
349 const CString hash(package->expected_hash()); | |
350 | |
351 if (!package_cache()->IsCached(key, hash)) { | |
352 CORE_LOG(L3, (_T("[The package is not cached]"))); | |
353 | |
354 // TODO(omaha3): May need to consider the DownloadPackage case. Also, we may | |
355 // want a error code that does not include "UPDATE". If this is a valid | |
356 // case, need to add message for | |
357 // GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED to GetMessageForError(). | |
358 // As of 9/7/2010, the offline case does not allow downloading if the | |
359 // package cannot be found, so offline scenarios should never get here. | |
360 if (!app->is_eula_accepted()) { | |
361 ASSERT(false, (_T("Can't download because app EULA is not accepted."))); | |
362 return GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED; | |
363 } | |
364 | |
365 if (!ConfigManager::Instance()->CanUseNetwork(is_machine_)) { | |
366 CORE_LOG(LE, (_T("[DoDownloadPackage][network use prohibited]"))); | |
367 return GOOPDATE_E_CANNOT_USE_NETWORK; | |
368 } | |
369 | |
370 CString unique_filename_path; | |
371 HRESULT hr = BuildUniqueFileName(package_name, &unique_filename_path); | |
372 if (FAILED(hr)) { | |
373 CORE_LOG(LE, (_T("[BuildUniqueFileName failed][0x%08x]"), hr)); | |
374 return hr; | |
375 } | |
376 | |
377 NetworkRequest* network_request = state->network_request(); | |
378 | |
379 network_request->set_callback(package); | |
380 | |
381 const std::vector<CString> download_base_urls( | |
382 package->app_version()->download_base_urls()); | |
383 | |
384 hr = E_FAIL; | |
385 for (size_t i = 0; i < download_base_urls.size() && FAILED(hr); ++i) { | |
386 // TODO(omaha3): Append nicely. | |
387 const CString url = download_base_urls[i] + package_name; | |
388 | |
389 if (i > 0) { | |
390 CORE_LOG(L3, (_T("[retrying download with fallback base url][%s]"), | |
391 url)); | |
392 } | |
393 // TODO(omaha3): Increment a usage stat for the ith url being used. | |
394 // Supporting 3 or 4 should be enough. | |
395 | |
396 CORE_LOG(L3, (_T("[starting file download][from '%s'][to '%s']"), | |
397 url, unique_filename_path)); | |
398 | |
399 // Downloading a file is a blocking call. It assumes the model is not | |
400 // locked by the calling thread, otherwise other threads won't be able to | |
401 // to access the model until the file download is complete. | |
402 ASSERT1(!package->model()->IsLockedByCaller()); | |
403 | |
404 hr = network_request->DownloadFile(url, unique_filename_path); | |
405 if (FAILED(hr)) { | |
406 CORE_LOG(LW, (_T("[DownloadFile failed from url][0x%08x]['%s']['%s']"), | |
407 hr, package_name, download_base_urls[i])); | |
408 worker_utils::AddHttpRequestDataToEventLog( | |
409 hr, | |
410 network_request->http_status_code(), | |
411 network_request->trace(), | |
412 is_machine_); | |
413 continue; | |
414 } | |
415 | |
416 // A file has been successfully downloaded from current url. Validate | |
417 // and cache it. | |
418 hr = CallAsSelfAndImpersonate2( | |
419 this, | |
420 &DownloadManager::CachePackage, | |
421 static_cast<const Package*>(package), | |
422 static_cast<const CString*>(&unique_filename_path)); | |
423 if (SUCCEEDED(hr)) { | |
424 break; | |
425 } | |
426 | |
427 CORE_LOG(LE, (_T("[failed to cache package][0x%08x]"), hr)); | |
428 } | |
429 VERIFY1(SUCCEEDED(network_request->Close())); | |
430 DeleteBeforeOrAfterReboot(unique_filename_path); | |
431 | |
432 if (FAILED(hr)) { | |
433 CORE_LOG(LE, (_T("[DownloadFile/caching failed from all urls][0x%08x]"), | |
434 hr)); | |
435 return hr; | |
436 } | |
437 | |
438 // Assumes that downloaded bytes equal to the expected package size. | |
439 app->UpdateNumBytesDownloaded(package->expected_size()); | |
440 } else { | |
441 CORE_LOG(L3, (_T("[package is cached]"))); | |
442 | |
443 // TODO(omaha3): We probably need to update the download stats that | |
444 // Package::OnProgress would set. It may be misleading to set | |
445 // bytes_downloaded to anything other than zero, but App uses this to | |
446 // calculate progress. I suppose we could add an is_complete field instead. | |
447 // There is a related issue with the callback not being called with the | |
448 // final size. See the TODO in the unit tests. | |
449 } | |
450 | |
451 ASSERT1(package_cache()->IsCached(key, hash)); | |
452 return S_OK; | |
453 } | |
454 | |
455 void DownloadManager::Cancel(App* app) { | |
456 CORE_LOG(L3, (_T("[DownloadManager::Cancel][0x%p]"), app)); | |
457 ASSERT1(app); | |
458 | |
459 __mutexScope(lock()); | |
460 | |
461 for (size_t i = 0; i != download_state_.size(); ++i) { | |
462 if (app == download_state_[i]->app()) { | |
463 VERIFY1(SUCCEEDED(download_state_[i]->CancelNetworkRequest())); | |
464 } | |
465 } | |
466 } | |
467 | |
468 void DownloadManager::CancelAll() { | |
469 CORE_LOG(L3, (_T("[DownloadManager::CancelAll]"))); | |
470 | |
471 __mutexScope(lock()); | |
472 | |
473 for (size_t i = 0; i != download_state_.size(); ++i) { | |
474 VERIFY1(SUCCEEDED(download_state_[i]->CancelNetworkRequest())); | |
475 } | |
476 } | |
477 | |
478 bool DownloadManager::IsBusy() const { | |
479 __mutexScope(lock()); | |
480 return !download_state_.empty(); | |
481 } | |
482 | |
483 HRESULT DownloadManager::PurgeAppLowerVersions(const CString& app_id, | |
484 const CString& version) { | |
485 return package_cache()->PurgeAppLowerVersions(app_id, version); | |
486 } | |
487 | |
488 HRESULT DownloadManager::CachePackage(const Package* package, | |
489 const CString* filename_path) { | |
490 ASSERT1(package); | |
491 ASSERT1(filename_path); | |
492 | |
493 const CString app_id(package->app_version()->app()->app_guid_string()); | |
494 const CString version(package->app_version()->version()); | |
495 const CString package_name(package->filename()); | |
496 PackageCache::Key key(app_id, version, package_name); | |
497 | |
498 const CString hash(package->expected_hash()); | |
499 | |
500 HRESULT hr = package_cache()->Put(key, *filename_path, hash); | |
501 if (hr != SIGS_E_INVALID_SIGNATURE) { | |
502 if (FAILED(hr)) { | |
503 set_error_extra_code1(static_cast<int>(hr)); | |
504 return GOOPDATEDOWNLOAD_E_CACHING_FAILED; | |
505 } | |
506 return hr; | |
507 } | |
508 | |
509 // Get a more specific error if possible. | |
510 // TODO(omaha): It would be nice to detect that we downloaded a proxy | |
511 // page and tell the user this. It would be even better if we could | |
512 // display it; that would require a lot more plumbing. | |
513 HRESULT size_hr = ValidateSize(*filename_path, package->expected_size()); | |
514 if (FAILED(size_hr)) { | |
515 hr = size_hr; | |
516 } | |
517 | |
518 return hr; | |
519 } | |
520 | |
521 // The file is initially downloaded to a temporary unique name, to account | |
522 // for the case where the same file is downloaded by multiple callers. | |
523 HRESULT DownloadManager::BuildUniqueFileName(const CString& filename, | |
524 CString* unique_filename) { | |
525 ASSERT1(unique_filename); | |
526 | |
527 GUID guid(GUID_NULL); | |
528 HRESULT hr = ::CoCreateGuid(&guid); | |
529 if (FAILED(hr)) { | |
530 CORE_LOG(L3, (_T("[CoCreateGuid failed][0x%08x]"), hr)); | |
531 return hr; | |
532 } | |
533 | |
534 // Format of the unique file name is: <temp_download_dir>/<guid>-<filename>. | |
535 const CString temp_dir(ConfigManager::Instance()->GetTempDownloadDir()); | |
536 CString temp_filename; | |
537 SafeCStringFormat(&temp_filename, _T("%s-%s"), GuidToString(guid), filename); | |
538 *unique_filename = ConcatenatePath(temp_dir, temp_filename); | |
539 | |
540 return unique_filename->IsEmpty() ? | |
541 GOOPDATEDOWNLOAD_E_UNIQUE_FILE_PATH_EMPTY : S_OK; | |
542 } | |
543 | |
544 HRESULT DownloadManager::CreateStateForApp(App* app, State** state) { | |
545 ASSERT1(app); | |
546 ASSERT1(state); | |
547 | |
548 *state = NULL; | |
549 | |
550 NetworkRequest* network_request = NULL; | |
551 HRESULT hr = CreateNetworkRequest(&network_request); | |
552 if (FAILED(hr)) { | |
553 return hr; | |
554 } | |
555 | |
556 ASSERT1(network_request); | |
557 | |
558 const bool use_background_priority = | |
559 (app->app_bundle()->priority() < INSTALL_PRIORITY_HIGH); | |
560 network_request->set_low_priority(use_background_priority); | |
561 | |
562 network_request->set_proxy_auth_config( | |
563 app->app_bundle()->GetProxyAuthConfig()); | |
564 | |
565 scoped_ptr<State> state_ptr(new State(app, network_request)); | |
566 | |
567 __mutexBlock(lock()) { | |
568 download_state_.push_back(state_ptr.release()); | |
569 *state = download_state_.back(); | |
570 } | |
571 | |
572 return S_OK; | |
573 } | |
574 | |
575 HRESULT DownloadManager::DeleteStateForApp(App* app) { | |
576 ASSERT1(app); | |
577 | |
578 __mutexScope(lock()); | |
579 | |
580 typedef std::vector<State*>::iterator Iter; | |
581 for (Iter it(download_state_.begin()); it != download_state_.end(); ++it) { | |
582 if (app == (*it)->app()) { | |
583 delete *it; | |
584 download_state_.erase(it); | |
585 return S_OK; | |
586 } | |
587 } | |
588 | |
589 ASSERT1(false); | |
590 | |
591 return E_UNEXPECTED; | |
592 } | |
593 | |
594 DownloadManager::State::State(App* app, NetworkRequest* network_request) | |
595 : app_(app), network_request_(network_request) { | |
596 ASSERT1(app); | |
597 ASSERT1(network_request); | |
598 } | |
599 | |
600 DownloadManager::State::~State() { | |
601 } | |
602 | |
603 NetworkRequest* DownloadManager::State::network_request() const { | |
604 ASSERT1(ConfigManager::Instance()->CanUseNetwork( | |
605 app_->app_bundle()->is_machine())); | |
606 | |
607 return network_request_.get(); | |
608 } | |
609 | |
610 HRESULT DownloadManager::State::CancelNetworkRequest() { | |
611 return network_request_->Cancel(); | |
612 } | |
613 | |
614 } // namespace omaha | |
OLD | NEW |