// If keep alive has been disabled and no read or write has been seen on // the connection yet, we must be in a state where the server is being asked to // shut down before any data has been seen on the connection ifself.conn.is_write_closed() || self.conn.has_initial_read_write_state() { self.close();
}
}
/// Run this dispatcher until HTTP says this connection is done, /// but don't call `Write::shutdown` on the underlying IO. /// /// This is useful for old-style HTTP upgrades, but ignores /// newer-style upgrade API. pub(crate) fn poll_without_shutdown(
&mutself,
cx: &mut Context<'_>,
) -> Poll<crate::Result<()>> {
Pin::new(self).poll_catch(cx, false).map_ok(|ds| { iflet Dispatched::Upgrade(pending) = ds {
pending.manual();
}
})
}
fn poll_catch(
&mutself,
cx: &mut Context<'_>,
should_shutdown: bool,
) -> Poll<crate::Result<Dispatched>> {
Poll::Ready(ready!(self.poll_inner(cx, should_shutdown)).or_else(|e| { // Be sure to alert a streaming body of the failure. iflet Some(mut body) = self.body_tx.take() {
body.send_error(crate::Error::new_body("connection error"));
} // An error means we're shutting down either way. // We just try to give the error to the user, // and close the connection with an Ok. If we // cannot give it to the user, then return the Err. self.dispatch.recv_msg(Err(e))?;
Ok(Dispatched::Shutdown)
}))
}
fn poll_loop(&mutself, cx: &mut Context<'_>) -> Poll<crate::Result<()>> { // Limit the looping on this connection, in case it is ready far too // often, so that other futures don't starve. // // 16 was chosen arbitrarily, as that is number of pipelined requests // benchmarks often use. Perhaps it should be a config option instead. for _ in0..16 { let _ = self.poll_read(cx)?; let _ = self.poll_write(cx)?; let _ = self.poll_flush(cx)?;
// This could happen if reading paused before blocking on IO, // such as getting to the end of a framed message, but then // writing/flushing set the state back to Init. In that case, // if the read buffer still had bytes, we'd want to try poll_read // again, or else we wouldn't ever be woken up again. // // Using this instead of task::current() and notify() inside // the Conn is noticeably faster in pipelined benchmarks. if !self.conn.wants_read_again() { //break; return Poll::Ready(Ok(()));
}
}
trace!("poll_loop yielding (self = {:p})", self);
task::yield_now(cx).map(|never| match never {})
}
fn poll_read(&mutself, cx: &mut Context<'_>) -> Poll<crate::Result<()>> { loop { ifself.is_closing { return Poll::Ready(Ok(()));
} elseifself.conn.can_read_head() {
ready!(self.poll_read_head(cx))?;
} elseiflet Some(mut body) = self.body_tx.take() { ifself.conn.can_read_body() { match body.poll_ready(cx) {
Poll::Ready(Ok(())) => (),
Poll::Pending => { self.body_tx = Some(body); return Poll::Pending;
}
Poll::Ready(Err(_canceled)) => { // user doesn't care about the body // so we should stop reading
trace!("body receiver dropped before eof, draining or closing"); self.conn.poll_drain_or_close_read(cx); continue;
}
} matchself.conn.poll_read_body(cx) {
Poll::Ready(Some(Ok(frame))) => { if frame.is_data() { let chunk = frame.into_data().unwrap_or_else(|_| unreachable!()); match body.try_send_data(chunk) {
Ok(()) => { self.body_tx = Some(body);
}
Err(_canceled) => { ifself.conn.can_read_body() {
trace!("body receiver dropped before eof, closing"); self.conn.close_read();
}
}
}
} elseif frame.is_trailers() { let trailers =
frame.into_trailers().unwrap_or_else(|_| unreachable!()); match body.try_send_trailers(trailers) {
Ok(()) => { self.body_tx = Some(body);
}
Err(_canceled) => { ifself.conn.can_read_body() {
trace!("body receiver dropped before eof, closing"); self.conn.close_read();
}
}
}
} else { // we should have dropped all unknown frames in poll_read_body
error!("unexpected frame");
}
}
Poll::Ready(None) => { // just drop, the body will close automatically
}
Poll::Pending => { self.body_tx = Some(body); return Poll::Pending;
}
Poll::Ready(Some(Err(e))) => {
body.send_error(crate::Error::new_body(e));
}
}
} else { // just drop, the body will close automatically
}
} else { returnself.conn.poll_read_keep_alive(cx);
}
}
}
fn poll_read_head(&mutself, cx: &mut Context<'_>) -> Poll<crate::Result<()>> { // can dispatch receive, or does it still care about other incoming message? match ready!(self.dispatch.poll_ready(cx)) {
Ok(()) => (),
Err(()) => {
trace!("dispatch no longer receiving messages"); self.close(); return Poll::Ready(Ok(()));
}
}
// dispatch is ready for a message, try to read one match ready!(self.conn.poll_read_head(cx)) {
Some(Ok((mut head, body_len, wants))) => { let body = match body_len {
DecodedLength::ZERO => IncomingBody::empty(),
other => { let (tx, rx) =
IncomingBody::new_channel(other, wants.contains(Wants::EXPECT)); self.body_tx = Some(tx);
rx
}
}; if wants.contains(Wants::UPGRADE) { let upgrade = self.conn.on_upgrade();
debug_assert!(!upgrade.is_none(), "empty upgrade");
debug_assert!(
head.extensions.get::<OnUpgrade>().is_none(), "OnUpgrade already set"
);
head.extensions.insert(upgrade);
} self.dispatch.recv_msg(Ok((head, body)))?;
Poll::Ready(Ok(()))
}
Some(Err(err)) => {
debug!("read_head error: {}", err); self.dispatch.recv_msg(Err(err))?; // if here, the dispatcher gave the user the error // somewhere else. we still need to shutdown, but // not as a second error. self.close();
Poll::Ready(Ok(()))
}
None => { // read eof, the write side will have been closed too unless // allow_read_close was set to true, in which case just do // nothing...
debug_assert!(self.conn.is_read_closed()); ifself.conn.is_write_closed() { self.close();
}
Poll::Ready(Ok(()))
}
}
}
if !T::should_read_first() && read_done { // a client that cannot read may was well be done. true
} else { let write_done = self.conn.is_write_closed()
|| (!self.dispatch.should_poll() && self.body_rx.is_none());
read_done && write_done
}
}
}
impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T> where
D: Dispatch<
PollItem = MessageHead<T::Outgoing>,
PollBody = Bs,
RecvItem = MessageHead<T::Incoming>,
> + Unpin,
D::PollError: Into<Box<dyn StdError + Send + Sync>>,
I: Read + Write + Unpin,
T: Http1Transaction + Unpin,
Bs: Body + 'static,
Bs::Error: Into<Box<dyn StdError + Send + Sync>>,
{ type Output = crate::Result<Dispatched>;
/// A drop guard to allow a mutable borrow of an Option while being able to /// set whether the `Option` should be cleared on drop. struct OptGuard<'a, T>(Pin<&'a mut Option<T>>, bool);
impl<B> Dispatch for Client<B> where
B: Body,
{ type PollItem = RequestHead; type PollBody = B; type PollError = Infallible; type RecvItem = crate::proto::ResponseHead;
fn poll_msg( mutself: Pin<&mutSelf>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Infallible>>> { letmut this = self.as_mut();
debug_assert!(!this.rx_closed); match this.rx.poll_recv(cx) {
Poll::Ready(Some((req, mut cb))) => { // check that future hasn't been canceled already match cb.poll_canceled(cx) {
Poll::Ready(()) => {
trace!("request canceled");
Poll::Ready(None)
}
Poll::Pending => { let (parts, body) = req.into_parts(); let head = RequestHead {
version: parts.version,
subject: crate::proto::RequestLine(parts.method, parts.uri),
headers: parts.headers,
extensions: parts.extensions,
};
this.callback = Some(cb);
Poll::Ready(Some(Ok((head, body))))
}
}
}
Poll::Ready(None) => { // user has dropped sender handle
trace!("client tx closed");
this.rx_closed = true;
Poll::Ready(None)
}
Poll::Pending => Poll::Pending,
}
}
fn recv_msg(&mutself, msg: crate::Result<(Self::RecvItem, IncomingBody)>) -> crate::Result<()> { match msg {
Ok((msg, body)) => { iflet Some(cb) = self.callback.take() { let res = msg.into_response(body);
cb.send(Ok(res));
Ok(())
} else { // Getting here is likely a bug! An error should have happened // in Conn::require_empty_read() before ever parsing a // full message!
Err(crate::Error::new_unexpected_message())
}
}
Err(err) => { iflet Some(cb) = self.callback.take() {
cb.send(Err(TrySendError {
error: err,
message: None,
}));
Ok(())
} elseif !self.rx_closed { self.rx.close(); iflet Some((req, cb)) = self.rx.try_recv() {
trace!("canceling queued request with connection error: {}", err); // in this case, the message was never even started, so it's safe to tell // the user that the request was completely canceled
cb.send(Err(TrySendError {
error: crate::Error::new_canceled().with(err),
message: Some(req),
}));
Ok(())
} else {
Err(err)
}
} else {
Err(err)
}
}
}
}
#[cfg(test)] mod tests { usesuper::*; usecrate::common::io::Compat; usecrate::proto::h1::ClientTransaction; use std::time::Duration;
#[test] fn client_read_bytes_before_writing_request() { let _ = pretty_env_logger::try_init();
tokio_test::task::spawn(()).enter(|cx, _| { let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();
// Block at 0 for now, but we will release this response before // the request is ready to write later... let (mut tx, rx) = crate::client::dispatch::channel(); let conn = Conn::<_, bytes::Bytes, ClientTransaction>::new(Compat::new(io)); letmut dispatcher = Dispatcher::new(Client::new(rx), conn);
// First poll is needed to allow tx to send...
assert!(Pin::new(&mut dispatcher).poll(cx).is_pending());
// Unblock our IO, which has a response before we've sent request! //
handle.read(b"HTTP/1.1 200 OK\r\n\r\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.