summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKevin (Kun) "Kassimo" Qian <kevinkassimo@gmail.com>2018-10-09 17:31:06 -0700
committerRyan Dahl <ry@tinyclouds.org>2018-10-09 20:31:06 -0400
commit888824c61787edb4a1a0d4141f6c08855d87d2b7 (patch)
treee571448effd72496d1480bc8ec8e04f010f8e0d2 /src
parent94889aef08909171ac5dc7b7c9c72c38d439bd7d (diff)
Add redirect follow feature (#934)
Diffstat (limited to 'src')
-rw-r--r--src/http.rs74
1 files changed, 52 insertions, 22 deletions
diff --git a/src/http.rs b/src/http.rs
index 86684207d..0d3189d27 100644
--- a/src/http.rs
+++ b/src/http.rs
@@ -4,12 +4,10 @@ use errors;
use errors::{DenoError, DenoResult};
use tokio_util;
-use futures;
-use futures::future::Either;
+use futures::future::{loop_fn, Loop};
use futures::{Future, Stream};
use hyper;
-use hyper::client::Client;
-use hyper::client::HttpConnector;
+use hyper::client::{Client, HttpConnector};
use hyper::Uri;
use hyper_rustls;
@@ -33,24 +31,46 @@ pub fn get_client() -> Client<Connector, hyper::Body> {
pub fn fetch_sync_string(module_name: &str) -> DenoResult<String> {
let url = module_name.parse::<Uri>().unwrap();
let client = get_client();
- let fetch_future = client
- .get(url)
- .map_err(|err| DenoError::from(err))
- .and_then(|response| {
- if !response.status().is_success() {
- return Either::A(futures::future::err(errors::new(
- errors::ErrorKind::NotFound,
- "module not found".to_string(),
- )));
- }
- Either::B(
- response
- .into_body()
- .concat2()
- .map(|body| String::from_utf8(body.to_vec()).unwrap())
- .map_err(|err| DenoError::from(err)),
- )
- });
+ // 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)
}
@@ -63,3 +83,13 @@ fn test_fetch_sync_string() {
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);
+ });
+}