use origin_domain::ErrorKind;
use origin_http::{HttpClient, HttpRequest};
use origin_http_reqwest::ReqwestHttpClient;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
async fn one_shot_server(response: &'static [u8]) -> std::net::SocketAddr {
let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind");
let address = listener.local_addr().expect("local addr");
tokio::spawn(async move {
let (mut stream, _) = listener.accept().await.expect("accept");
let mut buffer = [0u8; 1024];
let _ = stream.read(&mut buffer).await;
let _ = stream.write_all(response).await;
let _ = stream.shutdown().await;
});
address
}
#[tokio::test]
async fn a_response_within_the_limit_is_read_in_full() {
let address =
one_shot_server(b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\nConnection: close\r\n\r\nhello")
.await;
let client = ReqwestHttpClient::new("origin-tests").unwrap();
let response = client
.send(HttpRequest::get(format!("http://{address}/")))
.await
.unwrap();
assert_eq!(response.status, 200);
assert_eq!(response.body, b"hello");
}
#[tokio::test]
async fn a_declared_content_length_over_the_limit_is_rejected_before_reading_the_body() {
let address =
one_shot_server(b"HTTP/1.1 200 OK\r\nContent-Length: 1000000\r\nConnection: close\r\n\r\n")
.await;
let client = ReqwestHttpClient::builder("origin-tests")
.max_response_bytes(16)
.build()
.unwrap();
let error = client
.send(HttpRequest::get(format!("http://{address}/")))
.await
.unwrap_err();
assert_eq!(error.kind(), ErrorKind::ExternalService);
assert!(error.to_string().contains("16 byte limit"), "got: {error}");
}
#[tokio::test]
async fn a_body_with_no_declared_length_is_still_capped_while_streaming() {
let address = one_shot_server(
b"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nthis body is well over sixteen bytes long",
)
.await;
let client = ReqwestHttpClient::builder("origin-tests")
.max_response_bytes(16)
.build()
.unwrap();
let error = client
.send(HttpRequest::get(format!("http://{address}/")))
.await
.unwrap_err();
assert_eq!(error.kind(), ErrorKind::ExternalService);
assert!(error.to_string().contains("16 byte limit"), "got: {error}");
}
#[tokio::test]
async fn a_connection_refused_is_reported_as_offline() {
let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind");
let address = listener.local_addr().expect("local addr");
drop(listener);
let client = ReqwestHttpClient::new("origin-tests").unwrap();
let error = client
.send(HttpRequest::get(format!("http://{address}/")))
.await
.unwrap_err();
assert_eq!(error.kind(), ErrorKind::Offline);
}