Skip to content

Commit 14d9246

Browse files
ubnt-intrepidseanmonstar
authored andcommitted
feat(server): add http1_only configuration
A new configuration http1_only to Builder and Connection are added, which indicates that the upgrading to h2 does not perform when a parsing error occurs. Fixes #1512.
1 parent 785914e commit 14d9246

File tree

2 files changed

+58
-18
lines changed

2 files changed

+58
-18
lines changed

src/server/conn.rs

+50-18
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,23 @@ use error::{Kind, Parse};
3737
#[derive(Clone, Debug)]
3838
pub struct Http {
3939
exec: Exec,
40-
http2: bool,
40+
mode: ConnectionMode,
4141
keep_alive: bool,
4242
max_buf_size: Option<usize>,
4343
pipeline_flush: bool,
4444
}
4545

46+
/// The internal mode of HTTP protocol which indicates the behavior when an parse error occurs.
47+
#[derive(Clone, Debug, PartialEq)]
48+
enum ConnectionMode {
49+
/// Always use HTTP/1 and do not upgrade when an parse error occurs.
50+
H1Only,
51+
/// Always use HTTP/2.
52+
H2Only,
53+
/// Use HTTP/1 and try to upgrade to h2 when an parse error occurs.
54+
Fallback,
55+
}
56+
4657
/// A stream mapping incoming IOs to new services.
4758
///
4859
/// Yields `Connecting`s that are futures that should be put on a reactor.
@@ -94,6 +105,7 @@ where
94105
S::ResBody,
95106
>,
96107
>>,
108+
fallback: bool,
97109
}
98110

99111
/// Deconstructed parts of a `Connection`.
@@ -126,18 +138,34 @@ impl Http {
126138
pub fn new() -> Http {
127139
Http {
128140
exec: Exec::Default,
129-
http2: false,
141+
mode: ConnectionMode::Fallback,
130142
keep_alive: true,
131143
max_buf_size: None,
132144
pipeline_flush: false,
133145
}
134146
}
135147

148+
/// Sets whether HTTP1 is required.
149+
///
150+
/// Default is false
151+
pub fn http1_only(&mut self, val: bool) -> &mut Self {
152+
if val {
153+
self.mode = ConnectionMode::H1Only;
154+
} else {
155+
self.mode = ConnectionMode::Fallback;
156+
}
157+
self
158+
}
159+
136160
/// Sets whether HTTP2 is required.
137161
///
138162
/// Default is false
139163
pub fn http2_only(&mut self, val: bool) -> &mut Self {
140-
self.http2 = val;
164+
if val {
165+
self.mode = ConnectionMode::H2Only;
166+
} else {
167+
self.mode = ConnectionMode::Fallback;
168+
}
141169
self
142170
}
143171

@@ -230,25 +258,29 @@ impl Http {
230258
Bd: Payload,
231259
I: AsyncRead + AsyncWrite,
232260
{
233-
let either = if !self.http2 {
234-
let mut conn = proto::Conn::new(io);
235-
if !self.keep_alive {
236-
conn.disable_keep_alive();
261+
let either = match self.mode {
262+
ConnectionMode::H1Only | ConnectionMode::Fallback => {
263+
let mut conn = proto::Conn::new(io);
264+
if !self.keep_alive {
265+
conn.disable_keep_alive();
266+
}
267+
conn.set_flush_pipeline(self.pipeline_flush);
268+
if let Some(max) = self.max_buf_size {
269+
conn.set_max_buf_size(max);
270+
}
271+
let sd = proto::h1::dispatch::Server::new(service);
272+
Either::A(proto::h1::Dispatcher::new(sd, conn))
237273
}
238-
conn.set_flush_pipeline(self.pipeline_flush);
239-
if let Some(max) = self.max_buf_size {
240-
conn.set_max_buf_size(max);
274+
ConnectionMode::H2Only => {
275+
let rewind_io = Rewind::new(io);
276+
let h2 = proto::h2::Server::new(rewind_io, service, self.exec.clone());
277+
Either::B(h2)
241278
}
242-
let sd = proto::h1::dispatch::Server::new(service);
243-
Either::A(proto::h1::Dispatcher::new(sd, conn))
244-
} else {
245-
let rewind_io = Rewind::new(io);
246-
let h2 = proto::h2::Server::new(rewind_io, service, self.exec.clone());
247-
Either::B(h2)
248279
};
249280

250281
Connection {
251282
conn: Some(either),
283+
fallback: self.mode == ConnectionMode::Fallback,
252284
}
253285
}
254286

@@ -385,7 +417,7 @@ where
385417
Err(e) => {
386418
debug!("error polling connection protocol without shutdown: {}", e);
387419
match *e.kind() {
388-
Kind::Parse(Parse::VersionH2) => {
420+
Kind::Parse(Parse::VersionH2) if self.fallback => {
389421
self.upgrade_h2();
390422
continue;
391423
}
@@ -435,7 +467,7 @@ where
435467
Err(e) => {
436468
debug!("error polling connection protocol: {}", e);
437469
match *e.kind() {
438-
Kind::Parse(Parse::VersionH2) => {
470+
Kind::Parse(Parse::VersionH2) if self.fallback => {
439471
self.upgrade_h2();
440472
continue;
441473
}

src/server/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ impl<I> Builder<I> {
167167
}
168168
}
169169

170+
/// Sets whether HTTP/1 is required.
171+
///
172+
/// Default is `false`.
173+
pub fn http1_only(mut self, val: bool) -> Self {
174+
self.protocol.http1_only(val);
175+
self
176+
}
177+
170178
/// Sets whether HTTP/2 is required.
171179
///
172180
/// Default is `false`.

0 commit comments

Comments
 (0)