Rust noob here.
I'm using a CONNECT proxy (using TLS and HTTP2) and then making a HTTP/1.1 (or even HTTP/2) request to the target server. This works fine but after the response, the connection is closed via RST rather than FIN. I have confirmed this with a packet capture.
I tried with 'Connection: close' header for the request to target and the connection was closed via FIN from the proxy server.
What is it that I'm doing wrong here? Any pointers are appreciated!
Ideally, I would like the client to send the TLS close notify to shutdown TLS session normally between the client and proxy and then close the TCP socket using FIN.
async fn fetch_url(_url: hyper::Uri) -> Result<()> {
// connect to proxy first
let mut root_cert_store = rustls::RootCertStore::empty();
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
let mut config = rustls::ClientConfig::builder()
.with_root_certificates(root_cert_store)
.with_no_client_auth();
let mut dangerous_config = rustls::ClientConfig::dangerous(&mut config);
dangerous_config.set_certificate_verifier(Arc::new(NoCertificateVerification::new(
provider::default_provider(),
)));
let connector = TlsConnector::from(Arc::new(config));
let stream = TcpStream::connect("localhost:8000").await?;
let domain = pki_types::ServerName::try_from("localhost")
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?
.to_owned();
let mut tls_stream = connector.connect(domain, stream).await?;
let io = TokioIo::new(tls_stream);
let executor = hyper_util::rt::tokio::TokioExecutor::new();
let (mut sender, conn) = hyper::client::conn::http2::handshake::<
TokioExecutor,
TokioIo<tokio_rustls::client::TlsStream<tokio::net::TcpStream>>,
Empty<Bytes>,
>(executor, io)
.await?;
tokio::task::spawn(async move {
if let Err(err) = conn.await {
println!("Connection failed: {:?}", err);
}
});
println!("bulding request");
let req = Request::builder()
.method(Method::CONNECT)
.version(Version::HTTP_2)
.uri("http://google.com:80")
.body(Empty::<Bytes>::new())?;
println!("sending request: {:?}", req);
let res = sender.send_request(req).await?;
println!("{:?}", res);
let upgraded = hyper::upgrade::on(res).await?;
println!("{:?}", upgraded);
// send the actually request
{
let (mut sender, conn) = hyper::client::conn::http1::handshake(upgraded).await?;
tokio::task::spawn(async move {
if let Err(err) = conn.await {
println!("Connection failed: {:?}", err);
}
});
let url = hyper::Uri::from_static("http://google.com/");
let authority = url.authority().unwrap().clone();
let path = url.path();
let req = Request::builder()
.uri(path)
.header(hyper::header::HOST, authority.as_str())
.body(Empty::<Bytes>::new())?;
let mut res = sender.send_request(req).await?;
while let Some(next) = res.frame().await {
let frame = next?;
if let Some(chunk) = frame.data_ref() {
io::stdout().write_all(&chunk).await?;
}
}
}
// connection resets here
Ok(())
}