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