1use crate::error::Reason;
2use crate::frame::{Pseudo, StreamId};
3use crate::proto::{Error, Open};
4
5use http::{HeaderMap, Request, Response};
6
7use std::fmt;
8
9/// Either a Client or a Server
10pub(crate) trait Peer {
11 /// Message type polled from the transport
12 type Poll: fmt::Debug;
13 const NAME: &'static str;
14
15 fn r#dyn() -> Dyn;
16
17 fn is_server() -> bool;
18
19 fn convert_poll_message(
20 pseudo: Pseudo,
21 fields: HeaderMap,
22 stream_id: StreamId,
23 ) -> Result<Self::Poll, Error>;
24
25 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)]
35pub(crate) enum Dyn {
36 Client,
37 Server,
38}
39
40#[derive(Debug)]
41pub enum PollMessage {
42 Client(Response<()>),
43 Server(Request<()>),
44}
45
46// ===== impl Dyn =====
47
48impl Dyn {
49 pub fn is_server(&self) -> bool {
50 *self == Dyn::Server
51 }
52
53 pub fn is_local_init(&self, id: StreamId) -> bool {
54 assert!(!id.is_zero());
55 self.is_server() == id.is_server_initiated()
56 }
57
58 pub fn convert_poll_message(
59 &self,
60 pseudo: Pseudo,
61 fields: HeaderMap,
62 stream_id: StreamId,
63 ) -> Result<PollMessage, Error> {
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.
74 pub fn ensure_can_open(&self, id: StreamId, mode: Open) -> Result<(), Error> {
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(Error::library_go_away(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(Error::library_go_away(Reason::PROTOCOL_ERROR));
88 }
89
90 Ok(())
91 }
92 }
93}
94