Skip to main content

script/dom/serviceworker/
navigationpreloadmanager.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::realm::CurrentRealm;
8use net_traits::trim_http_whitespace;
9use script_bindings::reflector::{Reflector, reflect_dom_object};
10
11use crate::dom::bindings::codegen::Bindings::NavigationPreloadManagerBinding::{
12    NavigationPreloadManagerMethods, NavigationPreloadState,
13};
14use crate::dom::bindings::error::Error;
15use crate::dom::bindings::root::{Dom, DomRoot};
16use crate::dom::bindings::str::ByteString;
17use crate::dom::globalscope::GlobalScope;
18use crate::dom::promise::{Promise, RootedPromise};
19use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
20
21#[dom_struct]
22pub(crate) struct NavigationPreloadManager {
23    reflector_: Reflector,
24    serviceworker_registration: Dom<ServiceWorkerRegistration>,
25}
26
27impl NavigationPreloadManager {
28    fn new_inherited(registration: &ServiceWorkerRegistration) -> NavigationPreloadManager {
29        NavigationPreloadManager {
30            reflector_: Reflector::new(),
31            serviceworker_registration: Dom::from_ref(registration),
32        }
33    }
34
35    #[cfg_attr(crown, expect(crown::unrooted_must_root))]
36    pub(crate) fn new(
37        cx: &mut JSContext,
38        global: &GlobalScope,
39        registration: &ServiceWorkerRegistration,
40    ) -> DomRoot<NavigationPreloadManager> {
41        let manager = NavigationPreloadManager::new_inherited(registration);
42        reflect_dom_object(cx, Box::new(manager), global)
43    }
44}
45
46impl NavigationPreloadManagerMethods<crate::DomTypeHolder> for NavigationPreloadManager {
47    /// <https://w3c.github.io/ServiceWorker/#navigation-preload-manager-enable>
48    fn Enable(&self, cx: &mut CurrentRealm) -> RootedPromise {
49        // Step 1. Let promise be a new promise.
50        let promise = Promise::new_in_realm(cx);
51
52        // Step 2.
53        // 1. If registration’s active worker is null, then reject promise with an "InvalidStateError" DOMException.
54        if !self.serviceworker_registration.is_active() {
55            promise.reject_error(
56                cx,
57                Error::InvalidState(Some("Registration has no active worker".into())),
58            );
59        } else {
60            // 2. Set registration’s navigation preload enabled to true.
61            self.serviceworker_registration
62                .set_navigation_preload_enabled(true);
63
64            // 3. Resolve promise with undefined.
65            promise.resolve_native(cx, &());
66        }
67
68        // Step 3. Return promise.
69        promise
70    }
71
72    /// <https://w3c.github.io/ServiceWorker/#navigation-preload-manager-disable>
73    fn Disable(&self, cx: &mut CurrentRealm) -> RootedPromise {
74        // Step 1. Let promise be a new promise.
75        let promise = Promise::new_in_realm(cx);
76
77        // Step 2.
78        // 1. If registration’s active worker is null, then reject promise with an "InvalidStateError" DOMException.
79        if !self.serviceworker_registration.is_active() {
80            promise.reject_error(
81                cx,
82                Error::InvalidState(Some("Registration has no active worker".into())),
83            );
84        } else {
85            // 2. Set registration’s navigation preload enabled to false.
86            self.serviceworker_registration
87                .set_navigation_preload_enabled(false);
88
89            // 3. Resolve promise with undefined.
90            promise.resolve_native(cx, &());
91        }
92
93        // Step 3. Return promise.
94        promise
95    }
96
97    /// <https://w3c.github.io/ServiceWorker/#navigation-preload-manager-setheadervalue>
98    fn SetHeaderValue(&self, cx: &mut CurrentRealm, value: ByteString) -> RootedPromise {
99        // Step 1. Let value be the result of normalizing value.
100        let value = Vec::<u8>::from(value);
101        let normalized_value = trim_http_whitespace(&value);
102
103        // Step 2. If value is not a header value, return a promise rejected with a TypeError.
104        let promise = Promise::new_in_realm(cx);
105        if normalized_value.contains(&b'\0') {
106            promise.reject_error(cx, Error::Type(c"Invalid header value".to_owned()));
107            return promise;
108        }
109
110        // Step 4.
111        // 1. If registration’s active worker is null, then reject promise with an "InvalidStateError" DOMException.
112        if !self.serviceworker_registration.is_active() {
113            promise.reject_error(
114                cx,
115                Error::InvalidState(Some("Registration has no active worker".into())),
116            );
117        } else {
118            // 2. Set registration’s navigation preload header value to value.
119            self.serviceworker_registration
120                .set_navigation_preload_header_value(ByteString::new(normalized_value.to_vec()));
121
122            // 3. Resolve promise with undefined.
123            promise.resolve_native(cx, &());
124        }
125
126        // Step 5. Return promise.
127        promise
128    }
129
130    /// <https://w3c.github.io/ServiceWorker/#navigation-preload-manager-getstate>
131    fn GetState(&self, cx: &mut CurrentRealm) -> RootedPromise {
132        // Step 1. Let promise be a new promise.
133        let promise = Promise::new_in_realm(cx);
134
135        // Step 2.
136        // 1. Let state be a new NavigationPreloadState dictionary.
137        let mut state = NavigationPreloadState::empty();
138
139        // 2. Set state["enabled"] to registration’s navigation preload enabled.
140        if self
141            .serviceworker_registration
142            .get_navigation_preload_enabled()
143        {
144            state.enabled = true;
145        }
146
147        // 3. Set state["headerValue"] to registration’s navigation preload header value.
148        state.headerValue = Some(
149            self.serviceworker_registration
150                .get_navigation_preload_header_value(),
151        );
152
153        // 4. Resolve promise with state.
154        promise.resolve_native(cx, &state);
155
156        // Step 3. Return promise.
157        promise
158    }
159}