diff options
Diffstat (limited to 'components/script/dom/formdata.rs')
-rw-r--r-- | components/script/dom/formdata.rs | 239 |
1 files changed, 139 insertions, 100 deletions
diff --git a/components/script/dom/formdata.rs b/components/script/dom/formdata.rs index af4c692e7d9..3a8f3ce4b5b 100644 --- a/components/script/dom/formdata.rs +++ b/components/script/dom/formdata.rs @@ -1,60 +1,64 @@ /* 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 http://mozilla.org/MPL/2.0/. */ - -use dom::bindings::cell::DOMRefCell; -use dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods; -use dom::bindings::codegen::Bindings::FormDataBinding::FormDataWrap; -use dom::bindings::codegen::UnionTypes::FileOrUSVString; -use dom::bindings::error::Fallible; -use dom::bindings::inheritance::Castable; -use dom::bindings::iterable::Iterable; -use dom::bindings::js::Root; -use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; -use dom::bindings::str::{DOMString, USVString}; -use dom::blob::{Blob, BlobImpl}; -use dom::file::File; -use dom::globalscope::GlobalScope; -use dom::htmlformelement::{HTMLFormElement, FormDatumValue, FormDatum}; + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods; +use crate::dom::bindings::codegen::UnionTypes::FileOrUSVString; +use crate::dom::bindings::error::{Error, Fallible}; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::iterable::Iterable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::{DOMString, USVString}; +use crate::dom::blob::Blob; +use crate::dom::file::File; +use crate::dom::globalscope::GlobalScope; +use crate::dom::htmlformelement::{FormDatum, FormDatumValue, HTMLFormElement}; use dom_struct::dom_struct; -use html5ever_atoms::LocalName; -use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::iter; +use html5ever::LocalName; +use script_traits::serializable::BlobImpl; #[dom_struct] pub struct FormData { reflector_: Reflector, - data: DOMRefCell<HashMap<LocalName, Vec<FormDatum>>>, + data: DomRefCell<Vec<(LocalName, FormDatum)>>, } impl FormData { - fn new_inherited(opt_form: Option<&HTMLFormElement>) -> FormData { - let mut hashmap: HashMap<LocalName, Vec<FormDatum>> = HashMap::new(); - - if let Some(form) = opt_form { - for datum in form.get_form_dataset(None) { - match hashmap.entry(LocalName::from(datum.name.as_ref())) { - Occupied(entry) => entry.into_mut().push(datum), - Vacant(entry) => { entry.insert(vec!(datum)); } - } - } - } + fn new_inherited(form_datums: Option<Vec<FormDatum>>) -> FormData { + let data = match form_datums { + Some(data) => data + .iter() + .map(|datum| (LocalName::from(datum.name.as_ref()), datum.clone())) + .collect::<Vec<(LocalName, FormDatum)>>(), + None => Vec::new(), + }; FormData { reflector_: Reflector::new(), - data: DOMRefCell::new(hashmap), + data: DomRefCell::new(data), } } - pub fn new(form: Option<&HTMLFormElement>, global: &GlobalScope) -> Root<FormData> { - reflect_dom_object(box FormData::new_inherited(form), - global, FormDataWrap) + pub fn new(form_datums: Option<Vec<FormDatum>>, global: &GlobalScope) -> DomRoot<FormData> { + reflect_dom_object(Box::new(FormData::new_inherited(form_datums)), global) } - pub fn Constructor(global: &GlobalScope, form: Option<&HTMLFormElement>) -> Fallible<Root<FormData>> { - // TODO: Construct form data set for form if it is supplied - Ok(FormData::new(form, global)) + // https://xhr.spec.whatwg.org/#dom-formdata + #[allow(non_snake_case)] + pub fn Constructor( + global: &GlobalScope, + form: Option<&HTMLFormElement>, + ) -> Fallible<DomRoot<FormData>> { + if let Some(opt_form) = form { + return match opt_form.get_form_dataset(None, None) { + Some(form_datums) => Ok(FormData::new(Some(form_datums), global)), + None => Err(Error::InvalidState), + }; + } + + Ok(FormData::new(None, global)) } } @@ -67,11 +71,9 @@ impl FormDataMethods for FormData { value: FormDatumValue::String(DOMString::from(str_value.0)), }; - let mut data = self.data.borrow_mut(); - match data.entry(LocalName::from(name.0)) { - Occupied(entry) => entry.into_mut().push(datum), - Vacant(entry) => { entry.insert(vec!(datum)); } - } + self.data + .borrow_mut() + .push((LocalName::from(name.0), datum)); } #[allow(unrooted_must_root)] @@ -80,90 +82,134 @@ impl FormDataMethods for FormData { let datum = FormDatum { ty: DOMString::from("file"), name: DOMString::from(name.0.clone()), - value: FormDatumValue::File(Root::from_ref(&*self.create_an_entry(blob, filename))), + value: FormDatumValue::File(DomRoot::from_ref(&*self.create_an_entry(blob, filename))), }; - let mut data = self.data.borrow_mut(); - - match data.entry(LocalName::from(name.0)) { - Occupied(entry) => entry.into_mut().push(datum), - Vacant(entry) => { entry.insert(vec!(datum)); }, - } + self.data + .borrow_mut() + .push((LocalName::from(name.0), datum)); } // https://xhr.spec.whatwg.org/#dom-formdata-delete fn Delete(&self, name: USVString) { - self.data.borrow_mut().remove(&LocalName::from(name.0)); + self.data + .borrow_mut() + .retain(|(datum_name, _)| datum_name != &LocalName::from(name.0.clone())); } // https://xhr.spec.whatwg.org/#dom-formdata-get fn Get(&self, name: USVString) -> Option<FileOrUSVString> { - self.data.borrow() - .get(&LocalName::from(name.0)) - .map(|entry| match entry[0].value { - FormDatumValue::String(ref s) => FileOrUSVString::USVString(USVString(s.to_string())), - FormDatumValue::File(ref b) => FileOrUSVString::File(Root::from_ref(&*b)), - }) + self.data + .borrow() + .iter() + .filter(|(datum_name, _)| datum_name == &LocalName::from(name.0.clone())) + .next() + .map(|(_, datum)| match &datum.value { + FormDatumValue::String(ref s) => { + FileOrUSVString::USVString(USVString(s.to_string())) + }, + FormDatumValue::File(ref b) => FileOrUSVString::File(DomRoot::from_ref(&*b)), + }) } // https://xhr.spec.whatwg.org/#dom-formdata-getall fn GetAll(&self, name: USVString) -> Vec<FileOrUSVString> { - self.data.borrow() - .get(&LocalName::from(name.0)) - .map_or(vec![], |data| - data.iter().map(|item| match item.value { - FormDatumValue::String(ref s) => FileOrUSVString::USVString(USVString(s.to_string())), - FormDatumValue::File(ref b) => FileOrUSVString::File(Root::from_ref(&*b)), - }).collect() - ) + self.data + .borrow() + .iter() + .filter_map(|datum| { + if datum.0 != LocalName::from(name.0.clone()) { + return None; + } + + Some(match &datum.1.value { + FormDatumValue::String(ref s) => { + FileOrUSVString::USVString(USVString(s.to_string())) + }, + FormDatumValue::File(ref b) => FileOrUSVString::File(DomRoot::from_ref(&*b)), + }) + }) + .collect() } // https://xhr.spec.whatwg.org/#dom-formdata-has fn Has(&self, name: USVString) -> bool { - self.data.borrow().contains_key(&LocalName::from(name.0)) + self.data + .borrow() + .iter() + .any(|(datum_name, _0)| datum_name == &LocalName::from(name.0.clone())) } // https://xhr.spec.whatwg.org/#dom-formdata-set fn Set(&self, name: USVString, str_value: USVString) { - self.data.borrow_mut().insert(LocalName::from(name.0.clone()), vec![FormDatum { - ty: DOMString::from("string"), - name: DOMString::from(name.0), - value: FormDatumValue::String(DOMString::from(str_value.0)), - }]); + let mut data = self.data.borrow_mut(); + let local_name = LocalName::from(name.0.clone()); + + data.retain(|(datum_name, _)| datum_name != &local_name); + + data.push(( + local_name, + FormDatum { + ty: DOMString::from("string"), + name: DOMString::from(name.0), + value: FormDatumValue::String(DOMString::from(str_value.0)), + }, + )); } #[allow(unrooted_must_root)] // https://xhr.spec.whatwg.org/#dom-formdata-set fn Set_(&self, name: USVString, blob: &Blob, filename: Option<USVString>) { - self.data.borrow_mut().insert(LocalName::from(name.0.clone()), vec![FormDatum { - ty: DOMString::from("file"), - name: DOMString::from(name.0), - value: FormDatumValue::File(Root::from_ref(&*self.create_an_entry(blob, filename))), - }]); - } + let mut data = self.data.borrow_mut(); + let local_name = LocalName::from(name.0.clone()); -} + data.retain(|(datum_name, _)| datum_name != &local_name); + data.push(( + LocalName::from(name.0.clone()), + FormDatum { + ty: DOMString::from("file"), + name: DOMString::from(name.0), + value: FormDatumValue::File(DomRoot::from_ref( + &*self.create_an_entry(blob, filename), + )), + }, + )); + } +} impl FormData { // https://xhr.spec.whatwg.org/#create-an-entry - // Steps 3-4. - fn create_an_entry(&self, blob: &Blob, opt_filename: Option<USVString>) -> Root<File> { + fn create_an_entry(&self, blob: &Blob, opt_filename: Option<USVString>) -> DomRoot<File> { + // Steps 3-4 let name = match opt_filename { Some(filename) => DOMString::from(filename.0), - None if blob.downcast::<File>().is_none() => DOMString::from("blob"), - None => DOMString::from(""), + None => match blob.downcast::<File>() { + None => DOMString::from("blob"), + // If it is already a file and no filename was given, + // then neither step 3 nor step 4 happens, so instead of + // creating a new File object we use the existing one. + Some(file) => { + return DomRoot::from_ref(file); + }, + }, }; let bytes = blob.get_bytes().unwrap_or(vec![]); - File::new(&self.global(), BlobImpl::new_from_bytes(bytes), name, None, &blob.type_string()) + File::new( + &self.global(), + BlobImpl::new_from_bytes(bytes, blob.type_string()), + name, + None, + ) } pub fn datums(&self) -> Vec<FormDatum> { - self.data.borrow().values() - .flat_map(|value| value.iter()) - .map(|value| value.clone()) + self.data + .borrow() + .iter() + .map(|(_, datum)| datum.clone()) .collect() } } @@ -173,28 +219,21 @@ impl Iterable for FormData { type Value = FileOrUSVString; fn get_iterable_length(&self) -> u32 { - self.data.borrow().values().map(|value| value.len()).sum::<usize>() as u32 + self.data.borrow().len() as u32 } fn get_value_at_index(&self, n: u32) -> FileOrUSVString { let data = self.data.borrow(); - let value = &data.values() - .flat_map(|value| value.iter()) - .nth(n as usize) - .unwrap() - .value; - match *value { + let datum = &data.get(n as usize).unwrap().1; + match &datum.value { FormDatumValue::String(ref s) => FileOrUSVString::USVString(USVString(s.to_string())), - FormDatumValue::File(ref b) => FileOrUSVString::File(Root::from_ref(&*b)), + FormDatumValue::File(ref b) => FileOrUSVString::File(DomRoot::from_ref(b)), } } fn get_key_at_index(&self, n: u32) -> USVString { let data = self.data.borrow(); - let value = &data.iter() - .flat_map(|(key, value)| iter::repeat(key).take(value.len())) - .nth(n as usize) - .unwrap(); - USVString(value.to_string()) + let key = &data.get(n as usize).unwrap().0; + USVString(key.to_string()) } } |