diff options
Diffstat (limited to 'third_party/rust/h2/src/proto/peer.rs')
-rw-r--r-- | third_party/rust/h2/src/proto/peer.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/third_party/rust/h2/src/proto/peer.rs b/third_party/rust/h2/src/proto/peer.rs new file mode 100644 index 0000000000..d62d9e24e0 --- /dev/null +++ b/third_party/rust/h2/src/proto/peer.rs @@ -0,0 +1,93 @@ +use crate::error::Reason; +use crate::frame::{Pseudo, StreamId}; +use crate::proto::{Error, Open}; + +use http::{HeaderMap, Request, Response}; + +use std::fmt; + +/// Either a Client or a Server +pub(crate) trait Peer { + /// Message type polled from the transport + type Poll: fmt::Debug; + const NAME: &'static str; + + fn r#dyn() -> Dyn; + + fn is_server() -> bool; + + fn convert_poll_message( + pseudo: Pseudo, + fields: HeaderMap, + stream_id: StreamId, + ) -> Result<Self::Poll, Error>; + + fn is_local_init(id: StreamId) -> bool { + assert!(!id.is_zero()); + Self::is_server() == id.is_server_initiated() + } +} + +/// A dynamic representation of `Peer`. +/// +/// This is used internally to avoid incurring a generic on all internal types. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub(crate) enum Dyn { + Client, + Server, +} + +#[derive(Debug)] +pub enum PollMessage { + Client(Response<()>), + Server(Request<()>), +} + +// ===== impl Dyn ===== + +impl Dyn { + pub fn is_server(&self) -> bool { + *self == Dyn::Server + } + + pub fn is_local_init(&self, id: StreamId) -> bool { + assert!(!id.is_zero()); + self.is_server() == id.is_server_initiated() + } + + pub fn convert_poll_message( + &self, + pseudo: Pseudo, + fields: HeaderMap, + stream_id: StreamId, + ) -> Result<PollMessage, Error> { + if self.is_server() { + crate::server::Peer::convert_poll_message(pseudo, fields, stream_id) + .map(PollMessage::Server) + } else { + crate::client::Peer::convert_poll_message(pseudo, fields, stream_id) + .map(PollMessage::Client) + } + } + + /// Returns true if the remote peer can initiate a stream with the given ID. + pub fn ensure_can_open(&self, id: StreamId, mode: Open) -> Result<(), Error> { + if self.is_server() { + // Ensure that the ID is a valid client initiated ID + if mode.is_push_promise() || !id.is_client_initiated() { + proto_err!(conn: "cannot open stream {:?} - not client initiated", id); + return Err(Error::library_go_away(Reason::PROTOCOL_ERROR)); + } + + Ok(()) + } else { + // Ensure that the ID is a valid server initiated ID + if !mode.is_push_promise() || !id.is_server_initiated() { + proto_err!(conn: "cannot open stream {:?} - not server initiated", id); + return Err(Error::library_go_away(Reason::PROTOCOL_ERROR)); + } + + Ok(()) + } + } +} |