|
38 | 38 | B: Payload,
|
39 | 39 | {
|
40 | 40 | conn: Connection<T, SendBuf<B::Data>>,
|
| 41 | + closing: Option<::Error>, |
41 | 42 | }
|
42 | 43 |
|
43 | 44 |
|
|
46 | 47 | T: AsyncRead + AsyncWrite,
|
47 | 48 | S: Service<ReqBody=Body, ResBody=B>,
|
48 | 49 | S::Error: Into<Box<::std::error::Error + Send + Sync>>,
|
49 |
| - //S::Future: Send + 'static, |
50 | 50 | B: Payload,
|
51 | 51 | E: H2Exec<S::Future, B>,
|
52 | 52 | {
|
|
66 | 66 | // fall-through, to replace state with Closed
|
67 | 67 | },
|
68 | 68 | State::Serving(ref mut srv) => {
|
69 |
| - srv.conn.graceful_shutdown(); |
| 69 | + if srv.closing.is_none() { |
| 70 | + srv.conn.graceful_shutdown(); |
| 71 | + } |
70 | 72 | return;
|
71 | 73 | },
|
72 | 74 | State::Closed => {
|
|
82 | 84 | T: AsyncRead + AsyncWrite,
|
83 | 85 | S: Service<ReqBody=Body, ResBody=B>,
|
84 | 86 | S::Error: Into<Box<::std::error::Error + Send + Sync>>,
|
85 |
| - //S::Future: Send + 'static, |
86 | 87 | B: Payload,
|
87 | 88 | E: H2Exec<S::Future, B>,
|
88 | 89 | {
|
|
95 | 96 | State::Handshaking(ref mut h) => {
|
96 | 97 | let conn = try_ready!(h.poll().map_err(::Error::new_h2));
|
97 | 98 | State::Serving(Serving {
|
98 |
| - conn: conn, |
| 99 | + conn, |
| 100 | + closing: None, |
99 | 101 | })
|
100 | 102 | },
|
101 | 103 | State::Serving(ref mut srv) => {
|
@@ -127,37 +129,57 @@ where
|
127 | 129 | S::Error: Into<Box<::std::error::Error + Send + Sync>>,
|
128 | 130 | E: H2Exec<S::Future, B>,
|
129 | 131 | {
|
130 |
| - loop { |
131 |
| - // At first, polls the readiness of supplied service. |
132 |
| - match service.poll_ready() { |
133 |
| - Ok(Async::Ready(())) => (), |
134 |
| - Ok(Async::NotReady) => { |
135 |
| - // use `poll_close` instead of `poll`, in order to avoid accepting a request. |
136 |
| - try_ready!(self.conn.poll_close().map_err(::Error::new_h2)); |
137 |
| - trace!("incoming connection complete"); |
138 |
| - return Ok(Async::Ready(())); |
139 |
| - } |
140 |
| - Err(err) => { |
141 |
| - trace!("service closed"); |
142 |
| - return Err(::Error::new_user_service(err)); |
| 132 | + if self.closing.is_none() { |
| 133 | + loop { |
| 134 | + // At first, polls the readiness of supplied service. |
| 135 | + match service.poll_ready() { |
| 136 | + Ok(Async::Ready(())) => (), |
| 137 | + Ok(Async::NotReady) => { |
| 138 | + // use `poll_close` instead of `poll`, in order to avoid accepting a request. |
| 139 | + try_ready!(self.conn.poll_close().map_err(::Error::new_h2)); |
| 140 | + trace!("incoming connection complete"); |
| 141 | + return Ok(Async::Ready(())); |
| 142 | + } |
| 143 | + Err(err) => { |
| 144 | + let err = ::Error::new_user_service(err); |
| 145 | + debug!("service closed: {}", err); |
| 146 | + |
| 147 | + let reason = err.h2_reason(); |
| 148 | + if reason == h2::Reason::NO_ERROR { |
| 149 | + // NO_ERROR is only used for graceful shutdowns... |
| 150 | + trace!("interpretting NO_ERROR user error as graceful_shutdown"); |
| 151 | + self.conn.graceful_shutdown(); |
| 152 | + } else { |
| 153 | + trace!("abruptly shutting down with {:?}", reason); |
| 154 | + self.conn.abrupt_shutdown(reason); |
| 155 | + } |
| 156 | + self.closing = Some(err); |
| 157 | + break; |
| 158 | + } |
143 | 159 | }
|
144 |
| - } |
145 | 160 |
|
146 |
| - // When the service is ready, accepts an incoming request. |
147 |
| - if let Some((req, respond)) = try_ready!(self.conn.poll().map_err(::Error::new_h2)) { |
148 |
| - trace!("incoming request"); |
149 |
| - let content_length = content_length_parse_all(req.headers()); |
150 |
| - let req = req.map(|stream| { |
151 |
| - ::Body::h2(stream, content_length) |
152 |
| - }); |
153 |
| - let fut = H2Stream::new(service.call(req), respond); |
154 |
| - exec.execute_h2stream(fut)?; |
155 |
| - } else { |
156 |
| - // no more incoming streams... |
157 |
| - trace!("incoming connection complete"); |
158 |
| - return Ok(Async::Ready(())) |
| 161 | + // When the service is ready, accepts an incoming request. |
| 162 | + if let Some((req, respond)) = try_ready!(self.conn.poll().map_err(::Error::new_h2)) { |
| 163 | + trace!("incoming request"); |
| 164 | + let content_length = content_length_parse_all(req.headers()); |
| 165 | + let req = req.map(|stream| { |
| 166 | + ::Body::h2(stream, content_length) |
| 167 | + }); |
| 168 | + let fut = H2Stream::new(service.call(req), respond); |
| 169 | + exec.execute_h2stream(fut)?; |
| 170 | + } else { |
| 171 | + // no more incoming streams... |
| 172 | + trace!("incoming connection complete"); |
| 173 | + return Ok(Async::Ready(())) |
| 174 | + } |
159 | 175 | }
|
160 | 176 | }
|
| 177 | + |
| 178 | + debug_assert!(self.closing.is_some(), "poll_server broke loop without closing"); |
| 179 | + |
| 180 | + try_ready!(self.conn.poll_close().map_err(::Error::new_h2)); |
| 181 | + |
| 182 | + Err(self.closing.take().expect("polled after error")) |
161 | 183 | }
|
162 | 184 | }
|
163 | 185 |
|
|
0 commit comments