mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Add script::dom::utils::validate_and_extract()
Accidentally fixes bugs about Document::createElementNS() where the implementation of "validate and extract" used to check whether the local name extracted from the qualified name was "xmlns" instead of the qualified name itself.
This commit is contained in:
parent
abc01d598a
commit
7b4f6126c8
5 changed files with 67 additions and 161 deletions
|
@ -7,14 +7,17 @@
|
|||
use dom::bindings::codegen::PrototypeList;
|
||||
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
|
||||
use dom::bindings::conversions::{native_from_reflector_jsmanaged, is_dom_class};
|
||||
use dom::bindings::error::{Error, ErrorResult, throw_type_error};
|
||||
use dom::bindings::error::{Error, ErrorResult, Fallible, throw_type_error};
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::js::{Temporary, Root};
|
||||
use dom::browsercontext;
|
||||
use dom::window;
|
||||
use util::namespace;
|
||||
use util::str::DOMString;
|
||||
|
||||
use libc;
|
||||
use libc::c_uint;
|
||||
use std::borrow::ToOwned;
|
||||
use std::boxed;
|
||||
use std::cell::Cell;
|
||||
use std::ffi::CString;
|
||||
|
@ -43,6 +46,7 @@ use js::rust::with_compartment;
|
|||
use js::{JSPROP_ENUMERATE, JSPROP_READONLY, JSPROP_PERMANENT};
|
||||
use js::JSFUN_CONSTRUCTOR;
|
||||
use js;
|
||||
use string_cache::{Atom, Namespace};
|
||||
|
||||
/// Proxy handler for a WindowProxy.
|
||||
pub struct WindowProxyHandler(pub *const libc::c_void);
|
||||
|
@ -619,6 +623,53 @@ pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
|
|||
}
|
||||
}
|
||||
|
||||
/// Validate a namespace and qualified name and extract their parts.
|
||||
/// See https://dom.spec.whatwg.org/#validate-and-extract for details.
|
||||
pub fn validate_and_extract(namespace: Option<DOMString>, qualified_name: &str)
|
||||
-> Fallible<(Namespace, Option<DOMString>, Atom)> {
|
||||
// Step 1.
|
||||
let namespace = namespace::from_domstring(namespace);
|
||||
|
||||
// Step 2.
|
||||
try!(validate_qualified_name(qualified_name));
|
||||
|
||||
let (prefix, local_name) = if qualified_name.contains(":") {
|
||||
// Step 5.
|
||||
let mut parts = qualified_name.splitn(1, ':');
|
||||
let prefix = parts.next().unwrap();
|
||||
debug_assert!(!prefix.is_empty());
|
||||
let local_name = parts.next().unwrap();
|
||||
debug_assert!(!local_name.contains(":"));
|
||||
(Some(prefix), local_name)
|
||||
} else {
|
||||
(None, qualified_name)
|
||||
};
|
||||
|
||||
match (namespace, prefix) {
|
||||
(ns!(""), Some(_)) => {
|
||||
// Step 6.
|
||||
Err(Error::Namespace)
|
||||
},
|
||||
(ref ns, Some("xml")) if ns != &ns!(XML) => {
|
||||
// Step 7.
|
||||
Err(Error::Namespace)
|
||||
},
|
||||
(ref ns, p) if ns != &ns!(XMLNS) &&
|
||||
(qualified_name == "xmlns" || p == Some("xmlns")) => {
|
||||
// Step 8.
|
||||
Err(Error::Namespace)
|
||||
},
|
||||
(ns!(XMLNS), p) if qualified_name != "xmlns" && p != Some("xmlns") => {
|
||||
// Step 9.
|
||||
Err(Error::Namespace)
|
||||
},
|
||||
(ns, p) => {
|
||||
// Step 10.
|
||||
Ok((ns, p.map(|s| s.to_owned()), Atom::from_slice(local_name)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Results of `xml_name_type`.
|
||||
#[derive(PartialEq)]
|
||||
#[allow(missing_docs)]
|
||||
|
|
|
@ -21,20 +21,20 @@ use dom::bindings::codegen::InheritTypes::{HTMLFormElementDerived, HTMLImageElem
|
|||
use dom::bindings::codegen::InheritTypes::{HTMLScriptElementDerived};
|
||||
use dom::bindings::error::{ErrorResult, Fallible};
|
||||
use dom::bindings::error::Error::{NotSupported, InvalidCharacter, Security};
|
||||
use dom::bindings::error::Error::{HierarchyRequest, Namespace};
|
||||
use dom::bindings::error::Error::HierarchyRequest;
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable};
|
||||
use dom::bindings::js::{OptionalRootable, RootedReference};
|
||||
use dom::bindings::refcounted::Trusted;
|
||||
use dom::bindings::utils::reflect_dom_object;
|
||||
use dom::bindings::utils::{xml_name_type, validate_qualified_name};
|
||||
use dom::bindings::utils::{xml_name_type, validate_and_extract};
|
||||
use dom::bindings::utils::XMLName::InvalidXMLName;
|
||||
use dom::comment::Comment;
|
||||
use dom::customevent::CustomEvent;
|
||||
use dom::documentfragment::DocumentFragment;
|
||||
use dom::documenttype::DocumentType;
|
||||
use dom::domimplementation::DOMImplementation;
|
||||
use dom::element::{Element, ElementCreator, AttributeHandlers, get_attribute_parts};
|
||||
use dom::element::{Element, ElementCreator, AttributeHandlers};
|
||||
use dom::element::{ElementTypeId, ActivationElementHelpers};
|
||||
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
|
||||
use dom::eventtarget::{EventTarget, EventTargetTypeId, EventTargetHelpers};
|
||||
|
@ -67,7 +67,7 @@ use net_traits::CookieSource::NonHTTP;
|
|||
use net_traits::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl};
|
||||
use script_task::Runnable;
|
||||
use script_traits::{MouseButton, UntrustedNodeAddress};
|
||||
use util::{opts, namespace};
|
||||
use util::opts;
|
||||
use util::str::{DOMString, split_html_space_chars};
|
||||
use layout_interface::{ReflowGoal, ReflowQueryType};
|
||||
|
||||
|
@ -975,35 +975,10 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
|
|||
fn CreateElementNS(self,
|
||||
namespace: Option<DOMString>,
|
||||
qualified_name: DOMString) -> Fallible<Temporary<Element>> {
|
||||
let ns = namespace::from_domstring(namespace);
|
||||
try!(validate_qualified_name(&qualified_name));
|
||||
|
||||
let (prefix_from_qname, local_name_from_qname) = get_attribute_parts(&qualified_name);
|
||||
match (&ns, prefix_from_qname, local_name_from_qname) {
|
||||
// throw if prefix is not null and namespace is null
|
||||
(&ns!(""), Some(_), _) => {
|
||||
debug!("Namespace can't be null with a non-null prefix");
|
||||
return Err(Namespace);
|
||||
},
|
||||
// throw if prefix is "xml" and namespace is not the XML namespace
|
||||
(_, Some(ref prefix), _) if "xml" == *prefix && ns != ns!(XML) => {
|
||||
debug!("Namespace must be the xml namespace if the prefix is 'xml'");
|
||||
return Err(Namespace);
|
||||
},
|
||||
// throw if namespace is the XMLNS namespace and neither qualifiedName nor prefix is
|
||||
// "xmlns"
|
||||
(&ns!(XMLNS), Some(ref prefix), _) if "xmlns" == *prefix => {},
|
||||
(&ns!(XMLNS), _, "xmlns") => {},
|
||||
(&ns!(XMLNS), _, _) => {
|
||||
debug!("The prefix or the qualified name must be 'xmlns' if namespace is the XMLNS namespace ");
|
||||
return Err(Namespace);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let name = QualName::new(ns, Atom::from_slice(local_name_from_qname));
|
||||
Ok(Element::create(name, prefix_from_qname.map(|s| s.to_owned()), self,
|
||||
ElementCreator::ScriptCreated))
|
||||
let (namespace, prefix, local_name) =
|
||||
try!(validate_and_extract(namespace, &qualified_name));
|
||||
let name = QualName::new(namespace, local_name);
|
||||
Ok(Element::create(name, prefix, self, ElementCreator::ScriptCreated))
|
||||
}
|
||||
|
||||
// http://dom.spec.whatwg.org/#dom-document-createattribute
|
||||
|
|
|
@ -24,13 +24,12 @@ use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, HTMLTextA
|
|||
use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast};
|
||||
use dom::bindings::codegen::InheritTypes::HTMLAnchorElementCast;
|
||||
use dom::bindings::error::{ErrorResult, Fallible};
|
||||
use dom::bindings::error::Error;
|
||||
use dom::bindings::error::Error::{InvalidCharacter, Syntax};
|
||||
use dom::bindings::error::Error::NoModificationAllowed;
|
||||
use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable};
|
||||
use dom::bindings::js::{OptionalRootable, RootedReference};
|
||||
use dom::bindings::trace::RootedVec;
|
||||
use dom::bindings::utils::{xml_name_type, validate_qualified_name};
|
||||
use dom::bindings::utils::{xml_name_type, validate_and_extract};
|
||||
use dom::bindings::utils::XMLName::InvalidXMLName;
|
||||
use dom::create::create_element;
|
||||
use dom::domrect::DOMRect;
|
||||
|
@ -1031,52 +1030,14 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
|
|||
|
||||
// http://dom.spec.whatwg.org/#dom-element-setattributens
|
||||
fn SetAttributeNS(self,
|
||||
namespace_url: Option<DOMString>,
|
||||
name: DOMString,
|
||||
namespace: Option<DOMString>,
|
||||
qualified_name: DOMString,
|
||||
value: DOMString) -> ErrorResult {
|
||||
// Step 1.
|
||||
let namespace = namespace::from_domstring(namespace_url);
|
||||
|
||||
// Steps 2-3.
|
||||
try!(validate_qualified_name(&name));
|
||||
|
||||
// Step 4.
|
||||
let (prefix, local_name) = get_attribute_parts(&name);
|
||||
|
||||
if let Some(ref prefix_str) = prefix {
|
||||
// Step 5.
|
||||
if namespace == ns!("") {
|
||||
return Err(Error::Namespace);
|
||||
}
|
||||
|
||||
// Step 6.
|
||||
if "xml" == *prefix_str && namespace != ns!(XML) {
|
||||
return Err(Error::Namespace);
|
||||
}
|
||||
|
||||
// Step 7b.
|
||||
if "xmlns" == *prefix_str && namespace != ns!(XMLNS) {
|
||||
return Err(Error::Namespace);
|
||||
}
|
||||
}
|
||||
|
||||
let name = Atom::from_slice(&name);
|
||||
let local_name = Atom::from_slice(local_name);
|
||||
let xmlns = atom!("xmlns");
|
||||
|
||||
// Step 7a.
|
||||
if xmlns == name && namespace != ns!(XMLNS) {
|
||||
return Err(Error::Namespace);
|
||||
}
|
||||
|
||||
// Step 8.
|
||||
if namespace == ns!(XMLNS) && xmlns != name && Some("xmlns") != prefix {
|
||||
return Err(Error::Namespace);
|
||||
}
|
||||
|
||||
// Step 9.
|
||||
let (namespace, prefix, local_name) =
|
||||
try!(validate_and_extract(namespace, &qualified_name));
|
||||
let qualified_name = Atom::from_slice(&qualified_name);
|
||||
let value = self.parse_attribute(&namespace, &local_name, value);
|
||||
self.do_set_attribute(local_name.clone(), value, name,
|
||||
self.do_set_attribute(local_name.clone(), value, qualified_name,
|
||||
namespace.clone(), prefix.map(|s| s.to_owned()),
|
||||
|attr| {
|
||||
*attr.local_name() == local_name &&
|
||||
|
@ -1266,17 +1227,6 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_attribute_parts<'a>(name: &'a str) -> (Option<&'a str>, &'a str) {
|
||||
//FIXME: Throw for XML-invalid names
|
||||
//FIXME: Throw for XMLNS-invalid names
|
||||
if name.contains(":") {
|
||||
let mut parts = name.splitn(1, ':');
|
||||
(Some(parts.next().unwrap()), parts.next().unwrap())
|
||||
} else {
|
||||
(None, name)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VirtualMethods for JSRef<'a, Element> {
|
||||
fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
|
||||
let node: &JSRef<Node> = NodeCast::from_borrowed_ref(self);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue