summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/deno_dir.rs178
-rw-r--r--src/http_util.rs24
-rw-r--r--src/msg.fbs8
-rw-r--r--src/ops.rs1
4 files changed, 199 insertions, 12 deletions
diff --git a/src/deno_dir.rs b/src/deno_dir.rs
index e8cc86b18..186dce1b8 100644
--- a/src/deno_dir.rs
+++ b/src/deno_dir.rs
@@ -5,6 +5,7 @@ use errors::DenoResult;
use errors::ErrorKind;
use fs as deno_fs;
use http_util;
+use msg;
use ring;
use std;
use std::fmt::Write;
@@ -109,21 +110,28 @@ impl DenoDir {
self: &DenoDir,
module_name: &str,
filename: &str,
- ) -> DenoResult<String> {
+ ) -> DenoResult<(String, msg::MediaType)> {
let p = Path::new(filename);
+ // We write a special ".mime" file into the `.deno/deps` directory along side the
+ // cached file, containing just the media type.
+ let mut media_type_filename = filename.to_string();
+ media_type_filename.push_str(".mime");
+ let mt = Path::new(&media_type_filename);
let src = if self.reload || !p.exists() {
println!("Downloading {}", module_name);
- let source = http_util::fetch_sync_string(module_name)?;
+ let (source, content_type) = http_util::fetch_sync_string(module_name)?;
match p.parent() {
Some(ref parent) => fs::create_dir_all(parent),
None => Ok(()),
}?;
deno_fs::write_file(&p, source.as_bytes(), 0o666)?;
- source
+ deno_fs::write_file(&mt, content_type.as_bytes(), 0o666)?;
+ (source, map_content_type(&p, Some(&content_type)))
} else {
let source = fs::read_to_string(&p)?;
- source
+ let content_type = fs::read_to_string(&mt)?;
+ (source, map_content_type(&p, Some(&content_type)))
};
Ok(src)
}
@@ -141,18 +149,20 @@ impl DenoDir {
let use_extension = |ext| {
let module_name = format!("{}{}", module_name, ext);
let filename = format!("{}{}", filename, ext);
- let source_code = if is_module_remote {
+ let (source_code, media_type) = if is_module_remote {
self.fetch_remote_source(&module_name, &filename)?
} else {
assert_eq!(
module_name, filename,
"if a module isn't remote, it should have the same filename"
);
- fs::read_to_string(Path::new(&filename))?
+ let path = Path::new(&filename);
+ (fs::read_to_string(path)?, map_content_type(path, None))
};
return Ok(CodeFetchOutput {
module_name: module_name.to_string(),
filename: filename.to_string(),
+ media_type,
source_code,
maybe_output_code: None,
});
@@ -215,6 +225,7 @@ impl DenoDir {
Ok(output_code) => Ok(CodeFetchOutput {
module_name: out.module_name,
filename: out.filename,
+ media_type: out.media_type,
source_code: out.source_code,
maybe_output_code: Some(output_code),
}),
@@ -324,6 +335,7 @@ fn test_get_cache_filename() {
pub struct CodeFetchOutput {
pub module_name: String,
pub filename: String,
+ pub media_type: msg::MediaType,
pub source_code: String,
pub maybe_output_code: Option<String>,
}
@@ -646,3 +658,157 @@ fn parse_local_or_remote(p: &str) -> Result<url::Url, url::ParseError> {
Url::from_file_path(p).map_err(|_err| url::ParseError::IdnaError)
}
}
+
+fn map_file_extension(path: &Path) -> msg::MediaType {
+ match path.extension() {
+ None => msg::MediaType::Unknown,
+ Some(os_str) => match os_str.to_str() {
+ Some("ts") => msg::MediaType::TypeScript,
+ Some("js") => msg::MediaType::JavaScript,
+ Some("json") => msg::MediaType::Json,
+ _ => msg::MediaType::Unknown,
+ },
+ }
+}
+
+#[test]
+fn test_map_file_extension() {
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.ts")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.d.ts")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.js")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.json")),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.txt")),
+ msg::MediaType::Unknown
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar")),
+ msg::MediaType::Unknown
+ );
+}
+
+// convert a ContentType string into a enumerated MediaType
+fn map_content_type(path: &Path, content_type: Option<&str>) -> msg::MediaType {
+ match content_type {
+ Some(content_type) => {
+ // sometimes there is additional data after the media type in
+ // Content-Type so we have to do a bit of manipulation so we are only
+ // dealing with the actual media type
+ let ct_vector: Vec<&str> = content_type.split(";").collect();
+ let ct: &str = ct_vector.first().unwrap();
+ match ct.to_lowercase().as_ref() {
+ "application/typescript"
+ | "text/typescript"
+ | "video/vnd.dlna.mpeg-tts"
+ | "video/mp2t" => msg::MediaType::TypeScript,
+ "application/javascript"
+ | "text/javascript"
+ | "application/ecmascript"
+ | "text/ecmascript"
+ | "application/x-javascript" => msg::MediaType::JavaScript,
+ "application/json" | "text/json" => msg::MediaType::Json,
+ "text/plain" => map_file_extension(path),
+ _ => {
+ debug!("unknown content type: {}", content_type);
+ msg::MediaType::Unknown
+ }
+ }
+ }
+ None => map_file_extension(path),
+ }
+}
+
+#[test]
+fn test_map_content_type() {
+ // Extension only
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.ts"), None),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.d.ts"), None),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.js"), None),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.json"), None),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.txt"), None),
+ msg::MediaType::Unknown
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), None),
+ msg::MediaType::Unknown
+ );
+
+ // Media Type
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/typescript")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/typescript")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("video/vnd.dlna.mpeg-tts")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("video/mp2t")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/javascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/javascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/ecmascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/ecmascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/x-javascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/json")),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/json")),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.ts"), Some("text/plain")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.ts"), Some("foo/bar")),
+ msg::MediaType::Unknown
+ );
+}
diff --git a/src/http_util.rs b/src/http_util.rs
index 1c6079c08..9c5ff9529 100644
--- a/src/http_util.rs
+++ b/src/http_util.rs
@@ -4,9 +4,10 @@ use errors::{DenoError, DenoResult};
use tokio_util;
use futures::future::{loop_fn, Loop};
-use futures::{Future, Stream};
+use futures::{future, Future, Stream};
use hyper;
use hyper::client::{Client, HttpConnector};
+use hyper::header::CONTENT_TYPE;
use hyper::Uri;
use hyper_rustls;
@@ -27,7 +28,7 @@ pub fn get_client() -> Client<Connector, hyper::Body> {
// The CodeFetch message is used to load HTTP javascript resources and expects a
// synchronous response, this utility method supports that.
-pub fn fetch_sync_string(module_name: &str) -> DenoResult<String> {
+pub fn fetch_sync_string(module_name: &str) -> DenoResult<(String, String)> {
let url = module_name.parse::<Uri>().unwrap();
let client = get_client();
// TODO(kevinkassimo): consider set a max redirection counter
@@ -63,11 +64,18 @@ pub fn fetch_sync_string(module_name: &str) -> DenoResult<String> {
Ok(Loop::Break(response))
})
}).and_then(|response| {
- response
+ let content_type = response
+ .headers()
+ .get(CONTENT_TYPE)
+ .map(|content_type| content_type.to_str().unwrap().to_string());
+ let body = response
.into_body()
.concat2()
.map(|body| String::from_utf8(body.to_vec()).unwrap())
- .map_err(|err| DenoError::from(err))
+ .map_err(|err| DenoError::from(err));
+ body.join(future::ok(content_type))
+ }).and_then(|(body_string, maybe_content_type)| {
+ future::ok((body_string, maybe_content_type.unwrap()))
});
tokio_util::block_on(fetch_future)
@@ -77,9 +85,11 @@ pub fn fetch_sync_string(module_name: &str) -> DenoResult<String> {
fn test_fetch_sync_string() {
// Relies on external http server. See tools/http_server.py
tokio_util::init(|| {
- let p = fetch_sync_string("http://127.0.0.1:4545/package.json").unwrap();
+ let (p, m) =
+ fetch_sync_string("http://127.0.0.1:4545/package.json").unwrap();
println!("package.json len {}", p.len());
assert!(p.len() > 1);
+ assert!(m == "application/json")
});
}
@@ -87,8 +97,10 @@ fn test_fetch_sync_string() {
fn test_fetch_sync_string_with_redirect() {
// Relies on external http server. See tools/http_server.py
tokio_util::init(|| {
- let p = fetch_sync_string("http://127.0.0.1:4546/package.json").unwrap();
+ let (p, m) =
+ fetch_sync_string("http://127.0.0.1:4546/package.json").unwrap();
println!("package.json len {}", p.len());
assert!(p.len() > 1);
+ assert!(m == "application/json")
});
}
diff --git a/src/msg.fbs b/src/msg.fbs
index 9aa9b069c..870da1c40 100644
--- a/src/msg.fbs
+++ b/src/msg.fbs
@@ -102,6 +102,13 @@ table CwdRes {
cwd: string;
}
+enum MediaType: byte {
+ JavaScript = 0,
+ TypeScript,
+ Json,
+ Unknown
+}
+
table Base {
cmd_id: uint32;
sync: bool = true; // TODO(ry) Change default to false.
@@ -137,6 +144,7 @@ table CodeFetchRes {
// is the location of the locally downloaded source code.
module_name: string;
filename: string;
+ media_type: MediaType;
source_code: string;
output_code: string; // Non-empty only if cached.
}
diff --git a/src/ops.rs b/src/ops.rs
index 4adea46f6..83a719a29 100644
--- a/src/ops.rs
+++ b/src/ops.rs
@@ -253,6 +253,7 @@ fn op_code_fetch(
let mut msg_args = msg::CodeFetchResArgs {
module_name: Some(builder.create_string(&out.module_name)),
filename: Some(builder.create_string(&out.filename)),
+ media_type: out.media_type,
source_code: Some(builder.create_string(&out.source_code)),
..Default::default()
};