Skip to content

Commit b5a2248

Browse files
committed
refactor(body): move channel h2 incoming body implementation to H2Body type
1 parent 9872591 commit b5a2248

File tree

2 files changed

+100
-65
lines changed

2 files changed

+100
-65
lines changed

src/body/incoming/h2.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use std::task::{Context, Poll};
2+
3+
use bytes::Bytes;
4+
use futures_util::ready;
5+
use http_body::{Frame, SizeHint};
6+
7+
use crate::body::DecodedLength;
8+
use crate::proto::h2::ping;
9+
10+
pub(super) struct H2Body {
11+
content_length: DecodedLength,
12+
data_done: bool,
13+
ping: ping::Recorder,
14+
recv: h2::RecvStream,
15+
}
16+
17+
impl H2Body {
18+
pub(super) fn new(
19+
recv: h2::RecvStream,
20+
mut content_length: DecodedLength,
21+
ping: ping::Recorder,
22+
) -> Self {
23+
// If the stream is already EOS, then the "unknown length" is clearly
24+
// actually ZERO.
25+
if !content_length.is_exact() && recv.is_end_stream() {
26+
content_length = DecodedLength::ZERO;
27+
}
28+
29+
Self {
30+
data_done: false,
31+
ping,
32+
content_length,
33+
recv,
34+
}
35+
}
36+
37+
pub(super) fn poll_frame(
38+
&mut self,
39+
cx: &mut Context<'_>,
40+
) -> Poll<Option<Result<Frame<Bytes>, crate::Error>>> {
41+
let Self {
42+
ref mut data_done,
43+
ref ping,
44+
recv: ref mut h2,
45+
content_length: ref mut len,
46+
} = self;
47+
48+
if !*data_done {
49+
match ready!(h2.poll_data(cx)) {
50+
Some(Ok(bytes)) => {
51+
let _ = h2.flow_control().release_capacity(bytes.len());
52+
len.sub_if(bytes.len() as u64);
53+
ping.record_data(bytes.len());
54+
return Poll::Ready(Some(Ok(Frame::data(bytes))));
55+
}
56+
Some(Err(e)) => {
57+
return match e.reason() {
58+
// These reasons should cause the body reading to stop, but not fail it.
59+
// The same logic as for `Read for H2Upgraded` is applied here.
60+
Some(h2::Reason::NO_ERROR) | Some(h2::Reason::CANCEL) => Poll::Ready(None),
61+
_ => Poll::Ready(Some(Err(crate::Error::new_body(e)))),
62+
};
63+
}
64+
None => {
65+
*data_done = true;
66+
// fall through to trailers
67+
}
68+
}
69+
}
70+
71+
// after data, check trailers
72+
match ready!(h2.poll_trailers(cx)) {
73+
Ok(t) => {
74+
ping.record_non_data();
75+
Poll::Ready(Ok(t.map(Frame::trailers)).transpose())
76+
}
77+
Err(e) => Poll::Ready(Some(Err(crate::Error::new_h2(e)))),
78+
}
79+
}
80+
81+
pub(super) fn is_end_stream(&self) -> bool {
82+
self.recv.is_end_stream()
83+
}
84+
85+
pub(super) fn size_hint(&self) -> SizeHint {
86+
super::opt_len(self.content_length)
87+
}
88+
}

src/body/incoming/mod.rs

Lines changed: 12 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
22
mod channel;
3+
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
4+
mod h2;
35

46
use std::fmt;
57
use std::pin::Pin;
68
use std::task::{Context, Poll};
79

810
use bytes::Bytes;
9-
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
10-
use futures_util::ready;
1111
use http_body::{Body, Frame, SizeHint};
1212

1313
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
1414
use self::channel::ChanBody;
1515
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
1616
pub(crate) use self::channel::Sender;
1717

18+
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
19+
use self::h2::H2Body;
20+
1821
#[cfg(all(
1922
any(feature = "http1", feature = "http2"),
2023
any(feature = "client", feature = "server")
@@ -48,12 +51,7 @@ enum Kind {
4851
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
4952
Chan(ChanBody),
5053
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
51-
H2 {
52-
content_length: DecodedLength,
53-
data_done: bool,
54-
ping: ping::Recorder,
55-
recv: h2::RecvStream,
56-
},
54+
H2(H2Body),
5755
#[cfg(feature = "ffi")]
5856
Ffi(crate::ffi::UserBody),
5957
}
@@ -81,22 +79,11 @@ impl Incoming {
8179

8280
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
8381
pub(crate) fn h2(
84-
recv: h2::RecvStream,
85-
mut content_length: DecodedLength,
82+
recv: ::h2::RecvStream,
83+
content_length: DecodedLength,
8684
ping: ping::Recorder,
8785
) -> Self {
88-
// If the stream is already EOS, then the "unknown length" is clearly
89-
// actually ZERO.
90-
if !content_length.is_exact() && recv.is_end_stream() {
91-
content_length = DecodedLength::ZERO;
92-
}
93-
94-
Incoming::new(Kind::H2 {
95-
data_done: false,
96-
ping,
97-
content_length,
98-
recv,
99-
})
86+
Incoming::new(Kind::H2(H2Body::new(recv, content_length, ping)))
10087
}
10188

10289
#[cfg(feature = "ffi")]
@@ -142,47 +129,7 @@ impl Body for Incoming {
142129
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
143130
Kind::Chan(ref mut body) => body.poll_frame(cx),
144131
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
145-
Kind::H2 {
146-
ref mut data_done,
147-
ref ping,
148-
recv: ref mut h2,
149-
content_length: ref mut len,
150-
} => {
151-
if !*data_done {
152-
match ready!(h2.poll_data(cx)) {
153-
Some(Ok(bytes)) => {
154-
let _ = h2.flow_control().release_capacity(bytes.len());
155-
len.sub_if(bytes.len() as u64);
156-
ping.record_data(bytes.len());
157-
return Poll::Ready(Some(Ok(Frame::data(bytes))));
158-
}
159-
Some(Err(e)) => {
160-
return match e.reason() {
161-
// These reasons should cause the body reading to stop, but not fail it.
162-
// The same logic as for `Read for H2Upgraded` is applied here.
163-
Some(h2::Reason::NO_ERROR) | Some(h2::Reason::CANCEL) => {
164-
Poll::Ready(None)
165-
}
166-
_ => Poll::Ready(Some(Err(crate::Error::new_body(e)))),
167-
};
168-
}
169-
None => {
170-
*data_done = true;
171-
// fall through to trailers
172-
}
173-
}
174-
}
175-
176-
// after data, check trailers
177-
match ready!(h2.poll_trailers(cx)) {
178-
Ok(t) => {
179-
ping.record_non_data();
180-
Poll::Ready(Ok(t.map(Frame::trailers)).transpose())
181-
}
182-
Err(e) => Poll::Ready(Some(Err(crate::Error::new_h2(e)))),
183-
}
184-
}
185-
132+
Kind::H2(ref mut body) => body.poll_frame(cx),
186133
#[cfg(feature = "ffi")]
187134
Kind::Ffi(ref mut body) => body.poll_data(cx),
188135
}
@@ -194,7 +141,7 @@ impl Body for Incoming {
194141
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
195142
Kind::Chan(ref body) => body.is_end_stream(),
196143
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
197-
Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(),
144+
Kind::H2(ref body) => body.is_end_stream(),
198145
#[cfg(feature = "ffi")]
199146
Kind::Ffi(..) => false,
200147
}
@@ -206,7 +153,7 @@ impl Body for Incoming {
206153
#[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
207154
Kind::Chan(ref body) => body.size_hint(),
208155
#[cfg(all(feature = "http2", any(feature = "client", feature = "server")))]
209-
Kind::H2 { content_length, .. } => opt_len(content_length),
156+
Kind::H2(ref body) => body.size_hint(),
210157
#[cfg(feature = "ffi")]
211158
Kind::Ffi(..) => SizeHint::default(),
212159
}

0 commit comments

Comments
 (0)