Commit 786b4918 authored by Amos Lim's avatar Amos Lim Committed by Commit Bot

service worker: Let register('data://blah') throw a TypeError

register('data://blah') should throw a TypeError instead of SecurityError.
If scopeURL’s scheme is not one of "http" and "https", reject promise
with a TypeError and abort these steps.[1]

[1]: https://w3c.github.io/ServiceWorker/#start-register-algorithm

Bug: 877138
Change-Id: Ic1e8cae52ec9393152044aa37da389eb499165bb
Reviewed-on: https://chromium-review.googlesource.com/c/1189688
Commit-Queue: Amos Lim <eui-sang.lim@samsung.com>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608635}
parent 53ce5a61
This is a testharness.js-based test.
PASS Script URL including URL-encoded slash
PASS Script URL including uppercase URL-encoded slash
PASS Script URL including URL-encoded backslash
PASS Script URL including uppercase URL-encoded backslash
FAIL Script URL is a data URL assert_throws: Data URLs should not be registered as service workers. function "function() { throw e }" threw object "SecurityError: Failed to register a ServiceWorker: The origin of the provided scriptURL ('null') does not match the current origin ('https://web-platform.test:8444')." ("SecurityError") expected object "TypeError" ("TypeError")
PASS Script URL including self-reference
PASS Script URL including parent-reference
Harness: the test ran to completion.
......@@ -94,9 +94,9 @@ function registration_tests_scope(register_method, check_error_types) {
var script = 'resources/empty-worker.js';
var scope = 'filesystem:' + normalizeURL('resources/scope/filesystem-scope-url');
return promise_rejects(t,
check_error_types ? 'SecurityError' : null,
check_error_types ? new TypeError : null,
register_method(script, {scope: scope}),
'Registering with the scope that has same-origin filesystem: URL ' +
'should fail with SecurityError.');
'should fail with TypeError.');
}, 'Scope URL is same-origin filesystem: URL');
}
......@@ -70,9 +70,9 @@ function registration_tests_security_error(register_method, check_error_types) {
var script = 'filesystem:' + normalizeURL('resources/empty-worker.js');
var scope = 'resources/scope/filesystem-script-url';
return promise_rejects(t,
check_error_types ? 'SecurityError' : null,
check_error_types ? new TypeError : null,
register_method(script, {scope: scope}),
'Registering a script which has same-origin filesystem: URL should ' +
'fail with SecurityError.');
'fail with TypeError.');
}, 'Script URL is same-origin filesystem: URL');
}
......@@ -10,7 +10,7 @@ async_test(function(t) {
assert_unreached('register() should fail');
}, function(e) {
assert_throws(
'SecurityError', function() { throw e; },
new TypeError, function() { throw e; },
'register() on local file should fail');
assert_equals(
e.message,
......
......@@ -243,7 +243,7 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker(
if (!SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers(
page_url.Protocol())) {
callbacks->OnError(WebServiceWorkerError(
mojom::blink::ServiceWorkerErrorType::kSecurity,
mojom::blink::ServiceWorkerErrorType::kType,
String("Failed to register a ServiceWorker: The URL protocol of the "
"current origin ('" +
document_origin->ToString() + "') is not supported.")));
......@@ -253,6 +253,16 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker(
KURL script_url = execution_context->CompleteURL(url);
script_url.RemoveFragmentIdentifier();
if (!SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers(
script_url.Protocol())) {
callbacks->OnError(WebServiceWorkerError(
mojom::blink::ServiceWorkerErrorType::kType,
String("Failed to register a ServiceWorker: The URL protocol of the "
"script ('" +
script_url.GetString() + "') is not supported.")));
return promise;
}
if (!document_origin->CanRequest(script_url)) {
scoped_refptr<const SecurityOrigin> script_origin =
SecurityOrigin::Create(script_url);
......@@ -265,47 +275,39 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker(
document_origin->ToString() + "').")));
return promise;
}
KURL scope_url;
if (options->scope().IsNull())
scope_url = KURL(script_url, "./");
else
scope_url = execution_context->CompleteURL(options->scope());
scope_url.RemoveFragmentIdentifier();
if (!SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers(
script_url.Protocol())) {
scope_url.Protocol())) {
callbacks->OnError(WebServiceWorkerError(
mojom::blink::ServiceWorkerErrorType::kSecurity,
mojom::blink::ServiceWorkerErrorType::kType,
String("Failed to register a ServiceWorker: The URL protocol of the "
"script ('" +
script_url.GetString() + "') is not supported.")));
"scope ('" +
scope_url.GetString() + "') is not supported.")));
return promise;
}
KURL pattern_url;
if (options->scope().IsNull())
pattern_url = KURL(script_url, "./");
else
pattern_url = execution_context->CompleteURL(options->scope());
pattern_url.RemoveFragmentIdentifier();
if (!document_origin->CanRequest(pattern_url)) {
scoped_refptr<const SecurityOrigin> pattern_origin =
SecurityOrigin::Create(pattern_url);
if (!document_origin->CanRequest(scope_url)) {
scoped_refptr<const SecurityOrigin> scope_origin =
SecurityOrigin::Create(scope_url);
callbacks->OnError(
WebServiceWorkerError(mojom::blink::ServiceWorkerErrorType::kSecurity,
String("Failed to register a ServiceWorker: The "
"origin of the provided scope ('" +
pattern_origin->ToString() +
scope_origin->ToString() +
"') does not match the current origin ('" +
document_origin->ToString() + "').")));
return promise;
}
if (!SchemeRegistry::ShouldTreatURLSchemeAsAllowingServiceWorkers(
pattern_url.Protocol())) {
callbacks->OnError(WebServiceWorkerError(
mojom::blink::ServiceWorkerErrorType::kSecurity,
String("Failed to register a ServiceWorker: The URL protocol of the "
"scope ('" +
pattern_url.GetString() + "') is not supported.")));
return promise;
}
WebString web_error_message;
if (!provider_->ValidateScopeAndScriptURL(pattern_url, script_url,
if (!provider_->ValidateScopeAndScriptURL(scope_url, script_url,
&web_error_message)) {
callbacks->OnError(WebServiceWorkerError(
mojom::blink::ServiceWorkerErrorType::kType,
......@@ -335,7 +337,7 @@ ScriptPromise ServiceWorkerContainer::registerServiceWorker(
ParseUpdateViaCache(options->updateViaCache());
mojom::ScriptType type = ParseScriptType(options->type());
provider_->RegisterServiceWorker(pattern_url, script_url, type,
provider_->RegisterServiceWorker(scope_url, script_url, type,
update_via_cache, std::move(callbacks));
return promise;
}
......
// Copyright 2014 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.
......@@ -121,6 +120,33 @@ class ExpectDOMException : public ScriptValueTest {
String expected_message_;
};
// Matches a ScriptValue and a TypeError with a message.
class ExpectTypeError : public ScriptValueTest {
public:
ExpectTypeError(const String& expected_message)
: expected_message_(expected_message) {}
~ExpectTypeError() override = default;
void operator()(ScriptValue value) const override {
v8::Isolate* isolate = value.GetIsolate();
v8::Local<v8::Context> context = value.GetContext();
v8::Local<v8::Object> error_object =
value.V8Value()->ToObject(context).ToLocalChecked();
v8::Local<v8::Value> name =
error_object->Get(context, V8String(isolate, "name")).ToLocalChecked();
v8::Local<v8::Value> message =
error_object->Get(context, V8String(isolate, "message"))
.ToLocalChecked();
EXPECT_EQ("TypeError", ToCoreString(name->ToString(isolate)));
EXPECT_EQ(expected_message_, ToCoreString(message->ToString(isolate)));
}
private:
String expected_message_;
};
// Service Worker-specific tests.
class NotReachedWebServiceWorkerProvider : public WebServiceWorkerProvider {
......@@ -128,7 +154,7 @@ class NotReachedWebServiceWorkerProvider : public WebServiceWorkerProvider {
~NotReachedWebServiceWorkerProvider() override = default;
void RegisterServiceWorker(
const WebURL& pattern,
const WebURL& scope,
const WebURL& script_url,
blink::mojom::ScriptType script_type,
mojom::ServiceWorkerUpdateViaCache update_via_cache,
......@@ -213,14 +239,24 @@ TEST_F(ServiceWorkerContainerTest, Register_CrossOriginScriptIsRejected) {
"current origin ('https://www.example.com')."));
}
TEST_F(ServiceWorkerContainerTest, Register_UnsupportedSchemeIsRejected) {
SetPageURL("https://www.example.com");
TestRegisterRejected(
"https://www.example.com",
"wss://www.example.com/", // Only support http and https
ExpectTypeError(
"Failed to register a ServiceWorker: The URL protocol "
"of the scope ('wss://www.example.com/') is not supported."));
}
TEST_F(ServiceWorkerContainerTest, Register_CrossOriginScopeIsRejected) {
SetPageURL("https://www.example.com");
TestRegisterRejected(
"https://www.example.com",
"wss://www.example.com/", // Differs by protocol
"http://www.example.com/", // Differs by protocol
ExpectDOMException("SecurityError",
"Failed to register a ServiceWorker: The origin of "
"the provided scope ('wss://www.example.com') does "
"the provided scope ('http://www.example.com') does "
"not match the current origin "
"('https://www.example.com')."));
}
......@@ -271,14 +307,14 @@ class StubWebServiceWorkerProvider {
~WebServiceWorkerProviderImpl() override = default;
void RegisterServiceWorker(
const WebURL& pattern,
const WebURL& scope,
const WebURL& script_url,
blink::mojom::ScriptType script_type,
mojom::ServiceWorkerUpdateViaCache update_via_cache,
std::unique_ptr<WebServiceWorkerRegistrationCallbacks> callbacks)
override {
owner_.register_call_count_++;
owner_.register_scope_ = pattern;
owner_.register_scope_ = scope;
owner_.register_script_url_ = script_url;
owner_.script_type_ = script_type;
owner_.update_via_cache_ = update_via_cache;
......
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