1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use filemanager_thread::FileManager;
6 use hyper::header::{Charset, ContentLength, ContentType, Headers};
7 use hyper::header::{ContentDisposition, DispositionParam, DispositionType};
8 use ipc_channel::ipc;
9 use mime::{Attr, Mime};
10 use net_traits::NetworkError;
11 use net_traits::blob_url_store::parse_blob_url;
12 use net_traits::filemanager_thread::ReadFileProgress;
13 use servo_url::ServoUrl;
14 
15 // TODO: Check on GET
16 // https://w3c.github.io/FileAPI/#requestResponseModel
17 
18 /// https://fetch.spec.whatwg.org/#concept-basic-fetch (partial)
19 // TODO: make async.
load_blob_sync(url: ServoUrl, filemanager: FileManager) -> Result<(Headers, Vec<u8>), NetworkError>20 pub fn load_blob_sync
21             (url: ServoUrl,
22              filemanager: FileManager)
23              -> Result<(Headers, Vec<u8>), NetworkError> {
24     let (id, origin) = match parse_blob_url(&url) {
25         Ok((id, origin)) => (id, origin),
26         Err(()) => {
27             let e = format!("Invalid blob URL format {:?}", url);
28             return Err(NetworkError::Internal(e));
29         }
30     };
31 
32     let (sender, receiver) = ipc::channel().unwrap();
33     let check_url_validity = true;
34     filemanager.read_file(sender, id, check_url_validity, origin);
35 
36     let blob_buf = match receiver.recv().unwrap() {
37         Ok(ReadFileProgress::Meta(blob_buf)) => blob_buf,
38         Ok(_) => {
39             return Err(NetworkError::Internal("Invalid filemanager reply".to_string()));
40         }
41         Err(e) => {
42             return Err(NetworkError::Internal(format!("{:?}", e)));
43         }
44     };
45 
46     let content_type: Mime = blob_buf.type_string.parse().unwrap_or(mime!(Text / Plain));
47     let charset = content_type.get_param(Attr::Charset);
48 
49     let mut headers = Headers::new();
50 
51     if let Some(name) = blob_buf.filename {
52         let charset = charset.and_then(|c| c.as_str().parse().ok());
53         headers.set(ContentDisposition {
54             disposition: DispositionType::Inline,
55             parameters: vec![
56                 DispositionParam::Filename(charset.unwrap_or(Charset::Us_Ascii),
57                                            None, name.as_bytes().to_vec())
58             ]
59         });
60     }
61 
62     // Basic fetch, Step 4.
63     headers.set(ContentLength(blob_buf.size as u64));
64     // Basic fetch, Step 5.
65     headers.set(ContentType(content_type.clone()));
66 
67     let mut bytes = blob_buf.bytes;
68     loop {
69         match receiver.recv().unwrap() {
70             Ok(ReadFileProgress::Partial(ref mut new_bytes)) => {
71                 bytes.append(new_bytes);
72             }
73             Ok(ReadFileProgress::EOF) => {
74                 return Ok((headers, bytes));
75             }
76             Ok(_) => {
77                 return Err(NetworkError::Internal("Invalid filemanager reply".to_string()));
78             }
79             Err(e) => {
80                 return Err(NetworkError::Internal(format!("{:?}", e)));
81             }
82         }
83     }
84 }
85