Files
servo/components/script/dom/workers/serviceworkercontainer.rs
Simon Wülker c4ae451612 Turn all commented links before functions into doccomments (#40331)
Servo has a lot of comments like this:
```rust
// https://example-spec.com/#do-the-thing
fn do_the_thing() {}
```
and I keep turning these into doc comments whenever I'm working close to
one of them. Doing so allows me to hover over a function call in an IDE
and open its specification without having to jump to the function
definition first. This change fixes all of these comments at once.

This was done using `find components -name '*.rs' -exec perl -i -0777
-pe 's|^([ \t]*)// (https?://.*)\n\1(fn )|\1/// <$2>\n\1$3|mg' {} +`.

Note that these comments should be doc comments even within trait `impl`
blocks, because rustdoc will use them as fallback documentation when the
method definition on the trait does not have documentation.

Testing: Comments only, no testing required
Preparation for https://github.com/servo/servo/pull/39552

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
2025-11-01 05:32:45 +00:00

266 lines
9.3 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 base::generic_channel::GenericCallback;
use constellation_traits::{
Job, JobError, JobResult, JobResultValue, JobType, ScriptToConstellationMessage,
};
use dom_struct::dom_struct;
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::{DomGlobal, reflect_dom_object};
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::{InRealm, enter_realm};
use crate::script_runtime::CanGc;
use crate::task_source::SendableTaskSource;
#[dom_struct]
pub(crate) 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),
}
}
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<ServiceWorkerContainer> {
let client = Client::new(global.as_window(), can_gc);
let container = ServiceWorkerContainer::new_inherited(&client);
reflect_dom_object(Box::new(container), global, can_gc)
}
}
impl ServiceWorkerContainerMethods<crate::DomTypeHolder> 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,
can_gc: CanGc,
) -> Rc<Promise> {
// A: Step 2.
let global = self.client.global();
// A: Step 1
let promise = Promise::new_in_current_realm(comp, can_gc);
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()), can_gc);
return promise;
},
};
// A: Step 4-5
let scope = match options.scope {
Some(ref scope) => {
let USVString(inner_scope) = scope;
match api_base_url.join(inner_scope) {
Ok(url) => url,
Err(_) => {
promise.reject_error(Error::Type("Invalid scope URL".to_owned()), can_gc);
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()),
can_gc,
);
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()),
can_gc,
);
return promise;
}
// B: Step 6
match scope.scheme() {
"https" | "http" => {},
_ => {
promise.reject_error(
Error::Type("Only secure origins are allowed".to_owned()),
can_gc,
);
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()),
can_gc,
);
return promise;
}
// Setup the callback for reject/resolve of the promise,
// from steps running "in-parallel" from here in the serviceworker manager.
let mut handler = RegisterJobResultHandler {
trusted_promise: Some(TrustedPromise::new(promise.clone())),
task_source: global.task_manager().dom_manipulation_task_source().into(),
};
let result_handler = GenericCallback::new(move |message| match message {
Ok(msg) => handler.handle(msg),
Err(err) => warn!("Error receiving a JobResult: {:?}", err),
})
.expect("Failed to create callback");
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,
result_handler,
self.client.creation_url(),
Some(scope_things),
);
// B: Step 14: schedule job.
let _ = global
.script_to_constellation_chan()
.send(ScriptToConstellationMessage::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: SendableTaskSource,
}
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(crate) 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
self.task_source
.queue(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()),
CanGc::note(),
);
},
JobError::SecurityError => {
promise.reject_error(Error::Security, CanGc::note());
},
}
}));
// 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
self.task_source.queue(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,
CanGc::note()
);
// Step 1.4
promise.resolve_native(&*registration, CanGc::note());
}));
// TODO: step 2, handle equivalent jobs.
},
}
}
}