Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement file related functionalities in htmlinputelement and related #11225

Merged
merged 1 commit into from May 23, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Implement file-type functionalities in htmlinputelement and related

Changes include:
- Implement file selection and other DOM behaviours in htmlinputelement
- Integrate IpcSender<FileManagerThreadMsg> into ResourceThreads
- Improve filemanager_thread, including adding type_string field to SelectedFile
- Improve interfaces in FileList/File/Blob to accommodate the above changes
  • Loading branch information
izgzhen committed May 23, 2016
commit dd590d088b036e06dd5775237e04ac45de3b1488
@@ -3,7 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerResult, FileManagerThreadError};
use mime_guess::guess_mime_type_opt;
use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerResult};
use net_traits::filemanager_thread::{SelectedFile, FileManagerThreadError};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
@@ -17,15 +19,13 @@ pub struct FileManager {
idmap: RefCell<HashMap<Uuid, PathBuf>>,
}

impl FileManager {
fn new(recv: IpcReceiver<FileManagerThreadMsg>) -> FileManager {
FileManager {
receiver: recv,
idmap: RefCell::new(HashMap::new()),
}
}
pub trait FileManagerThreadFactory {
fn new() -> Self;
}

pub fn new_thread() -> IpcSender<FileManagerThreadMsg> {
impl FileManagerThreadFactory for IpcSender<FileManagerThreadMsg> {
/// Create a FileManagerThread
fn new() -> IpcSender<FileManagerThreadMsg> {
let (chan, recv) = ipc::channel().unwrap();

spawn_named("FileManager".to_owned(), move || {
@@ -34,6 +34,16 @@ impl FileManager {

chan
}
}


impl FileManager {
fn new(recv: IpcReceiver<FileManagerThreadMsg>) -> FileManager {
FileManager {
receiver: recv,
idmap: RefCell::new(HashMap::new()),
}
}

/// Start the file manager event loop
fn start(&mut self) {
@@ -49,7 +59,7 @@ impl FileManager {
}

impl FileManager {
fn select_file(&mut self, sender: IpcSender<FileManagerResult<(Uuid, PathBuf, u64)>>) {
fn select_file(&mut self, sender: IpcSender<FileManagerResult<SelectedFile>>) {
// TODO: Pull the dialog UI in and get selected
let selected_path = Path::new("");

@@ -63,7 +73,7 @@ impl FileManager {
}
}

fn select_files(&mut self, sender: IpcSender<FileManagerResult<Vec<(Uuid, PathBuf, u64)>>>) {
fn select_files(&mut self, sender: IpcSender<FileManagerResult<Vec<SelectedFile>>>) {
let selected_paths = vec![Path::new("")];

let mut replies = vec![];
@@ -81,7 +91,7 @@ impl FileManager {
let _ = sender.send(Ok(replies));
}

fn create_entry(&mut self, file_path: &Path) -> Option<(Uuid, PathBuf, u64)> {
fn create_entry(&mut self, file_path: &Path) -> Option<SelectedFile> {
match File::open(file_path) {
Ok(handler) => {
let id = Uuid::new_v4();
@@ -100,7 +110,19 @@ impl FileManager {
let filename = file_path.file_name();

match (epoch, filename) {
(Ok(epoch), Some(filename)) => Some((id, Path::new(filename).to_path_buf(), epoch)),
(Ok(epoch), Some(filename)) => {
let filename_path = Path::new(filename);
let mime = guess_mime_type_opt(filename_path);

This comment has been minimized.

Copy link
@Manishearth

Manishearth May 17, 2016

Member

We shouldn't be guessing the MIME here, right?

This comment has been minimized.

Copy link
@izgzhen

izgzhen May 19, 2016

Author Contributor

https://w3c.github.io/FileAPI/#dfn-type it said that:

User agents can also determine the type of a Blob, especially if the byte sequence is from an on-disk file

And also, I can't image other source of type instead of determining it at the time of reading.

Some(SelectedFile {
id: id,
filename: filename_path.to_path_buf(),
modified: epoch,
type_string: match mime {
Some(x) => format!("{}", x),
None => "".to_string(),
},
})
}
_ => None
}
},
@@ -11,6 +11,7 @@ use cookie_storage::CookieStorage;
use data_loader;
use devtools_traits::{DevtoolsControlMsg};
use file_loader;
use filemanager_thread::FileManagerThreadFactory;
use hsts::HstsList;
use http_loader::{self, HttpState};
use hyper::client::pool::Pool;
@@ -154,7 +155,8 @@ pub fn new_resource_threads(user_agent: String,
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
profiler_chan: ProfilerChan) -> ResourceThreads {
ResourceThreads::new(new_core_resource_thread(user_agent, devtools_chan, profiler_chan),
StorageThreadFactory::new())
StorageThreadFactory::new(),
FileManagerThreadFactory::new())
}


@@ -6,13 +6,22 @@ use ipc_channel::ipc::IpcSender;
use std::path::PathBuf;
use uuid::Uuid;

#[derive(Deserialize, Serialize)]
pub struct SelectedFile {
pub id: Uuid,
pub filename: PathBuf,
pub modified: u64,
// https://w3c.github.io/FileAPI/#dfn-type
pub type_string: String,
}

#[derive(Deserialize, Serialize)]
pub enum FileManagerThreadMsg {
/// Select a single file, return triple (FileID, FileName, lastModified)
SelectFile(IpcSender<FileManagerResult<(Uuid, PathBuf, u64)>>),
SelectFile(IpcSender<FileManagerResult<SelectedFile>>),

/// Select multiple files, return a vector of triples
SelectFiles(IpcSender<FileManagerResult<Vec<(Uuid, PathBuf, u64)>>>),
SelectFiles(IpcSender<FileManagerResult<Vec<SelectedFile>>>),

/// Read file, return the bytes
ReadFile(IpcSender<FileManagerResult<Vec<u8>>>, Uuid),
@@ -23,7 +32,7 @@ pub enum FileManagerThreadMsg {

pub type FileManagerResult<T> = Result<T, FileManagerThreadError>;

#[derive(Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize)]
pub enum FileManagerThreadError {
/// The selection action is invalid, nothing is selected
InvalidSelection,
@@ -28,6 +28,7 @@ extern crate util;
extern crate uuid;
extern crate websocket;

use filemanager_thread::FileManagerThreadMsg;
use heapsize::HeapSizeOf;
use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
@@ -186,8 +187,13 @@ pub type CoreResourceThread = IpcSender<CoreResourceMsg>;

pub type IpcSendResult = Result<(), IOError>;

/// Abstraction of the ability to send a particular type of message,
/// used by net_traits::ResourceThreads to ease the use its IpcSender sub-fields
/// XXX: If this trait will be used more in future, some auto derive might be appealing
pub trait IpcSend<T> where T: serde::Serialize + serde::Deserialize {
/// send message T
fn send(&self, T) -> IpcSendResult;
/// get underlying sender
fn sender(&self) -> IpcSender<T>;
}

@@ -200,13 +206,17 @@ pub trait IpcSend<T> where T: serde::Serialize + serde::Deserialize {
pub struct ResourceThreads {
core_thread: CoreResourceThread,
storage_thread: IpcSender<StorageThreadMsg>,
filemanager_thread: IpcSender<FileManagerThreadMsg>,
}

impl ResourceThreads {
pub fn new(c: CoreResourceThread, s: IpcSender<StorageThreadMsg>) -> ResourceThreads {
pub fn new(c: CoreResourceThread,
s: IpcSender<StorageThreadMsg>,
f: IpcSender<FileManagerThreadMsg>) -> ResourceThreads {
ResourceThreads {
core_thread: c,
storage_thread: s,
filemanager_thread: f,
}
}
}
@@ -231,6 +241,16 @@ impl IpcSend<StorageThreadMsg> for ResourceThreads {
}
}

impl IpcSend<FileManagerThreadMsg> for ResourceThreads {
fn send(&self, msg: FileManagerThreadMsg) -> IpcSendResult {
self.filemanager_thread.send(msg)
}

fn sender(&self) -> IpcSender<FileManagerThreadMsg> {
self.filemanager_thread.clone()
}
}

// Ignore the sub-fields
impl HeapSizeOf for ResourceThreads {
fn heap_size_of_children(&self) -> usize { 0 }
@@ -60,7 +60,7 @@ use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
use net_traits::response::HttpsState;
use net_traits::storage_thread::StorageType;
use net_traits::{Metadata, NetworkError};
use net_traits::{Metadata, NetworkError, ResourceThreads};
use offscreen_gl_context::GLLimits;
use profile_traits::mem::ProfilerChan as MemProfilerChan;
use profile_traits::time::ProfilerChan as TimeProfilerChan;
@@ -321,6 +321,7 @@ no_jsmanaged_fields!(HttpsState);
no_jsmanaged_fields!(SharedRt);
no_jsmanaged_fields!(TouchpadPressurePhase);
no_jsmanaged_fields!(ReferrerPolicy);
no_jsmanaged_fields!(ResourceThreads);

impl JSTraceable for Box<ScriptChan + Send> {
#[inline]
@@ -10,6 +10,8 @@ use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::blob::{Blob, DataSlice, blob_parts_to_bytes};
use dom::window::Window;
use net_traits::filemanager_thread::SelectedFile;
use std::sync::Arc;
use time;
use util::str::DOMString;
@@ -45,6 +47,19 @@ impl File {
FileBinding::Wrap)
}

// Construct from selected file message from file manager thread
pub fn new_from_selected(window: &Window, selected: SelectedFile) -> Root<File> {
let name = DOMString::from(selected.filename.to_str().expect("File name encoding error"));

// FIXME: fix this after PR #11221 is landed
let id = selected.id;
let slice = DataSlice::empty();

let global = GlobalRef::Window(window);

File::new(global, slice, name, Some(selected.modified as i64), "")
}

// https://w3c.github.io/FileAPI/#file-constructor
pub fn Constructor(global: GlobalRef,
fileBits: Vec<BlobOrString>,
@@ -64,7 +79,6 @@ impl File {
pub fn name(&self) -> &DOMString {
&self.name
}

}

impl FileMethods for File {
@@ -27,8 +27,10 @@ impl FileList {
}

#[allow(unrooted_must_root)]
pub fn new(window: &Window, files: Vec<JS<File>>) -> Root<FileList> {
reflect_dom_object(box FileList::new_inherited(files), GlobalRef::Window(window), FileListBinding::Wrap)
pub fn new(window: &Window, files: Vec<Root<File>>) -> Root<FileList> {
reflect_dom_object(box FileList::new_inherited(files.iter().map(|r| JS::from_rooted(&r)).collect()),

This comment has been minimized.

Copy link
@Manishearth

Manishearth May 20, 2016

Member

The rooting here seems sketchy; but I think it should work. @nox, sanity-check?

This comment has been minimized.

Copy link
@nox

nox May 20, 2016

Member

Should work, since files still root them.

GlobalRef::Window(window),
FileListBinding::Wrap)
}
}

@@ -615,7 +615,7 @@ impl HTMLFormElement {
// Step 4
for datum in &mut ret {
match &*datum.ty {
"file" | "textarea" => (),
"file" | "textarea" => (), // TODO
_ => {
datum.name = clean_crlf(&datum.name);
datum.value = FormDatumValue::String(clean_crlf( match datum.value {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.