Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServiceWorkerContainer::Promise #13419

Merged
merged 1 commit into from Oct 31, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -4,18 +4,20 @@

use dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::{ServiceWorkerContainerMethods, Wrap};
use dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::RegistrationOptions;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::error::Error;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::USVString;
use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use dom::serviceworker::ServiceWorker;
use dom::serviceworkerregistration::ServiceWorkerRegistration;
use script_thread::ScriptThread;
use std::ascii::AsciiExt;
use std::default::Default;
use std::rc::Rc;

#[dom_struct]
pub struct ServiceWorkerContainer {
@@ -53,55 +55,74 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer {
return self.controller.get()
}

#[allow(unrooted_must_root)]
// https://w3c.github.io/ServiceWorker/#service-worker-container-register-method
fn Register(&self,
script_url: USVString,
options: &RegistrationOptions) -> Fallible<Root<ServiceWorkerRegistration>> {
options: &RegistrationOptions) -> Rc<Promise> {
let promise = Promise::new(&*self.global());
let ctx = self.global().get_cx();
let USVString(ref script_url) = script_url;
let api_base_url = self.global().api_base_url();
// Step 3-4
let script_url = match api_base_url.join(script_url) {
Ok(url) => url,
Err(_) => return Err(Error::Type("Invalid script URL".to_owned()))
Err(_) => {
promise.reject_error(ctx, Error::Type("Invalid script URL".to_owned()));
return promise;
}
};
// Step 5
match script_url.scheme() {
"https" | "http" => {},
_ => return Err(Error::Type("Only secure origins are allowed".to_owned()))
_ => {
promise.reject_error(ctx, Error::Type("Only secure origins are allowed".to_owned()));
return promise;
}
}
// Step 6
if script_url.path().to_ascii_lowercase().contains("%2f") ||
script_url.path().to_ascii_lowercase().contains("%5c") {
return Err(Error::Type("Script URL contains forbidden characters".to_owned()));
promise.reject_error(ctx, Error::Type("Script URL contains forbidden characters".to_owned()));
return promise;
}
// Step 8-9
let scope = match options.scope {
Some(ref scope) => {
let &USVString(ref inner_scope) = scope;
match api_base_url.join(inner_scope) {
Ok(url) => url,
Err(_) => return Err(Error::Type("Invalid scope URL".to_owned()))
Err(_) => {
promise.reject_error(ctx, Error::Type("Invalid scope URL".to_owned()));
return promise;
}
}
},
None => script_url.join("./").unwrap()
};
// Step 11
match scope.scheme() {
"https" | "http" => {},
_ => return Err(Error::Type("Only secure origins are allowed".to_owned()))
_ => {
promise.reject_error(ctx, Error::Type("Only secure origins are allowed".to_owned()));
return promise;
}
}
// Step 12
if scope.path().to_ascii_lowercase().contains("%2f") ||
scope.path().to_ascii_lowercase().contains("%5c") {
return Err(Error::Type("Scope URL contains forbidden characters".to_owned()));
promise.reject_error(ctx, Error::Type("Scope URL contains forbidden characters".to_owned()));
return promise;
}

let global = self.global();
let worker_registration = ServiceWorkerRegistration::new(&global,
script_url,
scope.clone(),
self);
ScriptThread::set_registration(scope, &*worker_registration, global.pipeline_id());
Ok(worker_registration)
ScriptThread::set_registration(scope, &*worker_registration, self.global().pipeline_id());

promise.resolve_native(ctx, &*worker_registration);
promise
}
}
@@ -8,7 +8,7 @@ interface ServiceWorkerContainer : EventTarget {
[Unforgeable] readonly attribute ServiceWorker? controller;
//[SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;

[NewObject, Throws] ServiceWorkerRegistration register(USVString scriptURL, optional RegistrationOptions options);
[NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);

//[NewObject] /*Promise<any>*/ any getRegistration(optional USVString clientURL = "");
//[NewObject] /* Promise */<sequence<ServiceWorkerRegistration>> getRegistrations();
@@ -19,17 +19,22 @@
<button onclick="post_message_root()">Msg to Root service worker</button>
</div>
<script>

var reg = navigator.serviceWorker.register('iframe_sw.js', { 'scope': '/demo_iframe.html' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
document.getElementById('iframe_sw').src = 'demo_iframe.html';
post_message('/demo_iframe');
navigator.serviceWorker.register('iframe_sw.js', { 'scope': '/demo_iframe.html' }).then(function(registration) {
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: iframe_sw.js");
document.getElementById('iframe_sw').src = 'demo_iframe.html';
post_message('/demo_iframe');
}).catch(function(error) {
console.log("Error in loading `iframe_sw.js` -->" + error);
});

function register_zero() {
var reg = navigator.serviceWorker.register('sw.js', { 'scope': './*' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
navigator.serviceWorker.register('sw.js', { 'scope': './*' }).then(function(registration) {
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: sw.js");
}).catch(function(error) {
console.log("Error in loading `sw.js` -->" + error);
});
}

function post_message_root() {
@@ -40,17 +45,23 @@
}

function register_one() {
var reg = navigator.serviceWorker.register('sw_dashboard.js', { 'scope': '/dashboard' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
post_message('/dashboard');
navigator.serviceWorker.register('sw_dashboard.js', { 'scope': '/dashboard' }).then(function(registration) {
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: sw_dashboard.js");
post_message('/dashboard');
}).catch(function(error) {
console.log("Error in loading `sw_dashboard.js` -->" + error);
});
}

function register_two() {
var reg = navigator.serviceWorker.register('sw_profile.js', { 'scope': '/profile' });
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: "+ navigator.serviceWorker.controller.scriptURL);
post_message('/profile');
navigator.serviceWorker.register('sw_profile.js', { 'scope': '/profile' }).then(function(registration) {
console.log("From client worker registered: ", navigator.serviceWorker.controller);
console.log("Registered script source: sw_profile.js");
post_message('/profile');
}).catch(function(error) {
console.log("Error in loading `sw_profile.js` --> " + error);
});
}

navigator.serviceWorker.addEventListener('controllerchange', function(e) {
@@ -14,39 +14,39 @@
assert_true('serviceWorker' in navigator);
}, "Test: Asserts ServiceWorkerContainer in Navigator");

test(function() {
var sw_reg = register_sw('sw.js');
assert_class_string(sw_reg, "ServiceWorkerRegistration");
assert_class_string(sw_reg.active, "ServiceWorker");
assert_class_string(navigator.serviceWorker.controller, "ServiceWorker");
promise_test(function() {
return register_sw('sw.js').then(function(sw_reg) {
assert_class_string(sw_reg, "ServiceWorkerRegistration");
assert_class_string(sw_reg.active, "ServiceWorker");
assert_class_string(navigator.serviceWorker.controller, "ServiceWorker");
});
}, "Test: Asserts Active Service Worker and its Registration");

test(function() {
var sw_reg = register_sw('resources/sw.js', './');
assert_equals(sw_reg.scope, location.href.replace("service-worker-registration.html", ""));
promise_test(function() {
return register_sw('resources/sw.js', './').then(function(sw_reg) {
assert_equals(sw_reg.scope, location.href.replace("service-worker-registration.html", ""));
});
}, "Test: Service Worker Registration property scope Url when no scope");

test(function() {
var sw_reg = register_sw('resources/sw.js', '/some/nested/cache/directory');
var expected_scope_url = location.protocol + '//' + location.host + '/some/nested/cache/directory';
assert_equals(sw_reg.scope, expected_scope_url);
promise_test(function() {
return register_sw('resources/sw.js', '/some/nested/cache/directory').then(function(sw_reg) {
var expected_scope_url = location.protocol + '//' + location.host + '/some/nested/cache/directory';
assert_equals(sw_reg.scope, expected_scope_url);
});
}, "Test: Service Worker Registration property scope when provided a scope");

test(function () {
assert_throws(new TypeError(),
function() { var sw_reg = register_sw('./in%5Csome%5fdir/sw.js'); },
"Invalid URL Path");
promise_test(function (p) {
promise_rejects(p, new TypeError(), register_sw('./in%5Csome%5fdir/sw.js'));

This comment has been minimized.

@Coder206

Coder206 Oct 30, 2016

Author Contributor

@jdm I don't fancy an inline code like this but the code below would fail:

promise_test(function (p) {
  promise_rejects(p, new TypeError(), function () {
    register_sw('./in%5Csome%5fdir/sw.js');
  });
}, "Test: Throws Error when Invalid Url Path");

This comment has been minimized.

@jdm

jdm Oct 30, 2016

Member

That's because it needs to return the result of register_sw.

This comment has been minimized.

@Coder206

Coder206 Oct 31, 2016

Author Contributor

@jdm I am still getting promise.then() is not a function when I return, I am trying to figure out why and how to correct it from the testharness.js from the web platfor test folder

}, "Test: Throws Error when Invalid Url Path");

test(function () {
assert_throws(new TypeError(),
function() { var sw_reg = register_sw('sw.js', './mal%5fformed/sco%5Cpe/'); },
"Invalid URL Path");
promise_test(function (p) {
return promise_rejects(p, new TypeError(), register_sw('sw.js', './mal%5fformed/sco%5Cpe/'));

This comment has been minimized.

@Coder206

Coder206 Oct 30, 2016

Author Contributor

@jdm Same for this one.

}, "Test: Throws Error when Invalid Scope");

test(function() {
var sw_reg = register_sw('resources/sw.js');
assert_equals(sw_reg.active.scriptURL, location.href.replace("service-worker-registration.html", "resources/sw.js"));
promise_test(function() {
return register_sw('resources/sw.js').then(function(sw_reg) {
assert_equals(sw_reg.active.scriptURL, location.href.replace("service-worker-registration.html", "resources/sw.js"));
});
}, "Test: Active Service Worker ScriptURL property");

</script>
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.