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