mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
This fixes many rustdoc errors that occur due to raw URLs in rustdoc comments as well as unescaped Rust code that should be in backticks.
271 lines
9.5 KiB
Rust
271 lines
9.5 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::default::Default;
|
|
use std::rc::Rc;
|
|
|
|
use dom_struct::dom_struct;
|
|
use ipc_channel::ipc;
|
|
use ipc_channel::router::ROUTER;
|
|
use script_traits::{Job, JobError, JobResult, JobResultValue, JobType, ScriptMsg};
|
|
|
|
use crate::dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::{
|
|
RegistrationOptions, ServiceWorkerContainerMethods,
|
|
};
|
|
use crate::dom::bindings::error::Error;
|
|
use crate::dom::bindings::refcounted::TrustedPromise;
|
|
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
|
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
|
use crate::dom::bindings::str::USVString;
|
|
use crate::dom::client::Client;
|
|
use crate::dom::eventtarget::EventTarget;
|
|
use crate::dom::globalscope::GlobalScope;
|
|
use crate::dom::promise::Promise;
|
|
use crate::dom::serviceworker::ServiceWorker;
|
|
use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
|
|
use crate::realms::{enter_realm, InRealm};
|
|
use crate::task::TaskCanceller;
|
|
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
|
|
use crate::task_source::{TaskSource, TaskSourceName};
|
|
|
|
#[dom_struct]
|
|
pub struct ServiceWorkerContainer {
|
|
eventtarget: EventTarget,
|
|
controller: MutNullableDom<ServiceWorker>,
|
|
client: Dom<Client>,
|
|
}
|
|
|
|
impl ServiceWorkerContainer {
|
|
fn new_inherited(client: &Client) -> ServiceWorkerContainer {
|
|
ServiceWorkerContainer {
|
|
eventtarget: EventTarget::new_inherited(),
|
|
controller: Default::default(),
|
|
client: Dom::from_ref(client),
|
|
}
|
|
}
|
|
|
|
#[allow(crown::unrooted_must_root)]
|
|
pub fn new(global: &GlobalScope) -> DomRoot<ServiceWorkerContainer> {
|
|
let client = Client::new(&global.as_window());
|
|
let container = ServiceWorkerContainer::new_inherited(&*client);
|
|
reflect_dom_object(Box::new(container), global)
|
|
}
|
|
}
|
|
|
|
impl ServiceWorkerContainerMethods for ServiceWorkerContainer {
|
|
// https://w3c.github.io/ServiceWorker/#service-worker-container-controller-attribute
|
|
fn GetController(&self) -> Option<DomRoot<ServiceWorker>> {
|
|
self.client.get_controller()
|
|
}
|
|
|
|
/// <https://w3c.github.io/ServiceWorker/#dom-serviceworkercontainer-register> - A
|
|
/// and <https://w3c.github.io/ServiceWorker/#start-register> - B
|
|
fn Register(
|
|
&self,
|
|
script_url: USVString,
|
|
options: &RegistrationOptions,
|
|
comp: InRealm,
|
|
) -> Rc<Promise> {
|
|
// A: Step 2.
|
|
let global = self.client.global();
|
|
|
|
// A: Step 1
|
|
let promise = Promise::new_in_current_realm(comp);
|
|
let USVString(ref script_url) = script_url;
|
|
|
|
// A: Step 3
|
|
let api_base_url = global.api_base_url();
|
|
let script_url = match api_base_url.join(script_url) {
|
|
Ok(url) => url,
|
|
Err(_) => {
|
|
// B: Step 1
|
|
promise.reject_error(Error::Type("Invalid script URL".to_owned()));
|
|
return promise;
|
|
},
|
|
};
|
|
|
|
// A: Step 4-5
|
|
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(_) => {
|
|
promise.reject_error(Error::Type("Invalid scope URL".to_owned()));
|
|
return promise;
|
|
},
|
|
}
|
|
},
|
|
None => script_url.join("./").unwrap(),
|
|
};
|
|
|
|
// A: Step 6 -> invoke B.
|
|
|
|
// B: Step 3
|
|
match script_url.scheme() {
|
|
"https" | "http" => {},
|
|
_ => {
|
|
promise.reject_error(Error::Type("Only secure origins are allowed".to_owned()));
|
|
return promise;
|
|
},
|
|
}
|
|
// B: Step 4
|
|
if script_url.path().to_ascii_lowercase().contains("%2f") ||
|
|
script_url.path().to_ascii_lowercase().contains("%5c")
|
|
{
|
|
promise.reject_error(Error::Type(
|
|
"Script URL contains forbidden characters".to_owned(),
|
|
));
|
|
return promise;
|
|
}
|
|
|
|
// B: Step 6
|
|
match scope.scheme() {
|
|
"https" | "http" => {},
|
|
_ => {
|
|
promise.reject_error(Error::Type("Only secure origins are allowed".to_owned()));
|
|
return promise;
|
|
},
|
|
}
|
|
// B: Step 7
|
|
if scope.path().to_ascii_lowercase().contains("%2f") ||
|
|
scope.path().to_ascii_lowercase().contains("%5c")
|
|
{
|
|
promise.reject_error(Error::Type(
|
|
"Scope URL contains forbidden characters".to_owned(),
|
|
));
|
|
return promise;
|
|
}
|
|
|
|
// Setup the callback for reject/resolve of the promise,
|
|
// from steps running "in-parallel" from here in the serviceworker manager.
|
|
let (task_source, task_canceller) = (
|
|
global.dom_manipulation_task_source(),
|
|
global.task_canceller(TaskSourceName::DOMManipulation),
|
|
);
|
|
|
|
let mut handler = RegisterJobResultHandler {
|
|
trusted_promise: Some(TrustedPromise::new(promise.clone())),
|
|
task_source,
|
|
task_canceller,
|
|
};
|
|
|
|
let (job_result_sender, job_result_receiver) = ipc::channel().expect("ipc channel failure");
|
|
|
|
ROUTER.add_route(
|
|
job_result_receiver.to_opaque(),
|
|
Box::new(move |message| {
|
|
let msg = message.to();
|
|
match msg {
|
|
Ok(msg) => handler.handle(msg),
|
|
Err(err) => warn!("Error receiving a JobResult: {:?}", err),
|
|
}
|
|
}),
|
|
);
|
|
|
|
let scope_things =
|
|
ServiceWorkerRegistration::create_scope_things(&*global, script_url.clone());
|
|
|
|
// B: Step 8 - 13
|
|
let job = Job::create_job(
|
|
JobType::Register,
|
|
scope,
|
|
script_url,
|
|
job_result_sender,
|
|
self.client.creation_url(),
|
|
Some(scope_things),
|
|
);
|
|
|
|
// B: Step 14: schedule job.
|
|
let _ = global
|
|
.script_to_constellation_chan()
|
|
.send(ScriptMsg::ScheduleJob(job));
|
|
|
|
// A: Step 7
|
|
promise
|
|
}
|
|
}
|
|
|
|
/// Callback for resolve/reject job promise for Register.
|
|
/// <https://w3c.github.io/ServiceWorker/#register>
|
|
struct RegisterJobResultHandler {
|
|
trusted_promise: Option<TrustedPromise>,
|
|
task_source: DOMManipulationTaskSource,
|
|
task_canceller: TaskCanceller,
|
|
}
|
|
|
|
impl RegisterJobResultHandler {
|
|
/// <https://w3c.github.io/ServiceWorker/#reject-job-promise>
|
|
/// <https://w3c.github.io/ServiceWorker/#resolve-job-promise>
|
|
/// Handle a result to either resolve or reject the register job promise.
|
|
pub fn handle(&mut self, result: JobResult) {
|
|
match result {
|
|
JobResult::RejectPromise(error) => {
|
|
let promise = self
|
|
.trusted_promise
|
|
.take()
|
|
.expect("No promise to resolve for SW Register job.");
|
|
|
|
// Step 1
|
|
let _ = self.task_source.queue_with_canceller(
|
|
task!(reject_promise_with_security_error: move || {
|
|
let promise = promise.root();
|
|
let _ac = enter_realm(&*promise.global());
|
|
match error {
|
|
JobError::TypeError => {
|
|
promise.reject_error(Error::Type("Failed to register a ServiceWorker".to_string()));
|
|
},
|
|
JobError::SecurityError => {
|
|
promise.reject_error(Error::Security);
|
|
},
|
|
}
|
|
|
|
}),
|
|
&self.task_canceller,
|
|
);
|
|
|
|
// TODO: step 2, handle equivalent jobs.
|
|
},
|
|
JobResult::ResolvePromise(job, value) => {
|
|
let promise = self
|
|
.trusted_promise
|
|
.take()
|
|
.expect("No promise to resolve for SW Register job.");
|
|
|
|
// Step 1
|
|
let _ = self.task_source.queue_with_canceller(
|
|
task!(resolve_promise: move || {
|
|
let promise = promise.root();
|
|
let global = promise.global();
|
|
let _ac = enter_realm(&*global);
|
|
|
|
// Step 1.1
|
|
let JobResultValue::Registration {
|
|
id,
|
|
installing_worker,
|
|
waiting_worker,
|
|
active_worker,
|
|
} = value;
|
|
|
|
// Step 1.2 (Job type is "register").
|
|
let registration = global.get_serviceworker_registration(
|
|
&job.script_url,
|
|
&job.scope_url,
|
|
id,
|
|
installing_worker,
|
|
waiting_worker,
|
|
active_worker,
|
|
);
|
|
|
|
// Step 1.4
|
|
promise.resolve_native(&*registration);
|
|
}),
|
|
&self.task_canceller,
|
|
);
|
|
|
|
// TODO: step 2, handle equivalent jobs.
|
|
},
|
|
}
|
|
}
|
|
}
|