When running a slightly modified version of the example (to get it to connect to an easily reproducable real world-endpoint), RecvStream's never stops returning when called and is_end_stream() never returns true.
Example Code
use std::error::Error as StdError;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4};
use std::sync::Arc;
use rustls::pki_types::pem::PemObject;
use rustls::pki_types::{CertificateDer, DnsName};
use tokio::net::TcpStream;
use tokio_rustls::{TlsConnector, rustls};
use h2::client;
use http::Request;
#[tokio::main]
async fn main() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> {
let mut root_cert_store = rustls::RootCertStore::empty();
let (a, b) = root_cert_store.add_parsable_certificates(
CertificateDer::pem_file_iter("/etc/ssl/cert.pem")
.expect("Cannot open CA file")
.map(|result| result.unwrap()),
);
let mut config = rustls::ClientConfig::builder()
.with_root_certificates(root_cert_store)
.with_no_client_auth();
config.alpn_protocols = vec![b"h2".to_vec()];
let domain: DnsName = "google.com".try_into().unwrap();
let addr: SocketAddrV4 = "142.250.117.139:443".parse().unwrap(); // manual dns check for google.com
let tcp_stream = TcpStream::connect(addr).await?;
let tls_stream = TlsConnector::from(Arc::new(config))
.connect(domain.into(), tcp_stream)
.await?;
let (mut client, h2) = client::handshake(tls_stream).await?;
let request = Request::builder()
.uri("https://google.com/")
.body(())
.unwrap();
let (response, _) = client.send_request(request.clone(), false).unwrap();
// Spawn a task to run the conn...
tokio::spawn(async move {
if let Err(e) = h2.await {
println!("GOT ERR={:?}", e);
}
});
let response = response.await?;
// Get the body
let mut body = response.into_body();
let mut i = 0;
while let Some(chunk) = body.data().await {
match chunk {
Ok(data) => println!("Yay data: {data:?}"),
Err(err) => {
println!("Boo! {err:?}. {:?}", body.is_end_stream());
}
}
// Safety to prevent this going on forever.
i += 1;
if i > 10 {
break;
}
}
Ok(())
}
Output
Yay data: b"<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<TITLE>301 Moved</TITLE></HEAD><BODY>\n<H1>301 Moved</H1>\nThe document has moved\n<A HREF=\"https://www.google.com/\">here</A>.\r\n</BODY></HTML>\r\n"
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
Boo! Error { kind: Reset(StreamId(1), NO_ERROR, Remote) }. false
This is despite confirming via tcpdump while this code is running that the server does not send Reset frames over and over. Connecting to the endpoint via curl shows they set the eos flag on the first frame with html data in it. This never seems to be picked up by h2.
A frame with the end stream flag set should be enough to mark is_end_stream to true, surely, or failing that a real Reset frame with a reason of NO_ERROR should also.
This behaviour began with 0.4.10.
When running a slightly modified version of the example (to get it to connect to an easily reproducable real world-endpoint),
RecvStream's never stops returning when called andis_end_stream()never returns true.Example Code
Output
This is despite confirming via tcpdump while this code is running that the server does not send Reset frames over and over. Connecting to the endpoint via curl shows they set the eos flag on the first frame with html data in it. This never seems to be picked up by h2.
A frame with the end stream flag set should be enough to mark
is_end_streamto true, surely, or failing that a real Reset frame with a reason ofNO_ERRORshould also.This behaviour began with 0.4.10.