Skip to content

Commit efc2cd0

Browse files
authored
Merge branch 'master' into sean/xmqyvnyporqr
2 parents 5811a88 + af432e9 commit efc2cd0

6 files changed

Lines changed: 83 additions & 21 deletions

File tree

src/body/incoming.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,6 @@ mod tests {
491491
body_expected_size,
492492
);
493493

494-
//assert_eq!(body_size, mem::size_of::<Option<Incoming>>(), "Option<Incoming>");
495-
496494
assert_eq!(
497495
mem::size_of::<Sender>(),
498496
mem::size_of::<usize>() * 5,

src/body/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,52 @@
1717
//! There are additional implementations available in [`http-body-util`][],
1818
//! such as a `Full` or `Empty` body.
1919
//!
20+
//! ## Reading a body
21+
//!
22+
//! The [`BodyExt`][] extension trait provides an asynchronous way to read the
23+
//! frames of a body. A frame can contain either data or trailers:
24+
//!
25+
//! ```
26+
//! use http_body_util::BodyExt as _;
27+
//! use hyper::body::Incoming;
28+
//!
29+
//! async fn read_body(mut body: Incoming) -> Result<(), hyper::Error> {
30+
//! while let Some(frame) = body.frame().await {
31+
//! let frame = frame?;
32+
//!
33+
//! if let Some(data) = frame.data_ref() {
34+
//! println!("received {} bytes", data.len());
35+
//! }
36+
//!
37+
//! if let Some(trailers) = frame.trailers_ref() {
38+
//! println!("received trailers: {trailers:?}");
39+
//! }
40+
//! }
41+
//!
42+
//! Ok(())
43+
//! }
44+
//! ```
45+
//!
46+
//! A body only advances when it is polled. Processing each frame before
47+
//! polling for the next one preserves back-pressure on the connection.
48+
//!
49+
//! If a body is known to be small, it can be collected into memory instead:
50+
//!
51+
//! ```
52+
//! use http_body_util::BodyExt as _;
53+
//! use hyper::body::{Bytes, Incoming};
54+
//!
55+
//! /// Consider using `Limited` if the body is untrusted.
56+
//! async fn read_entire_body(body: Incoming) -> Result<Bytes, hyper::Error> {
57+
//! Ok(body.collect().await?.to_bytes())
58+
//! }
59+
//! ```
60+
//!
61+
//! Collecting buffers the whole body, so it should be avoided for large or
62+
//! untrusted bodies unless their size is limited.
63+
//!
2064
//! [`http-body-util`]: https://docs.rs/http-body-util
65+
//! [`BodyExt`]: https://docs.rs/http-body-util/latest/http_body_util/trait.BodyExt.html
2166
2267
pub use bytes::{Buf, Bytes};
2368
pub use http_body::Body;

src/common/io/rewind.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ impl<T> Rewind<T> {
4646
pub(crate) fn into_inner(self) -> (T, Bytes) {
4747
(self.inner, self.pre.unwrap_or_default())
4848
}
49-
50-
// pub(crate) fn get_mut(&mut self) -> &mut T {
51-
// &mut self.inner
52-
// }
5349
}
5450

5551
impl<T> Read for Rewind<T>

src/proto/h1/io.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -657,19 +657,6 @@ mod tests {
657657

658658
use tokio_test::io::Builder as Mock;
659659

660-
// #[cfg(feature = "nightly")]
661-
// use test::Bencher;
662-
663-
/*
664-
impl<T: Read> MemRead for AsyncIo<T> {
665-
fn read_mem(&mut self, len: usize) -> Poll<Bytes, io::Error> {
666-
let mut v = vec![0; len];
667-
let n = try_nb!(self.read(v.as_mut_slice()));
668-
Ok(Async::Ready(BytesMut::from(&v[..n]).freeze()))
669-
}
670-
}
671-
*/
672-
673660
#[tokio::test]
674661
#[ignore]
675662
async fn iobuf_write_empty_slice() {

src/proto/h1/role.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ fn is_complete_fast(bytes: &[u8], prev_len: usize) -> bool {
106106
if bytes[i + 1..].chunks(3).next() == Some(&b"\n\r\n"[..]) {
107107
return true;
108108
}
109-
} else if b == b'\n' && bytes.get(i + 1) == Some(&b'\n') {
109+
} else if b == b'\n'
110+
&& (bytes.get(i + 1) == Some(&b'\n')
111+
|| bytes[i + 1..].chunks(2).next() == Some(&b"\r\n"[..]))
112+
{
110113
return true;
111114
}
112115
}
@@ -2977,6 +2980,10 @@ mod tests {
29772980
for n in 0..s.len() {
29782981
assert!(is_complete_fast(s, n));
29792982
}
2983+
let s = b"GET / HTTP/1.1\r\na: b\n\r\n";
2984+
for n in 0..s.len() {
2985+
assert!(is_complete_fast(s, n), "{:?}; {}", s, n);
2986+
}
29802987

29812988
// Not
29822989
let s = b"GET / HTTP/1.1\r\na: b\r\n\r";
@@ -2987,6 +2994,36 @@ mod tests {
29872994
for n in 0..s.len() {
29882995
assert!(!is_complete_fast(s, n));
29892996
}
2997+
let s = b"GET / HTTP/1.1\r\na: b\n\r";
2998+
for n in 0..s.len() {
2999+
assert!(!is_complete_fast(s, n));
3000+
}
3001+
}
3002+
3003+
#[cfg(feature = "server")]
3004+
#[test]
3005+
fn test_parse_accepts_lf_crlf_terminator() {
3006+
// The full parser (httparse) accepts a bare-LF line ending followed
3007+
// by a CRLF blank line as the end of the head, so the partial-read
3008+
// fast path must recognize it too.
3009+
let mut bytes = BytesMut::from("GET / HTTP/1.1\r\na: b\n\r\n");
3010+
Server::parse(
3011+
&mut bytes,
3012+
ParseContext {
3013+
cached_headers: &mut None,
3014+
req_method: &mut None,
3015+
h1_parser_config: Default::default(),
3016+
h1_max_headers: None,
3017+
preserve_header_case: false,
3018+
#[cfg(feature = "ffi")]
3019+
preserve_header_order: false,
3020+
h09_responses: false,
3021+
#[cfg(feature = "client")]
3022+
on_informational: &mut None,
3023+
},
3024+
)
3025+
.expect("parse ok")
3026+
.expect("parse complete");
29903027
}
29913028

29923029
#[test]

src/upgrade.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,6 @@ mod tests {
405405
_: &mut Context<'_>,
406406
buf: &[u8],
407407
) -> Poll<io::Result<usize>> {
408-
// panic!("poll_write shouldn't be called");
409408
Poll::Ready(Ok(buf.len()))
410409
}
411410

0 commit comments

Comments
 (0)