#![cfg(not(target_arch = "wasm32"))]
mod server;
use axum::extract::Request;
use cyper::{
Client,
proxy::{NoProxy, Proxy},
};
use http::{Method, StatusCode};
#[compio::test]
async fn http_proxy() {
let server = server::http(move |req: Request| async move {
assert_eq!(req.method(), Method::GET);
assert_eq!(req.uri().to_string(), format!("http://cyper.local/prox"));
assert_eq!(req.headers()["host"], "cyper.local");
"OK"
})
.await;
let proxy_url = format!("http://{}", server.addr());
let client = Client::builder()
.proxy(Proxy::http(&proxy_url).unwrap())
.build();
let res = client
.get("http://cyper.local/prox")
.unwrap()
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "OK");
}
#[compio::test]
async fn http_proxy_basic_auth() {
let server = server::http(move |req: Request| async move {
assert_eq!(req.method(), Method::GET);
assert_eq!(req.uri().to_string(), format!("http://cyper.local/prox"));
assert_eq!(req.headers()["host"], "cyper.local");
assert_eq!(
req.headers()["proxy-authorization"],
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
);
"OK"
})
.await;
let proxy_url = format!("http://{}", server.addr());
let client = Client::builder()
.proxy(
Proxy::http(&proxy_url)
.unwrap()
.basic_auth("Aladdin", "open sesame"),
)
.build();
let res = client
.get("http://cyper.local/prox")
.unwrap()
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "OK");
}
#[compio::test]
async fn http_proxy_basic_auth_parsed() {
let server = server::http(move |req: Request| async move {
assert_eq!(req.method(), Method::GET);
assert_eq!(req.uri().to_string(), format!("http://cyper.local/prox"));
assert_eq!(req.headers()["host"], "cyper.local");
assert_eq!(
req.headers()["proxy-authorization"],
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
);
"OK"
})
.await;
let proxy_url = format!("http://Aladdin:open sesame@{}", server.addr());
let client = Client::builder()
.proxy(Proxy::http(&proxy_url).unwrap())
.build();
let res = client
.get("http://cyper.local/prox")
.unwrap()
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "OK");
}
#[compio::test]
async fn http_proxy_custom_auth_header() {
let server = server::http(move |req: Request| async move {
assert_eq!(req.method(), Method::GET);
assert_eq!(req.uri().to_string(), format!("http://cyper.local/prox"));
assert_eq!(req.headers()["proxy-authorization"], "testme");
"OK"
})
.await;
let proxy_url = format!("http://{}", server.addr());
let client = Client::builder()
.proxy(
Proxy::http(&proxy_url)
.unwrap()
.custom_http_auth(http::HeaderValue::from_static("testme")),
)
.build();
let res = client
.get("http://cyper.local/prox")
.unwrap()
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "OK");
}
#[compio::test]
async fn test_no_proxy() {
let server = server::http(move |req: Request| async move {
assert_eq!(req.method(), Method::GET);
assert_eq!(req.uri(), "/4");
"OK"
})
.await;
let proxy_url = format!("http://{}", server.addr());
let client = Client::builder()
.proxy(Proxy::http(&proxy_url).unwrap().no_proxy(Some(
NoProxy::from_string(&server.addr().ip().to_string()).unwrap(),
)))
.build();
let url = format!("http://{}/4", server.addr());
let res = client.get(&url).unwrap().send().await.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "OK");
}
#[cfg(tls)]
#[compio::test]
async fn tunnel_detects_unsuccessful() {
let mock = server::http(move |req: Request| async move {
assert_eq!(req.method(), http::Method::CONNECT);
assert_eq!(req.uri(), "cyper.local:443");
StatusCode::BAD_REQUEST
})
.await;
let proxy_url = format!("http://{}", mock.addr());
let client = Client::builder()
.proxy(Proxy::https(&proxy_url).unwrap())
.danger_accept_invalid_certs(true)
.build();
let err = client
.get("https://cyper.local/prox")
.unwrap()
.send()
.await
.unwrap_err();
let err_msg = format!("{err:?}");
assert!(
err_msg.contains("400")
|| err_msg.contains("unsuccessful")
|| err_msg.contains("Unsuccessful")
|| err_msg.contains("Bad Request"),
"expected error to mention 400, got: {err_msg}"
);
}
#[cfg(tls)]
#[compio::test]
async fn tunnel_includes_proxy_auth() {
let mock = server::http(move |req: Request| async move {
assert_eq!(req.method(), http::Method::CONNECT);
assert_eq!(
req.headers()
.get(http::header::PROXY_AUTHORIZATION)
.unwrap()
.to_str()
.unwrap(),
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
);
StatusCode::BAD_REQUEST
})
.await;
let proxy_url = format!("http://Aladdin:open sesame@{}", mock.addr());
let client = Client::builder()
.proxy(Proxy::https(&proxy_url).unwrap())
.danger_accept_invalid_certs(true)
.build();
let err = client
.get("https://cyper.local/prox")
.unwrap()
.send()
.await
.unwrap_err();
let err_msg = format!("{err:?}");
assert!(
err_msg.contains("400")
|| err_msg.contains("unsuccessful")
|| err_msg.contains("Unsuccessful")
|| err_msg.contains("Bad Request"),
"expected error from failed CONNECT, got: {err_msg}"
);
}
#[compio::test]
async fn proxy_https_matches_https_only() {
let server = server::http(move |_req: Request| async move {
"SHOULD_NOT_REACH"
})
.await;
let proxy_url = format!("http://{}", server.addr());
let client = Client::builder()
.proxy(Proxy::https(&proxy_url).unwrap())
.build();
let res = client.get("http://cyper.local/prox").unwrap().send().await;
assert!(res.is_err());
}
#[compio::test]
async fn proxy_multiple_matches_correct() {
let server = server::http(move |req: Request| async move {
assert_eq!(req.method(), Method::GET);
assert_eq!(req.uri().to_string(), format!("http://cyper.local/prox"));
"OK"
})
.await;
let proxy_url = format!("http://{}", server.addr());
let client = Client::builder()
.proxy(Proxy::https("http://unreachable.example").unwrap())
.proxy(Proxy::http(&proxy_url).unwrap())
.build();
let res = client
.get("http://cyper.local/prox")
.unwrap()
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "OK");
}