• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //! http2 send and recv window definition.
15 
16 use ylong_http::h2::{ErrorCode, Frame, FrameFlags, H2Error, Payload, StreamId, WindowUpdate};
17 
18 pub(crate) struct SendWindow {
19     // As the sending window, the client retains only its visible window size,
20     // and updates only when the SETTINGS frame and WINDOW_UPDATE frame are received from the
21     // server.
22     size: i32,
23 }
24 
25 impl SendWindow {
new(size: i32) -> Self26     pub(crate) fn new(size: i32) -> Self {
27         Self { size }
28     }
29 
size_available(&self) -> u3230     pub(crate) fn size_available(&self) -> u32 {
31         if self.size < 0 {
32             0
33         } else {
34             self.size as u32
35         }
36     }
37 
reduce_size(&mut self, size: u32)38     pub(crate) fn reduce_size(&mut self, size: u32) {
39         self.size -= size as i32;
40     }
41 
increase_size(&mut self, size: u32) -> Result<(), H2Error>42     pub(crate) fn increase_size(&mut self, size: u32) -> Result<(), H2Error> {
43         let (curr, overflow) = self.size.overflowing_add(size as i32);
44         if overflow {
45             return Err(H2Error::ConnectionError(ErrorCode::FlowControlError));
46         }
47         if curr > crate::util::h2::MAX_FLOW_CONTROL_WINDOW as i32 {
48             return Err(H2Error::ConnectionError(ErrorCode::FlowControlError));
49         }
50         self.size = curr;
51         Ok(())
52     }
53 
send_data(&mut self, size: u32)54     pub(crate) fn send_data(&mut self, size: u32) {
55         self.size -= size as i32;
56     }
57 }
58 
59 #[derive(Default)]
60 pub(crate) struct RecvWindow {
61     // The window size visible to the server.
62     // notification decreases the value when a DATA frame is received
63     // and increases the value when a WINDOW_UPDATE is sent.
64     notification: i32,
65     // The window size visible to the client.
66     // Since client is a receiving (WINDOW_UPDATE sending) window,
67     // the actual remains unchanged except for SETTINGS set by the user updates.
68     actual: i32,
69 }
70 
71 impl RecvWindow {
new(size: i32) -> Self72     pub(crate) fn new(size: i32) -> Self {
73         Self {
74             notification: size,
75             actual: size,
76         }
77     }
78 
unreleased_size(&self) -> Option<u32>79     pub(crate) fn unreleased_size(&self) -> Option<u32> {
80         let unreleased = self.actual - self.notification;
81         if unreleased <= 0 {
82             return None;
83         }
84         if unreleased * 2 > self.notification {
85             Some(unreleased as u32)
86         } else {
87             None
88         }
89     }
90 
actual_size(&self) -> i3291     pub(crate) fn actual_size(&self) -> i32 {
92         self.actual
93     }
94 
notification_available(&self) -> u3295     pub(crate) fn notification_available(&self) -> u32 {
96         if self.notification < 0 {
97             0
98         } else {
99             self.notification as u32
100         }
101     }
102 
reduce_actual(&mut self, size: u32)103     pub(crate) fn reduce_actual(&mut self, size: u32) {
104         self.actual -= size as i32
105     }
106 
increase_actual(&mut self, size: u32)107     pub(crate) fn increase_actual(&mut self, size: u32) {
108         self.actual += size as i32
109     }
110 
reduce_notification(&mut self, size: u32)111     pub(crate) fn reduce_notification(&mut self, size: u32) {
112         self.notification -= size as i32
113     }
114 
increase_notification(&mut self, size: u32)115     pub(crate) fn increase_notification(&mut self, size: u32) {
116         self.notification += size as i32
117     }
118 
check_window_update(&mut self, id: StreamId) -> Option<Frame>119     pub(crate) fn check_window_update(&mut self, id: StreamId) -> Option<Frame> {
120         if let Some(size) = self.unreleased_size() {
121             self.increase_notification(size);
122             let window_update = WindowUpdate::new(size);
123             let frame = Frame::new(id, FrameFlags::new(0), Payload::WindowUpdate(window_update));
124             Some(frame)
125         } else {
126             None
127         }
128     }
129 
130     // The client receiving a DATA frame means that the server has less visible
131     // Windows
recv_data(&mut self, size: u32)132     pub(crate) fn recv_data(&mut self, size: u32) {
133         self.notification -= size as i32;
134     }
135 }
136 
137 #[cfg(test)]
138 mod ut_send_window {
139     use ylong_http::h2::{ErrorCode, H2Error};
140 
141     use super::*;
142 
143     /// UT test case for `SendWindow::new`.
144     ///
145     /// # Brief
146     /// 1. Creates a new `SendWindow` instance.
147     /// 2. Asserts that the window size is initialized to the provided value.
148     #[test]
ut_sw_new()149     fn ut_sw_new() {
150         let sw = SendWindow::new(100);
151         assert_eq!(sw.size, 100);
152     }
153 
154     /// UT test case for `SendWindow::size_available`.
155     ///
156     /// # Brief
157     /// 1. Creates a new `SendWindow` instance.
158     /// 2. Checks that the available size is returns correctly.
159     #[test]
ut_sw_size_available()160     fn ut_sw_size_available() {
161         let sw = SendWindow::new(100);
162         assert_eq!(sw.size_available(), 100);
163         let sw = SendWindow::new(-1);
164         assert_eq!(sw.size_available(), 0);
165     }
166 
167     /// UT test case for `SendWindow::reduce_size`.
168     ///
169     /// # Brief
170     /// 1. Reduces the send window size by a specified value.
171     /// 2. Asserts that the size is correctly reduce.
172     #[test]
ut_sw_reduce_size()173     fn ut_sw_reduce_size() {
174         let mut sw = SendWindow::new(100);
175         sw.reduce_size(50);
176         assert_eq!(sw.size, 50);
177     }
178 
179     /// UT test case for `SendWindow::increase_size`.
180     ///
181     /// # Brief
182     /// 1. Increases the send window size.
183     /// 2. Asserts that the size is increased correctly.
184     /// 3. Attempts to increase the window size beyond the maximum allowable
185     ///    value or beyond the maximum flow control window size.
186     /// 4. Asserts that the operation fails.
187     #[test]
ut_sw_window_increase_size()188     fn ut_sw_window_increase_size() {
189         let mut sw = SendWindow::new(100);
190         assert!(sw.increase_size(50).is_ok());
191         assert_eq!(sw.size, 150);
192 
193         let mut sw = SendWindow::new(i32::MAX);
194         let res = sw.increase_size(1);
195         assert!(res.is_err());
196         if let Err(H2Error::ConnectionError(code)) = res {
197             assert_eq!(code, ErrorCode::FlowControlError);
198         }
199 
200         let mut sw = SendWindow::new(1);
201         let res = sw.increase_size(crate::util::h2::MAX_FLOW_CONTROL_WINDOW);
202         assert!(res.is_err());
203         assert_eq!(
204             res,
205             Err(H2Error::ConnectionError(ErrorCode::FlowControlError))
206         );
207     }
208 
209     /// UT test case for `SendWindow::send_data`.
210     ///
211     /// # Brief
212     /// 1. Sends data by reducing the send window size.
213     /// 2. Asserts that the send window size is correctly redueced after the
214     ///    data is sent.
215     #[test]
ut_sw_send_data()216     fn ut_sw_send_data() {
217         let mut sw = SendWindow::new(100);
218         sw.send_data(50);
219         assert_eq!(sw.size, 50);
220     }
221 }
222 
223 #[cfg(test)]
224 mod ut_recv_window {
225     use super::*;
226 
227     /// UT test case for `RecvWindow::new`.
228     ///
229     /// # Brief
230     /// 1. Creates a new `RecvWindow` instance.
231     /// 2. Asserts that both the `notification` and `actual` sizes are
232     ///    initialized to the provided value.
233     #[test]
ut_rw_new()234     fn ut_rw_new() {
235         let rw = RecvWindow::new(100);
236         assert_eq!(rw.notification, 100);
237         assert_eq!(rw.actual, 100);
238     }
239 
240     /// UT test case for `RecvWindow::unreleased_size`.
241     ///
242     /// # Brief
243     /// 1. Creates a `RecvWindow` instance.
244     /// 2. Asserts that no unreleased size is reported when the notification is
245     ///    greater than or equal to the actual size.
246     /// 3. Simulate a scenario where the notification size is smaller than the
247     ///    actual size and asserts that unreleased size is repoeted.
248     /// 4. Simulate a scenario where the notification size is slightly less than
249     ///    the actual size but still no unreleased size is reported.
250     #[test]
ut_rw_unreleased_size()251     fn ut_rw_unreleased_size() {
252         let mut rw = RecvWindow::new(100);
253         assert_eq!(rw.unreleased_size(), None);
254         rw.notification = 50;
255         assert_eq!(rw.unreleased_size(), Some(50));
256         rw.notification = 80;
257         assert_eq!(rw.unreleased_size(), None);
258     }
259 
260     /// UT test case for `RecvWindow::actual_size`.
261     ///
262     /// # Brief
263     /// 1. Retrieves the actual window size.
264     /// 2. Asserts that the size is returned correctly.
265     #[test]
ut_rw_actual_size()266     fn ut_rw_actual_size() {
267         let rw = RecvWindow::new(100);
268         assert_eq!(rw.actual_size(), 100);
269     }
270 
271     /// UT test case for `RecvWindow::notification_available`.
272     ///
273     /// # Brief
274     /// 1. Asserts that the available notification size is correctly reported
275     ///    for a positive value.
276     /// 2. Simulates a scenario where the notification size is negative and
277     ///    asserts that the available notification size reported as zero.
278     #[test]
ut_rw_notification_available()279     fn ut_rw_notification_available() {
280         let rw = RecvWindow::new(100);
281         assert_eq!(rw.notification_available(), 100);
282         let rw = RecvWindow::new(-1);
283         assert_eq!(rw.notification_available(), 0);
284     }
285 
286     /// UT test case for `RecvWindow::{reduce_actual,increase_actual}`
287     ///
288     /// # Brief
289     /// 1. Reduces and increase the actual window size.
290     /// 2. Asserts that the size is correctly reduced and increased.
291     #[test]
ut_rw_reduce_and_increase_actual()292     fn ut_rw_reduce_and_increase_actual() {
293         let mut rw = RecvWindow::new(100);
294         rw.reduce_actual(50);
295         assert_eq!(rw.actual, 50);
296         rw.increase_actual(50);
297         assert_eq!(rw.actual, 100);
298     }
299 
300     /// UT test case for
301     /// `RecvWindow::{reduce_notification,increase_notificaiton}`
302     ///
303     /// # Brief
304     /// 1. Reduces and increase the notification window size.
305     /// 2. Asserts that the size is correctly reduced and increased.
306     #[test]
ut_rw_reduce_and_increase_notification()307     fn ut_rw_reduce_and_increase_notification() {
308         let mut rw = RecvWindow::new(100);
309         rw.reduce_notification(50);
310         assert_eq!(rw.notification, 50);
311         rw.increase_notification(50);
312         assert_eq!(rw.notification, 100);
313     }
314 
315     /// UT test case for `RecvWindow::check_window_update`.
316     ///
317     /// # Brief
318     /// 1. Checks for a window update when there is no unreleased size.
319     /// 2. Asserts that no `Frame` is generated.
320     /// 3. Checks for a window update when there is unreleased size available.
321     /// 4. Asserts that a `Frame` is generated for the window update.
322     #[test]
ut_rw_check_window_update()323     fn ut_rw_check_window_update() {
324         let mut rw = RecvWindow::new(100);
325         let frame = rw.check_window_update(1);
326         assert!(frame.is_none());
327         rw.notification = 50;
328         let frame = rw.check_window_update(1);
329         assert!(frame.is_some());
330     }
331 
332     /// UT test case for `RecvWindow::recv_data`.
333     ///
334     /// # Brief
335     /// 1. Simulates receiving data, whice reduces the notification size.
336     /// 2. Asserts that the notification size is correctly reduced after
337     ///    receiving data.
338     #[test]
ut_rw_send_data()339     fn ut_rw_send_data() {
340         let mut rw = RecvWindow::new(100);
341         rw.recv_data(50);
342         assert_eq!(rw.notification, 50);
343     }
344 }
345