#[macro_use]
pub mod support;
use submillisecond::{response::Response as SubmsResponse, router, RequestContext};
use support::RouterFn;
fn redirect(code: u16) -> SubmsResponse {
http::Response::builder()
.status(code)
.header("location", "/dst")
.header("server", "test-redirect")
.body(Default::default())
.unwrap()
}
fn handle_301() -> SubmsResponse {
redirect(301)
}
fn handle_302() -> SubmsResponse {
redirect(302)
}
fn handle_303() -> SubmsResponse {
redirect(303)
}
fn handle_307() -> SubmsResponse {
println!("HANDLING 307");
redirect(307)
}
fn handle_308() -> SubmsResponse {
redirect(308)
}
fn dst(body: Vec<u8>) -> SubmsResponse {
SubmsResponse::builder()
.header("server", "test-dst")
.body(body)
.unwrap()
}
fn dst_get() -> SubmsResponse {
dst("GET".into())
}
fn dst_post() -> SubmsResponse {
dst("POST".into())
}
fn end_server(req: RequestContext) -> SubmsResponse {
lunatic_log::info!("END SERVER {:?}", req.headers());
assert_eq!(req.headers().get("cookie"), None);
assert_eq!(
req.headers()["referer"],
format!("http://{}/sensitive", ADDR)
);
http::Response::default()
}
fn mid_server(req: RequestContext) -> SubmsResponse {
assert_eq!(req.headers()["cookie"], "foo=bar");
http::Response::builder()
.status(302)
.header("location", format!("http://{}/end", END_ADDR))
.body(Default::default())
.unwrap()
}
fn loop_handler(req: RequestContext) -> SubmsResponse {
assert_eq!(req.uri(), "/loop");
http::Response::builder()
.status(302)
.header("location", "/loop")
.body(Default::default())
.unwrap()
}
fn no_redirect() -> SubmsResponse {
http::Response::builder()
.status(302)
.header("location", "/dont")
.body(Default::default())
.unwrap()
}
fn no_referer() -> SubmsResponse {
SubmsResponse::builder()
.status(302)
.header("location", "/dst-no-refer")
.body(Default::default())
.unwrap()
}
fn dst_no_referer(req: RequestContext) -> SubmsResponse {
assert_eq!(req.uri(), "/dst");
assert_eq!(req.headers().get("referer"), None);
SubmsResponse::default()
}
fn yikes() -> SubmsResponse {
http::Response::builder()
.status(302)
.header("location", "http://www.yikes{KABOOM}")
.body(Default::default())
.unwrap()
}
fn handle_302_cookie() -> SubmsResponse {
http::Response::builder()
.status(302)
.header("location", "/dst")
.header("set-cookie", "key=value")
.body(Default::default())
.unwrap()
}
fn dst_cookie(req: RequestContext) -> SubmsResponse {
assert_eq!(req.headers()["cookie"], "key=value");
http::Response::default()
}
static ROUTER: RouterFn = router! {
POST "/301" => handle_301
POST "/302" => handle_302
POST "/303" => handle_303
POST "/307" => handle_307
POST "/308" => handle_308
GET "/307" => handle_307
GET "/308" => handle_308
GET "/dst" => dst_get
POST "/dst" => dst_post
GET "/sensitive" => mid_server
GET "/loop" => loop_handler
GET "/no-redirect" => no_redirect
GET "/no-refer" => no_referer
GET "/dst-no-refer" => dst_no_referer
GET "/yikes" => yikes
GET "/dst-cookie" => dst_cookie
GET "/302-cookie" => handle_302_cookie
};
static END_ROUTER: RouterFn = router! {
GET "/end" => end_server
};
static ADDR: &'static str = "0.0.0.0:3000";
static END_ADDR: &'static str = "0.0.0.0:3005";
wrap_server!(server, ROUTER, ADDR);
wrap_server!(end_server, END_ROUTER, END_ADDR);
#[lunatic::test]
fn test_redirect_301_and_302_and_303_changes_post_to_get() {
let _ = server::ensure_server();
let client = nightfly::Client::new();
let codes = [301u16, 302, 303];
for &code in codes.iter() {
let url = format!("http://{}/{}", ADDR, code);
let dst = format!("http://{}/{}", ADDR, "dst");
let res = client.post(&url).send().unwrap();
println!("RES code {} -> {:?}", code, res);
assert_eq!(res.url().as_str(), dst);
assert_eq!(res.status(), nightfly::StatusCode::OK);
assert_eq!(
res.headers().get(nightfly::header::SERVER).unwrap(),
&"test-dst"
);
assert_eq!(res.body, b"GET".to_vec());
}
}
#[lunatic::test]
fn test_redirect_307_and_308_tries_to_get_again() {
let _ = server::ensure_server();
let client = nightfly::Client::new();
let codes = [307u16, 308];
for &code in codes.iter() {
let url = format!("http://{}/{}", ADDR, code);
let dst = format!("http://{}/{}", ADDR, "dst");
let res = client.get(&url).send().unwrap();
assert_eq!(res.url().as_str(), dst);
assert_eq!(res.status(), nightfly::StatusCode::OK);
assert_eq!(
res.headers().get(nightfly::header::SERVER).unwrap(),
&"test-dst"
);
assert_eq!(res.body, b"GET".to_vec());
}
}
#[lunatic::test]
fn test_redirect_307_and_308_tries_to_post_again() {
let _ = server::ensure_server();
let client = nightfly::Client::new();
let codes = [307u16, 308];
for &code in codes.iter() {
let url = format!("http://{}/{}", ADDR, code);
let dst = format!("http://{}/{}", ADDR, "dst");
let res = client.post(&url).body("Hello").send().unwrap();
assert_eq!(res.url().as_str(), dst);
assert_eq!(res.status(), nightfly::StatusCode::OK);
assert_eq!(
res.headers().get(nightfly::header::SERVER).unwrap(),
&"test-dst"
);
assert_eq!(res.body, b"POST".to_vec());
}
}
#[lunatic::test]
fn test_redirect_removes_sensitive_headers() {
let _ = server::ensure_server();
let _ = end_server::ensure_server();
let res = nightfly::Client::builder()
.build()
.unwrap()
.get(&format!("http://{}/sensitive", ADDR))
.header(
nightfly::header::COOKIE,
nightfly::header::HeaderValue::from_static("foo=bar"),
)
.send()
.unwrap();
println!("SENSITIVE {:?}", res);
assert_eq!(res.status, 200);
}
#[lunatic::test]
fn test_redirect_policy_can_return_errors() {
let _ = server::ensure_server();
let url = format!("http://{}/loop", ADDR);
let err = nightfly::get(&url).unwrap_err();
assert!(err.is_redirect());
}
#[lunatic::test]
fn test_redirect_policy_can_stop_redirects_without_an_error() {
let _ = server::ensure_server();
let url = format!("http://{}/no-redirect", ADDR);
let res = nightfly::Client::builder()
.redirect(nightfly::redirect::Policy::none())
.build()
.unwrap()
.get(&url)
.send();
let res = res.unwrap();
assert_eq!(res.url().as_str(), url);
assert_eq!(res.status(), nightfly::StatusCode::FOUND);
}
#[lunatic::test]
fn test_referer_is_not_set_if_disabled() {
let _ = server::ensure_server();
nightfly::Client::builder()
.referer(false)
.build()
.unwrap()
.get(&format!("http://{}/no-refer", ADDR))
.send()
.unwrap();
}
#[lunatic::test]
fn test_invalid_location_stops_redirect_gh484() {
let _ = server::ensure_server();
let url = format!("http://{}/yikes", ADDR);
let res = nightfly::get(&url).unwrap();
assert_eq!(res.url().as_str(), url);
assert_eq!(res.status(), nightfly::StatusCode::FOUND);
}
#[cfg(feature = "cookies")]
#[lunatic::test]
fn test_redirect_302_with_set_cookies() {
let _ = server::ensure_server();
let url = format!("http://{}/302-cookie", ADDR);
let dst = format!("http://{}/{}", ADDR, "dst");
let client = nightfly::ClientBuilder::new().build().unwrap();
let res = client.get(&url).send().unwrap();
assert_eq!(res.url().as_str(), dst);
assert_eq!(res.status(), nightfly::StatusCode::OK);
}