1 use crate::codec::RecvError; 2 use crate::error::Reason; 3 use crate::frame::{Pseudo, StreamId}; 4 use crate::proto::Open; 5 6 use http::{HeaderMap, Request, Response}; 7 8 use std::fmt; 9 10 /// Either a Client or a Server 11 pub(crate) trait Peer { 12 /// Message type polled from the transport 13 type Poll: fmt::Debug; 14 15 fn r#dyn() -> Dyn; 16 is_server() -> bool17 fn is_server() -> bool; 18 convert_poll_message( pseudo: Pseudo, fields: HeaderMap, stream_id: StreamId, ) -> Result<Self::Poll, RecvError>19 fn convert_poll_message( 20 pseudo: Pseudo, 21 fields: HeaderMap, 22 stream_id: StreamId, 23 ) -> Result<Self::Poll, RecvError>; 24 is_local_init(id: StreamId) -> bool25 fn is_local_init(id: StreamId) -> bool { 26 assert!(!id.is_zero()); 27 Self::is_server() == id.is_server_initiated() 28 } 29 } 30 31 /// A dynamic representation of `Peer`. 32 /// 33 /// This is used internally to avoid incurring a generic on all internal types. 34 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 35 pub(crate) enum Dyn { 36 Client, 37 Server, 38 } 39 40 #[derive(Debug)] 41 pub enum PollMessage { 42 Client(Response<()>), 43 Server(Request<()>), 44 } 45 46 // ===== impl Dyn ===== 47 48 impl Dyn { is_server(&self) -> bool49 pub fn is_server(&self) -> bool { 50 *self == Dyn::Server 51 } 52 is_local_init(&self, id: StreamId) -> bool53 pub fn is_local_init(&self, id: StreamId) -> bool { 54 assert!(!id.is_zero()); 55 self.is_server() == id.is_server_initiated() 56 } 57 convert_poll_message( &self, pseudo: Pseudo, fields: HeaderMap, stream_id: StreamId, ) -> Result<PollMessage, RecvError>58 pub fn convert_poll_message( 59 &self, 60 pseudo: Pseudo, 61 fields: HeaderMap, 62 stream_id: StreamId, 63 ) -> Result<PollMessage, RecvError> { 64 if self.is_server() { 65 crate::server::Peer::convert_poll_message(pseudo, fields, stream_id) 66 .map(PollMessage::Server) 67 } else { 68 crate::client::Peer::convert_poll_message(pseudo, fields, stream_id) 69 .map(PollMessage::Client) 70 } 71 } 72 73 /// Returns true if the remote peer can initiate a stream with the given ID. ensure_can_open(&self, id: StreamId, mode: Open) -> Result<(), RecvError>74 pub fn ensure_can_open(&self, id: StreamId, mode: Open) -> Result<(), RecvError> { 75 if self.is_server() { 76 // Ensure that the ID is a valid client initiated ID 77 if mode.is_push_promise() || !id.is_client_initiated() { 78 proto_err!(conn: "cannot open stream {:?} - not client initiated", id); 79 return Err(RecvError::Connection(Reason::PROTOCOL_ERROR)); 80 } 81 82 Ok(()) 83 } else { 84 // Ensure that the ID is a valid server initiated ID 85 if !mode.is_push_promise() || !id.is_server_initiated() { 86 proto_err!(conn: "cannot open stream {:?} - not server initiated", id); 87 return Err(RecvError::Connection(Reason::PROTOCOL_ERROR)); 88 } 89 90 Ok(()) 91 } 92 } 93 } 94