/src/h2/tests/h2-support/src/frames.rs
Line | Count | Source |
1 | | use std::convert::TryInto; |
2 | | use std::fmt; |
3 | | |
4 | | use bytes::Bytes; |
5 | | use http::{HeaderMap, StatusCode}; |
6 | | |
7 | | use h2::frame::{self, Frame, StreamId}; |
8 | | |
9 | | pub const SETTINGS: &[u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0]; |
10 | | pub const SETTINGS_ACK: &[u8] = &[0, 0, 0, 4, 1, 0, 0, 0, 0]; |
11 | | |
12 | | // ==== helper functions to easily construct h2 Frames ==== |
13 | | |
14 | 0 | pub fn headers<T>(id: T) -> Mock<frame::Headers> |
15 | 0 | where |
16 | 0 | T: Into<StreamId>, |
17 | | { |
18 | 0 | Mock(frame::Headers::new( |
19 | 0 | id.into(), |
20 | 0 | frame::Pseudo::default(), |
21 | 0 | HeaderMap::default(), |
22 | 0 | )) |
23 | 0 | } |
24 | | |
25 | 0 | pub fn data<T, B>(id: T, buf: B) -> Mock<frame::Data> |
26 | 0 | where |
27 | 0 | T: Into<StreamId>, |
28 | 0 | B: AsRef<[u8]>, |
29 | | { |
30 | 0 | let buf = Bytes::copy_from_slice(buf.as_ref()); |
31 | 0 | Mock(frame::Data::new(id.into(), buf)) |
32 | 0 | } |
33 | | |
34 | 0 | pub fn push_promise<T1, T2>(id: T1, promised: T2) -> Mock<frame::PushPromise> |
35 | 0 | where |
36 | 0 | T1: Into<StreamId>, |
37 | 0 | T2: Into<StreamId>, |
38 | | { |
39 | 0 | Mock(frame::PushPromise::new( |
40 | 0 | id.into(), |
41 | 0 | promised.into(), |
42 | 0 | frame::Pseudo::default(), |
43 | 0 | HeaderMap::default(), |
44 | 0 | )) |
45 | 0 | } |
46 | | |
47 | 0 | pub fn window_update<T>(id: T, sz: u32) -> frame::WindowUpdate |
48 | 0 | where |
49 | 0 | T: Into<StreamId>, |
50 | | { |
51 | 0 | frame::WindowUpdate::new(id.into(), sz) |
52 | 0 | } |
53 | | |
54 | 0 | pub fn go_away<T>(id: T) -> Mock<frame::GoAway> |
55 | 0 | where |
56 | 0 | T: Into<StreamId>, |
57 | | { |
58 | 0 | Mock(frame::GoAway::new(id.into(), frame::Reason::NO_ERROR)) |
59 | 0 | } |
60 | | |
61 | 0 | pub fn reset<T>(id: T) -> Mock<frame::Reset> |
62 | 0 | where |
63 | 0 | T: Into<StreamId>, |
64 | | { |
65 | 0 | Mock(frame::Reset::new(id.into(), frame::Reason::NO_ERROR)) |
66 | 0 | } |
67 | | |
68 | | pub fn settings() -> Mock<frame::Settings> { |
69 | | Mock(frame::Settings::default()) |
70 | | } |
71 | | |
72 | | pub fn settings_ack() -> Mock<frame::Settings> { |
73 | | Mock(frame::Settings::ack()) |
74 | | } |
75 | | |
76 | | pub fn ping(payload: [u8; 8]) -> Mock<frame::Ping> { |
77 | | Mock(frame::Ping::new(payload)) |
78 | | } |
79 | | |
80 | | // === Generic helpers of all frame types |
81 | | |
82 | | pub struct Mock<T>(T); |
83 | | |
84 | | impl<T: fmt::Debug> fmt::Debug for Mock<T> { |
85 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
86 | 0 | fmt::Debug::fmt(&self.0, f) |
87 | 0 | } |
88 | | } |
89 | | |
90 | | impl<T> From<Mock<T>> for Frame |
91 | | where |
92 | | T: Into<Frame>, |
93 | | { |
94 | 0 | fn from(src: Mock<T>) -> Self { |
95 | 0 | src.0.into() |
96 | 0 | } |
97 | | } |
98 | | |
99 | | // Headers helpers |
100 | | |
101 | | impl Mock<frame::Headers> { |
102 | 0 | pub fn request<M, U>(self, method: M, uri: U) -> Self |
103 | 0 | where |
104 | 0 | M: TryInto<http::Method>, |
105 | 0 | M::Error: fmt::Debug, |
106 | 0 | U: TryInto<http::Uri>, |
107 | 0 | U::Error: fmt::Debug, |
108 | | { |
109 | 0 | let method = method.try_into().unwrap(); |
110 | 0 | let uri = uri.try_into().unwrap(); |
111 | 0 | let (id, _, fields) = self.into_parts(); |
112 | 0 | let extensions = Default::default(); |
113 | 0 | let pseudo = frame::Pseudo::request(method, uri, extensions); |
114 | 0 | let frame = frame::Headers::new(id, pseudo, fields); |
115 | 0 | Mock(frame) |
116 | 0 | } |
117 | | |
118 | 0 | pub fn method<M>(self, method: M) -> Self |
119 | 0 | where |
120 | 0 | M: TryInto<http::Method>, |
121 | 0 | M::Error: fmt::Debug, |
122 | | { |
123 | 0 | let method = method.try_into().unwrap(); |
124 | 0 | let (id, pseudo, fields) = self.into_parts(); |
125 | 0 | let frame = frame::Headers::new( |
126 | 0 | id, |
127 | 0 | frame::Pseudo { |
128 | 0 | method: Some(method), |
129 | 0 | ..pseudo |
130 | 0 | }, |
131 | 0 | fields, |
132 | | ); |
133 | 0 | Mock(frame) |
134 | 0 | } |
135 | | |
136 | | pub fn pseudo(self, pseudo: frame::Pseudo) -> Self { |
137 | | let (id, _, fields) = self.into_parts(); |
138 | | let frame = frame::Headers::new(id, pseudo, fields); |
139 | | Mock(frame) |
140 | | } |
141 | | |
142 | 0 | pub fn response<S>(self, status: S) -> Self |
143 | 0 | where |
144 | 0 | S: TryInto<http::StatusCode>, |
145 | 0 | S::Error: fmt::Debug, |
146 | | { |
147 | 0 | let status = status.try_into().unwrap(); |
148 | 0 | let (id, _, fields) = self.into_parts(); |
149 | 0 | let frame = frame::Headers::new(id, frame::Pseudo::response(status), fields); |
150 | 0 | Mock(frame) |
151 | 0 | } |
152 | | |
153 | | pub fn fields(self, fields: HeaderMap) -> Self { |
154 | | let (id, pseudo, _) = self.into_parts(); |
155 | | let frame = frame::Headers::new(id, pseudo, fields); |
156 | | Mock(frame) |
157 | | } |
158 | | |
159 | 0 | pub fn field<K, V>(self, key: K, value: V) -> Self |
160 | 0 | where |
161 | 0 | K: TryInto<http::header::HeaderName>, |
162 | 0 | K::Error: fmt::Debug, |
163 | 0 | V: TryInto<http::header::HeaderValue>, |
164 | 0 | V::Error: fmt::Debug, |
165 | | { |
166 | 0 | let (id, pseudo, mut fields) = self.into_parts(); |
167 | 0 | fields.insert(key.try_into().unwrap(), value.try_into().unwrap()); |
168 | 0 | let frame = frame::Headers::new(id, pseudo, fields); |
169 | 0 | Mock(frame) |
170 | 0 | } |
171 | | |
172 | | pub fn status(self, value: StatusCode) -> Self { |
173 | | let (id, mut pseudo, fields) = self.into_parts(); |
174 | | |
175 | | pseudo.set_status(value); |
176 | | |
177 | | Mock(frame::Headers::new(id, pseudo, fields)) |
178 | | } |
179 | | |
180 | | pub fn scheme(self, value: &str) -> Self { |
181 | | let (id, mut pseudo, fields) = self.into_parts(); |
182 | | let value = value.parse().unwrap(); |
183 | | |
184 | | pseudo.set_scheme(value); |
185 | | |
186 | | Mock(frame::Headers::new(id, pseudo, fields)) |
187 | | } |
188 | | |
189 | | pub fn eos(mut self) -> Self { |
190 | | self.0.set_end_stream(); |
191 | | self |
192 | | } |
193 | | |
194 | | pub fn into_fields(self) -> HeaderMap { |
195 | | self.0.into_parts().1 |
196 | | } |
197 | | |
198 | | fn into_parts(self) -> (StreamId, frame::Pseudo, HeaderMap) { |
199 | | assert!(!self.0.is_end_stream(), "eos flag will be lost"); |
200 | | assert!(self.0.is_end_headers(), "unset eoh will be lost"); |
201 | | let id = self.0.stream_id(); |
202 | | let parts = self.0.into_parts(); |
203 | | (id, parts.0, parts.1) |
204 | | } |
205 | | } |
206 | | |
207 | | impl From<Mock<frame::Headers>> for frame::Headers { |
208 | | fn from(src: Mock<frame::Headers>) -> Self { |
209 | | src.0 |
210 | | } |
211 | | } |
212 | | |
213 | | // Data helpers |
214 | | |
215 | | impl Mock<frame::Data> { |
216 | | pub fn padded(mut self) -> Self { |
217 | | self.0.set_padded(); |
218 | | self |
219 | | } |
220 | | |
221 | | pub fn eos(mut self) -> Self { |
222 | | self.0.set_end_stream(true); |
223 | | self |
224 | | } |
225 | | } |
226 | | |
227 | | // PushPromise helpers |
228 | | |
229 | | impl Mock<frame::PushPromise> { |
230 | 0 | pub fn request<M, U>(self, method: M, uri: U) -> Self |
231 | 0 | where |
232 | 0 | M: TryInto<http::Method>, |
233 | 0 | M::Error: fmt::Debug, |
234 | 0 | U: TryInto<http::Uri>, |
235 | 0 | U::Error: fmt::Debug, |
236 | | { |
237 | 0 | let method = method.try_into().unwrap(); |
238 | 0 | let uri = uri.try_into().unwrap(); |
239 | 0 | let (id, promised, _, fields) = self.into_parts(); |
240 | 0 | let extensions = Default::default(); |
241 | 0 | let pseudo = frame::Pseudo::request(method, uri, extensions); |
242 | 0 | let frame = frame::PushPromise::new(id, promised, pseudo, fields); |
243 | 0 | Mock(frame) |
244 | 0 | } |
245 | | |
246 | | pub fn fields(self, fields: HeaderMap) -> Self { |
247 | | let (id, promised, pseudo, _) = self.into_parts(); |
248 | | let frame = frame::PushPromise::new(id, promised, pseudo, fields); |
249 | | Mock(frame) |
250 | | } |
251 | | |
252 | 0 | pub fn field<K, V>(self, key: K, value: V) -> Self |
253 | 0 | where |
254 | 0 | K: TryInto<http::header::HeaderName>, |
255 | 0 | K::Error: fmt::Debug, |
256 | 0 | V: TryInto<http::header::HeaderValue>, |
257 | 0 | V::Error: fmt::Debug, |
258 | | { |
259 | 0 | let (id, promised, pseudo, mut fields) = self.into_parts(); |
260 | 0 | fields.insert(key.try_into().unwrap(), value.try_into().unwrap()); |
261 | 0 | let frame = frame::PushPromise::new(id, promised, pseudo, fields); |
262 | 0 | Mock(frame) |
263 | 0 | } |
264 | | |
265 | | fn into_parts(self) -> (StreamId, StreamId, frame::Pseudo, HeaderMap) { |
266 | | assert!(self.0.is_end_headers(), "unset eoh will be lost"); |
267 | | let id = self.0.stream_id(); |
268 | | let promised = self.0.promised_id(); |
269 | | let parts = self.0.into_parts(); |
270 | | (id, promised, parts.0, parts.1) |
271 | | } |
272 | | } |
273 | | |
274 | | // GoAway helpers |
275 | | |
276 | | impl Mock<frame::GoAway> { |
277 | | pub fn protocol_error(self) -> Self { |
278 | | self.reason(frame::Reason::PROTOCOL_ERROR) |
279 | | } |
280 | | |
281 | | pub fn internal_error(self) -> Self { |
282 | | self.reason(frame::Reason::INTERNAL_ERROR) |
283 | | } |
284 | | |
285 | | pub fn flow_control(self) -> Self { |
286 | | self.reason(frame::Reason::FLOW_CONTROL_ERROR) |
287 | | } |
288 | | |
289 | | pub fn frame_size(self) -> Self { |
290 | | self.reason(frame::Reason::FRAME_SIZE_ERROR) |
291 | | } |
292 | | |
293 | | pub fn calm(self) -> Self { |
294 | | self.reason(frame::Reason::ENHANCE_YOUR_CALM) |
295 | | } |
296 | | |
297 | | pub fn no_error(self) -> Self { |
298 | | self.reason(frame::Reason::NO_ERROR) |
299 | | } |
300 | | |
301 | 0 | pub fn data<I>(self, debug_data: I) -> Self |
302 | 0 | where |
303 | 0 | I: Into<Bytes>, |
304 | | { |
305 | 0 | Mock(frame::GoAway::with_debug_data( |
306 | 0 | self.0.last_stream_id(), |
307 | 0 | self.0.reason(), |
308 | 0 | debug_data.into(), |
309 | 0 | )) |
310 | 0 | } |
311 | | |
312 | | pub fn reason(self, reason: frame::Reason) -> Self { |
313 | | Mock(frame::GoAway::with_debug_data( |
314 | | self.0.last_stream_id(), |
315 | | reason, |
316 | | self.0.debug_data().clone(), |
317 | | )) |
318 | | } |
319 | | } |
320 | | |
321 | | // ==== Reset helpers |
322 | | |
323 | | impl Mock<frame::Reset> { |
324 | | pub fn protocol_error(self) -> Self { |
325 | | let id = self.0.stream_id(); |
326 | | Mock(frame::Reset::new(id, frame::Reason::PROTOCOL_ERROR)) |
327 | | } |
328 | | |
329 | | pub fn flow_control(self) -> Self { |
330 | | let id = self.0.stream_id(); |
331 | | Mock(frame::Reset::new(id, frame::Reason::FLOW_CONTROL_ERROR)) |
332 | | } |
333 | | |
334 | | pub fn refused(self) -> Self { |
335 | | let id = self.0.stream_id(); |
336 | | Mock(frame::Reset::new(id, frame::Reason::REFUSED_STREAM)) |
337 | | } |
338 | | |
339 | | pub fn cancel(self) -> Self { |
340 | | let id = self.0.stream_id(); |
341 | | Mock(frame::Reset::new(id, frame::Reason::CANCEL)) |
342 | | } |
343 | | |
344 | | pub fn stream_closed(self) -> Self { |
345 | | let id = self.0.stream_id(); |
346 | | Mock(frame::Reset::new(id, frame::Reason::STREAM_CLOSED)) |
347 | | } |
348 | | |
349 | | pub fn internal_error(self) -> Self { |
350 | | let id = self.0.stream_id(); |
351 | | Mock(frame::Reset::new(id, frame::Reason::INTERNAL_ERROR)) |
352 | | } |
353 | | |
354 | | pub fn reason(self, reason: frame::Reason) -> Self { |
355 | | let id = self.0.stream_id(); |
356 | | Mock(frame::Reset::new(id, reason)) |
357 | | } |
358 | | } |
359 | | |
360 | | // ==== Settings helpers |
361 | | |
362 | | impl Mock<frame::Settings> { |
363 | | pub fn max_concurrent_streams(mut self, max: u32) -> Self { |
364 | | self.0.set_max_concurrent_streams(Some(max)); |
365 | | self |
366 | | } |
367 | | |
368 | | pub fn max_frame_size(mut self, val: u32) -> Self { |
369 | | self.0.set_max_frame_size(Some(val)); |
370 | | self |
371 | | } |
372 | | |
373 | | pub fn initial_window_size(mut self, val: u32) -> Self { |
374 | | self.0.set_initial_window_size(Some(val)); |
375 | | self |
376 | | } |
377 | | |
378 | | pub fn max_header_list_size(mut self, val: u32) -> Self { |
379 | | self.0.set_max_header_list_size(Some(val)); |
380 | | self |
381 | | } |
382 | | |
383 | | pub fn disable_push(mut self) -> Self { |
384 | | self.0.set_enable_push(false); |
385 | | self |
386 | | } |
387 | | |
388 | | pub fn enable_connect_protocol(mut self, val: u32) -> Self { |
389 | | self.0.set_enable_connect_protocol(Some(val)); |
390 | | self |
391 | | } |
392 | | |
393 | | pub fn header_table_size(mut self, val: u32) -> Self { |
394 | | self.0.set_header_table_size(Some(val)); |
395 | | self |
396 | | } |
397 | | } |
398 | | |
399 | | impl From<Mock<frame::Settings>> for frame::Settings { |
400 | | fn from(src: Mock<frame::Settings>) -> Self { |
401 | | src.0 |
402 | | } |
403 | | } |
404 | | |
405 | | // ==== Ping helpers |
406 | | |
407 | | impl Mock<frame::Ping> { |
408 | | pub fn pong(self) -> Self { |
409 | | let payload = self.0.into_payload(); |
410 | | Mock(frame::Ping::pong(payload)) |
411 | | } |
412 | | } |