1 use codec::RecvError;
2 use error::Reason;
3 use frame::{Pseudo, StreamId};
4 use 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 
dyn() -> Dyn15     fn 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, fields: HeaderMap, stream_id: StreamId
21     ) -> Result<Self::Poll, RecvError>;
22 
is_local_init(id: StreamId) -> bool23     fn is_local_init(id: StreamId) -> bool {
24         assert!(!id.is_zero());
25         Self::is_server() == id.is_server_initiated()
26     }
27 }
28 
29 /// A dynamic representation of `Peer`.
30 ///
31 /// This is used internally to avoid incurring a generic on all internal types.
32 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
33 pub(crate) enum Dyn {
34     Client,
35     Server,
36 }
37 
38 #[derive(Debug)]
39 pub enum PollMessage {
40     Client(Response<()>),
41     Server(Request<()>),
42 }
43 
44 // ===== impl Dyn =====
45 
46 impl Dyn {
is_server(&self) -> bool47     pub fn is_server(&self) -> bool {
48         *self == Dyn::Server
49     }
50 
is_local_init(&self, id: StreamId) -> bool51     pub fn is_local_init(&self, id: StreamId) -> bool {
52         assert!(!id.is_zero());
53         self.is_server() == id.is_server_initiated()
54     }
55 
convert_poll_message( &self, pseudo: Pseudo, fields: HeaderMap, stream_id: StreamId ) -> Result<PollMessage, RecvError>56     pub fn convert_poll_message(
57         &self, pseudo: Pseudo, fields: HeaderMap, stream_id: StreamId
58     ) -> Result<PollMessage, RecvError> {
59         if self.is_server() {
60             ::server::Peer::convert_poll_message(pseudo, fields, stream_id)
61                 .map(PollMessage::Server)
62         } else {
63             ::client::Peer::convert_poll_message(pseudo, fields, stream_id)
64                 .map(PollMessage::Client)
65         }
66     }
67 
68     /// Returns true if the remote peer can initiate a stream with the given ID.
ensure_can_open(&self, id: StreamId, mode: Open) -> Result<(), RecvError>69     pub fn ensure_can_open(&self, id: StreamId, mode: Open) -> Result<(), RecvError> {
70         if self.is_server() {
71             // Ensure that the ID is a valid client initiated ID
72             if mode.is_push_promise() || !id.is_client_initiated() {
73                 proto_err!(conn: "cannot open stream {:?} - not client initiated", id);
74                 return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
75             }
76 
77             Ok(())
78         } else {
79             // Ensure that the ID is a valid server initiated ID
80             if !mode.is_push_promise() || !id.is_server_initiated() {
81                 proto_err!(conn: "cannot open stream {:?} - not server initiated", id);
82                 return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
83             }
84 
85             Ok(())
86         }
87     }
88 }
89