diff options
-rw-r--r-- | components/script/dom/blob.rs | 105 | ||||
-rw-r--r-- | components/script/dom/file.rs | 51 | ||||
-rw-r--r-- | components/script/dom/formdata.rs | 2 | ||||
-rw-r--r-- | components/script/dom/testbinding.rs | 12 | ||||
-rw-r--r-- | components/script/dom/webidls/Blob.webidl | 7 | ||||
-rw-r--r-- | components/script/dom/webidls/File.webidl | 14 | ||||
-rw-r--r-- | components/script/dom/websocket.rs | 6 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 5 | ||||
-rw-r--r-- | tests/wpt/metadata/FileAPI/file/File-constructor.html.ini | 31 | ||||
-rw-r--r-- | tests/wpt/metadata/FileAPI/file/Worker-read-file-constructor.worker.js.ini | 5 | ||||
-rw-r--r-- | tests/wpt/metadata/FileAPI/idlharness.html.ini | 36 | ||||
-rw-r--r-- | tests/wpt/metadata/FileAPI/idlharness.worker.js.ini | 36 |
12 files changed, 125 insertions, 185 deletions
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index 74ddce1609a..e0d260b2b78 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -28,6 +28,7 @@ pub struct DataSlice { } impl DataSlice { + /// Construct DataSlice from reference counted bytes pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice { let size = bytes.len() as i64; let relativeStart: i64 = match start { @@ -62,14 +63,21 @@ impl DataSlice { } } - pub fn get_bytes(&self) -> &[u8] { - &self.bytes[self.bytes_start..self.bytes_end] + /// Construct an empty data slice + pub fn empty() -> DataSlice { + DataSlice { + bytes: Arc::new(Vec::new()), + bytes_start: 0, + bytes_end: 0, + } } - pub fn get_all_bytes(&self) -> Arc<Vec<u8>> { - self.bytes.clone() + /// Get sliced bytes + pub fn get_bytes(&self) -> &[u8] { + &self.bytes[self.bytes_start..self.bytes_end] } + /// Get length of sliced bytes pub fn size(&self) -> u64 { (self.bytes_end as u64) - (self.bytes_start as u64) } @@ -86,40 +94,22 @@ pub struct Blob { isClosed_: Cell<bool>, } -fn is_ascii_printable(string: &str) -> bool { - // Step 5.1 in Sec 5.1 of File API spec - // https://w3c.github.io/FileAPI/#constructorBlob - string.chars().all(|c| c >= '\x20' && c <= '\x7E') -} - impl Blob { - pub fn new_inherited(bytes: Arc<Vec<u8>>, - bytes_start: Option<i64>, - bytes_end: Option<i64>, - typeString: &str) -> Blob { + + pub fn new(global: GlobalRef, slice: DataSlice, typeString: &str) -> Root<Blob> { + let boxed_blob = box Blob::new_inherited(slice, typeString); + reflect_dom_object(boxed_blob, global, BlobBinding::Wrap) + } + + pub fn new_inherited(slice: DataSlice, typeString: &str) -> Blob { Blob { reflector_: Reflector::new(), - data: DataSlice::new(bytes, bytes_start, bytes_end), + data: slice, typeString: typeString.to_owned(), isClosed_: Cell::new(false), } } - pub fn new(global: GlobalRef, bytes: Vec<u8>, typeString: &str) -> Root<Blob> { - let boxed_blob = box Blob::new_inherited(Arc::new(bytes), None, None, typeString); - reflect_dom_object(boxed_blob, global, BlobBinding::Wrap) - } - - fn new_sliced(global: GlobalRef, - bytes: Arc<Vec<u8>>, - bytes_start: Option<i64>, - bytes_end: Option<i64>, - typeString: &str) -> Root<Blob> { - - let boxed_blob = box Blob::new_inherited(bytes, bytes_start, bytes_end, typeString); - reflect_dom_object(boxed_blob, global, BlobBinding::Wrap) - } - // https://w3c.github.io/FileAPI/#constructorBlob pub fn Constructor(global: GlobalRef, blobParts: Option<Vec<BlobOrString>>, @@ -129,26 +119,11 @@ impl Blob { // TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView let bytes: Vec<u8> = match blobParts { None => Vec::new(), - Some(blobs) => { - blobs.iter().flat_map(|bPart| { - match bPart { - &BlobOrString::String(ref s) => { - UTF_8.encode(s, EncoderTrap::Replace).unwrap() - }, - &BlobOrString::Blob(ref b) => { - b.get_data().get_bytes().to_vec() - }, - } - }) - .collect() - } + Some(blobparts) => blob_parts_to_bytes(blobparts), }; - let typeString = if is_ascii_printable(&blobPropertyBag.type_) { - &*blobPropertyBag.type_ - } else { - "" - }; - Ok(Blob::new(global, bytes, &typeString.to_ascii_lowercase())) + + let slice = DataSlice::new(Arc::new(bytes), None, None); + Ok(Blob::new(global, slice, &blobPropertyBag.get_typestring())) } pub fn get_data(&self) -> &DataSlice { @@ -156,6 +131,19 @@ impl Blob { } } +pub fn blob_parts_to_bytes(blobparts: Vec<BlobOrString>) -> Vec<u8> { + blobparts.iter().flat_map(|blobpart| { + match blobpart { + &BlobOrString::String(ref s) => { + UTF_8.encode(s, EncoderTrap::Replace).unwrap() + }, + &BlobOrString::Blob(ref b) => { + b.get_data().get_bytes().to_vec() + }, + } + }).collect::<Vec<u8>>() +} + impl BlobMethods for Blob { // https://w3c.github.io/FileAPI/#dfn-size fn Size(&self) -> u64 { @@ -187,7 +175,7 @@ impl BlobMethods for Blob { }; let global = self.global(); let bytes = self.data.bytes.clone(); - Blob::new_sliced(global.r(), bytes, start, end, &relativeContentType) + Blob::new(global.r(), DataSlice::new(bytes, start, end), &relativeContentType) } // https://w3c.github.io/FileAPI/#dfn-isClosed @@ -209,3 +197,20 @@ impl BlobMethods for Blob { } } + + +impl BlobBinding::BlobPropertyBag { + pub fn get_typestring(&self) -> String { + if is_ascii_printable(&self.type_) { + self.type_.to_lowercase() + } else { + "".to_string() + } + } +} + +fn is_ascii_printable(string: &str) -> bool { + // Step 5.1 in Sec 5.1 of File API spec + // https://w3c.github.io/FileAPI/#constructorBlob + string.chars().all(|c| c >= '\x20' && c <= '\x7E') +} diff --git a/components/script/dom/file.rs b/components/script/dom/file.rs index 598537cbe00..9667182671a 100644 --- a/components/script/dom/file.rs +++ b/components/script/dom/file.rs @@ -4,45 +4,78 @@ use dom::bindings::codegen::Bindings::FileBinding; use dom::bindings::codegen::Bindings::FileBinding::FileMethods; +use dom::bindings::codegen::UnionTypes::BlobOrString; +use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; -use dom::blob::Blob; +use dom::blob::{Blob, DataSlice, blob_parts_to_bytes}; use std::sync::Arc; +use time; use util::str::DOMString; #[dom_struct] pub struct File { blob: Blob, name: DOMString, + modified: i64, } impl File { - fn new_inherited(file_bits: &Blob, name: DOMString) -> File { - // TODO: FilePropertyBag - let mut bytes = Vec::new(); - bytes.extend_from_slice(file_bits.get_data().get_all_bytes().as_slice()); - + fn new_inherited(slice: DataSlice, name: DOMString, + modified: Option<i64>, typeString: &str) -> File { File { - blob: Blob::new_inherited(Arc::new(bytes), None, None, ""), + blob: Blob::new_inherited(slice, typeString), name: name, + // https://w3c.github.io/FileAPI/#dfn-lastModified + modified: match modified { + Some(m) => m, + None => { + let time = time::get_time(); + time.sec * 1000 + (time.nsec / 1000000) as i64 + } + }, } } - pub fn new(global: GlobalRef, file_bits: &Blob, name: DOMString) -> Root<File> { - reflect_dom_object(box File::new_inherited(file_bits, name), + pub fn new(global: GlobalRef, slice: DataSlice, + name: DOMString, modified: Option<i64>, typeString: &str) -> Root<File> { + reflect_dom_object(box File::new_inherited(slice, name, modified, typeString), global, FileBinding::Wrap) } + // https://w3c.github.io/FileAPI/#file-constructor + pub fn Constructor(global: GlobalRef, + fileBits: Vec<BlobOrString>, + filename: DOMString, + filePropertyBag: &FileBinding::FilePropertyBag) + -> Fallible<Root<File>> { + let bytes: Vec<u8> = blob_parts_to_bytes(fileBits); + + let ref blobPropertyBag = filePropertyBag.parent; + let typeString = blobPropertyBag.get_typestring(); + + let slice = DataSlice::new(Arc::new(bytes), None, None); + let modified = filePropertyBag.lastModified; + Ok(File::new(global, slice, filename, modified, &typeString)) + } + pub fn name(&self) -> &DOMString { &self.name } + } impl FileMethods for File { + // https://w3c.github.io/FileAPI/#dfn-name fn Name(&self) -> DOMString { self.name.clone() } + + // https://w3c.github.io/FileAPI/#dfn-lastModified + fn LastModified(&self) -> i64 { + self.modified + } } diff --git a/components/script/dom/formdata.rs b/components/script/dom/formdata.rs index 6f6b47d42ce..f396a79660c 100644 --- a/components/script/dom/formdata.rs +++ b/components/script/dom/formdata.rs @@ -128,7 +128,7 @@ impl FormData { Some(fname) => { let global = self.global(); let name = DOMString::from(fname.0); - Root::upcast(File::new(global.r(), value, name)) + Root::upcast(File::new(global.r(), value.get_data().clone(), name, None, "")) } None => Root::from_ref(value) } diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 04116b29534..f8b45599b18 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -20,7 +20,7 @@ use dom::bindings::num::Finite; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::{ByteString, USVString}; use dom::bindings::weakref::MutableWeakRef; -use dom::blob::Blob; +use dom::blob::{Blob, DataSlice}; use dom::url::URL; use js::jsapi::{HandleValue, JSContext, JSObject}; use js::jsval::{JSVal, NullValue}; @@ -100,7 +100,7 @@ impl TestBindingMethods for TestBinding { fn EnumAttribute(&self) -> TestEnum { TestEnum::_empty } fn SetEnumAttribute(&self, _: TestEnum) {} fn InterfaceAttribute(&self) -> Root<Blob> { - Blob::new(self.global().r(), Vec::new(), "") + Blob::new(self.global().r(), DataSlice::empty(), "") } fn SetInterfaceAttribute(&self, _: &Blob) {} fn UnionAttribute(&self) -> HTMLElementOrLong { HTMLElementOrLong::Long(0) } @@ -178,7 +178,7 @@ impl TestBindingMethods for TestBinding { fn SetAttr_to_automatically_rename(&self, _: DOMString) {} fn GetEnumAttributeNullable(&self) -> Option<TestEnum> { Some(TestEnum::_empty) } fn GetInterfaceAttributeNullable(&self) -> Option<Root<Blob>> { - Some(Blob::new(self.global().r(), Vec::new(), "")) + Some(Blob::new(self.global().r(), DataSlice::empty(), "")) } fn SetInterfaceAttributeNullable(&self, _: Option<&Blob>) {} fn GetInterfaceAttributeWeak(&self) -> Option<Root<URL>> { @@ -229,7 +229,7 @@ impl TestBindingMethods for TestBinding { fn ReceiveByteString(&self) -> ByteString { ByteString::new(vec!()) } fn ReceiveEnum(&self) -> TestEnum { TestEnum::_empty } fn ReceiveInterface(&self) -> Root<Blob> { - Blob::new(self.global().r(), Vec::new(), "") + Blob::new(self.global().r(), DataSlice::empty(), "") } fn ReceiveAny(&self, _: *mut JSContext) -> JSVal { NullValue() } fn ReceiveObject(&self, _: *mut JSContext) -> *mut JSObject { panic!() } @@ -246,7 +246,7 @@ impl TestBindingMethods for TestBinding { } fn ReceiveSequence(&self) -> Vec<i32> { vec![1] } fn ReceiveInterfaceSequence(&self) -> Vec<Root<Blob>> { - vec![Blob::new(self.global().r(), Vec::new(), "")] + vec![Blob::new(self.global().r(), DataSlice::empty(), "")] } fn ReceiveNullableBoolean(&self) -> Option<bool> { Some(false) } @@ -267,7 +267,7 @@ impl TestBindingMethods for TestBinding { fn ReceiveNullableByteString(&self) -> Option<ByteString> { Some(ByteString::new(vec!())) } fn ReceiveNullableEnum(&self) -> Option<TestEnum> { Some(TestEnum::_empty) } fn ReceiveNullableInterface(&self) -> Option<Root<Blob>> { - Some(Blob::new(self.global().r(), Vec::new(), "")) + Some(Blob::new(self.global().r(), DataSlice::empty(), "")) } fn ReceiveNullableObject(&self, _: *mut JSContext) -> *mut JSObject { ptr::null_mut() } fn ReceiveNullableUnion(&self) -> Option<HTMLElementOrLong> { diff --git a/components/script/dom/webidls/Blob.webidl b/components/script/dom/webidls/Blob.webidl index f0e3413d086..dcc7cb5ea42 100644 --- a/components/script/dom/webidls/Blob.webidl +++ b/components/script/dom/webidls/Blob.webidl @@ -2,8 +2,9 @@ * 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/. */ -// http://dev.w3.org/2006/webapi/FileAPI/#dfn-Blob -[Constructor(optional sequence<(/*ArrayBuffer or ArrayBufferView or */Blob or DOMString)> blobParts, +// https://w3c.github.io/FileAPI/#blob + +[Constructor(optional sequence<BlobPart> blobParts, optional BlobPropertyBag options), Exposed=Window/*,Worker*/] interface Blob { @@ -26,3 +27,5 @@ dictionary BlobPropertyBag { DOMString type = ""; }; + +typedef (/*ArrayBuffer or ArrayBufferView or */Blob or DOMString) BlobPart; diff --git a/components/script/dom/webidls/File.webidl b/components/script/dom/webidls/File.webidl index 7c0d4be7c29..6e7797c4d5e 100644 --- a/components/script/dom/webidls/File.webidl +++ b/components/script/dom/webidls/File.webidl @@ -2,13 +2,17 @@ * 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/. */ -// http://dev.w3.org/2006/webapi/FileAPI/#dfn-file +// https://w3c.github.io/FileAPI/#file -// [Constructor(sequence<(Blob or DOMString or ArrayBufferView or ArrayBuffer)> fileBits, -// [EnsureUTF16] DOMString fileName, optional FilePropertyBag options)] +[Constructor(sequence<BlobPart> fileBits, + DOMString fileName, + optional FilePropertyBag options), + Exposed=Window/*,Worker*/] interface File : Blob { - readonly attribute DOMString name; - // readonly attribute Date lastModifiedDate; + readonly attribute long long lastModified; +}; +dictionary FilePropertyBag : BlobPropertyBag { + long long lastModified; }; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index 861c91090c8..1145e188555 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -18,7 +18,7 @@ use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::{USVString, is_token}; use dom::bindings::trace::JSTraceable; -use dom::blob::Blob; +use dom::blob::{Blob, DataSlice}; use dom::closeevent::CloseEvent; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; @@ -42,6 +42,7 @@ use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::Cell; use std::ptr; +use std::sync::Arc; use std::thread; use util::str::DOMString; use websocket::client::request::Url; @@ -598,7 +599,8 @@ impl Runnable for MessageReceivedTask { MessageData::Binary(data) => { match ws.binary_type.get() { BinaryType::Blob => { - let blob = Blob::new(global.r(), data, ""); + let slice = DataSlice::new(Arc::new(data), None, None); + let blob = Blob::new(global.r(), slice, ""); blob.to_jsval(cx, message.handle_mut()); } BinaryType::Arraybuffer => { diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index a061230898b..49f4be06d9b 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -22,7 +22,7 @@ use dom::bindings::js::{Root, RootedReference}; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::{ByteString, USVString, is_token}; -use dom::blob::Blob; +use dom::blob::{Blob, DataSlice}; use dom::document::DocumentSource; use dom::document::{Document, IsHTMLDocument}; use dom::event::{Event, EventBubbles, EventCancelable}; @@ -1117,7 +1117,8 @@ impl XMLHttpRequest { let mime = self.final_mime_type().as_ref().map(Mime::to_string).unwrap_or("".to_owned()); // Step 3, 4 - let blob = Blob::new(self.global().r(), self.response.borrow().to_vec(), &mime); + let slice = DataSlice::new(Arc::new(self.response.borrow().to_vec()), None, None); + let blob = Blob::new(self.global().r(), slice, &mime); self.response_blob.set(Some(blob.r())); blob } diff --git a/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini b/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini index 88e2fe94e2f..a0c942de8ce 100644 --- a/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini +++ b/tests/wpt/metadata/FileAPI/file/File-constructor.html.ini @@ -1,17 +1,5 @@ [File-constructor.html] type: testharness - [DOMString fileBits] - expected: FAIL - - [Unicode DOMString fileBits] - expected: FAIL - - [Empty Blob fileBits] - expected: FAIL - - [Blob fileBits] - expected: FAIL - [ArrayBuffer fileBits] expected: FAIL @@ -21,24 +9,5 @@ [Various fileBits] expected: FAIL - [Using fileName] - expected: FAIL - [Using special character in fileName] expected: FAIL - - [Using type on the File constructor] - expected: FAIL - - [Using uppercase characters in type] - expected: FAIL - - [Using illegal character for type] - expected: FAIL - - [Using lastModified] - expected: FAIL - - [Misusing name] - expected: FAIL - diff --git a/tests/wpt/metadata/FileAPI/file/Worker-read-file-constructor.worker.js.ini b/tests/wpt/metadata/FileAPI/file/Worker-read-file-constructor.worker.js.ini deleted file mode 100644 index 0a9b6879919..00000000000 --- a/tests/wpt/metadata/FileAPI/file/Worker-read-file-constructor.worker.js.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Worker-read-file-constructor.worker] - type: testharness - [FileReader in Worker] - expected: FAIL - diff --git a/tests/wpt/metadata/FileAPI/idlharness.html.ini b/tests/wpt/metadata/FileAPI/idlharness.html.ini index c91eb848d80..33a274d116f 100644 --- a/tests/wpt/metadata/FileAPI/idlharness.html.ini +++ b/tests/wpt/metadata/FileAPI/idlharness.html.ini @@ -9,42 +9,6 @@ [URL interface: operation revokeObjectURL(DOMString)] expected: FAIL - [File interface object length] - expected: FAIL - - [File interface: attribute lastModified] - expected: FAIL - - [File must be primary interface of new File(["myFileBits"\], "myFileName")] - expected: FAIL - - [Stringification of new File(["myFileBits"\], "myFileName")] - expected: FAIL - - [File interface: new File(["myFileBits"\], "myFileName") must inherit property "name" with the proper type (0)] - expected: FAIL - - [File interface: new File(["myFileBits"\], "myFileName") must inherit property "lastModified" with the proper type (1)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "size" with the proper type (0)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "type" with the proper type (1)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "isClosed" with the proper type (2)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "slice" with the proper type (3)] - expected: FAIL - - [Blob interface: calling slice(long long,long long,DOMString) on new File(["myFileBits"\], "myFileName") with too few arguments must throw TypeError] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "close" with the proper type (4)] - expected: FAIL - [FileList must be primary interface of file_input.files] expected: FAIL diff --git a/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini b/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini index 33363991f7e..d9f9c83bdc3 100644 --- a/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini +++ b/tests/wpt/metadata/FileAPI/idlharness.worker.js.ini @@ -9,42 +9,6 @@ [URL interface: operation revokeObjectURL(DOMString)] expected: FAIL - [File interface object length] - expected: FAIL - - [File interface: attribute lastModified] - expected: FAIL - - [File must be primary interface of new File(["myFileBits"\], "myFileName")] - expected: FAIL - - [Stringification of new File(["myFileBits"\], "myFileName")] - expected: FAIL - - [File interface: new File(["myFileBits"\], "myFileName") must inherit property "name" with the proper type (0)] - expected: FAIL - - [File interface: new File(["myFileBits"\], "myFileName") must inherit property "lastModified" with the proper type (1)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "size" with the proper type (0)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "type" with the proper type (1)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "isClosed" with the proper type (2)] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "slice" with the proper type (3)] - expected: FAIL - - [Blob interface: calling slice(long long,long long,DOMString) on new File(["myFileBits"\], "myFileName") with too few arguments must throw TypeError] - expected: FAIL - - [Blob interface: new File(["myFileBits"\], "myFileName") must inherit property "close" with the proper type (4)] - expected: FAIL - [FileReader interface: operation readAsArrayBuffer(Blob)] expected: FAIL |