1use base::id::{DomExceptionId, DomExceptionIndex};
6use constellation_traits::DomException;
7use dom_struct::dom_struct;
8use js::rust::HandleObject;
9use rustc_hash::FxHashMap;
10
11use crate::dom::bindings::codegen::Bindings::DOMExceptionBinding::{
12 DOMExceptionConstants, DOMExceptionMethods,
13};
14use crate::dom::bindings::error::Error;
15use crate::dom::bindings::reflector::{
16 Reflector, reflect_dom_object, reflect_dom_object_with_proto,
17};
18use crate::dom::bindings::root::DomRoot;
19use crate::dom::bindings::serializable::Serializable;
20use crate::dom::bindings::str::DOMString;
21use crate::dom::bindings::structuredclone::StructuredData;
22use crate::dom::globalscope::GlobalScope;
23use crate::script_runtime::CanGc;
24
25#[repr(u16)]
26#[allow(clippy::enum_variant_names)]
27#[derive(Clone, Copy, Debug, Eq, JSTraceable, MallocSizeOf, Ord, PartialEq, PartialOrd)]
28pub(crate) enum DOMErrorName {
29 IndexSizeError = DOMExceptionConstants::INDEX_SIZE_ERR,
30 HierarchyRequestError = DOMExceptionConstants::HIERARCHY_REQUEST_ERR,
31 WrongDocumentError = DOMExceptionConstants::WRONG_DOCUMENT_ERR,
32 InvalidCharacterError = DOMExceptionConstants::INVALID_CHARACTER_ERR,
33 NoModificationAllowedError = DOMExceptionConstants::NO_MODIFICATION_ALLOWED_ERR,
34 NotFoundError = DOMExceptionConstants::NOT_FOUND_ERR,
35 NotSupportedError = DOMExceptionConstants::NOT_SUPPORTED_ERR,
36 InUseAttributeError = DOMExceptionConstants::INUSE_ATTRIBUTE_ERR,
37 InvalidStateError = DOMExceptionConstants::INVALID_STATE_ERR,
38 SyntaxError = DOMExceptionConstants::SYNTAX_ERR,
39 InvalidModificationError = DOMExceptionConstants::INVALID_MODIFICATION_ERR,
40 NamespaceError = DOMExceptionConstants::NAMESPACE_ERR,
41 InvalidAccessError = DOMExceptionConstants::INVALID_ACCESS_ERR,
42 SecurityError = DOMExceptionConstants::SECURITY_ERR,
43 NetworkError = DOMExceptionConstants::NETWORK_ERR,
44 AbortError = DOMExceptionConstants::ABORT_ERR,
45 TypeMismatchError = DOMExceptionConstants::TYPE_MISMATCH_ERR,
46 URLMismatchError = DOMExceptionConstants::URL_MISMATCH_ERR,
47 QuotaExceededError = DOMExceptionConstants::QUOTA_EXCEEDED_ERR,
48 TimeoutError = DOMExceptionConstants::TIMEOUT_ERR,
49 InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR,
50 DataCloneError = DOMExceptionConstants::DATA_CLONE_ERR,
51 DataError,
52 TransactionInactiveError,
53 ReadOnlyError,
54 VersionError,
55 EncodingError,
56 NotReadableError,
57 OperationError,
58 NotAllowedError,
59 ConstraintError,
60}
61
62impl DOMErrorName {
63 pub(crate) fn from(s: &DOMString) -> Option<DOMErrorName> {
64 match s.as_ref() {
65 "IndexSizeError" => Some(DOMErrorName::IndexSizeError),
66 "HierarchyRequestError" => Some(DOMErrorName::HierarchyRequestError),
67 "WrongDocumentError" => Some(DOMErrorName::WrongDocumentError),
68 "InvalidCharacterError" => Some(DOMErrorName::InvalidCharacterError),
69 "NoModificationAllowedError" => Some(DOMErrorName::NoModificationAllowedError),
70 "NotFoundError" => Some(DOMErrorName::NotFoundError),
71 "NotSupportedError" => Some(DOMErrorName::NotSupportedError),
72 "InUseAttributeError" => Some(DOMErrorName::InUseAttributeError),
73 "InvalidStateError" => Some(DOMErrorName::InvalidStateError),
74 "SyntaxError" => Some(DOMErrorName::SyntaxError),
75 "InvalidModificationError" => Some(DOMErrorName::InvalidModificationError),
76 "NamespaceError" => Some(DOMErrorName::NamespaceError),
77 "InvalidAccessError" => Some(DOMErrorName::InvalidAccessError),
78 "SecurityError" => Some(DOMErrorName::SecurityError),
79 "NetworkError" => Some(DOMErrorName::NetworkError),
80 "AbortError" => Some(DOMErrorName::AbortError),
81 "TypeMismatchError" => Some(DOMErrorName::TypeMismatchError),
82 "URLMismatchError" => Some(DOMErrorName::URLMismatchError),
83 "QuotaExceededError" => Some(DOMErrorName::QuotaExceededError),
84 "TimeoutError" => Some(DOMErrorName::TimeoutError),
85 "InvalidNodeTypeError" => Some(DOMErrorName::InvalidNodeTypeError),
86 "DataCloneError" => Some(DOMErrorName::DataCloneError),
87 "DataError" => Some(DOMErrorName::DataError),
88 "TransactionInactiveError" => Some(DOMErrorName::TransactionInactiveError),
89 "ReadOnlyError" => Some(DOMErrorName::ReadOnlyError),
90 "VersionError" => Some(DOMErrorName::VersionError),
91 "EncodingError" => Some(DOMErrorName::EncodingError),
92 "NotReadableError" => Some(DOMErrorName::NotReadableError),
93 "OperationError" => Some(DOMErrorName::OperationError),
94 "NotAllowedError" => Some(DOMErrorName::NotAllowedError),
95 "ConstraintError" => Some(DOMErrorName::ConstraintError),
96 _ => None,
97 }
98 }
99}
100
101#[dom_struct]
102pub(crate) struct DOMException {
103 reflector_: Reflector,
104 message: DOMString,
105 name: DOMString,
106}
107
108impl DOMException {
109 fn get_error_data_by_code(code: DOMErrorName) -> (DOMString, DOMString) {
110 let message = match &code {
111 DOMErrorName::IndexSizeError => "The index is not in the allowed range.",
112 DOMErrorName::HierarchyRequestError => {
113 "The operation would yield an incorrect node tree."
114 },
115 DOMErrorName::WrongDocumentError => "The object is in the wrong document.",
116 DOMErrorName::InvalidCharacterError => "The string contains invalid characters.",
117 DOMErrorName::NoModificationAllowedError => "The object can not be modified.",
118 DOMErrorName::NotFoundError => "The object can not be found here.",
119 DOMErrorName::NotSupportedError => "The operation is not supported.",
120 DOMErrorName::InUseAttributeError => "The attribute already in use.",
121 DOMErrorName::InvalidStateError => "The object is in an invalid state.",
122 DOMErrorName::SyntaxError => "The string did not match the expected pattern.",
123 DOMErrorName::InvalidModificationError => "The object can not be modified in this way.",
124 DOMErrorName::NamespaceError => "The operation is not allowed by Namespaces in XML.",
125 DOMErrorName::InvalidAccessError => {
126 "The object does not support the operation or argument."
127 },
128 DOMErrorName::SecurityError => "The operation is insecure.",
129 DOMErrorName::NetworkError => "A network error occurred.",
130 DOMErrorName::AbortError => "The operation was aborted.",
131 DOMErrorName::TypeMismatchError => "The given type does not match any expected type.",
132 DOMErrorName::URLMismatchError => "The given URL does not match another URL.",
133 DOMErrorName::QuotaExceededError => "The quota has been exceeded.",
134 DOMErrorName::TimeoutError => "The operation timed out.",
135 DOMErrorName::InvalidNodeTypeError => {
136 "The supplied node is incorrect or has an incorrect ancestor for this operation."
137 },
138 DOMErrorName::DataCloneError => "The object can not be cloned.",
139 DOMErrorName::DataError => "Provided data is inadequate.",
140 DOMErrorName::TransactionInactiveError => {
141 "A request was placed against a transaction which is currently not active, or which is finished."
142 },
143 DOMErrorName::ReadOnlyError => {
144 "The mutating operation was attempted in a \"readonly\" transaction."
145 },
146 DOMErrorName::VersionError => {
147 "An attempt was made to open a database using a lower version than the existing version."
148 },
149 DOMErrorName::EncodingError => {
150 "The encoding operation (either encoded or decoding) failed."
151 },
152 DOMErrorName::NotReadableError => "The I/O read operation failed.",
153 DOMErrorName::OperationError => {
154 "The operation failed for an operation-specific reason."
155 },
156 DOMErrorName::NotAllowedError => {
157 r#"The request is not allowed by the user agent or the platform in the current context,
158 possibly because the user denied permission."#
159 },
160 DOMErrorName::ConstraintError => {
161 "A mutation operation in a transaction failed because a constraint was not satisfied."
162 },
163 };
164
165 (
166 DOMString::from(message),
167 DOMString::from(format!("{:?}", code)),
168 )
169 }
170
171 pub(crate) fn new_inherited(message: DOMString, name: DOMString) -> DOMException {
172 DOMException {
173 reflector_: Reflector::new(),
174 message,
175 name,
176 }
177 }
178
179 pub(crate) fn new(
180 global: &GlobalScope,
181 code: DOMErrorName,
182 can_gc: CanGc,
183 ) -> DomRoot<DOMException> {
184 let (message, name) = DOMException::get_error_data_by_code(code);
185
186 reflect_dom_object(
187 Box::new(DOMException::new_inherited(message, name)),
188 global,
189 can_gc,
190 )
191 }
192
193 pub(crate) fn new_with_custom_message(
194 global: &GlobalScope,
195 code: DOMErrorName,
196 message: String,
197 can_gc: CanGc,
198 ) -> DomRoot<DOMException> {
199 let (_, name) = DOMException::get_error_data_by_code(code);
200
201 reflect_dom_object(
202 Box::new(DOMException::new_inherited(DOMString::from(message), name)),
203 global,
204 can_gc,
205 )
206 }
207
208 pub(crate) fn stringifier(&self) -> DOMString {
210 DOMString::from(format!("{}: {}", self.name, self.message))
211 }
212}
213
214impl DOMExceptionMethods<crate::DomTypeHolder> for DOMException {
215 fn Constructor(
217 global: &GlobalScope,
218 proto: Option<HandleObject>,
219 can_gc: CanGc,
220 message: DOMString,
221 name: DOMString,
222 ) -> Result<DomRoot<DOMException>, Error> {
223 Ok(reflect_dom_object_with_proto(
224 Box::new(DOMException::new_inherited(message, name)),
225 global,
226 proto,
227 can_gc,
228 ))
229 }
230
231 fn Code(&self) -> u16 {
233 match DOMErrorName::from(&self.name) {
234 Some(code) if code <= DOMErrorName::DataCloneError => code as u16,
235 _ => 0,
236 }
237 }
238
239 fn Name(&self) -> DOMString {
241 self.name.clone()
242 }
243
244 fn Message(&self) -> DOMString {
246 self.message.clone()
247 }
248}
249
250impl Serializable for DOMException {
251 type Index = DomExceptionIndex;
252 type Data = DomException;
253
254 fn serialize(&self) -> Result<(DomExceptionId, Self::Data), ()> {
256 let serialized = DomException {
257 message: self.message.to_string(),
258 name: self.name.to_string(),
259 };
260 Ok((DomExceptionId::new(), serialized))
261 }
262
263 fn deserialize(
265 owner: &GlobalScope,
266 serialized: Self::Data,
267 can_gc: CanGc,
268 ) -> Result<DomRoot<Self>, ()>
269 where
270 Self: Sized,
271 {
272 Ok(Self::new_with_custom_message(
273 owner,
274 DOMErrorName::from(&DOMString::from_string(serialized.name)).ok_or(())?,
275 serialized.message,
276 can_gc,
277 ))
278 }
279
280 fn serialized_storage<'a>(
281 data: StructuredData<'a, '_>,
282 ) -> &'a mut Option<FxHashMap<DomExceptionId, Self::Data>> {
283 match data {
284 StructuredData::Reader(reader) => &mut reader.exceptions,
285 StructuredData::Writer(writer) => &mut writer.exceptions,
286 }
287 }
288}