use std::time::Duration;
#[tokio::test]
async fn test_cors_header_present_on_get() {
let cors = oxihttp::CorsConfig::permissive();
let router = oxihttp::Router::new().get("/api/data", |_req| async {
oxihttp::response::text_response("data")
});
let (addr, _handle) = oxihttp::Server::bind("127.0.0.1:0")
.with_cors(cors)
.serve_with_addr(router)
.await
.expect("server bind");
tokio::time::sleep(Duration::from_millis(5)).await;
let client = oxihttp_client::Client::builder().build().expect("client");
let url = format!("http://{addr}/api/data");
let req = http::Request::builder()
.method(http::Method::GET)
.uri(&url)
.header("origin", "https://example.com")
.body(http_body_util::Full::new(bytes::Bytes::new()))
.expect("request build");
let resp = client.execute(req).await.expect("execute");
assert_eq!(resp.status(), http::StatusCode::OK);
assert!(
resp.headers()
.contains_key(http::header::ACCESS_CONTROL_ALLOW_ORIGIN),
"CORS header ACCESS_CONTROL_ALLOW_ORIGIN should be present"
);
let body = resp.body_text().await.expect("body text");
assert_eq!(body, "data");
}
#[tokio::test]
async fn test_cors_preflight_options() {
let cors = oxihttp::CorsConfig::permissive();
let router = oxihttp::Router::new().post("/submit", |_req| async {
oxihttp::response::text_response("submitted")
});
let (addr, _handle) = oxihttp::Server::bind("127.0.0.1:0")
.with_cors(cors)
.serve_with_addr(router)
.await
.expect("server bind");
tokio::time::sleep(Duration::from_millis(5)).await;
let client = oxihttp_client::Client::builder().build().expect("client");
let url = format!("http://{addr}/submit");
let req = http::Request::builder()
.method(http::Method::OPTIONS)
.uri(&url)
.header("origin", "https://example.com")
.header("access-control-request-method", "POST")
.body(http_body_util::Full::new(bytes::Bytes::new()))
.expect("request build");
let resp = client.execute(req).await.expect("execute");
assert_eq!(resp.status(), http::StatusCode::NO_CONTENT);
assert!(
resp.headers()
.contains_key(http::header::ACCESS_CONTROL_ALLOW_ORIGIN),
"CORS header should be present on preflight"
);
}
#[tokio::test]
async fn test_timeout_does_not_interrupt_fast_handler() {
let router = oxihttp::Router::new().get("/fast", |_req| async {
oxihttp::response::text_response("fast-response")
});
let (addr, _handle) = oxihttp::Server::bind("127.0.0.1:0")
.with_timeout(Duration::from_secs(5))
.serve_with_addr(router)
.await
.expect("server bind");
tokio::time::sleep(Duration::from_millis(5)).await;
let client = oxihttp_client::Client::builder().build().expect("client");
let url = format!("http://{addr}/fast");
let resp = client.get(&url).expect("GET").send().await.expect("send");
assert_eq!(
resp.status(),
http::StatusCode::OK,
"fast handler should succeed within timeout"
);
let body = resp.body_text().await.expect("body text");
assert_eq!(body, "fast-response");
}
#[tokio::test]
async fn test_timeout_interrupts_slow_handler() {
let router = oxihttp::Router::new().get("/slow", |_req| async {
tokio::time::sleep(Duration::from_secs(10)).await;
oxihttp::response::text_response("too-late")
});
let (addr, _handle) = oxihttp::Server::bind("127.0.0.1:0")
.with_timeout(Duration::from_millis(50))
.serve_with_addr(router)
.await
.expect("server bind");
tokio::time::sleep(Duration::from_millis(5)).await;
let client = oxihttp_client::Client::builder().build().expect("client");
let url = format!("http://{addr}/slow");
let resp = client.get(&url).expect("GET").send().await.expect("send");
assert_eq!(
resp.status(),
http::StatusCode::REQUEST_TIMEOUT,
"slow handler should return 408 Request Timeout after timeout exceeded"
);
}
#[tokio::test]
async fn test_cors_with_timeout_combined() {
let cors = oxihttp::CorsConfig::permissive();
let router = oxihttp::Router::new().get("/combined", |_req| async {
oxihttp::response::text_response("ok")
});
let (addr, _handle) = oxihttp::Server::bind("127.0.0.1:0")
.with_cors(cors)
.with_timeout(Duration::from_secs(5))
.serve_with_addr(router)
.await
.expect("server bind");
tokio::time::sleep(Duration::from_millis(5)).await;
let client = oxihttp_client::Client::builder().build().expect("client");
let url = format!("http://{addr}/combined");
let req = http::Request::builder()
.method(http::Method::GET)
.uri(&url)
.header("origin", "https://example.com")
.body(http_body_util::Full::new(bytes::Bytes::new()))
.expect("request build");
let resp = client.execute(req).await.expect("execute");
assert_eq!(resp.status(), http::StatusCode::OK);
assert!(
resp.headers()
.contains_key(http::header::ACCESS_CONTROL_ALLOW_ORIGIN),
"CORS headers should be present when both CORS and timeout middleware are active"
);
let body = resp.body_text().await.expect("body text");
assert_eq!(body, "ok");
}