summaryrefslogtreecommitdiff
path: root/src/http_util.rs
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2018-10-10 13:35:10 -0400
committerRyan Dahl <ry@tinyclouds.org>2018-10-10 14:29:55 -0400
commit417ea7bb6d14ea18b9b4caefe1f4ca2b12216d3e (patch)
tree95c8bde38d91d200c0e6f992c82127cd1db6b5bd /src/http_util.rs
parentc99207bf3976bfd3c5c3ef91d782c86f933977e6 (diff)
src/http.rs -> src/http_util.rs
So as not to conflict with http crate.
Diffstat (limited to 'src/http_util.rs')
-rw-r--r--src/http_util.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/http_util.rs b/src/http_util.rs
new file mode 100644
index 000000000..0d3189d27
--- /dev/null
+++ b/src/http_util.rs
@@ -0,0 +1,95 @@
+// Copyright 2018 the Deno authors. All rights reserved. MIT license.
+
+use errors;
+use errors::{DenoError, DenoResult};
+use tokio_util;
+
+use futures::future::{loop_fn, Loop};
+use futures::{Future, Stream};
+use hyper;
+use hyper::client::{Client, HttpConnector};
+use hyper::Uri;
+use hyper_rustls;
+
+type Connector = hyper_rustls::HttpsConnector<HttpConnector>;
+
+lazy_static! {
+ static ref CONNECTOR: Connector = {
+ let num_dns_threads = 4;
+ Connector::new(num_dns_threads)
+ };
+}
+
+pub fn get_client() -> Client<Connector, hyper::Body> {
+ // TODO use Hyper's connection pool.
+ let c = CONNECTOR.clone();
+ Client::builder().build(c)
+}
+
+// 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> {
+ let url = module_name.parse::<Uri>().unwrap();
+ let client = get_client();
+ // TODO(kevinkassimo): consider set a max redirection counter
+ // to avoid bouncing between 2 or more urls
+ let fetch_future = loop_fn((client, Some(url)), |(client, maybe_url)| {
+ let url = maybe_url.expect("target url should not be None");
+ client
+ .get(url)
+ .map_err(|err| DenoError::from(err))
+ .and_then(|response| {
+ if response.status().is_redirection() {
+ let new_url_string = response
+ .headers()
+ .get("location")
+ .expect("url redirection should provide 'location' header")
+ .to_str()
+ .unwrap()
+ .to_string();
+ debug!("Redirecting to {}...", &new_url_string);
+ let maybe_new_url = Some(
+ new_url_string
+ .parse::<Uri>()
+ .expect("provided redirect url should be a valid url"),
+ );
+ return Ok(Loop::Continue((client, maybe_new_url)));
+ }
+ if !response.status().is_success() {
+ return Err(errors::new(
+ errors::ErrorKind::NotFound,
+ "module not found".to_string(),
+ ));
+ }
+ Ok(Loop::Break(response))
+ })
+ }).and_then(|response| {
+ response
+ .into_body()
+ .concat2()
+ .map(|body| String::from_utf8(body.to_vec()).unwrap())
+ .map_err(|err| DenoError::from(err))
+ });
+
+ tokio_util::block_on(fetch_future)
+}
+
+#[test]
+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();
+ println!("package.json len {}", p.len());
+ assert!(p.len() > 1);
+ });
+}
+
+#[test]
+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();
+ println!("package.json len {}", p.len());
+ assert!(p.len() > 1);
+ });
+}