summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/http.rs74
-rw-r--r--tests/017_import_redirect.ts5
-rw-r--r--tests/017_import_redirect.ts.out2
-rwxr-xr-xtools/http_server.py25
4 files changed, 84 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);
+ });
+}
diff --git a/tests/017_import_redirect.ts b/tests/017_import_redirect.ts
new file mode 100644
index 000000000..22003e9dc
--- /dev/null
+++ b/tests/017_import_redirect.ts
@@ -0,0 +1,5 @@
+// http -> https redirect would happen:
+// tslint:disable-next-line:max-line-length
+import { printHello } from "http://gist.githubusercontent.com/ry/f12b2aa3409e6b52645bc346a9e22929/raw/79318f239f51d764384a8bded8d7c6a833610dde/print_hello.ts";
+
+printHello();
diff --git a/tests/017_import_redirect.ts.out b/tests/017_import_redirect.ts.out
new file mode 100644
index 000000000..d1ec08c42
--- /dev/null
+++ b/tests/017_import_redirect.ts.out
@@ -0,0 +1,2 @@
+Downloading http://gist.githubusercontent.com/ry/f12b2aa3409e6b52645bc346a9e22929/raw/79318f239f51d764384a8bded8d7c6a833610dde/print_hello.ts
+Hello
diff --git a/tools/http_server.py b/tools/http_server.py
index fdb8686cd..d33f24d5d 100755
--- a/tools/http_server.py
+++ b/tools/http_server.py
@@ -9,6 +9,7 @@ from util import root_path
from time import sleep
PORT = 4545
+REDIRECT_PORT = 4546
def server():
@@ -20,11 +21,35 @@ def server():
return s
+def redirect_server():
+ os.chdir(root_path)
+ target_host = "http://localhost:%d" % PORT
+
+ class RedirectHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+ def do_GET(self):
+ self.send_response(301)
+ self.send_header('Location', target_host + self.path)
+ self.end_headers()
+
+ Handler = RedirectHandler
+ SocketServer.TCPServer.allow_reuse_address = True
+ s = SocketServer.TCPServer(("", REDIRECT_PORT), Handler)
+ print "Deno redirect server http://localhost:%d/ -> http://localhost:%d/" % (
+ REDIRECT_PORT, PORT)
+ return s
+
+
def spawn():
+ # Main http server
s = server()
thread = Thread(target=s.serve_forever)
thread.daemon = True
thread.start()
+ # Redirect server
+ rs = redirect_server()
+ r_thread = Thread(target=rs.serve_forever)
+ r_thread.daemon = True
+ r_thread.start()
sleep(1) # TODO I'm too lazy to figure out how to do this properly.
return thread