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/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
11 #include "chrome/browser/ssl/security_state_tab_helper.h" | 11 #include "chrome/browser/ssl/security_state_tab_helper.h" |
12 #include "components/security_state/core/security_state.h" | 12 #include "components/security_state/core/security_state.h" |
13 #include "content/public/browser/browser_context.h" | 13 #include "content/public/browser/browser_context.h" |
14 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
15 #include "content/public/browser/manifest_icon_downloader.h" | 15 #include "content/public/browser/manifest_icon_downloader.h" |
16 #include "content/public/browser/manifest_icon_selector.h" | 16 #include "content/public/browser/manifest_icon_selector.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; |
| 297 } |
| 298 |
| 299 bool InstallableManager::worker_waiting() const { |
| 300 return worker_->is_waiting; |
265 } | 301 } |
266 | 302 |
267 InstallableStatusCode InstallableManager::icon_error( | 303 InstallableStatusCode InstallableManager::icon_error( |
268 const IconParams& icon_params) { | 304 const IconParams& icon_params) { |
269 return icons_[icon_params].error; | 305 return icons_[icon_params].error; |
270 } | 306 } |
271 | 307 |
272 GURL& InstallableManager::icon_url(const IconParams& icon_params) { | 308 GURL& InstallableManager::icon_url(const IconParams& icon_params) { |
273 return icons_[icon_params].url; | 309 return icons_[icon_params].url; |
274 } | 310 } |
275 | 311 |
276 const SkBitmap* InstallableManager::icon(const IconParams& icon_params) { | 312 const SkBitmap* InstallableManager::icon(const IconParams& icon_params) { |
277 return icons_[icon_params].icon.get(); | 313 return icons_[icon_params].icon.get(); |
278 } | 314 } |
279 | 315 |
280 content::WebContents* InstallableManager::GetWebContents() { | 316 content::WebContents* InstallableManager::GetWebContents() { |
281 content::WebContents* contents = web_contents(); | 317 content::WebContents* contents = web_contents(); |
282 if (!contents || contents->IsBeingDestroyed()) | 318 if (!contents || contents->IsBeingDestroyed()) |
283 return nullptr; | 319 return nullptr; |
284 return contents; | 320 return contents; |
285 } | 321 } |
286 | 322 |
287 bool InstallableManager::IsComplete(const InstallableParams& params) const { | 323 bool InstallableManager::IsComplete(const InstallableParams& params) const { |
288 // Returns true if for all resources: | 324 // Returns true if for all resources: |
289 // a. the params did not request it, OR | 325 // a. the params did not request it, OR |
290 // b. the resource has been fetched/checked. | 326 // b. the resource has been fetched/checked. |
291 return manifest_->fetched && | 327 return manifest_->fetched && |
292 (!params.check_installable || installable_->fetched) && | 328 (!params.check_installable || |
| 329 (valid_manifest_->fetched && worker_->fetched)) && |
293 (!params.fetch_valid_primary_icon || | 330 (!params.fetch_valid_primary_icon || |
294 IsIconFetched(ParamsForPrimaryIcon(params))) && | 331 IsIconFetched(ParamsForPrimaryIcon(params))) && |
295 (!params.fetch_valid_badge_icon || | 332 (!params.fetch_valid_badge_icon || |
296 IsIconFetched(ParamsForBadgeIcon(params))); | 333 IsIconFetched(ParamsForBadgeIcon(params))); |
297 } | 334 } |
298 | 335 |
299 void InstallableManager::Reset() { | 336 void InstallableManager::Reset() { |
300 // Prevent any outstanding callbacks to or from this object from being called. | 337 // Prevent any outstanding callbacks to or from this object from being called. |
301 weak_factory_.InvalidateWeakPtrs(); | 338 weak_factory_.InvalidateWeakPtrs(); |
302 tasks_.clear(); | 339 tasks_.clear(); |
303 icons_.clear(); | 340 icons_.clear(); |
304 | 341 |
305 // We may have reset prior to completion, in which case |menu_open_count_| or | 342 // 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 | 343 // |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 | 344 // one of NOT_STARTED or NOT_COMPLETED. If we completed, then these values |
308 // cannot be anything except 0. | 345 // cannot be anything except 0. |
309 is_pwa_check_complete_ = false; | 346 is_pwa_check_complete_ = false; |
310 | 347 |
311 for (; menu_open_count_ > 0; --menu_open_count_) | 348 for (; menu_open_count_ > 0; --menu_open_count_) |
312 InstallableMetrics::RecordMenuOpenHistogram(page_status_); | 349 InstallableMetrics::RecordMenuOpenHistogram(page_status_); |
313 | 350 |
314 for (; menu_item_add_to_homescreen_count_ > 0; | 351 for (; menu_item_add_to_homescreen_count_ > 0; |
315 --menu_item_add_to_homescreen_count_) { | 352 --menu_item_add_to_homescreen_count_) { |
316 InstallableMetrics::RecordMenuItemAddToHomescreenHistogram(page_status_); | 353 InstallableMetrics::RecordMenuItemAddToHomescreenHistogram(page_status_); |
317 } | 354 } |
318 | 355 |
319 page_status_ = InstallabilityCheckStatus::NOT_STARTED; | 356 page_status_ = InstallabilityCheckStatus::NOT_STARTED; |
320 manifest_.reset(new ManifestProperty()); | 357 manifest_ = base::MakeUnique<ManifestProperty>(); |
321 installable_.reset(new InstallableProperty()); | 358 valid_manifest_ = base::MakeUnique<ValidManifestProperty>(); |
| 359 worker_ = base::MakeUnique<ServiceWorkerProperty>(); |
322 | 360 |
323 is_active_ = false; | 361 is_active_ = false; |
324 } | 362 } |
325 | 363 |
326 void InstallableManager::SetManifestDependentTasksComplete() { | 364 void InstallableManager::SetManifestDependentTasksComplete() { |
327 DCHECK(!tasks_.empty()); | 365 DCHECK(!tasks_.empty()); |
328 const InstallableParams& params = tasks_[0].first; | 366 const InstallableParams& params = tasks_[0].first; |
329 | 367 |
330 installable_->fetched = true; | 368 valid_manifest_->fetched = true; |
| 369 worker_->fetched = true; |
331 SetIconFetched(ParamsForPrimaryIcon(params)); | 370 SetIconFetched(ParamsForPrimaryIcon(params)); |
332 SetIconFetched(ParamsForBadgeIcon(params)); | 371 SetIconFetched(ParamsForBadgeIcon(params)); |
333 } | 372 } |
334 | 373 |
335 void InstallableManager::RunCallback(const Task& task, | 374 void InstallableManager::RunCallback(const Task& task, |
336 InstallableStatusCode code) { | 375 InstallableStatusCode code) { |
337 const InstallableParams& params = task.first; | 376 const InstallableParams& params = task.first; |
338 IconProperty null_icon; | 377 IconProperty null_icon; |
339 IconProperty* primary_icon = &null_icon; | 378 IconProperty* primary_icon = &null_icon; |
340 IconProperty* badge_icon = &null_icon; | 379 IconProperty* badge_icon = &null_icon; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 void InstallableManager::WorkOnTask() { | 413 void InstallableManager::WorkOnTask() { |
375 DCHECK(!tasks_.empty()); | 414 DCHECK(!tasks_.empty()); |
376 const Task& task = tasks_[0]; | 415 const Task& task = tasks_[0]; |
377 const InstallableParams& params = task.first; | 416 const InstallableParams& params = task.first; |
378 | 417 |
379 InstallableStatusCode code = GetErrorCode(params); | 418 InstallableStatusCode code = GetErrorCode(params); |
380 bool check_passed = (code == NO_ERROR_DETECTED); | 419 bool check_passed = (code == NO_ERROR_DETECTED); |
381 if (!check_passed || IsComplete(params)) { | 420 if (!check_passed || IsComplete(params)) { |
382 RecordQueuedMetricsOnTaskCompletion(params, check_passed); | 421 RecordQueuedMetricsOnTaskCompletion(params, check_passed); |
383 RunCallback(task, code); | 422 RunCallback(task, code); |
| 423 |
| 424 // Sites can always register a service worker after we finish checking, so |
| 425 // don't cache a missing service worker error to ensure we always check |
| 426 // again. |
| 427 if (worker_error() == NO_MATCHING_SERVICE_WORKER) |
| 428 worker_ = base::MakeUnique<ServiceWorkerProperty>(); |
384 tasks_.erase(tasks_.begin()); | 429 tasks_.erase(tasks_.begin()); |
385 StartNextTask(); | 430 StartNextTask(); |
386 return; | 431 return; |
387 } | 432 } |
388 | 433 |
389 if (!manifest_->fetched) { | 434 if (!manifest_->fetched) { |
390 FetchManifest(); | 435 FetchManifest(); |
391 } else if (params.fetch_valid_primary_icon && | 436 } else if (params.fetch_valid_primary_icon && |
392 !IsIconFetched(ParamsForPrimaryIcon(params))) { | 437 !IsIconFetched(ParamsForPrimaryIcon(params))) { |
393 CheckAndFetchBestIcon(ParamsForPrimaryIcon(params)); | 438 CheckAndFetchBestIcon(ParamsForPrimaryIcon(params)); |
394 } else if (params.check_installable && !installable_->fetched) { | 439 } else if (params.check_installable && !valid_manifest_->fetched) { |
395 CheckInstallable(); | 440 CheckInstallable(); |
| 441 } else if (params.check_installable && !worker_->fetched) { |
| 442 CheckServiceWorker(); |
396 } else if (params.fetch_valid_badge_icon && | 443 } else if (params.fetch_valid_badge_icon && |
397 !IsIconFetched(ParamsForBadgeIcon(params))) { | 444 !IsIconFetched(ParamsForBadgeIcon(params))) { |
398 CheckAndFetchBestIcon(ParamsForBadgeIcon(params)); | 445 CheckAndFetchBestIcon(ParamsForBadgeIcon(params)); |
399 } else { | 446 } else { |
400 NOTREACHED(); | 447 NOTREACHED(); |
401 } | 448 } |
402 } | 449 } |
403 | 450 |
404 void InstallableManager::FetchManifest() { | 451 void InstallableManager::FetchManifest() { |
405 DCHECK(!manifest_->fetched); | 452 DCHECK(!manifest_->fetched); |
(...skipping 18 matching lines...) Expand all Loading... |
424 SetManifestDependentTasksComplete(); | 471 SetManifestDependentTasksComplete(); |
425 } | 472 } |
426 | 473 |
427 manifest_->url = manifest_url; | 474 manifest_->url = manifest_url; |
428 manifest_->manifest = manifest; | 475 manifest_->manifest = manifest; |
429 manifest_->fetched = true; | 476 manifest_->fetched = true; |
430 WorkOnTask(); | 477 WorkOnTask(); |
431 } | 478 } |
432 | 479 |
433 void InstallableManager::CheckInstallable() { | 480 void InstallableManager::CheckInstallable() { |
434 DCHECK(!installable_->fetched); | 481 DCHECK(!valid_manifest_->fetched); |
435 DCHECK(!manifest().IsEmpty()); | 482 DCHECK(!manifest().IsEmpty()); |
436 | 483 |
437 if (IsManifestValidForWebApp(manifest())) { | 484 valid_manifest_->is_valid = IsManifestValidForWebApp(manifest()); |
438 CheckServiceWorker(); | 485 valid_manifest_->fetched = true; |
439 } else { | 486 WorkOnTask(); |
440 installable_->installable = false; | |
441 installable_->fetched = true; | |
442 WorkOnTask(); | |
443 } | |
444 } | 487 } |
445 | 488 |
446 bool InstallableManager::IsManifestValidForWebApp( | 489 bool InstallableManager::IsManifestValidForWebApp( |
447 const content::Manifest& manifest) { | 490 const content::Manifest& manifest) { |
448 if (manifest.IsEmpty()) { | 491 if (manifest.IsEmpty()) { |
449 installable_->error = MANIFEST_EMPTY; | 492 valid_manifest_->error = MANIFEST_EMPTY; |
450 return false; | 493 return false; |
451 } | 494 } |
452 | 495 |
453 if (!manifest.start_url.is_valid()) { | 496 if (!manifest.start_url.is_valid()) { |
454 installable_->error = START_URL_NOT_VALID; | 497 valid_manifest_->error = START_URL_NOT_VALID; |
455 return false; | 498 return false; |
456 } | 499 } |
457 | 500 |
458 if ((manifest.name.is_null() || manifest.name.string().empty()) && | 501 if ((manifest.name.is_null() || manifest.name.string().empty()) && |
459 (manifest.short_name.is_null() || manifest.short_name.string().empty())) { | 502 (manifest.short_name.is_null() || manifest.short_name.string().empty())) { |
460 installable_->error = MANIFEST_MISSING_NAME_OR_SHORT_NAME; | 503 valid_manifest_->error = MANIFEST_MISSING_NAME_OR_SHORT_NAME; |
461 return false; | 504 return false; |
462 } | 505 } |
463 | 506 |
464 // TODO(dominickn,mlamouri): when Chrome supports "minimal-ui", it should be | 507 // 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 | 508 // accepted. If we accept it today, it would fallback to "browser" and make |
466 // this check moot. See https://crbug.com/604390. | 509 // this check moot. See https://crbug.com/604390. |
467 if (manifest.display != blink::kWebDisplayModeStandalone && | 510 if (manifest.display != blink::kWebDisplayModeStandalone && |
468 manifest.display != blink::kWebDisplayModeFullscreen) { | 511 manifest.display != blink::kWebDisplayModeFullscreen) { |
469 installable_->error = MANIFEST_DISPLAY_NOT_SUPPORTED; | 512 valid_manifest_->error = MANIFEST_DISPLAY_NOT_SUPPORTED; |
470 return false; | 513 return false; |
471 } | 514 } |
472 | 515 |
473 if (!DoesManifestContainRequiredIcon(manifest)) { | 516 if (!DoesManifestContainRequiredIcon(manifest)) { |
474 installable_->error = MANIFEST_MISSING_SUITABLE_ICON; | 517 valid_manifest_->error = MANIFEST_MISSING_SUITABLE_ICON; |
475 return false; | 518 return false; |
476 } | 519 } |
477 | 520 |
478 return true; | 521 return true; |
479 } | 522 } |
480 | 523 |
481 void InstallableManager::CheckServiceWorker() { | 524 void InstallableManager::CheckServiceWorker() { |
482 DCHECK(!installable_->fetched); | 525 DCHECK(!worker_->fetched); |
483 DCHECK(!manifest().IsEmpty()); | 526 DCHECK(!manifest().IsEmpty()); |
484 DCHECK(manifest().start_url.is_valid()); | 527 DCHECK(manifest().start_url.is_valid()); |
485 | 528 |
486 content::WebContents* web_contents = GetWebContents(); | |
487 | |
488 // Check to see if there is a single service worker controlling this page | 529 // Check to see if there is a single service worker controlling this page |
489 // and the manifest's start url. | 530 // and the manifest's start url. |
490 content::StoragePartition* storage_partition = | 531 service_worker_context_->CheckHasServiceWorker( |
491 content::BrowserContext::GetStoragePartition( | 532 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, | 533 base::Bind(&InstallableManager::OnDidCheckHasServiceWorker, |
499 weak_factory_.GetWeakPtr())); | 534 weak_factory_.GetWeakPtr())); |
500 } | 535 } |
501 | 536 |
502 void InstallableManager::OnDidCheckHasServiceWorker( | 537 void InstallableManager::OnDidCheckHasServiceWorker( |
503 content::ServiceWorkerCapability capability) { | 538 content::ServiceWorkerCapability capability) { |
504 if (!GetWebContents()) | 539 if (!GetWebContents()) |
505 return; | 540 return; |
506 | 541 |
507 switch (capability) { | 542 switch (capability) { |
508 case content::ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER: | 543 case content::ServiceWorkerCapability::SERVICE_WORKER_WITH_FETCH_HANDLER: |
509 installable_->installable = true; | 544 worker_->has_worker = true; |
510 break; | 545 break; |
511 case content::ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER: | 546 case content::ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER: |
512 installable_->installable = false; | 547 worker_->has_worker = false; |
513 installable_->error = NOT_OFFLINE_CAPABLE; | 548 worker_->error = NOT_OFFLINE_CAPABLE; |
514 break; | 549 break; |
515 case content::ServiceWorkerCapability::NO_SERVICE_WORKER: | 550 case content::ServiceWorkerCapability::NO_SERVICE_WORKER: |
516 installable_->installable = false; | 551 InstallableParams& params = tasks_[0].first; |
517 installable_->error = NO_MATCHING_SERVICE_WORKER; | 552 if (params.wait_for_worker) { |
| 553 // Wait for ServiceWorkerContextObserver::OnRegistrationStored. Set the |
| 554 // param |wait_for_worker| to false so we only wait once per task. |
| 555 params.wait_for_worker = false; |
| 556 worker_->is_waiting = true; |
| 557 OnWaitingForServiceWorker(); |
| 558 return; |
| 559 } |
| 560 worker_->has_worker = false; |
| 561 worker_->error = NO_MATCHING_SERVICE_WORKER; |
518 break; | 562 break; |
519 } | 563 } |
520 | 564 |
521 installable_->fetched = true; | 565 worker_->fetched = true; |
522 WorkOnTask(); | 566 WorkOnTask(); |
523 } | 567 } |
524 | 568 |
525 void InstallableManager::CheckAndFetchBestIcon(const IconParams& params) { | 569 void InstallableManager::CheckAndFetchBestIcon(const IconParams& params) { |
526 DCHECK(!manifest().IsEmpty()); | 570 DCHECK(!manifest().IsEmpty()); |
527 | 571 |
528 int ideal_icon_size_in_px = std::get<0>(params); | 572 int ideal_icon_size_in_px = std::get<0>(params); |
529 int minimum_icon_size_in_px = std::get<1>(params); | 573 int minimum_icon_size_in_px = std::get<1>(params); |
530 IconPurpose icon_purpose = std::get<2>(params); | 574 IconPurpose icon_purpose = std::get<2>(params); |
531 | 575 |
(...skipping 30 matching lines...) Expand all Loading... |
562 if (bitmap.drawsNothing()) { | 606 if (bitmap.drawsNothing()) { |
563 icon.error = NO_ICON_AVAILABLE; | 607 icon.error = NO_ICON_AVAILABLE; |
564 } else { | 608 } else { |
565 icon.url = icon_url; | 609 icon.url = icon_url; |
566 icon.icon.reset(new SkBitmap(bitmap)); | 610 icon.icon.reset(new SkBitmap(bitmap)); |
567 } | 611 } |
568 | 612 |
569 WorkOnTask(); | 613 WorkOnTask(); |
570 } | 614 } |
571 | 615 |
| 616 void InstallableManager::OnRegistrationStored(const GURL& pattern) { |
| 617 // If we aren't currently waiting, either: |
| 618 // a) we've already failed the check, or |
| 619 // b) we haven't yet called CheckHasServiceWorker. |
| 620 // Otherwise if the scope doesn't match we keep waiting. |
| 621 if (!worker_->is_waiting || !content::ServiceWorkerContext::ScopeMatches( |
| 622 pattern, manifest().start_url)) { |
| 623 return; |
| 624 } |
| 625 |
| 626 // This will call CheckHasServiceWorker to check whether the service worker |
| 627 // controls the start_url and if it has a fetch handler. |
| 628 worker_->is_waiting = false; |
| 629 WorkOnTask(); |
| 630 } |
| 631 |
572 void InstallableManager::DidFinishNavigation( | 632 void InstallableManager::DidFinishNavigation( |
573 content::NavigationHandle* handle) { | 633 content::NavigationHandle* handle) { |
574 if (handle->IsInMainFrame() && handle->HasCommitted() && | 634 if (handle->IsInMainFrame() && handle->HasCommitted() && |
575 !handle->IsSameDocument()) { | 635 !handle->IsSameDocument()) { |
576 Reset(); | 636 Reset(); |
577 } | 637 } |
578 } | 638 } |
579 | 639 |
580 void InstallableManager::WebContentsDestroyed() { | 640 void InstallableManager::WebContentsDestroyed() { |
581 Reset(); | 641 Reset(); |
582 Observe(nullptr); | 642 Observe(nullptr); |
583 } | 643 } |
584 | 644 |
585 const GURL& InstallableManager::manifest_url() const { | 645 const GURL& InstallableManager::manifest_url() const { |
586 return manifest_->url; | 646 return manifest_->url; |
587 } | 647 } |
588 | 648 |
589 const content::Manifest& InstallableManager::manifest() const { | 649 const content::Manifest& InstallableManager::manifest() const { |
590 return manifest_->manifest; | 650 return manifest_->manifest; |
591 } | 651 } |
592 | 652 |
593 bool InstallableManager::is_installable() const { | 653 bool InstallableManager::is_installable() const { |
594 return installable_->installable; | 654 return valid_manifest_->is_valid && worker_->has_worker; |
595 } | 655 } |
OLD | NEW |