use bytes::{Buf, Bytes}; use http::{HeaderMap, Request, Response}; use std::task::{Context, Poll, Waker}; use tokio::io::AsyncWrite;
use std::sync::{Arc, Mutex}; use std::{fmt, io};
#[derive(Debug)] pub(crate) struct Streams<B, P> where
P: Peer,
{ /// Holds most of the connection and stream related state for processing /// HTTP/2 frames associated with streams.
inner: Arc<Mutex<Inner>>,
/// This is the queue of frames to be written to the wire. This is split out /// to avoid requiring a `B` generic on all public API types even if `B` is /// not technically required. /// /// Currently, splitting this out requires a second `Arc` + `Mutex`. /// However, it should be possible to avoid this duplication with a little /// bit of unsafe code. This optimization has been postponed until it has /// been shown to be necessary.
send_buffer: Arc<SendBuffer<B>>,
_p: ::std::marker::PhantomData<P>,
}
// Like `Streams` but with a `peer::Dyn` field instead of a static `P: Peer` type parameter. // Ensures that the methods only get one instantiation, instead of two (client and server) #[derive(Debug)] pub(crate) struct DynStreams<'a, B> {
inner: &'a Mutex<Inner>,
send_buffer: &'a SendBuffer<B>,
peer: peer::Dyn,
}
/// Reference to the stream state #[derive(Debug)] pub(crate) struct StreamRef<B> {
opaque: OpaqueStreamRef,
send_buffer: Arc<SendBuffer<B>>,
}
/// Reference to the stream state that hides the send data chunk generic pub(crate) struct OpaqueStreamRef {
inner: Arc<Mutex<Inner>>,
key: store::Key,
}
/// Fields needed to manage state related to managing the set of streams. This /// is mostly split out to make ownership happy. /// /// TODO: better name #[derive(Debug)] struct Inner { /// Tracks send & recv stream concurrency.
counts: Counts,
/// Connection level state and performs actions on streams
actions: Actions,
/// Stores stream state
store: Store,
/// The number of stream refs to this shared state.
refs: usize,
}
#[derive(Debug)] struct Actions { /// Manages state transitions initiated by receiving frames
recv: Recv,
/// Manages state transitions initiated by sending frames
send: Send,
/// Task that calls `poll_complete`.
task: Option<Waker>,
/// If the connection errors, a copy is kept for any StreamRefs.
conn_error: Option<proto::Error>,
}
/// Contains the buffer of frames to be written to the wire. #[derive(Debug)] struct SendBuffer<B> {
inner: Mutex<Buffer<Frame<B>>>,
}
// ===== impl Streams =====
impl<B, P> Streams<B, P> where
B: Buf,
P: Peer,
{ pubfn new(config: Config) -> Self { let peer = P::r#dyn();
pubfn next_incoming(&mutself) -> Option<StreamRef<B>> { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
me.actions.recv.next_incoming(&mut me.store).map(|key| { let stream = &mut me.store.resolve(key);
tracing::trace!( "next_incoming; id={:?}, state={:?}",
stream.id,
stream.state
); // TODO: ideally, OpaqueStreamRefs::new would do this, but we're holding // the lock, so it can't.
me.refs += 1;
// Pending-accepted remotely-reset streams are counted. if stream.state.is_remote_reset() {
me.counts.dec_num_remote_reset_streams();
}
let protocol = request.extensions_mut().remove::<Protocol>();
// Clear before taking lock, incase extensions contain a StreamRef.
request.extensions_mut().clear();
// TODO: There is a hazard with assigning a stream ID before the // prioritize layer. If prioritization reorders new streams, this // implicitly closes the earlier stream IDs. // // See: hyperium/h2#11 letmut me = self.inner.lock().unwrap(); let me = &mut *me;
letmut send_buffer = self.send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
// The `pending` argument is provided by the `Client`, and holds // a store `Key` of a `Stream` that may have been not been opened // yet. // // If that stream is still pending, the Client isn't allowed to // queue up another pending stream. They should use `poll_ready`. iflet Some(stream) = pending { if me.store.resolve(stream.key).is_pending_open { return Err(UserError::Rejected.into());
}
}
if me.counts.peer().is_server() { // Servers cannot open streams. PushPromise must first be reserved. return Err(UserError::UnexpectedFrameType.into());
}
let sent = me.actions.send.send_headers(
headers,
send_buffer,
&mut stream,
&mut me.counts,
&mut me.actions.task,
);
// send_headers can return a UserError, if it does, // we should forget about this stream. iflet Err(err) = sent {
stream.unlink();
stream.remove(); return Err(err.into());
}
// Given that the stream has been initialized, it should not be in the // closed state.
debug_assert!(!stream.state.is_closed());
// TODO: ideally, OpaqueStreamRefs::new would do this, but we're holding // the lock, so it can't.
me.refs += 1;
fn recv_headers<B>(
&mutself,
peer: peer::Dyn,
send_buffer: &SendBuffer<B>,
frame: frame::Headers,
) -> Result<(), Error> { let id = frame.stream_id();
// The GOAWAY process has begun. All streams with a greater ID than // specified as part of GOAWAY should be ignored. if id > self.actions.recv.max_stream_id() {
tracing::trace!( "id ({:?}) > max_stream_id ({:?}), ignoring HEADERS",
id, self.actions.recv.max_stream_id()
); return Ok(());
}
let key = matchself.store.find_entry(id) {
Entry::Occupied(e) => e.key(),
Entry::Vacant(e) => { // Client: it's possible to send a request, and then send // a RST_STREAM while the response HEADERS were in transit. // // Server: we can't reset a stream before having received // the request headers, so don't allow. if !peer.is_server() { // This may be response headers for a stream we've already // forgotten about... ifself.actions.may_have_forgotten_stream(peer, id) {
tracing::debug!( "recv_headers for old stream={:?}, sending STREAM_CLOSED",
id,
); return Err(Error::library_reset(id, Reason::STREAM_CLOSED));
}
}
if stream.state.is_local_error() { // Locally reset streams must ignore frames "for some time". // This is because the remote may have sent trailers before // receiving the RST_STREAM frame.
tracing::trace!("recv_headers; ignoring trailers on {:?}", stream.id); return Ok(());
}
let actions = &mutself.actions; letmut send_buffer = send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
let res = if stream.state.is_recv_headers() { match actions.recv.recv_headers(frame, stream, counts) {
Ok(()) => Ok(()),
Err(RecvHeaderBlockError::Oversize(resp)) => { iflet Some(resp) = resp { let sent = actions.send.send_headers(
resp, send_buffer, stream, counts, &mut actions.task);
debug_assert!(sent.is_ok(), "oversize response should not fail");
Ok(())
} else {
Err(Error::library_reset(stream.id, Reason::REFUSED_STREAM))
}
},
Err(RecvHeaderBlockError::State(err)) => Err(err),
}
} else { if !frame.is_end_stream() { // Receiving trailers that don't set EOS is a "malformed" // message. Malformed messages are a stream error.
proto_err!(stream: "recv_headers: trailers frame was not EOS; stream={:?}", stream.id); return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR));
}
fn recv_data<B>(
&mutself,
peer: peer::Dyn,
send_buffer: &SendBuffer<B>,
frame: frame::Data,
) -> Result<(), Error> { let id = frame.stream_id();
let stream = matchself.store.find_mut(&id) {
Some(stream) => stream,
None => { // The GOAWAY process has begun. All streams with a greater ID // than specified as part of GOAWAY should be ignored. if id > self.actions.recv.max_stream_id() {
tracing::trace!( "id ({:?}) > max_stream_id ({:?}), ignoring DATA",
id, self.actions.recv.max_stream_id()
); return Ok(());
}
ifself.actions.may_have_forgotten_stream(peer, id) {
tracing::debug!("recv_data for old stream={:?}, sending STREAM_CLOSED", id,);
let sz = frame.payload().len(); // This should have been enforced at the codec::FramedRead layer, so // this is just a sanity check.
assert!(sz <= super::MAX_WINDOW_SIZE as usize); let sz = sz as WindowSize;
let actions = &mutself.actions; letmut send_buffer = send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
self.counts.transition(stream, |counts, stream| { let sz = frame.payload().len(); let res = actions.recv.recv_data(frame, stream);
// Any stream error after receiving a DATA frame means // we won't give the data to the user, and so they can't // release the capacity. We do it automatically. iflet Err(Error::Reset(..)) = res {
actions
.recv
.release_connection_capacity(sz as WindowSize, &mut None);
}
actions.reset_on_recv_stream_err(send_buffer, stream, counts, res)
})
}
fn recv_reset<B>(
&mutself,
send_buffer: &SendBuffer<B>,
frame: frame::Reset,
) -> Result<(), Error> { let id = frame.stream_id();
if id.is_zero() {
proto_err!(conn: "recv_reset: invalid stream ID 0"); return Err(Error::library_go_away(Reason::PROTOCOL_ERROR));
}
// The GOAWAY process has begun. All streams with a greater ID than // specified as part of GOAWAY should be ignored. if id > self.actions.recv.max_stream_id() {
tracing::trace!( "id ({:?}) > max_stream_id ({:?}), ignoring RST_STREAM",
id, self.actions.recv.max_stream_id()
); return Ok(());
}
let stream = matchself.store.find_mut(&id) {
Some(stream) => stream,
None => { // TODO: Are there other error cases? self.actions
.ensure_not_idle(self.counts.peer(), id)
.map_err(Error::library_go_away)?;
return Ok(());
}
};
letmut send_buffer = send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
fn recv_window_update<B>(
&mutself,
send_buffer: &SendBuffer<B>,
frame: frame::WindowUpdate,
) -> Result<(), Error> { let id = frame.stream_id();
letmut send_buffer = send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
if id.is_zero() { self.actions
.send
.recv_connection_window_update(frame, &mutself.store, &tyle='color:red'>mutself.counts)
.map_err(Error::library_go_away)?;
} else { // The remote may send window updates for streams that the local now // considers closed. It's ok... iflet Some(mut stream) = self.store.find_mut(&id) { // This result is ignored as there is nothing to do when there // is an error. The stream is reset by the function on error and // the error is informational. let _ = self.actions.send.recv_stream_window_update(
frame.size_increment(),
send_buffer,
&mut stream,
&mutself.counts,
&mutself.actions.task,
);
} else { self.actions
.ensure_not_idle(self.counts.peer(), id)
.map_err(Error::library_go_away)?;
}
}
Ok(())
}
fn handle_error<B>(&mutself, send_buffer: &SendBuffer<B>, err: proto::Error) -> StreamId { let actions = &mutself.actions; let counts = &mutself.counts; letmut send_buffer = send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
let last_processed_id = actions.recv.last_processed_id();
fn recv_push_promise<B>(
&mutself,
send_buffer: &SendBuffer<B>,
frame: frame::PushPromise,
) -> Result<(), Error> { let id = frame.stream_id(); let promised_id = frame.promised_id();
// First, ensure that the initiating stream is still in a valid state. let parent_key = matchself.store.find_mut(&id) {
Some(stream) => { // The GOAWAY process has begun. All streams with a greater ID // than specified as part of GOAWAY should be ignored. if id > self.actions.recv.max_stream_id() {
tracing::trace!( "id ({:?}) > max_stream_id ({:?}), ignoring PUSH_PROMISE",
id, self.actions.recv.max_stream_id()
); return Ok(());
}
// The stream must be receive open if !stream.state.ensure_recv_open()? {
proto_err!(conn: "recv_push_promise: initiating stream is not opened"); return Err(Error::library_go_away(Reason::PROTOCOL_ERROR));
}
stream.key()
}
None => {
proto_err!(conn: "recv_push_promise: initiating stream is in an invalid state"); return Err(Error::library_go_away(Reason::PROTOCOL_ERROR));
}
};
// TODO: Streams in the reserved states do not count towards the concurrency // limit. However, it seems like there should be a cap otherwise this // could grow in memory indefinitely.
// Ensure that we can reserve streams self.actions.recv.ensure_can_reserve()?;
// Next, open the stream. // // If `None` is returned, then the stream is being refused. There is no // further work to be done. ifself
.actions
.recv
.open(promised_id, Open::PushPromise, &mutself.counts)?
.is_none()
{ return Ok(());
}
// Try to handle the frame and create a corresponding key for the pushed stream // this requires a bit of indirection to make the borrow checker happy. let child_key: Option<store::Key> = { // Create state for the stream let stream = self.store.insert(promised_id, {
Stream::new(
promised_id, self.actions.send.init_window_sz(), self.actions.recv.init_window_sz(),
)
});
let actions = &mutself.actions;
self.counts.transition(stream, |counts, stream| { let stream_valid = actions.recv.recv_push_promise(frame, stream);
let parent = &mutself.store.resolve(parent_key);
parent.pending_push_promises = ppp;
parent.notify_recv();
};
Ok(())
}
fn recv_eof<B>(
&mutself,
send_buffer: &SendBuffer<B>,
clear_pending_accept: bool,
) -> Result<(), ()> { let actions = &mutself.actions; let counts = &mutself.counts; letmut send_buffer = send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
if actions.conn_error.is_none() {
actions.conn_error = Some(
io::Error::new(
io::ErrorKind::BrokenPipe, "connection closed because of a broken pipe",
)
.into(),
);
}
// Send WINDOW_UPDATE frames first // // TODO: It would probably be better to interleave updates w/ data // frames.
ready!(self
.actions
.recv
.poll_complete(cx, &mutself.store, &mutself.counts, dst))?;
// Send any other pending frames
ready!(self.actions.send.poll_complete(
cx,
send_buffer,
&mutself.store,
&mutself.counts,
dst
))?;
// Nothing else to do, track the task self.actions.task = Some(cx.waker().clone());
Poll::Ready(Ok(()))
}
fn send_reset<B>(&mutself, send_buffer: &SendBuffer<B>, id: StreamId, reason: Reason) { let key = matchself.store.find_entry(id) {
Entry::Occupied(e) => e.key(),
Entry::Vacant(e) => { // Resetting a stream we don't know about? That could be OK... // // 1. As a server, we just received a request, but that request // was bad, so we're resetting before even accepting it. // This is totally fine. // // 2. The remote may have sent us a frame on new stream that // it's *not* supposed to have done, and thus, we don't know // the stream. In that case, sending a reset will "open" the // stream in our store. Maybe that should be a connection // error instead? At least for now, we need to update what // our vision of the next stream is. ifself.counts.peer().is_local_init(id) { // We normally would open this stream, so update our // next-send-id record. self.actions.send.maybe_reset_next_stream_id(id);
} else { // We normally would recv this stream, so update our // next-recv-id record. self.actions.recv.maybe_reset_next_stream_id(id);
}
/// This function is safe to call multiple times. /// /// A `Result` is returned to avoid panicking if the mutex is poisoned. pubfn recv_eof(&mutself, clear_pending_accept: bool) -> Result<(), ()> { self.as_dyn().recv_eof(clear_pending_accept)
}
#[cfg(feature = "unstable")] pubfn num_active_streams(&self) -> usize { let me = self.inner.lock().unwrap();
me.store.num_active_streams()
}
pubfn has_streams(&self) -> bool { let me = self.inner.lock().unwrap();
me.counts.has_streams()
}
pubfn has_streams_or_other_references(&self) -> bool { let me = self.inner.lock().unwrap();
me.counts.has_streams() || me.refs > 1
}
#[cfg(feature = "unstable")] pubfn num_wired_streams(&self) -> usize { let me = self.inner.lock().unwrap();
me.store.num_wired_streams()
}
}
// no derive because we don't need B and P to be Clone. impl<B, P> Clone for Streams<B, P> where
P: Peer,
{ fn clone(&self) -> Self { self.inner.lock().unwrap().refs += 1;
Streams {
inner: self.inner.clone(),
send_buffer: self.send_buffer.clone(),
_p: ::std::marker::PhantomData,
}
}
}
impl<B, P> Drop for Streams<B, P> where
P: Peer,
{ fn drop(&mutself) { iflet Ok(mut inner) = self.inner.lock() {
inner.refs -= 1; if inner.refs == 1 { iflet Some(task) = inner.actions.task.take() {
task.wake();
}
}
}
}
}
// ===== impl StreamRef =====
impl<B> StreamRef<B> { pubfn send_data(&mutself, data: B, end_stream: bool) -> Result<(), UserError> where
B: Buf,
{ letmut me = self.opaque.inner.lock().unwrap(); let me = &mut *me;
let stream = me.store.resolve(self.opaque.key); let actions = &mut me.actions; letmut send_buffer = self.send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
me.counts.transition(stream, |counts, stream| { // Create the data frame letmut frame = frame::Data::new(stream.id, data);
frame.set_end_stream(end_stream);
// Send the data frame
actions
.send
.send_data(frame, send_buffer, stream, counts, &mut actions.task)
})
}
pubfn send_trailers(&mutself, trailers: HeaderMap) -> Result<(), UserError> { letmut me = self.opaque.inner.lock().unwrap(); let me = &mut *me;
let stream = me.store.resolve(self.opaque.key); let actions = &mut me.actions; letmut send_buffer = self.send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer;
me.counts.transition(stream, |counts, stream| { // Create the trailers frame let frame = frame::Headers::trailers(stream.id, trailers);
/// Called by the server after the stream is accepted. Given that clients /// initialize streams by sending HEADERS, the request will always be /// available. /// /// # Panics /// /// This function panics if the request isn't present. pubfn take_request(&self) -> Request<()> { letmut me = self.opaque.inner.lock().unwrap(); let me = &mut *me;
/// Called by a client to see if the current stream is pending open pubfn is_pending_open(&self) -> bool { letmut me = self.opaque.inner.lock().unwrap();
me.store.resolve(self.opaque.key).is_pending_open
}
/// Request capacity to send data pubfn reserve_capacity(&mutself, capacity: WindowSize) { letmut me = self.opaque.inner.lock().unwrap(); let me = &mut *me;
/// Returns the stream's current send capacity. pubfn capacity(&self) -> WindowSize { letmut me = self.opaque.inner.lock().unwrap(); let me = &mut *me;
/// Request to be notified when the stream's capacity increases pubfn poll_capacity(&mutself, cx: &Context) -> Poll<Option<Result<WindowSize, UserError>>> { letmut me = self.opaque.inner.lock().unwrap(); let me = &mut *me;
/// Request to be notified for if a `RST_STREAM` is received for this stream. pub(crate) fn poll_reset(
&mutself,
cx: &Context,
mode: proto::PollReset,
) -> Poll<Result<Reason, crate::Error>> { letmut me = self.opaque.inner.lock().unwrap(); let me = &mut *me;
impl OpaqueStreamRef { fn new(inner: Arc<Mutex<Inner>>, stream: &mut store::Ptr) -> OpaqueStreamRef {
stream.ref_inc();
OpaqueStreamRef {
inner,
key: stream.key(),
}
} /// Called by a client to check for a received response. pubfn poll_response(&mutself, cx: &Context) -> Poll<Result<Response<()>, proto::Error>> { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
letmut stream = me.store.resolve(self.key);
me.actions.recv.poll_response(cx, &mut stream)
} /// Called by a client to check for a pushed request. pubfn poll_pushed(
&mutself,
cx: &Context,
) -> Poll<Option<Result<(Request<()>, OpaqueStreamRef), proto::Error>>> { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
pubfn is_end_stream(&self) -> bool { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
let stream = me.store.resolve(self.key);
me.actions.recv.is_end_stream(&stream)
}
pubfn poll_data(&mutself, cx: &Context) -> Poll<Option<Result<Bytes, proto::Error>>> { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
letmut stream = me.store.resolve(self.key);
me.actions.recv.poll_data(cx, &mut stream)
}
pubfn poll_trailers(&mutself, cx: &Context) -> Poll<Option<Result<HeaderMap, proto::Error>>> { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
letmut stream = me.store.resolve(self.key);
me.actions.recv.poll_trailers(cx, &mut stream)
}
pub(crate) fn available_recv_capacity(&self) -> isize { let me = self.inner.lock().unwrap(); let me = &*me;
let stream = &me.store[self.key];
stream.recv_flow.available().into()
}
pub(crate) fn used_recv_capacity(&self) -> WindowSize { let me = self.inner.lock().unwrap(); let me = &*me;
let stream = &me.store[self.key];
stream.in_flight_recv_data
}
/// Releases recv capacity back to the peer. This may result in sending /// WINDOW_UPDATE frames on both the stream and connection. pubfn release_capacity(&mutself, capacity: WindowSize) -> Result<(), UserError> { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
/// Clear the receive queue and set the status to no longer receive data frames. pub(crate) fn clear_recv_buffer(&mutself) { letmut me = self.inner.lock().unwrap(); let me = &mut *me;
// decrement the stream's ref count by 1.
stream.ref_dec();
let actions = &mut me.actions;
// If the stream is not referenced and it is already // closed (does not have to go through logic below // of canceling the stream), we should notify the task // (connection) so that it can close properly if stream.ref_count == 0 && stream.is_closed() { iflet Some(task) = actions.task.take() {
task.wake();
}
}
if stream.ref_count == 0 { // Release any recv window back to connection, no one can access // it anymore.
actions
.recv
.release_closed_capacity(stream, &mut actions.task);
// We won't be able to reach our push promises anymore letmut ppp = stream.pending_push_promises.take(); whilelet Some(promise) = ppp.pop(stream.store_mut()) {
counts.transition(promise, |counts, stream| {
maybe_cancel(stream, actions, counts);
});
}
}
});
}
fn maybe_cancel(stream: &mut store::Ptr, actions: &mut Actions, counts: &mut Counts) { if stream.is_canceled_interest() { // Server is allowed to early respond without fully consuming the client input stream // But per the RFC, must send a RST_STREAM(NO_ERROR) in such cases. https://www.rfc-editor.org/rfc/rfc7540#section-8.1 // Some other http2 implementation may interpret other error code as fatal if not respected (i.e: nginx https://trac.nginx.org/nginx/ticket/2376) let reason = if counts.peer().is_server()
&& stream.state.is_send_closed()
&& stream.state.is_recv_streaming()
{
Reason::NO_ERROR
} else {
Reason::CANCEL
};
/// Check if we possibly could have processed and since forgotten this stream. /// /// If we send a RST_STREAM for a stream, we will eventually "forget" about /// the stream to free up memory. It's possible that the remote peer had /// frames in-flight, and by the time we receive them, our own state is /// gone. We *could* tear everything down by sending a GOAWAY, but it /// is more likely to be latency/memory constraints that caused this, /// and not a bad actor. So be less catastrophic, the spec allows /// us to send another RST_STREAM of STREAM_CLOSED. fn may_have_forgotten_stream(&self, peer: peer::Dyn, id: StreamId) -> bool { if id.is_zero() { returnfalse;
} if peer.is_local_init(id) { self.send.may_have_created_stream(id)
} else { self.recv.may_have_created_stream(id)
}
}
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.