use bytes::{Buf, Bytes}; use h2::{Reason, RecvStream, SendStream}; use http::header::{HeaderName, CONNECTION, TE, TRAILER, TRANSFER_ENCODING, UPGRADE}; use http::HeaderMap; use pin_project_lite::pin_project; use std::error::Error as StdError; use std::io::{self, Cursor, IoSlice}; use std::mem; use std::task::Context; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tracing::{debug, trace, warn};
cfg_client! { pub(crate) mod client; pub(crate) useself::client::ClientTask;
}
cfg_server! { pub(crate) mod server; pub(crate) useself::server::Server;
}
/// Default initial stream window size defined in HTTP2 spec. pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;
fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) { // List of connection headers from: // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection // // TE headers are allowed in HTTP/2 requests as long as the value is "trailers", so they're // tested separately. let connection_headers = [
HeaderName::from_lowercase(b"keep-alive").unwrap(),
HeaderName::from_lowercase(b"proxy-connection").unwrap(),
TRAILER,
TRANSFER_ENCODING,
UPGRADE,
];
for header in connection_headers.iter() { if headers.remove(header).is_some() {
warn!("Connection header illegal in HTTP/2: {}", header.as_str());
}
}
if is_request { if headers
.get(TE)
.map(|te_header| te_header != "trailers")
.unwrap_or(false)
{
warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
headers.remove(TE);
}
} elseif headers.remove(TE).is_some() {
warn!("TE headers illegal in HTTP/2 responses");
}
iflet Some(header) = headers.remove(CONNECTION) {
warn!( "Connection header illegal in HTTP/2: {}",
CONNECTION.as_str()
); let header_contents = header.to_str().unwrap();
// A `Connection` header may have a comma-separated list of names of other headers that // are meant for only this specific connection. // // Iterate these names and remove them as headers. Connection-specific headers are // forbidden in HTTP2, as that information has been moved into frame types of the h2 // protocol. for name in header_contents.split(',') { let name = name.trim();
headers.remove(name);
}
}
}
impl<S> Future for PipeToSendStream<S> where
S: HttpBody,
S::Error: Into<Box<dyn StdError + Send + Sync>>,
{ type Output = crate::Result<()>;
fn poll(self: Pin<&mutSelf>, cx: &mut task::Context<'_>) -> Poll<Self::Output> { letmut me = self.project(); loop { if !*me.data_done { // we don't have the next chunk of data yet, so just reserve 1 byte to make // sure there's some capacity available. h2 will handle the capacity management // for the actual body chunk.
me.body_tx.reserve_capacity(1);
if me.body_tx.capacity() == 0 { loop { match ready!(me.body_tx.poll_capacity(cx)) {
Some(Ok(0)) => {}
Some(Ok(_)) => break,
Some(Err(e)) => { return Poll::Ready(Err(crate::Error::new_body_write(e)))
}
None => { // None means the stream is no longer in a // streaming state, we either finished it // somehow, or the remote reset us. return Poll::Ready(Err(crate::Error::new_body_write( "send stream capacity unexpectedly closed",
)));
}
}
}
} elseiflet Poll::Ready(reason) = me
.body_tx
.poll_reset(cx)
.map_err(crate::Error::new_body_write)?
{
debug!("stream received RST_STREAM: {:?}", reason); return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
reason,
))));
}
match ready!(me.stream.as_mut().poll_data(cx)) {
Some(Ok(chunk)) => { let is_eos = me.stream.is_end_stream();
trace!( "send body chunk: {} bytes, eos={}",
chunk.remaining(),
is_eos,
);
let buf = SendBuf::Buf(chunk);
me.body_tx
.send_data(buf, is_eos)
.map_err(crate::Error::new_body_write)?;
if is_eos { return Poll::Ready(Ok(()));
}
}
Some(Err(e)) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
None => {
me.body_tx.reserve_capacity(0); let is_eos = me.stream.is_end_stream(); if is_eos { return Poll::Ready(me.body_tx.send_eos_frame());
} else {
*me.data_done = true; // loop again to poll_trailers
}
}
}
} else { iflet Poll::Ready(reason) = me
.body_tx
.poll_reset(cx)
.map_err(crate::Error::new_body_write)?
{
debug!("stream received RST_STREAM: {:?}", reason); return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
reason,
))));
}
match ready!(me.stream.poll_trailers(cx)) {
Ok(Some(trailers)) => {
me.body_tx
.send_trailers(trailers)
.map_err(crate::Error::new_body_write)?; return Poll::Ready(Ok(()));
}
Ok(None) => { // There were no trailers, so send an empty DATA frame... return Poll::Ready(me.body_tx.send_eos_frame());
}
Err(e) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
}
}
}
}
}
impl<B> AsyncWrite for H2Upgraded<B> where
B: Buf,
{ fn poll_write( mutself: Pin<&mutSelf>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, io::Error>> { if buf.is_empty() { return Poll::Ready(Ok(0));
} self.send_stream.reserve_capacity(buf.len());
// We ignore all errors returned by `poll_capacity` and `write`, as we // will get the correct from `poll_reset` anyway. let cnt = match ready!(self.send_stream.poll_capacity(cx)) {
None => Some(0),
Some(Ok(cnt)) => self
.send_stream
.write(&buf[..cnt], false)
.ok()
.map(|()| cnt),
Some(Err(_)) => None,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.