Commit 27b5ce74 authored by Eric Willigers's avatar Eric Willigers Committed by Commit Bot

Web App Installability: Check web manifest scope in service worker scope

The web app installability check now verifies that the entire web app
manifest scope is within a service worker's scope, instead of simply
checking the start url.


Bug: 809837
Change-Id: Ia4a957aae3e3d1737401376d2188c6f8dd85837e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1799649Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Commit-Queue: Eric Willigers <ericwilligers@chromium.org>
Cr-Commit-Position: refs/heads/master@{#696003}
parent 0cd22c6a
...@@ -564,17 +564,9 @@ void InstallableManager::CheckServiceWorker() { ...@@ -564,17 +564,9 @@ void InstallableManager::CheckServiceWorker() {
DCHECK(!worker_->fetched); DCHECK(!worker_->fetched);
DCHECK(!manifest().IsEmpty()); DCHECK(!manifest().IsEmpty());
if (!manifest().start_url.is_valid()) { // Check to see if there is a service worker for the manifest's scope.
worker_->has_worker = false;
worker_->error = NO_URL_FOR_SERVICE_WORKER;
worker_->fetched = true;
WorkOnTask();
return;
}
// Check to see if there is a service worker for the manifest's start url.
service_worker_context_->CheckHasServiceWorker( service_worker_context_->CheckHasServiceWorker(
manifest().start_url, manifest().scope,
base::BindOnce(&InstallableManager::OnDidCheckHasServiceWorker, base::BindOnce(&InstallableManager::OnDidCheckHasServiceWorker,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
...@@ -659,10 +651,8 @@ void InstallableManager::OnIconFetched(const GURL icon_url, ...@@ -659,10 +651,8 @@ void InstallableManager::OnIconFetched(const GURL icon_url,
void InstallableManager::OnRegistrationCompleted(const GURL& pattern) { void InstallableManager::OnRegistrationCompleted(const GURL& pattern) {
// If the scope doesn't match we keep waiting. // If the scope doesn't match we keep waiting.
if (!content::ServiceWorkerContext::ScopeMatches(pattern, if (!content::ServiceWorkerContext::ScopeMatches(pattern, manifest().scope))
manifest().start_url)) {
return; return;
}
bool was_active = task_queue_.HasCurrent(); bool was_active = task_queue_.HasCurrent();
......
...@@ -14,8 +14,10 @@ ...@@ -14,8 +14,10 @@
#include "chrome/browser/installable/installable_logging.h" #include "chrome/browser/installable/installable_logging.h"
#include "chrome/browser/installable/installable_manager.h" #include "chrome/browser/installable/installable_manager.h"
#include "chrome/browser/installable/installable_metrics.h" #include "chrome/browser/installable/installable_metrics.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/web_applications/test/service_worker_registration_waiter.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
...@@ -1483,7 +1485,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, ...@@ -1483,7 +1485,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
EXPECT_EQ(std::vector<InstallableStatusCode>( EXPECT_EQ(std::vector<InstallableStatusCode>(
{START_URL_NOT_VALID, MANIFEST_MISSING_NAME_OR_SHORT_NAME, {START_URL_NOT_VALID, MANIFEST_MISSING_NAME_OR_SHORT_NAME,
MANIFEST_DISPLAY_NOT_SUPPORTED, MANIFEST_MISSING_SUITABLE_ICON, MANIFEST_DISPLAY_NOT_SUPPORTED, MANIFEST_MISSING_SUITABLE_ICON,
NO_URL_FOR_SERVICE_WORKER, NO_ACCEPTABLE_ICON}), NO_ACCEPTABLE_ICON}),
tester->errors()); tester->errors());
} }
...@@ -1507,7 +1509,6 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, ...@@ -1507,7 +1509,6 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
GetErrorMessage(MANIFEST_MISSING_NAME_OR_SHORT_NAME), GetErrorMessage(MANIFEST_MISSING_NAME_OR_SHORT_NAME),
GetErrorMessage(MANIFEST_DISPLAY_NOT_SUPPORTED), GetErrorMessage(MANIFEST_DISPLAY_NOT_SUPPORTED),
GetErrorMessage(MANIFEST_MISSING_SUITABLE_ICON), GetErrorMessage(MANIFEST_MISSING_SUITABLE_ICON),
GetErrorMessage(NO_URL_FOR_SERVICE_WORKER),
GetErrorMessage(NO_ACCEPTABLE_ICON)}), GetErrorMessage(NO_ACCEPTABLE_ICON)}),
NavigateAndGetAllErrors(browser(), NavigateAndGetAllErrors(browser(),
GetURLOfPageWithServiceWorkerAndManifest( GetURLOfPageWithServiceWorkerAndManifest(
...@@ -1526,3 +1527,26 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerAllowlistOriginBrowserTest, ...@@ -1526,3 +1527,26 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerAllowlistOriginBrowserTest,
ui_test_utils::NavigateToURL(browser(), GURL(kOtherInsecureOrigin)); ui_test_utils::NavigateToURL(browser(), GURL(kOtherInsecureOrigin));
EXPECT_FALSE(InstallableManager::IsContentSecure(contents)); EXPECT_FALSE(InstallableManager::IsContentSecure(contents));
} }
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, NarrowServiceWorker) {
const GURL url =
embedded_test_server()->GetURL("/banners/scope_c/scope_c.html");
{
web_app::ServiceWorkerRegistrationWaiter registration_waiter(
browser()->profile(), url);
ui_test_utils::NavigateToURL(browser(), url);
registration_waiter.AwaitRegistration();
}
base::RunLoop run_loop;
std::unique_ptr<CallbackTester> tester(
new CallbackTester(run_loop.QuitClosure()));
InstallableParams params = GetWebAppParams();
params.wait_for_worker = false;
RunInstallableManager(browser(), tester.get(), params);
run_loop.Run();
EXPECT_EQ(std::vector<InstallableStatusCode>({NO_MATCHING_SERVICE_WORKER}),
tester->errors());
}
...@@ -79,6 +79,8 @@ source_set("web_applications_test_support") { ...@@ -79,6 +79,8 @@ source_set("web_applications_test_support") {
testonly = true testonly = true
sources = [ sources = [
"test/service_worker_registration_waiter.cc",
"test/service_worker_registration_waiter.h",
"test/test_app_registrar.cc", "test/test_app_registrar.cc",
"test/test_app_registrar.h", "test/test_app_registrar.h",
"test/test_data_retriever.cc", "test/test_data_retriever.cc",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/web_applications/test/service_worker_registration_waiter.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/storage_partition.h"
namespace web_app {
ServiceWorkerRegistrationWaiter::ServiceWorkerRegistrationWaiter(
content::BrowserContext* browser_context,
const GURL& url)
: url_(std::move(url)) {
content::StoragePartition* storage_partition =
content::BrowserContext::GetStoragePartitionForSite(browser_context,
url_);
DCHECK(storage_partition);
service_worker_context_ = storage_partition->GetServiceWorkerContext();
service_worker_context_->AddObserver(this);
}
ServiceWorkerRegistrationWaiter::~ServiceWorkerRegistrationWaiter() {
if (service_worker_context_)
service_worker_context_->RemoveObserver(this);
}
void ServiceWorkerRegistrationWaiter::AwaitRegistration() {
run_loop_.Run();
}
void ServiceWorkerRegistrationWaiter::OnRegistrationCompleted(
const GURL& pattern) {
if (content::ServiceWorkerContext::ScopeMatches(pattern, url_))
run_loop_.Quit();
}
void ServiceWorkerRegistrationWaiter::OnDestruct(
content::ServiceWorkerContext* context) {
service_worker_context_->RemoveObserver(this);
service_worker_context_ = nullptr;
}
} // namespace web_app
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_TEST_SERVICE_WORKER_REGISTRATION_WAITER_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_TEST_SERVICE_WORKER_REGISTRATION_WAITER_H_
#include "base/macros.h"
#include "base/run_loop.h"
#include "content/public/browser/service_worker_context_observer.h"
#include "url/gurl.h"
namespace content {
class BrowserContext;
class ServiceWorkerContext;
} // namespace content
namespace web_app {
class ServiceWorkerRegistrationWaiter
: public content::ServiceWorkerContextObserver {
public:
ServiceWorkerRegistrationWaiter(content::BrowserContext* browser_context,
const GURL& url);
~ServiceWorkerRegistrationWaiter() override;
void AwaitRegistration();
private:
// content::ServiceWorkerContextObserver:
void OnRegistrationCompleted(const GURL& pattern) override;
void OnDestruct(content::ServiceWorkerContext* context) override;
content::ServiceWorkerContext* service_worker_context_;
const GURL url_;
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationWaiter);
};
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_TEST_SERVICE_WORKER_REGISTRATION_WAITER_H_
{
"name": "Service worker scope is narrower than manifest scope",
"icons": [
{
"src": "/banners/image-512px.png",
"sizes": "512x512",
"type": "image/png"
}
],
"scope": "/banners/",
"start_url": "/banners/scope_c/scope_c.html",
"display": "standalone"
}
<head>
<title>Service worker scope is narrower than manifest scope</title>
<link rel="manifest" href="manifest.webmanifest">
<script>
navigator.serviceWorker.register('/banners/service_worker.js',
{scope: '/banners/scope_c/'});
</script>
</head>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment