h2/proto/
peer.rs

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