| 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 |