1use std::{
2 error::Error as StdError,
3 future::Future,
4 marker::Unpin,
5 pin::Pin,
6 task::{Context, Poll},
7};
8
9use crate::rt::{Read, Write};
10use bytes::{Buf, Bytes};
11use futures_core::ready;
12use http::Request;
13
14use super::{Http1Transaction, Wants};
15use crate::body::{Body, DecodedLength, Incoming as IncomingBody};
16#[cfg(feature = "client")]
17use crate::client::dispatch::TrySendError;
18use crate::common::task;
19use crate::proto::{BodyLength, Conn, Dispatched, MessageHead, RequestHead};
20use crate::upgrade::OnUpgrade;
21
22pub(crate) struct Dispatcher<D, Bs: Body, I, T> {
23 conn: Conn<I, Bs::Data, T>,
24 dispatch: D,
25 body_tx: SenderDropGuard,
26 body_rx: Pin<Box<Option<Bs>>>,
27 is_closing: bool,
28}
29
30pub(crate) trait Dispatch {
31 type PollItem;
32 type PollBody;
33 type PollError;
34 type RecvItem;
35 fn poll_msg(
36 self: Pin<&mut Self>,
37 cx: &mut Context<'_>,
38 ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>>;
39 fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, IncomingBody)>)
40 -> crate::Result<()>;
41 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>>;
42 fn should_poll(&self) -> bool;
43}
44
45cfg_server! {
46 use crate::service::HttpService;
47
48 pub(crate) struct Server<S: HttpService<B>, B> {
49 in_flight: Pin<Box<Option<S::Future>>>,
50 pub(crate) service: S,
51 }
52}
53
54cfg_client! {
55 pin_project_lite::pin_project! {
56 pub(crate) struct Client<B> {
57 callback: Option<crate::client::dispatch::Callback<Request<B>, http::Response<IncomingBody>>>,
58 #[pin]
59 rx: ClientRx<B>,
60 rx_closed: bool,
61 }
62 }
63
64 type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, http::Response<IncomingBody>>;
65}
66
67impl<D, Bs, I, T> Dispatcher<D, Bs, I, T>
68where
69 D: Dispatch<
70 PollItem = MessageHead<T::Outgoing>,
71 PollBody = Bs,
72 RecvItem = MessageHead<T::Incoming>,
73 > + Unpin,
74 D::PollError: Into<Box<dyn StdError + Send + Sync>>,
75 I: Read + Write + Unpin,
76 T: Http1Transaction + Unpin,
77 Bs: Body + 'static,
78 Bs::Error: Into<Box<dyn StdError + Send + Sync>>,
79{
80 pub(crate) fn new(dispatch: D, conn: Conn<I, Bs::Data, T>) -> Self {
81 Dispatcher {
82 conn,
83 dispatch,
84 body_tx: SenderDropGuard::none(),
85 body_rx: Box::pin(None),
86 is_closing: false,
87 }
88 }
89
90 #[cfg(feature = "server")]
91 pub(crate) fn disable_keep_alive(&mut self) {
92 self.conn.disable_keep_alive();
93
94 if self.conn.is_write_closed() || self.conn.has_initial_read_write_state() {
98 self.close();
99 }
100 }
101
102 pub(crate) fn into_inner(self) -> (I, Bytes, D) {
103 let (io, buf) = self.conn.into_inner();
104 (io, buf, self.dispatch)
105 }
106
107 pub(crate) fn poll_without_shutdown(
113 &mut self,
114 cx: &mut Context<'_>,
115 ) -> Poll<crate::Result<()>> {
116 Pin::new(self).poll_catch(cx, false).map_ok(|ds| {
117 if let Dispatched::Upgrade(pending) = ds {
118 pending.manual();
119 }
120 })
121 }
122
123 fn poll_catch(
124 &mut self,
125 cx: &mut Context<'_>,
126 should_shutdown: bool,
127 ) -> Poll<crate::Result<Dispatched>> {
128 Poll::Ready(ready!(self.poll_inner(cx, should_shutdown)).or_else(|e| {
129 if let Some(mut body) = self.body_tx.take() {
132 body.send_error(crate::Error::new_body("connection error"));
133 }
134 self.dispatch.recv_msg(Err(e))?;
139 Ok(Dispatched::Shutdown)
140 }))
141 }
142
143 fn poll_inner(
144 &mut self,
145 cx: &mut Context<'_>,
146 should_shutdown: bool,
147 ) -> Poll<crate::Result<Dispatched>> {
148 T::update_date();
149
150 ready!(self.poll_loop(cx))?;
151
152 if self.is_done() {
153 if let Some(pending) = self.conn.pending_upgrade() {
154 self.conn.take_error()?;
155 return Poll::Ready(Ok(Dispatched::Upgrade(pending)));
156 } else if should_shutdown {
157 ready!(self.conn.poll_shutdown(cx)).map_err(crate::Error::new_shutdown)?;
158 }
159 self.conn.take_error()?;
160 Poll::Ready(Ok(Dispatched::Shutdown))
161 } else {
162 Poll::Pending
163 }
164 }
165
166 fn poll_loop(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
167 for _ in 0..16 {
173 let _ = self.poll_read(cx)?;
174 let write_ready = self.poll_write(cx)?.is_ready();
175 let flush_ready = self.poll_flush(cx)?.is_ready();
176
177 let wants_write_again = self.can_write_again() && (write_ready || flush_ready);
182
183 let wants_read_again = self.conn.wants_read_again();
192
193 if !(wants_write_again || wants_read_again) {
196 return Poll::Ready(Ok(()));
197 }
198
199 if !wants_read_again && wants_write_again {
204 if self.poll_write(cx)?.is_pending() {
208 return Poll::Ready(Ok(()));
209 }
210 }
211 }
212 trace!("poll_loop yielding (self = {:p})", self);
213 task::yield_now(cx).map(|never| match never {})
214 }
215
216 fn poll_read(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
217 loop {
218 if self.is_closing {
219 return Poll::Ready(Ok(()));
220 } else if self.conn.can_read_head() {
221 ready!(self.poll_read_head(cx))?;
222 } else if let Some(mut body) = self.body_tx.take() {
223 if self.conn.can_read_body() {
224 match body.poll_ready(cx) {
225 Poll::Ready(Ok(())) => (),
226 Poll::Pending => {
227 self.body_tx.set(body);
228 return Poll::Pending;
229 }
230 Poll::Ready(Err(_canceled)) => {
231 trace!("body receiver dropped before eof, draining or closing");
234 self.conn.poll_drain_or_close_read(cx);
235 continue;
236 }
237 }
238 match self.conn.poll_read_body(cx) {
239 Poll::Ready(Some(Ok(frame))) => {
240 if frame.is_data() {
241 let chunk = frame.into_data().unwrap_or_else(|_| unreachable!());
242 match body.try_send_data(chunk) {
243 Ok(()) => {
244 self.body_tx.set(body);
245 }
246 Err(_canceled) => {
247 if self.conn.can_read_body() {
248 trace!("body receiver dropped before eof, closing");
249 self.conn.close_read();
250 }
251 }
252 }
253 } else if frame.is_trailers() {
254 let trailers =
255 frame.into_trailers().unwrap_or_else(|_| unreachable!());
256 match body.try_send_trailers(trailers) {
257 Ok(()) => {
258 self.body_tx.set(body);
259 }
260 Err(_canceled) => {
261 if self.conn.can_read_body() {
262 trace!("body receiver dropped before eof, closing");
263 self.conn.close_read();
264 }
265 }
266 }
267 } else {
268 error!("unexpected frame");
270 }
271 }
272 Poll::Ready(None) => {
273 }
275 Poll::Pending => {
276 self.body_tx.set(body);
277 return Poll::Pending;
278 }
279 Poll::Ready(Some(Err(e))) => {
280 body.send_error(crate::Error::new_body(e));
281 }
282 }
283 } else {
284 }
286 } else {
287 return self.conn.poll_read_keep_alive(cx);
288 }
289 }
290 }
291
292 fn poll_read_head(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
293 if let Ok(()) = ready!(self.dispatch.poll_ready(cx)) {
295 } else {
296 trace!("dispatch no longer receiving messages");
297 self.close();
298 return Poll::Ready(Ok(()));
299 }
300
301 match ready!(self.conn.poll_read_head(cx)) {
303 Some(Ok((mut head, body_len, wants))) => {
304 let body = match body_len {
305 DecodedLength::ZERO => IncomingBody::empty(),
306 other => {
307 let (tx, rx) =
308 IncomingBody::new_channel(other, wants.contains(Wants::EXPECT));
309 self.body_tx.set(tx);
310 rx
311 }
312 };
313 if wants.contains(Wants::UPGRADE) {
314 let upgrade = self.conn.on_upgrade();
315 debug_assert!(!upgrade.is_none(), "empty upgrade");
316 debug_assert!(
317 head.extensions.get::<OnUpgrade>().is_none(),
318 "OnUpgrade already set"
319 );
320 head.extensions.insert(upgrade);
321 }
322 self.dispatch.recv_msg(Ok((head, body)))?;
323 Poll::Ready(Ok(()))
324 }
325 Some(Err(err)) => {
326 debug!("read_head error: {}", err);
327 self.dispatch.recv_msg(Err(err))?;
328 self.close();
332 Poll::Ready(Ok(()))
333 }
334 None => {
335 debug_assert!(self.conn.is_read_closed());
339 if self.conn.is_write_closed() {
340 self.close();
341 }
342 Poll::Ready(Ok(()))
343 }
344 }
345 }
346
347 fn poll_write(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
348 loop {
349 if self.is_closing {
350 return Poll::Ready(Ok(()));
351 } else if self.body_rx.is_none()
352 && self.conn.can_write_head()
353 && self.dispatch.should_poll()
354 {
355 if let Some(msg) = ready!(Pin::new(&mut self.dispatch).poll_msg(cx)) {
356 let (head, body) = msg.map_err(crate::Error::new_user_service)?;
357
358 let body_type = if body.is_end_stream() {
359 self.body_rx.set(None);
360 None
361 } else {
362 let btype = body
363 .size_hint()
364 .exact()
365 .map(BodyLength::Known)
366 .or(Some(BodyLength::Unknown));
367 self.body_rx.set(Some(body));
368 btype
369 };
370 self.conn.write_head(head, body_type);
371 } else {
372 self.close();
373 return Poll::Ready(Ok(()));
374 }
375 } else if !self.conn.can_buffer_body() {
376 ready!(self.poll_flush(cx))?;
377 } else {
378 if let (Some(mut body), clear_body) =
380 OptGuard::new(self.body_rx.as_mut()).guard_mut()
381 {
382 debug_assert!(!*clear_body, "opt guard defaults to keeping body");
383 if !self.conn.can_write_body() {
384 trace!(
385 "no more write body allowed, user body is_end_stream = {}",
386 body.is_end_stream(),
387 );
388 *clear_body = true;
389 continue;
390 }
391
392 let item = ready!(body.as_mut().poll_frame(cx));
393 if let Some(item) = item {
394 let frame = item.map_err(|e| {
395 *clear_body = true;
396 crate::Error::new_user_body(e)
397 })?;
398
399 if frame.is_data() {
400 let chunk = frame.into_data().unwrap_or_else(|_| unreachable!());
401 let eos = body.is_end_stream();
402 if eos {
403 *clear_body = true;
404 if chunk.remaining() == 0 {
405 trace!("discarding empty chunk");
406 self.conn.end_body()?;
407 } else {
408 self.conn.write_body_and_end(chunk);
409 }
410 } else {
411 if chunk.remaining() == 0 {
412 trace!("discarding empty chunk");
413 continue;
414 }
415 self.conn.write_body(chunk);
416 }
417 } else if frame.is_trailers() {
418 *clear_body = true;
419 self.conn.write_trailers(
420 frame.into_trailers().unwrap_or_else(|_| unreachable!()),
421 );
422 } else {
423 trace!("discarding unknown frame");
424 continue;
425 }
426 } else {
427 *clear_body = true;
428 self.conn.end_body()?;
429 }
430 } else {
431 if self.conn.can_write_body() {
433 self.conn.end_body()?;
434 } else {
435 return Poll::Pending;
436 }
437 }
438 }
439 }
440 }
441
442 fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {
443 self.conn.poll_flush(cx).map_err(|err| {
444 debug!("error writing: {}", err);
445 crate::Error::new_body_write(err)
446 })
447 }
448
449 fn close(&mut self) {
450 self.is_closing = true;
451 self.conn.close_read();
452 self.conn.close_write();
453 }
454
455 fn can_write_again(&mut self) -> bool {
458 !self.is_closing && self.body_rx.is_some() && self.conn.can_write_body()
459 }
460
461 fn is_done(&self) -> bool {
462 if self.is_closing {
463 return true;
464 }
465
466 let read_done = self.conn.is_read_closed();
467
468 if !T::should_read_first() && read_done {
469 true
471 } else {
472 let write_done = self.conn.is_write_closed()
473 || (!self.dispatch.should_poll() && self.body_rx.is_none());
474 read_done && write_done
475 }
476 }
477}
478
479impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T>
480where
481 D: Dispatch<
482 PollItem = MessageHead<T::Outgoing>,
483 PollBody = Bs,
484 RecvItem = MessageHead<T::Incoming>,
485 > + Unpin,
486 D::PollError: Into<Box<dyn StdError + Send + Sync>>,
487 I: Read + Write + Unpin,
488 T: Http1Transaction + Unpin,
489 Bs: Body + 'static,
490 Bs::Error: Into<Box<dyn StdError + Send + Sync>>,
491{
492 type Output = crate::Result<Dispatched>;
493
494 #[inline]
495 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
496 self.poll_catch(cx, true)
497 }
498}
499
500struct OptGuard<'a, T>(Pin<&'a mut Option<T>>, bool);
505
506impl<'a, T> OptGuard<'a, T> {
507 fn new(pin: Pin<&'a mut Option<T>>) -> Self {
508 OptGuard(pin, false)
509 }
510
511 fn guard_mut(&mut self) -> (Option<Pin<&mut T>>, &mut bool) {
512 (self.0.as_mut().as_pin_mut(), &mut self.1)
513 }
514}
515
516impl<T> Drop for OptGuard<'_, T> {
517 fn drop(&mut self) {
518 if self.1 {
519 self.0.set(None);
520 }
521 }
522}
523
524struct SenderDropGuard(Option<crate::body::Sender>);
533
534impl SenderDropGuard {
535 fn none() -> Self {
536 SenderDropGuard(None)
537 }
538
539 fn set(&mut self, sender: crate::body::Sender) {
540 self.0 = Some(sender);
541 }
542
543 fn take(&mut self) -> Option<crate::body::Sender> {
544 self.0.take()
545 }
546}
547
548impl Drop for SenderDropGuard {
549 fn drop(&mut self) {
550 if let Some(mut sender) = self.0.take() {
551 sender.send_error(crate::Error::new_incomplete());
552 }
553 }
554}
555
556cfg_server! {
559 impl<S, B> Server<S, B>
560 where
561 S: HttpService<B>,
562 {
563 pub(crate) fn new(service: S) -> Server<S, B> {
564 Server {
565 in_flight: Box::pin(None),
566 service,
567 }
568 }
569
570 pub(crate) fn into_service(self) -> S {
571 self.service
572 }
573 }
574
575 impl<S: HttpService<B>, B> Unpin for Server<S, B> {}
577
578 impl<S, Bs> Dispatch for Server<S, IncomingBody>
579 where
580 S: HttpService<IncomingBody, ResBody = Bs>,
581 S::Error: Into<Box<dyn StdError + Send + Sync>>,
582 Bs: Body,
583 {
584 type PollItem = MessageHead<http::StatusCode>;
585 type PollBody = Bs;
586 type PollError = S::Error;
587 type RecvItem = RequestHead;
588
589 fn poll_msg(
590 mut self: Pin<&mut Self>,
591 cx: &mut Context<'_>,
592 ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>> {
593 let mut this = self.as_mut();
594 let ret = if let Some(ref mut fut) = this.in_flight.as_mut().as_pin_mut() {
595 let resp = ready!(fut.as_mut().poll(cx)?);
596 let (parts, body) = resp.into_parts();
597 let head = MessageHead {
598 version: parts.version,
599 subject: parts.status,
600 headers: parts.headers,
601 extensions: parts.extensions,
602 };
603 Poll::Ready(Some(Ok((head, body))))
604 } else {
605 unreachable!("poll_msg shouldn't be called if no inflight");
606 };
607
608 this.in_flight.set(None);
610 ret
611 }
612
613 fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, IncomingBody)>) -> crate::Result<()> {
614 let (msg, body) = msg?;
615 let mut req = Request::new(body);
616 *req.method_mut() = msg.subject.0;
617 *req.uri_mut() = msg.subject.1;
618 *req.headers_mut() = msg.headers;
619 *req.version_mut() = msg.version;
620 *req.extensions_mut() = msg.extensions;
621 let fut = self.service.call(req);
622 self.in_flight.set(Some(fut));
623 Ok(())
624 }
625
626 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
627 if self.in_flight.is_some() {
628 Poll::Pending
629 } else {
630 Poll::Ready(Ok(()))
631 }
632 }
633
634 fn should_poll(&self) -> bool {
635 self.in_flight.is_some()
636 }
637 }
638}
639
640cfg_client! {
643 use std::convert::Infallible;
644
645 impl<B> Client<B> {
646 pub(crate) fn new(rx: ClientRx<B>) -> Client<B> {
647 Client {
648 callback: None,
649 rx,
650 rx_closed: false,
651 }
652 }
653 }
654
655 impl<B> Dispatch for Client<B>
656 where
657 B: Body,
658 {
659 type PollItem = RequestHead;
660 type PollBody = B;
661 type PollError = Infallible;
662 type RecvItem = crate::proto::ResponseHead;
663
664 fn poll_msg(
665 mut self: Pin<&mut Self>,
666 cx: &mut Context<'_>,
667 ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Infallible>>> {
668 let mut this = self.as_mut();
669 debug_assert!(!this.rx_closed);
670 match this.rx.poll_recv(cx) {
671 Poll::Ready(Some((req, mut cb))) => {
672 match cb.poll_canceled(cx) {
674 Poll::Ready(()) => {
675 trace!("request canceled");
676 Poll::Ready(None)
677 }
678 Poll::Pending => {
679 let (parts, body) = req.into_parts();
680 let head = RequestHead {
681 version: parts.version,
682 subject: crate::proto::RequestLine(parts.method, parts.uri),
683 headers: parts.headers,
684 extensions: parts.extensions,
685 };
686 this.callback = Some(cb);
687 Poll::Ready(Some(Ok((head, body))))
688 }
689 }
690 }
691 Poll::Ready(None) => {
692 trace!("client tx closed");
694 this.rx_closed = true;
695 Poll::Ready(None)
696 }
697 Poll::Pending => Poll::Pending,
698 }
699 }
700
701 fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, IncomingBody)>) -> crate::Result<()> {
702 match msg {
703 Ok((msg, body)) => {
704 if let Some(cb) = self.callback.take() {
705 let res = msg.into_response(body);
706 cb.send(Ok(res));
707 Ok(())
708 } else {
709 Err(crate::Error::new_unexpected_message())
713 }
714 }
715 Err(err) => {
716 if let Some(cb) = self.callback.take() {
717 cb.send(Err(TrySendError {
718 error: err,
719 message: None,
720 }));
721 Ok(())
722 } else if !self.rx_closed {
723 self.rx.close();
724 if let Some((req, cb)) = self.rx.try_recv() {
725 trace!("canceling queued request with connection error: {}", err);
726 cb.send(Err(TrySendError {
729 error: crate::Error::new_canceled().with(err),
730 message: Some(req),
731 }));
732 Ok(())
733 } else {
734 Err(err)
735 }
736 } else {
737 Err(err)
738 }
739 }
740 }
741 }
742
743 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
744 match self.callback {
745 Some(ref mut cb) => match cb.poll_canceled(cx) {
746 Poll::Ready(()) => {
747 trace!("callback receiver has dropped");
748 Poll::Ready(Err(()))
749 }
750 Poll::Pending => Poll::Ready(Ok(())),
751 },
752 None => Poll::Ready(Err(())),
753 }
754 }
755
756 fn should_poll(&self) -> bool {
757 self.callback.is_none()
758 }
759 }
760}
761
762#[cfg(test)]
763mod tests {
764 use super::*;
765 use crate::common::io::Compat;
766 use crate::proto::h1::ClientTransaction;
767 use std::time::Duration;
768
769 #[test]
770 fn client_read_bytes_before_writing_request() {
771 let _ = pretty_env_logger::try_init();
772
773 tokio_test::task::spawn(()).enter(|cx, _| {
774 let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
775
776 let (mut tx, rx) = crate::client::dispatch::channel();
779 let conn = Conn::<_, bytes::Bytes, ClientTransaction>::new(Compat::new(io));
780 let mut dispatcher = Dispatcher::new(Client::new(rx), conn);
781
782 assert!(Pin::new(&mut dispatcher).poll(cx).is_pending());
784
785 handle.read(b"HTTP/1.1 200 OK\r\n\r\n");
788
789 let mut res_rx = tx
790 .try_send(crate::Request::new(IncomingBody::empty()))
791 .unwrap();
792
793 tokio_test::assert_ready_ok!(Pin::new(&mut dispatcher).poll(cx));
794 let err = tokio_test::assert_ready_ok!(Pin::new(&mut res_rx).poll(cx))
795 .expect_err("callback should send error");
796
797 match (err.error.is_canceled(), err.message.as_ref()) {
798 (true, Some(_)) => (),
799 _ => panic!("expected Canceled, got {:?}", err),
800 }
801 });
802 }
803
804 #[cfg(not(miri))]
805 #[tokio::test]
806 async fn client_flushing_is_not_ready_for_next_request() {
807 let _ = pretty_env_logger::try_init();
808
809 let (io, _handle) = tokio_test::io::Builder::new()
810 .write(b"POST / HTTP/1.1\r\ncontent-length: 4\r\n\r\n")
811 .read(b"HTTP/1.1 200 OK\r\ncontent-length: 0\r\n\r\n")
812 .wait(std::time::Duration::from_secs(2))
813 .build_with_handle();
814
815 let (mut tx, rx) = crate::client::dispatch::channel();
816 let mut conn = Conn::<_, bytes::Bytes, ClientTransaction>::new(Compat::new(io));
817 conn.set_write_strategy_queue();
818
819 let dispatcher = Dispatcher::new(Client::new(rx), conn);
820 let _dispatcher = tokio::spawn(async move { dispatcher.await });
821
822 let body = {
823 let (mut tx, body) = IncomingBody::new_channel(DecodedLength::new(4), false);
824 tx.try_send_data("reee".into()).unwrap();
825 body
826 };
827
828 let req = crate::Request::builder().method("POST").body(body).unwrap();
829
830 let res = tx.try_send(req).unwrap().await.expect("response");
831 drop(res);
832
833 assert!(!tx.is_ready());
834 }
835
836 #[cfg(not(miri))]
837 #[tokio::test]
838 async fn body_empty_chunks_ignored() {
839 let _ = pretty_env_logger::try_init();
840
841 let io = tokio_test::io::Builder::new()
842 .wait(Duration::from_secs(5))
844 .build();
845
846 let (mut tx, rx) = crate::client::dispatch::channel();
847 let conn = Conn::<_, bytes::Bytes, ClientTransaction>::new(Compat::new(io));
848 let mut dispatcher = tokio_test::task::spawn(Dispatcher::new(Client::new(rx), conn));
849
850 assert!(dispatcher.poll().is_pending());
852
853 let body = {
854 let (mut tx, body) = IncomingBody::channel();
855 tx.try_send_data("".into()).unwrap();
856 body
857 };
858
859 let _res_rx = tx.try_send(crate::Request::new(body)).unwrap();
860
861 assert!(dispatcher.poll().is_pending());
864 }
865}