Coverage Report

Created: 2025-10-28 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}