mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
Add redirect follow feature (#934)
This commit is contained in:
parent
94889aef08
commit
888824c617
4 changed files with 84 additions and 22 deletions
74
src/http.rs
74
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);
|
||||
});
|
||||
}
|
||||
|
|
5
tests/017_import_redirect.ts
Normal file
5
tests/017_import_redirect.ts
Normal file
|
@ -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();
|
2
tests/017_import_redirect.ts.out
Normal file
2
tests/017_import_redirect.ts.out
Normal file
|
@ -0,0 +1,2 @@
|
|||
Downloading http://gist.githubusercontent.com/ry/f12b2aa3409e6b52645bc346a9e22929/raw/79318f239f51d764384a8bded8d7c6a833610dde/print_hello.ts
|
||||
Hello
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue