Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
test(client): add test for ErroredConnectInfo
  • Loading branch information
magurotuna committed Aug 18, 2024
commit 0772c009bede1bba37b988f54396ef528efefea5
90 changes: 89 additions & 1 deletion tests/legacy_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
use hyper::body::Bytes;
use hyper::body::Frame;
use hyper::Request;
use hyper_util::client::legacy::connect::{capture_connection, HttpConnector};
use hyper_util::client::legacy::connect::{capture_connection, HttpConnector, HttpInfo};
use hyper_util::client::legacy::Client;
use hyper_util::rt::{TokioExecutor, TokioIo};

Expand Down Expand Up @@ -978,3 +978,91 @@ fn connection_poisoning() {
assert_eq!(num_conns.load(Ordering::SeqCst), 2);
assert_eq!(num_requests.load(Ordering::SeqCst), 5);
}

#[cfg(not(miri))]
#[tokio::test]
async fn connect_info_on_error() {
let client = Client::builder(TokioExecutor::new()).build(HttpConnector::new());

// srv1 accepts one connection, and cancel it after reading the second request.
let tcp1 = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr1 = tcp1.local_addr().unwrap();
let srv1 = tokio::spawn(async move {
let (mut sock, _addr) = tcp1.accept().await.unwrap();
let mut buf = [0; 4096];
sock.read(&mut buf).await.expect("read 1");
let body = Bytes::from("Hello, world!");
sock.write_all(
format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n", body.len()).as_bytes(),
)
.await
.expect("write header");
sock.write_all(&body).await.expect("write body");

sock.read(&mut buf).await.expect("read 2");
drop(sock);
});

// Makes a first request to srv1, which should succeed.
{
let req = Request::builder()
.uri(format!("http://{addr1}"))
.body(Empty::<Bytes>::new())
.unwrap();
let res = client.request(req).await.unwrap();
let http_info = res.extensions().get::<HttpInfo>().unwrap();
assert_eq!(http_info.remote_addr(), addr1);
let res_body = String::from_utf8(res.collect().await.unwrap().to_bytes().into()).unwrap();
assert_eq!(res_body, "Hello, world!");
}

// Makes a second request to srv1, which should use the same connection and fail.
{
let req = Request::builder()
.uri(format!("http://{addr1}"))
.body(Empty::<Bytes>::new())
.unwrap();
let err = client.request(req).await.unwrap_err();
let conn_info = err.connect_info().unwrap();
assert!(!conn_info.is_proxied());
assert!(!conn_info.is_negotiated_h2());
assert!(conn_info.is_reused());

let mut exts = http::Extensions::new();
conn_info.get_extras(&mut exts);
let http_info = exts.get::<HttpInfo>().unwrap();
assert_eq!(http_info.remote_addr(), addr1);
}

srv1.await.unwrap();

// srv2 accepts one connection, reads a request, and immediately closes it.
let tcp2 = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr2 = tcp2.local_addr().unwrap();
let srv2 = tokio::spawn(async move {
let (mut sock, _addr) = tcp2.accept().await.unwrap();
let mut buf = [0; 4096];
sock.read(&mut buf).await.expect("read");
drop(sock);
});

// Makes a first request to srv2, which should use a fresh connection and fail.
{
let req = Request::builder()
.uri(format!("http://{addr2}"))
.body(Empty::<Bytes>::new())
.unwrap();
let err = client.request(req).await.unwrap_err();
let conn_info = err.connect_info().unwrap();
assert!(!conn_info.is_proxied());
assert!(!conn_info.is_negotiated_h2());
assert!(!conn_info.is_reused());

let mut exts = http::Extensions::new();
conn_info.get_extras(&mut exts);
let http_info = exts.get::<HttpInfo>().unwrap();
assert_eq!(http_info.remote_addr(), addr2);
}

srv2.await.unwrap();
}