v0.26.0
This commit is contained in:
1 parent
d168ee2afa
commit
ddc5c6593f
70 files changed
+2293
-594
No files matched your search
@@ -0,0 +1,117 @@
|
||||
fn invalid_headers(headers: &HeaderMap) -> bool {
|
||||
[
|
||||
"connection",
|
||||
"keep-alive",
|
||||
"proxy-connection",
|
||||
"transfer-encoding",
|
||||
"upgrade",
|
||||
]
|
||||
.iter()
|
||||
.any(|name| headers.contains_key(*name))
|
||||
|| headers
|
||||
.get_all("te")
|
||||
.iter()
|
||||
.any(|value| value.as_bytes() != b"trailers")
|
||||
|| headers.get_all("content-length").iter().count() > 1
|
||||
|| headers.get("content-length").is_some_and(|value| {
|
||||
value
|
||||
.to_str()
|
||||
.ok()
|
||||
.and_then(|s| s.parse::<u64>().ok())
|
||||
.is_none()
|
||||
})
|
||||
}
|
||||
struct ReceiveBody {
|
||||
stream: h3::server::RequestStream<h3::quinn::RecvStream, Bytes>,
|
||||
expected: Option<u64>,
|
||||
received: u64,
|
||||
data_done: bool,
|
||||
done: bool,
|
||||
}
|
||||
impl HttpBody for ReceiveBody {
|
||||
type Data = Bytes;
|
||||
type Error = io::Error;
|
||||
fn poll_frame(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<std::result::Result<Frame<Bytes>, io::Error>>> {
|
||||
let this = self.get_mut();
|
||||
if this.done {
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
if !this.data_done {
|
||||
match this.stream.poll_recv_data(cx) {
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(Err(error)) => {
|
||||
this.done = true;
|
||||
return Poll::Ready(Some(Err(io::Error::other(error.to_string()))));
|
||||
}
|
||||
Poll::Ready(Ok(Some(mut data))) => {
|
||||
let length = data.remaining();
|
||||
this.received = this.received.saturating_add(length as u64);
|
||||
if this
|
||||
.expected
|
||||
.is_some_and(|expected| this.received > expected)
|
||||
{
|
||||
drop(data);
|
||||
this.done = true;
|
||||
this.stream.stop_sending(Code::H3_MESSAGE_ERROR);
|
||||
return Poll::Ready(Some(Err(io::Error::other(
|
||||
"HTTP/3 Content-Length exceeded",
|
||||
))));
|
||||
}
|
||||
return Poll::Ready(Some(Ok(Frame::data(data.copy_to_bytes(length)))));
|
||||
}
|
||||
Poll::Ready(Ok(None)) => this.data_done = true,
|
||||
}
|
||||
}
|
||||
match this.stream.poll_recv_trailers(cx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Err(error)) => {
|
||||
this.done = true;
|
||||
Poll::Ready(Some(Err(io::Error::other(error.to_string()))))
|
||||
}
|
||||
Poll::Ready(Ok(trailers)) => {
|
||||
this.done = true;
|
||||
if this
|
||||
.expected
|
||||
.is_some_and(|expected| expected != this.received)
|
||||
{
|
||||
this.stream.stop_sending(Code::H3_MESSAGE_ERROR);
|
||||
return Poll::Ready(Some(Err(io::Error::other(
|
||||
"HTTP/3 Content-Length mismatch",
|
||||
))));
|
||||
}
|
||||
Poll::Ready(trailers.map(|mut headers| {
|
||||
crate::proxy::headers::strip_hop_by_hop(&mut headers);
|
||||
Ok(Frame::trailers(headers))
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
fn is_end_stream(&self) -> bool {
|
||||
self.done
|
||||
}
|
||||
fn size_hint(&self) -> SizeHint {
|
||||
// A declared zero is not proof that the peer ended its stream. Unknown
|
||||
// lengths are verified by the cache's bounded empty-body probe.
|
||||
let mut hint = SizeHint::new();
|
||||
if self.done {
|
||||
hint.set_exact(0);
|
||||
} else if let Some(remaining) = self
|
||||
.expected
|
||||
.map(|n| n.saturating_sub(self.received))
|
||||
.filter(|n| *n > 0)
|
||||
{
|
||||
hint.set_upper(remaining);
|
||||
}
|
||||
hint
|
||||
}
|
||||
}
|
||||
impl Drop for ReceiveBody {
|
||||
fn drop(&mut self) {
|
||||
// Dropping the request stream cancels the receive side at QUIC level.
|
||||
// Explicit STOP_SENDING is used only from poll_frame paths where the
|
||||
// stream handle is available and a protocol error was detected.
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user