h2/proto/
settings.rs
1use crate::codec::UserError;
2use crate::error::Reason;
3use crate::proto::*;
4use std::task::{Context, Poll};
5
6#[derive(Debug)]
7pub(crate) struct Settings {
8 local: Local,
10 remote: Option<frame::Settings>,
14}
15
16#[derive(Debug)]
17enum Local {
18 ToSend(frame::Settings),
20 WaitingAck(frame::Settings),
23 Synced,
25}
26
27impl Settings {
28 pub(crate) fn new(local: frame::Settings) -> Self {
29 Settings {
30 local: Local::WaitingAck(local),
33 remote: None,
34 }
35 }
36
37 pub(crate) fn recv_settings<T, B, C, P>(
38 &mut self,
39 frame: frame::Settings,
40 codec: &mut Codec<T, B>,
41 streams: &mut Streams<C, P>,
42 ) -> Result<(), Error>
43 where
44 T: AsyncWrite + Unpin,
45 B: Buf,
46 C: Buf,
47 P: Peer,
48 {
49 if frame.is_ack() {
50 match &self.local {
51 Local::WaitingAck(local) => {
52 tracing::debug!("received settings ACK; applying {:?}", local);
53
54 if let Some(max) = local.max_frame_size() {
55 codec.set_max_recv_frame_size(max as usize);
56 }
57
58 if let Some(max) = local.max_header_list_size() {
59 codec.set_max_recv_header_list_size(max as usize);
60 }
61
62 if let Some(val) = local.header_table_size() {
63 codec.set_recv_header_table_size(val as usize);
64 }
65
66 streams.apply_local_settings(local)?;
67 self.local = Local::Synced;
68 Ok(())
69 }
70 Local::ToSend(..) | Local::Synced => {
71 proto_err!(conn: "received unexpected settings ack");
74 Err(Error::library_go_away(Reason::PROTOCOL_ERROR))
75 }
76 }
77 } else {
78 assert!(self.remote.is_none());
81 self.remote = Some(frame);
82 Ok(())
83 }
84 }
85
86 pub(crate) fn send_settings(&mut self, frame: frame::Settings) -> Result<(), UserError> {
87 assert!(!frame.is_ack());
88 match &self.local {
89 Local::ToSend(..) | Local::WaitingAck(..) => Err(UserError::SendSettingsWhilePending),
90 Local::Synced => {
91 tracing::trace!("queue to send local settings: {:?}", frame);
92 self.local = Local::ToSend(frame);
93 Ok(())
94 }
95 }
96 }
97
98 pub(crate) fn poll_send<T, B, C, P>(
99 &mut self,
100 cx: &mut Context,
101 dst: &mut Codec<T, B>,
102 streams: &mut Streams<C, P>,
103 ) -> Poll<Result<(), Error>>
104 where
105 T: AsyncWrite + Unpin,
106 B: Buf,
107 C: Buf,
108 P: Peer,
109 {
110 if let Some(settings) = &self.remote {
111 if !dst.poll_ready(cx)?.is_ready() {
112 return Poll::Pending;
113 }
114
115 let frame = frame::Settings::ack();
117
118 dst.buffer(frame.into()).expect("invalid settings frame");
120
121 tracing::trace!("ACK sent; applying settings");
122
123 streams.apply_remote_settings(settings)?;
124
125 if let Some(val) = settings.header_table_size() {
126 dst.set_send_header_table_size(val as usize);
127 }
128
129 if let Some(val) = settings.max_frame_size() {
130 dst.set_max_send_frame_size(val as usize);
131 }
132 }
133
134 self.remote = None;
135
136 match &self.local {
137 Local::ToSend(settings) => {
138 if !dst.poll_ready(cx)?.is_ready() {
139 return Poll::Pending;
140 }
141
142 dst.buffer(settings.clone().into())
144 .expect("invalid settings frame");
145 tracing::trace!("local settings sent; waiting for ack: {:?}", settings);
146
147 self.local = Local::WaitingAck(settings.clone());
148 }
149 Local::WaitingAck(..) | Local::Synced => {}
150 }
151
152 Poll::Ready(Ok(()))
153 }
154}