OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/installable/installable_manager.h" | 5 #include "chrome/browser/installable/installable_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "chrome/browser/manifest/manifest_icon_downloader.h" | 10 #include "chrome/browser/manifest/manifest_icon_downloader.h" |
11 #include "chrome/browser/manifest/manifest_icon_selector.h" | 11 #include "chrome/browser/manifest/manifest_icon_selector.h" |
12 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
13 #include "chrome/browser/ssl/security_state_tab_helper.h" | 13 #include "chrome/browser/ssl/security_state_tab_helper.h" |
14 #include "components/security_state/core/security_state.h" | 14 #include "components/security_state/core/security_state.h" |
15 #include "content/public/browser/browser_context.h" | 15 #include "content/public/browser/browser_context.h" |
16 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/navigation_handle.h" | 17 #include "content/public/browser/navigation_handle.h" |
18 #include "content/public/browser/service_worker_context.h" | |
19 #include "content/public/browser/storage_partition.h" | 18 #include "content/public/browser/storage_partition.h" |
20 #include "net/base/url_util.h" | 19 #include "net/base/url_util.h" |
21 #include "third_party/WebKit/public/platform/WebDisplayMode.h" | 20 #include "third_party/WebKit/public/platform/WebDisplayMode.h" |
22 | 21 |
23 using IconPurpose = content::Manifest::Icon::IconPurpose; | 22 using IconPurpose = content::Manifest::Icon::IconPurpose; |
24 | 23 |
25 namespace { | 24 namespace { |
26 | 25 |
27 const char kPngExtension[] = ".png"; | 26 const char kPngExtension[] = ".png"; |
28 | 27 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 | 69 |
71 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InstallableManager); | 70 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InstallableManager); |
72 | 71 |
73 struct InstallableManager::ManifestProperty { | 72 struct InstallableManager::ManifestProperty { |
74 InstallableStatusCode error = NO_ERROR_DETECTED; | 73 InstallableStatusCode error = NO_ERROR_DETECTED; |
75 GURL url; | 74 GURL url; |
76 content::Manifest manifest; | 75 content::Manifest manifest; |
77 bool fetched = false; | 76 bool fetched = false; |
78 }; | 77 }; |
79 | 78 |
80 struct InstallableManager::InstallableProperty { | 79 struct InstallableManager::ValidManifestProperty { |
81 InstallableStatusCode error = NO_ERROR_DETECTED; | 80 InstallableStatusCode error = NO_ERROR_DETECTED; |
82 bool installable = false; | 81 bool is_valid = false; |
83 bool fetched = false; | 82 bool fetched = false; |
84 }; | 83 }; |
85 | 84 |
| 85 struct InstallableManager::ServiceWorkerProperty { |
| 86 InstallableStatusCode error = NO_ERROR_DETECTED; |
| 87 bool has_worker = false; |
| 88 bool is_waiting = false; |
| 89 bool fetched = false; |
| 90 }; |
| 91 |
86 struct InstallableManager::IconProperty { | 92 struct InstallableManager::IconProperty { |
87 IconProperty() : | 93 IconProperty() : |
88 error(NO_ERROR_DETECTED), url(), icon(), fetched(false) { } | 94 error(NO_ERROR_DETECTED), url(), icon(), fetched(false) { } |
89 IconProperty(IconProperty&& other) = default; | 95 IconProperty(IconProperty&& other) = default; |
90 IconProperty& operator=(IconProperty&& other) = default; | 96 IconProperty& operator=(IconProperty&& other) = default; |
91 | 97 |
92 InstallableStatusCode error = NO_ERROR_DETECTED; | 98 InstallableStatusCode error = NO_ERROR_DETECTED; |
93 GURL url; | 99 GURL url; |
94 std::unique_ptr<SkBitmap> icon; | 100 std::unique_ptr<SkBitmap> icon; |
95 bool fetched; | 101 bool fetched; |
96 | 102 |
97 private: | 103 private: |
98 // This class contains a std::unique_ptr and therefore must be move-only. | 104 // This class contains a std::unique_ptr and therefore must be move-only. |
99 DISALLOW_COPY_AND_ASSIGN(IconProperty); | 105 DISALLOW_COPY_AND_ASSIGN(IconProperty); |
100 }; | 106 }; |
101 | 107 |
102 InstallableManager::InstallableManager(content::WebContents* web_contents) | 108 InstallableManager::InstallableManager(content::WebContents* web_contents) |
103 : content::WebContentsObserver(web_contents), | 109 : content::WebContentsObserver(web_contents), |
104 manifest_(new ManifestProperty()), | 110 manifest_(base::MakeUnique<ManifestProperty>()), |
105 installable_(new InstallableProperty()), | 111 valid_manifest_(base::MakeUnique<ValidManifestProperty>()), |
| 112 worker_(base::MakeUnique<ServiceWorkerProperty>()), |
| 113 service_worker_context_(nullptr), |
106 page_status_(InstallabilityCheckStatus::NOT_STARTED), | 114 page_status_(InstallabilityCheckStatus::NOT_STARTED), |
107 menu_open_count_(0), | 115 menu_open_count_(0), |
108 menu_item_add_to_homescreen_count_(0), | 116 menu_item_add_to_homescreen_count_(0), |
109 is_active_(false), | 117 is_active_(false), |
110 is_pwa_check_complete_(false), | 118 is_pwa_check_complete_(false), |
111 weak_factory_(this) {} | 119 weak_factory_(this) { |
| 120 // This is null in unit tests. |
| 121 if (web_contents) { |
| 122 content::StoragePartition* storage_partition = |
| 123 content::BrowserContext::GetStoragePartition( |
| 124 Profile::FromBrowserContext(web_contents->GetBrowserContext()), |
| 125 web_contents->GetSiteInstance()); |
| 126 DCHECK(storage_partition); |
112 | 127 |
113 InstallableManager::~InstallableManager() = default; | 128 service_worker_context_ = storage_partition->GetServiceWorkerContext(); |
| 129 service_worker_context_->AddObserver(this); |
| 130 } |
| 131 } |
| 132 |
| 133 InstallableManager::~InstallableManager() { |
| 134 // Null in unit tests. |
| 135 if (service_worker_context_) |
| 136 service_worker_context_->RemoveObserver(this); |
| 137 } |
114 | 138 |
115 // static | 139 // static |
116 bool InstallableManager::IsContentSecure(content::WebContents* web_contents) { | 140 bool InstallableManager::IsContentSecure(content::WebContents* web_contents) { |
117 if (!web_contents) | 141 if (!web_contents) |
118 return false; | 142 return false; |
119 | 143 |
120 // Whitelist localhost. Check the VisibleURL to match what the | 144 // Whitelist localhost. Check the VisibleURL to match what the |
121 // SecurityStateTabHelper looks at. | 145 // SecurityStateTabHelper looks at. |
122 if (net::IsLocalhost(web_contents->GetVisibleURL().HostNoBrackets())) | 146 if (net::IsLocalhost(web_contents->GetVisibleURL().HostNoBrackets())) |
123 return true; | 147 return true; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 | 246 |
223 void InstallableManager::SetIconFetched(const IconParams& params) { | 247 void InstallableManager::SetIconFetched(const IconParams& params) { |
224 icons_[params].fetched = true; | 248 icons_[params].fetched = true; |
225 } | 249 } |
226 | 250 |
227 InstallableStatusCode InstallableManager::GetErrorCode( | 251 InstallableStatusCode InstallableManager::GetErrorCode( |
228 const InstallableParams& params) { | 252 const InstallableParams& params) { |
229 if (manifest_->error != NO_ERROR_DETECTED) | 253 if (manifest_->error != NO_ERROR_DETECTED) |
230 return manifest_->error; | 254 return manifest_->error; |
231 | 255 |
232 if (params.check_installable && installable_->error != NO_ERROR_DETECTED) | 256 if (params.check_installable) { |
233 return installable_->error; | 257 if (valid_manifest_->error != NO_ERROR_DETECTED) |
| 258 return valid_manifest_->error; |
| 259 if (worker_->error != NO_ERROR_DETECTED) |
| 260 return worker_->error; |
| 261 } |
234 | 262 |
235 if (params.fetch_valid_primary_icon) { | 263 if (params.fetch_valid_primary_icon) { |
236 IconProperty& icon = icons_[ParamsForPrimaryIcon(params)]; | 264 IconProperty& icon = icons_[ParamsForPrimaryIcon(params)]; |
237 if (icon.error != NO_ERROR_DETECTED) | 265 if (icon.error != NO_ERROR_DETECTED) |
238 return icon.error; | 266 return icon.error; |
239 } | 267 } |
240 | 268 |
241 if (params.fetch_valid_badge_icon) { | 269 if (params.fetch_valid_badge_icon) { |
242 IconProperty& icon = icons_[ParamsForBadgeIcon(params)]; | 270 IconProperty& icon = icons_[ParamsForBadgeIcon(params)]; |
243 | 271 |
244 // If the error is NO_ACCEPTABLE_ICON, there is no icon suitable as a badge | 272 // If the error is NO_ACCEPTABLE_ICON, there is no icon suitable as a badge |
245 // in the manifest. Ignore this case since we only want to fail the check if | 273 // in the manifest. Ignore this case since we only want to fail the check if |
246 // there was a suitable badge icon specified and we couldn't fetch it. | 274 // there was a suitable badge icon specified and we couldn't fetch it. |
247 if (icon.error != NO_ERROR_DETECTED && icon.error != NO_ACCEPTABLE_ICON) | 275 if (icon.error != NO_ERROR_DETECTED && icon.error != NO_ACCEPTABLE_ICON) |
248 return icon.error; | 276 return icon.error; |
249 } | 277 } |
250 | 278 |
251 return NO_ERROR_DETECTED; | 279 return NO_ERROR_DETECTED; |
252 } | 280 } |
253 | 281 |
254 InstallableStatusCode InstallableManager::manifest_error() const { | 282 InstallableStatusCode InstallableManager::manifest_error() const { |
255 return manifest_->error; | 283 return manifest_->error; |
256 } | 284 } |
257 | 285 |
258 InstallableStatusCode InstallableManager::installable_error() const { | 286 InstallableStatusCode InstallableManager::valid_manifest_error() const { |
259 return installable_->error; | 287 return valid_manifest_->error; |
260 } | 288 } |
261 | 289 |
262 void InstallableManager::set_installable_error( | 290 void InstallableManager::set_valid_manifest_error( |
263 InstallableStatusCode error_code) { | 291 InstallableStatusCode error_code) { |
264 installable_->error = error_code; | 292 valid_manifest_->error = error_code; |
| 293 } |
| 294 |
| 295 InstallableStatusCode InstallableManager::worker_error() const { |
| 296 return worker_->error; |
265 } | 297 } |
266 | 298 |
267 InstallableStatusCode InstallableManager::icon_error( | 299 InstallableStatusCode InstallableManager::icon_error( |
268 const IconParams& icon_params) { | 300 const IconParams& icon_params) { |
269 return icons_[icon_params].error; | 301 return icons_[icon_params].error; |
270 } | 302 } |
271 | 303 |
272 GURL& InstallableManager::icon_url(const IconParams& icon_params) { | 304 GURL& InstallableManager::icon_url(const IconParams& icon_params) { |
273 return icons_[icon_params].url; | 305 return icons_[icon_params].url; |
274 } | 306 } |
275 | 307 |
276 const SkBitmap* InstallableManager::icon(const IconParams& icon_params) { | 308 const SkBitmap* InstallableManager::icon(const IconParams& icon_params) { |
277 return icons_[icon_params].icon.get(); | 309 return icons_[icon_params].icon.get(); |
278 } | 310 } |
279 | 311 |
280 content::WebContents* InstallableManager::GetWebContents() { | 312 content::WebContents* InstallableManager::GetWebContents() { |
281 content::WebContents* contents = web_contents(); | 313 content::WebContents* contents = web_contents(); |
282 if (!contents || contents->IsBeingDestroyed()) | 314 if (!contents || contents->IsBeingDestroyed()) |
283 return nullptr; | 315 return nullptr; |
284 return contents; | 316 return contents; |
285 } | 317 } |
286 | 318 |
287 bool InstallableManager::IsComplete(const InstallableParams& params) const { | 319 bool InstallableManager::IsComplete(const InstallableParams& params) const { |
288 // Returns true if for all resources: | 320 // Returns true if for all resources: |
289 // a. the params did not request it, OR | 321 // a. the params did not request it, OR |
290 // b. the resource has been fetched/checked. | 322 // b. the resource has been fetched/checked. |
291 return manifest_->fetched && | 323 return manifest_->fetched && |
292 (!params.check_installable || installable_->fetched) && | 324 (!params.check_installable || |
| 325 (valid_manifest_->fetched && worker_->fetched)) && |
293 (!params.fetch_valid_primary_icon || | 326 (!params.fetch_valid_primary_icon || |
294 IsIconFetched(ParamsForPrimaryIcon(params))) && | 327 IsIconFetched(ParamsForPrimaryIcon(params))) && |
295 (!params.fetch_valid_badge_icon || | 328 (!params.fetch_valid_badge_icon || |
296 IsIconFetched(ParamsForBadgeIcon(params))); | 329 IsIconFetched(ParamsForBadgeIcon(params))); |
297 } | 330 } |
298 | 331 |
299 void InstallableManager::Reset() { | 332 void InstallableManager::Reset() { |
300 // Prevent any outstanding callbacks to or from this object from being called. | 333 // Prevent any outstanding callbacks to or from this object from being called. |
301 weak_factory_.InvalidateWeakPtrs(); | 334 weak_factory_.InvalidateWeakPtrs(); |
302 tasks_.clear(); | 335 tasks_.clear(); |
303 icons_.clear(); | 336 icons_.clear(); |
304 | 337 |
305 // We may have reset prior to completion, in which case |menu_open_count_| or | 338 // We may have reset prior to completion, in which case |menu_open_count_| or |
306 // |menu_item_add_to_homescreen_count_| might be nonzero and |page_status_| is | 339 // |menu_item_add_to_homescreen_count_| might be nonzero and |page_status_| is |
307 // one of NOT_STARTED or NOT_COMPLETED. If we completed, then these values | 340 // one of NOT_STARTED or NOT_COMPLETED. If we completed, then these values |
308 // cannot be anything except 0. | 341 // cannot be anything except 0. |
309 is_pwa_check_complete_ = false; | 342 is_pwa_check_complete_ = false; |
310 | 343 |
311 for (; menu_open_count_ > 0; --menu_open_count_) | 344 for (; menu_open_count_ > 0; --menu_open_count_) |
312 InstallableMetrics::RecordMenuOpenHistogram(page_status_); | 345 InstallableMetrics::RecordMenuOpenHistogram(page_status_); |
313 | 346 |
314 for (; menu_item_add_to_homescreen_count_ > 0; | 347 for (; menu_item_add_to_homescreen_count_ > 0; |
315 --menu_item_add_to_homescreen_count_) { | 348 --menu_item_add_to_homescreen_count_) { |
316 InstallableMetrics::RecordMenuItemAddToHomescreenHistogram(page_status_); | 349 InstallableMetrics::RecordMenuItemAddToHomescreenHistogram(page_status_); |
317 } | 350 } |
318 | 351 |
319 page_status_ = InstallabilityCheckStatus::NOT_STARTED; | 352 page_status_ = InstallabilityCheckStatus::NOT_STARTED; |
320 manifest_.reset(new ManifestProperty()); | 353 manifest_ = base::MakeUnique<ManifestProperty>(); |
321 installable_.reset(new InstallableProperty()); | 354 valid_manifest_ = base::MakeUnique<ValidManifestProperty>(); |
| 355 worker_ = base::MakeUnique<ServiceWorkerProperty>(); |
322 | 356 |
323 is_active_ = false; | 357 is_active_ = false; |
324 } | 358 } |
325 | 359 |
326 void InstallableManager::SetManifestDependentTasksComplete() { | 360 void InstallableManager::SetManifestDependentTasksComplete() { |
327 DCHECK(!tasks_.empty()); | 361 DCHECK(!tasks_.empty()); |
328 const InstallableParams& params = tasks_[0].first; | 362 const InstallableParams& params = tasks_[0].first; |
329 | 363 |
330 installable_->fetched = true; | 364 valid_manifest_->fetched = true; |
| 365 worker_->fetched = true; |
331 SetIconFetched(ParamsForPrimaryIcon(params)); | 366 SetIconFetched(ParamsForPrimaryIcon(params)); |
332 SetIconFetched(ParamsForBadgeIcon(params)); | 367 SetIconFetched(ParamsForBadgeIcon(params)); |
333 } | 368 } |
334 | 369 |
335 void InstallableManager::RunCallback(const Task& task, | 370 void InstallableManager::RunCallback(const Task& task, |
336 InstallableStatusCode code) { | 371 InstallableStatusCode code) { |
337 const InstallableParams& params = task.first; | 372 const InstallableParams& params = task.first; |
338 IconProperty null_icon; | 373 IconProperty null_icon; |
339 IconProperty* primary_icon = &null_icon; | 374 IconProperty* primary_icon = &null_icon; |
340 IconProperty* badge_icon = &null_icon; | 375 IconProperty* badge_icon = &null_icon; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 tasks_.erase(tasks_.begin()); | 419 tasks_.erase(tasks_.begin()); |
385 StartNextTask(); | 420 StartNextTask(); |
386 return; | 421 return; |
387 } | 422 } |
388 | 423 |
389 if (!manifest_->fetched) { | 424 if (!manifest_->fetched) { |
390 FetchManifest(); | 425 FetchManifest(); |
391 } else if (params.fetch_valid_primary_icon && | 426 } else if (params.fetch_valid_primary_icon && |
392 !IsIconFetched(ParamsForPrimaryIcon(params))) { | 427 !IsIconFetched(ParamsForPrimaryIcon(params))) { |
393 CheckAndFetchBestIcon(ParamsForPrimaryIcon(params)); | 428 CheckAndFetchBestIcon(ParamsForPrimaryIcon(params)); |
394 } else if (params.check_installable && !installable_->fetched) { | 429 } else if (params.check_installable && !valid_manifest_->fetched) { |
395 CheckInstallable(); | 430 CheckInstallable(); |
| 431 } else if (params.check_installable && !worker_->fetched) { |
| 432 CheckServiceWorker(); |
396 } else if (params.fetch_valid_badge_icon && | 433 } else if (params.fetch_valid_badge_icon && |
397 !IsIconFetched(ParamsForBadgeIcon(params))) { | 434 !IsIconFetched(ParamsForBadgeIcon(params))) { |
398 CheckAndFetchBestIcon(ParamsForBadgeIcon(params)); | 435 CheckAndFetchBestIcon(ParamsForBadgeIcon(params)); |
399 } else { | 436 } else { |
400 NOTREACHED(); | 437 NOTREACHED(); |
401 } | 438 } |
402 } | 439 } |
403 | 440 |
404 void InstallableManager::FetchManifest() { | 441 void InstallableManager::FetchManifest() { |
405 DCHECK(!manifest_->fetched); | 442 DCHECK(!manifest_->fetched); |
(...skipping 18 matching lines...) Expand all Loading... |
424 SetManifestDependentTasksComplete(); | 461 SetManifestDependentTasksComplete(); |
425 } | 462 } |
426 | 463 |
427 manifest_->url = manifest_url; | 464 manifest_->url = manifest_url; |
428 manifest_->manifest = manifest; | 465 manifest_->manifest = manifest; |
429 manifest_->fetched = true; | 466 manifest_->fetched = true; |
430 WorkOnTask(); | 467 WorkOnTask(); |
431 } | 468 } |
432 | 469 |
433 void InstallableManager::CheckInstallable() { | 470 void InstallableManager::CheckInstallable() { |
434 DCHECK(!installable_->fetched); | 471 DCHECK(!valid_manifest_->fetched); |
435 DCHECK(!manifest().IsEmpty()); | 472 DCHECK(!manifest().IsEmpty()); |
436 | 473 |
437 if (IsManifestValidForWebApp(manifest())) { | 474 valid_manifest_->is_valid = IsManifestValidForWebApp(manifest()); |
438 CheckServiceWorker(); | 475 valid_manifest_->fetched = true; |
439 } else { | 476 WorkOnTask(); |
440 installable_->installable = false; | |
441 installable_->fetched = true; | |
442 WorkOnTask(); | |
443 } | |
444 } | 477 } |
445 | 478 |
446 bool InstallableManager::IsManifestValidForWebApp( | 479 bool InstallableManager::IsManifestValidForWebApp( |
447 const content::Manifest& manifest) { | 480 const content::Manifest& manifest) { |
448 if (manifest.IsEmpty()) { | 481 if (manifest.IsEmpty()) { |
449 installable_->error = MANIFEST_EMPTY; | 482 valid_manifest_->error = MANIFEST_EMPTY; |
450 return false; | 483 return false; |
451 } | 484 } |
452 | 485 |
453 if (!manifest.start_url.is_valid()) { | 486 if (!manifest.start_url.is_valid()) { |
454 installable_->error = START_URL_NOT_VALID; | 487 valid_manifest_->error = START_URL_NOT_VALID; |
455 return false; | 488 return false; |
456 } | 489 } |
457 | 490 |
458 if ((manifest.name.is_null() || manifest.name.string().empty()) && | 491 if ((manifest.name.is_null() || manifest.name.string().empty()) && |
459 (manifest.short_name.is_null() || manifest.short_name.string().empty())) { | 492 (manifest.short_name.is_null() || manifest.short_name.string().empty())) { |
460 installable_->error = MANIFEST_MISSING_NAME_OR_SHORT_NAME; | 493 valid_manifest_->error = MANIFEST_MISSING_NAME_OR_SHORT_NAME; |
461 return false; | 494 return false; |
462 } | 495 } |
463 | 496 |
464 // TODO(dominickn,mlamouri): when Chrome supports "minimal-ui", it should be | 497 // TODO(dominickn,mlamouri): when Chrome supports "minimal-ui", it should be |
465 // accepted. If we accept it today, it would fallback to "browser" and make | 498 // accepted. If we accept it today, it would fallback to "browser" and make |
466 // this check moot. See https://crbug.com/604390. | 499 // this check moot. See https://crbug.com/604390. |
467 if (manifest.display != blink::kWebDisplayModeStandalone && | 500 if (manifest.display != blink::kWebDisplayModeStandalone && |
468 manifest.display != blink::kWebDisplayModeFullscreen) { | 501 manifest.display != blink::kWebDisplayModeFullscreen) { |
469 installable_->error = MANIFEST_DISPLAY_NOT_SUPPORTED; | 502 valid_manifest_->error = MANIFEST_DISPLAY_NOT_SUPPORTED; |
470 return false; | 503 return false; |
471 } | 504 } |
472 | 505 |
473 if (!DoesManifestContainRequiredIcon(manifest)) { | 506 if (!DoesManifestContainRequiredIcon(manifest)) { |
474 installable_->error = MANIFEST_MISSING_SUITABLE_ICON; | 507 valid_manifest_->error = MANIFEST_MISSING_SUITABLE_ICON; |
475 return false; | 508 return false; |
476 } | 509 } |
477 | 510 |
478 return true; | 511 return true; |
479 } | 512 } |
480 | 513 |
481 void InstallableManager::CheckServiceWorker() { | 514 void InstallableManager::CheckServiceWorker() { |
482 DCHECK(!installable_->fetched); | 515 DCHECK(!worker_->fetched); |
483 DCHECK(!manifest().IsEmpty()); | 516 DCHECK(!manifest().IsEmpty()); |
484 DCHECK(manifest().start_url.is_valid()); | 517 DCHECK(manifest().start_url.is_valid()); |
485 | 518 |
486 content::WebContents* web_contents = GetWebContents(); | |
487 | |
488 // Check to see if there is a single service worker controlling this page | 519 // Check to see if there is a single service worker controlling this page |
489 // and the manifest's start url. | 520 // and the manifest's start url. |
490 content::StoragePartition* storage_partition = | 521 service_worker_context_->CheckHasServiceWorker( |
491 content::BrowserContext::GetStoragePartition( | 522 GetWebContents()->GetLastCommittedURL(), manifest().start_url, |
492 Profile::FromBrowserContext(web_contents->GetBrowserContext()), | |
493 web_contents->GetSiteInstance()); | |
494 DCHECK(storage_partition); | |
495 | |
496 storage_partition->GetServiceWorkerContext()->CheckHasServiceWorker( | |
497 web_contents->GetLastCommittedURL(), manifest().start_url, | |
498 base::Bind(&InstallableManager::OnDidCheckHasServiceWorker, | 523 base::Bind(&InstallableManager::OnDidCheckHasServiceWorker, |
499 weak_factory_.GetWeakPtr())); | 524 weak_factory_.GetWeakPtr())); |
500 } | 525 } |
501 | 526 |
502 void InstallableManager::OnDidCheckHasServiceWorker( | 527 void InstallableManager::OnDidCheckHasServiceWorker( |
503 content::ServiceWorkerCapability capability) { | 528 content::ServiceWorkerCapability capability) { |
504 if (!GetWebContents()) | 529 if (!GetWebContents()) |
505 return; | 530 return; |
506 | 531 |
507 switch (capability) { | 532 switch (capability) { |
508 case content::ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER: | 533 case content::ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER: |
509 installable_->installable = true; | 534 worker_->has_worker = true; |
510 break; | 535 break; |
511 case content::ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER: | 536 case content::ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER: |
512 installable_->installable = false; | 537 worker_->has_worker = false; |
513 installable_->error = NOT_OFFLINE_CAPABLE; | 538 worker_->error = NOT_OFFLINE_CAPABLE; |
514 break; | 539 break; |
515 case content::ServiceWorkerCapability::NO_SERVICE_WORKER: | 540 case content::ServiceWorkerCapability::NO_SERVICE_WORKER: |
516 installable_->installable = false; | 541 InstallableParams& params = tasks_[0].first; |
517 installable_->error = NO_MATCHING_SERVICE_WORKER; | 542 if (params.wait_for_worker) { |
| 543 // Wait for ServiceWorkerContextObserver::OnRegistrationStored. Set the |
| 544 // param |wait_for_worker| to false so we only wait once per task. |
| 545 params.wait_for_worker = false; |
| 546 worker_->is_waiting = true; |
| 547 return; |
| 548 } |
| 549 worker_->has_worker = false; |
| 550 worker_->error = NO_MATCHING_SERVICE_WORKER; |
518 break; | 551 break; |
519 } | 552 } |
520 | 553 |
521 installable_->fetched = true; | 554 worker_->fetched = true; |
522 WorkOnTask(); | 555 WorkOnTask(); |
523 } | 556 } |
524 | 557 |
525 void InstallableManager::CheckAndFetchBestIcon(const IconParams& params) { | 558 void InstallableManager::CheckAndFetchBestIcon(const IconParams& params) { |
526 DCHECK(!manifest().IsEmpty()); | 559 DCHECK(!manifest().IsEmpty()); |
527 | 560 |
528 int ideal_icon_size_in_px = std::get<0>(params); | 561 int ideal_icon_size_in_px = std::get<0>(params); |
529 int minimum_icon_size_in_px = std::get<1>(params); | 562 int minimum_icon_size_in_px = std::get<1>(params); |
530 IconPurpose icon_purpose = std::get<2>(params); | 563 IconPurpose icon_purpose = std::get<2>(params); |
531 | 564 |
(...skipping 30 matching lines...) Expand all Loading... |
562 if (bitmap.drawsNothing()) { | 595 if (bitmap.drawsNothing()) { |
563 icon.error = NO_ICON_AVAILABLE; | 596 icon.error = NO_ICON_AVAILABLE; |
564 } else { | 597 } else { |
565 icon.url = icon_url; | 598 icon.url = icon_url; |
566 icon.icon.reset(new SkBitmap(bitmap)); | 599 icon.icon.reset(new SkBitmap(bitmap)); |
567 } | 600 } |
568 | 601 |
569 WorkOnTask(); | 602 WorkOnTask(); |
570 } | 603 } |
571 | 604 |
| 605 void InstallableManager::OnRegistrationStored(const GURL& pattern) { |
| 606 // We aren't currently waiting, so either: |
| 607 // a) we've already failed the check, or |
| 608 // b) we haven't yet called CheckHasServiceWorker. |
| 609 if (!worker_->is_waiting || !content::ServiceWorkerContext::ScopeMatches( |
| 610 pattern, manifest().start_url)) { |
| 611 return; |
| 612 } |
| 613 |
| 614 // This will call CheckHasServiceWorker to check whether the service worker |
| 615 // controls the start_url and if it has a fetch handler. |
| 616 worker_->is_waiting = false; |
| 617 WorkOnTask(); |
| 618 } |
| 619 |
572 void InstallableManager::DidFinishNavigation( | 620 void InstallableManager::DidFinishNavigation( |
573 content::NavigationHandle* handle) { | 621 content::NavigationHandle* handle) { |
574 if (handle->IsInMainFrame() && handle->HasCommitted() && | 622 if (handle->IsInMainFrame() && handle->HasCommitted() && |
575 !handle->IsSameDocument()) { | 623 !handle->IsSameDocument()) { |
576 Reset(); | 624 Reset(); |
577 } | 625 } |
578 } | 626 } |
579 | 627 |
580 void InstallableManager::WebContentsDestroyed() { | 628 void InstallableManager::WebContentsDestroyed() { |
581 Reset(); | 629 Reset(); |
582 Observe(nullptr); | 630 Observe(nullptr); |
583 } | 631 } |
584 | 632 |
585 const GURL& InstallableManager::manifest_url() const { | 633 const GURL& InstallableManager::manifest_url() const { |
586 return manifest_->url; | 634 return manifest_->url; |
587 } | 635 } |
588 | 636 |
589 const content::Manifest& InstallableManager::manifest() const { | 637 const content::Manifest& InstallableManager::manifest() const { |
590 return manifest_->manifest; | 638 return manifest_->manifest; |
591 } | 639 } |
592 | 640 |
593 bool InstallableManager::is_installable() const { | 641 bool InstallableManager::is_installable() const { |
594 return installable_->installable; | 642 return valid_manifest_->is_valid && worker_->has_worker; |
595 } | 643 } |
OLD | NEW |