http2parse/
payload.rs

1use std::{slice, mem, fmt};
2use {FrameHeader, StreamIdentifier, Error, Kind,
3     ParserSettings, ErrorCode, SizeIncrement, Flag};
4
5use byteorder::ByteOrder;
6
7#[cfg(feature = "random")]
8use rand::{Rand, Rng};
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
11pub enum Payload<'a> {
12    Data {
13        data: &'a [u8]
14    },
15    Headers {
16        priority: Option<Priority>,
17        block: &'a [u8]
18    },
19    Priority(Priority),
20    Reset(ErrorCode),
21    Settings(&'a [Setting]),
22    PushPromise {
23        promised: StreamIdentifier,
24        block: &'a [u8]
25    },
26    Ping(u64),
27    GoAway {
28        last: StreamIdentifier,
29        error: ErrorCode,
30        data: &'a [u8]
31    },
32    WindowUpdate(SizeIncrement),
33    Continuation(&'a [u8]),
34    Unregistered(&'a [u8])
35}
36
37const PRIORITY_BYTES: u32 = 5;
38const PADDING_BYTES: u32 = 1;
39
40impl<'a> Payload<'a> {
41    #[inline]
42    pub fn kind(&self) -> Kind {
43        use self::Payload::*;
44
45        match *self {
46            Data { .. } => Kind::Data,
47            Headers { .. } => Kind::Headers,
48            Priority(..) => Kind::Priority,
49            Reset(..) => Kind::Reset,
50            Settings(..) => Kind::Settings,
51            PushPromise { .. } => Kind::PushPromise,
52            Ping(..) => Kind::Ping,
53            GoAway { .. } => Kind::GoAway,
54            WindowUpdate(_) => Kind::WindowUpdate,
55            Continuation(_) => Kind::Continuation,
56            Unregistered(_) => Kind::Unregistered
57        }
58    }
59
60    #[inline]
61    pub fn parse(header: FrameHeader, mut buf: &'a [u8]) -> Result<Payload<'a>, Error> {
62        let settings = ParserSettings {
63            padding: header.flag.contains(Flag::padded()),
64            priority: header.flag.contains(Flag::priority())
65        };
66
67        if buf.len() < header.length as usize {
68            return Err(Error::Short)
69        }
70
71        let min_payload_length =
72            if settings.priority && settings.padding {
73                PRIORITY_BYTES + PADDING_BYTES
74            } else if settings.priority {
75                PRIORITY_BYTES
76            } else if settings.padding {
77                PADDING_BYTES
78            } else {
79                0
80            };
81
82        if header.length < min_payload_length {
83            return Err(Error::PayloadLengthTooShort)
84        }
85
86        buf = &buf[..header.length as usize];
87
88        match header.kind {
89            Kind::Data => Payload::parse_data(header, buf, settings),
90            Kind::Headers => Payload::parse_headers(header, buf, settings),
91            Kind::Priority => {
92                let (_, priority) = try!(Priority::parse(true, buf));
93                Ok(Payload::Priority(priority.unwrap()))
94            },
95            Kind::Reset => Payload::parse_reset(header, buf),
96            Kind::Settings => Payload::parse_settings(header, buf),
97            Kind::Ping => Payload::parse_ping(header, buf),
98            Kind::GoAway => Payload::parse_goaway(header, buf),
99            Kind::WindowUpdate => Payload::parse_window_update(header, buf),
100            Kind::PushPromise => Payload::parse_push_promise(header, buf, settings),
101            Kind::Continuation => Ok(Payload::Continuation(buf)),
102            Kind::Unregistered => Ok(Payload::Unregistered(buf))
103        }
104    }
105
106    #[inline]
107    pub fn encode(&self, buf: &mut [u8]) -> usize {
108        match *self {
109            Payload::Data { ref data } => { encode_memory(data, buf) },
110            Payload::Headers { ref priority, ref block } => {
111                let priority_wrote = priority.map(|p| { p.encode(buf) }).unwrap_or(0);
112                let block_wrote = encode_memory(block, &mut buf[priority_wrote..]);
113                priority_wrote + block_wrote
114            },
115            Payload::Reset(ref err) => { err.encode(buf) },
116            Payload::Settings(ref settings) => {
117                encode_memory(Setting::to_bytes(settings), buf)
118            },
119            Payload::Ping(data) => { ::encode_u64(buf, data) },
120            Payload::GoAway { ref data, ref last, ref error } => {
121                let last_wrote = last.encode(buf);
122                let buf = &mut buf[last_wrote..];
123
124                let error_wrote = error.encode(buf);
125                let buf = &mut buf[error_wrote..];
126
127                encode_memory(data, buf) + last_wrote + error_wrote
128            },
129            Payload::WindowUpdate(ref increment) => { increment.encode(buf) },
130            Payload::PushPromise { ref promised, ref block } => {
131                promised.encode(buf);
132                encode_memory(block, &mut buf[4..]) + 4
133            },
134            Payload::Priority(ref priority) => { priority.encode(buf) },
135            Payload::Continuation(ref block) => { encode_memory(block, buf) },
136            Payload::Unregistered(ref block) => { encode_memory(block, buf) }
137        }
138    }
139
140    #[inline]
141    /// How many bytes this Payload would be encoded.
142    pub fn encoded_len(&self) -> usize {
143        use self::Payload::*;
144
145        match *self {
146            Data { ref data } => { data.len() },
147            Headers { ref priority, ref block } => {
148                let priority_len = if priority.is_some() { 5 } else { 0 };
149                priority_len + block.len()
150            },
151            Reset(_) => 4,
152            Settings(ref settings) => settings.len() * mem::size_of::<Setting>(),
153            Ping(_) => 8,
154            GoAway { ref data, .. } => 4 + 4 + data.len(),
155            WindowUpdate(_) => 4,
156            PushPromise { ref block, .. } => 4 + block.len(),
157            Priority(_) => 5,
158            Continuation(ref block) => block.len(),
159            Unregistered(ref block) => block.len()
160        }
161    }
162
163    #[inline]
164    pub fn padded(&self) -> Option<u32> {
165        None
166    }
167
168    #[inline]
169    pub fn priority(&self) -> Option<&Priority> {
170        match *self {
171            Payload::Priority(ref priority) => Some(priority),
172            Payload::Headers { ref priority, .. } => priority.as_ref(),
173            _ => None
174        }
175    }
176
177    #[inline]
178    fn parse_data(header: FrameHeader, buf: &'a [u8],
179                  settings: ParserSettings) -> Result<Payload<'a>, Error> {
180        Ok(Payload::Data {
181            data: try!(trim_padding(settings, header, buf))
182        })
183    }
184
185    #[inline]
186    fn parse_headers(header: FrameHeader, mut buf: &'a [u8],
187                     settings: ParserSettings) -> Result<Payload<'a>, Error> {
188        buf = try!(trim_padding(settings, header, buf));
189        let (buf, priority) = try!(Priority::parse(settings.priority, buf));
190        Ok(Payload::Headers {
191            priority: priority,
192            block: buf
193        })
194    }
195
196    #[inline]
197    fn parse_reset(header: FrameHeader,
198                   buf: &'a [u8]) -> Result<Payload<'a>, Error> {
199        if header.length < 4 {
200            return Err(Error::PayloadLengthTooShort)
201        }
202
203        Ok(Payload::Reset(ErrorCode::parse(buf)))
204    }
205
206    #[inline]
207    fn parse_settings(header: FrameHeader,
208                      buf: &'a [u8]) -> Result<Payload<'a>, Error> {
209        if header.length % mem::size_of::<Setting>() as u32 != 0 {
210            return Err(Error::PartialSettingLength)
211        }
212
213        Ok(Payload::Settings(Setting::from_bytes(&buf[..header.length as usize])))
214    }
215
216    #[inline]
217    fn parse_ping(header: FrameHeader,
218                  buf: &'a [u8]) -> Result<Payload<'a>, Error> {
219        if header.length != 8 {
220            return Err(Error::InvalidPayloadLength)
221        }
222
223        let data = ::byteorder::BigEndian::read_u64(buf);
224        Ok(Payload::Ping(data))
225    }
226
227    #[inline]
228    fn parse_goaway(header: FrameHeader,
229                    buf: &'a [u8]) -> Result<Payload<'a>, Error> {
230        if header.length < 8 {
231            return Err(Error::PayloadLengthTooShort)
232        }
233
234        let last = StreamIdentifier::parse(buf);
235        let error = ErrorCode::parse(&buf[4..]);
236        let rest = &buf[8..];
237
238        Ok(Payload::GoAway {
239            last: last,
240            error: error,
241            data: rest
242        })
243    }
244
245    #[inline]
246    fn parse_window_update(header: FrameHeader,
247                           buf: &'a [u8]) -> Result<Payload<'a>, Error> {
248        if header.length != 4 {
249            return Err(Error::InvalidPayloadLength)
250        }
251
252        Ok(Payload::WindowUpdate(SizeIncrement::parse(buf)))
253    }
254
255    #[inline]
256    fn parse_push_promise(header: FrameHeader, mut buf: &'a [u8],
257                          settings: ParserSettings) -> Result<Payload<'a>, Error> {
258        buf = try!(trim_padding(settings, header, buf));
259
260        if buf.len() < 4 {
261            return Err(Error::PayloadLengthTooShort)
262        }
263
264        let promised = StreamIdentifier::parse(buf);
265        let block = &buf[4..];
266
267        Ok(Payload::PushPromise {
268             promised: promised,
269             block: block
270        })
271    }
272}
273
274#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
275pub struct Priority {
276    exclusive: bool,
277    dependency: StreamIdentifier,
278    weight: u8
279}
280
281impl Priority {
282    #[inline]
283    pub fn parse(present: bool, buf: &[u8]) -> Result<(&[u8], Option<Priority>), Error> {
284        if present {
285            Ok((&buf[5..], Some(Priority {
286                // Most significant bit.
287                exclusive: buf[0] & 0x7F != buf[0],
288                dependency: StreamIdentifier::parse(buf),
289                weight: buf[4]
290            })))
291        } else {
292            Ok((buf, None))
293        }
294    }
295
296    #[inline]
297    pub fn encode(&self, buf: &mut [u8]) -> usize {
298        let mut dependency = self.dependency;
299        if self.exclusive { dependency.0 |= 1 << 31 }
300
301        dependency.encode(buf);
302        buf[PRIORITY_BYTES as usize - 1] = self.weight;
303
304        PRIORITY_BYTES as usize
305    }
306}
307
308// Settings are (u16, u32) in memory.
309#[repr(packed)]
310#[derive(Copy, Clone, PartialEq, Eq, Hash)]
311pub struct Setting {
312    identifier: u16,
313    value: u32
314}
315
316impl fmt::Debug for Setting {
317    #[inline]
318    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319        fmt::Debug::fmt(&self.identifier(), f)
320    }
321}
322
323impl Setting {
324    #[inline]
325    pub fn identifier(&self) -> Option<SettingIdentifier> {
326        match self.identifier {
327            0x1 => Some(SettingIdentifier::HeaderTableSize),
328            0x2 => Some(SettingIdentifier::EnablePush),
329            0x3 => Some(SettingIdentifier::MaxConcurrentStreams),
330            0x4 => Some(SettingIdentifier::InitialWindowSize),
331            0x5 => Some(SettingIdentifier::MaxFrameSize),
332            _ => None
333        }
334    }
335
336    #[inline]
337    fn to_bytes(settings: &[Setting]) -> &[u8] {
338        unsafe {
339            slice::from_raw_parts(
340                settings.as_ptr() as *const u8,
341                settings.len() * mem::size_of::<Setting>())
342        }
343    }
344
345    #[inline]
346    fn from_bytes(bytes: &[u8]) -> &[Setting] {
347        unsafe {
348            slice::from_raw_parts(
349                bytes.as_ptr() as *const Setting,
350                bytes.len() / mem::size_of::<Setting>())
351        }
352    }
353}
354
355#[repr(u16)]
356#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
357pub enum SettingIdentifier {
358    HeaderTableSize = 0x1,
359    EnablePush = 0x2,
360    MaxConcurrentStreams = 0x3,
361    InitialWindowSize = 0x4,
362    MaxFrameSize = 0x5
363}
364
365#[cfg(feature = "random")]
366impl Rand for Payload<'static> {
367    fn rand<R: Rng>(rng: &mut R) -> Self {
368        use self::Payload::*;
369
370        let choices = &[
371            Data {
372                data: rand_buf(rng)
373            },
374            Headers {
375                priority: rng.gen(),
376                block: rand_buf(rng),
377            },
378            Priority(rng.gen()),
379            Reset(ErrorCode(rng.gen())),
380            Settings(leak({
381                let len = rng.gen_range(0, 200);
382
383                (0..len).map(|_| Setting {
384                    identifier: *rng.choose(&[
385                        SettingIdentifier::HeaderTableSize,
386                        SettingIdentifier::EnablePush,
387                        SettingIdentifier::MaxConcurrentStreams,
388                        SettingIdentifier::InitialWindowSize,
389                        SettingIdentifier::MaxFrameSize
390                    ]).unwrap() as u16,
391                    value: rng.gen()
392                }).collect::<Vec<Setting>>()})),
393            PushPromise {
394                promised: StreamIdentifier(rng.gen_range(0, 1 << 31)),
395                block: rand_buf(rng)
396            },
397            Ping(rng.gen()),
398            GoAway {
399                last: StreamIdentifier(rng.gen_range(0, 1 << 31)),
400                error: ErrorCode(rng.gen()),
401                data: rand_buf(rng)
402            },
403            WindowUpdate(SizeIncrement(rng.gen())),
404            Continuation(rand_buf(rng)),
405            Unregistered(rand_buf(rng))
406        ];
407
408        *rng.choose(choices).unwrap()
409    }
410}
411
412#[cfg(feature = "random")]
413impl Rand for Priority {
414    fn rand<R: Rng>(rng: &mut R) -> Self {
415        Priority {
416            exclusive: rng.gen(),
417            dependency: StreamIdentifier(rng.gen_range(0, 1 << 31)),
418            weight: rng.gen()
419        }
420    }
421}
422
423#[cfg(feature = "random")]
424fn rand_buf<R: Rng>(rng: &mut R) -> &'static [u8] {
425    let len = rng.gen_range(0, 200);
426    let mut buf = vec![0; len];
427    rng.fill_bytes(&mut *buf);
428
429    leak(buf)
430}
431
432#[cfg(feature = "random")]
433fn leak<T>(buf: Vec<T>) -> &'static [T] {
434    let result = unsafe { mem::transmute::<&[T], &'static [T]>(&*buf) };
435    mem::forget(buf);
436    result
437}
438
439#[inline]
440fn trim_padding(settings: ParserSettings, header: FrameHeader,
441                buf: &[u8]) -> Result<&[u8], Error> {
442    if settings.padding {
443        let pad_length = buf[0];
444        if pad_length as u32 > header.length {
445            Err(Error::TooMuchPadding(pad_length))
446        } else {
447            Ok(&buf[1..header.length as usize - pad_length as usize])
448        }
449    } else {
450        Ok(buf)
451    }
452}
453
454#[inline]
455fn encode_memory(src: &[u8], mut dst: &mut [u8]) -> usize {
456    use std::io::Write;
457    dst.write(src).unwrap()
458}
459
460#[test]
461#[cfg(feature = "random")]
462fn test_specific_encode() {
463    fn roundtrip(buf: &mut [u8], payload: Payload) {
464        payload.encode(buf);
465
466        assert_eq!(payload, Payload::parse(::frame::rand_for_payload(&payload), &buf).unwrap());
467    }
468
469    let mut buf = vec![0; 5000];
470    roundtrip(&mut buf, Payload::PushPromise { promised: StreamIdentifier(2000064271), block: &[255, 108, 25, 19, 189, 134, 191, 26, 27, 56, 65, 237, 220, 161, 73, 167, 246, 154, 248, 216, 236, 6, 23, 200, 56, 128, 239, 218, 193, 25, 221, 115, 37, 74, 50, 35, 75, 254, 88, 173, 24, 193, 220, 201, 102, 114, 187, 68, 8, 59, 205, 49, 180, 217, 170, 241, 11, 155, 115, 146, 109, 160, 85, 197, 32, 243, 191, 94, 96, 143, 206, 11, 244, 4, 244, 136, 201, 232, 111, 246, 251, 139, 81, 67, 116, 16, 201, 109, 121, 170, 48, 38, 23, 99, 101, 182, 111, 110, 202, 153, 0, 230, 87, 242, 206, 72, 196, 106, 200, 243, 48, 16, 33, 205, 65, 112, 132, 150, 89, 161, 108, 231, 155, 243, 123, 92, 141, 128, 204, 33, 207] });
471    roundtrip(&mut buf, Payload::Ping(4513863121605750535));
472}
473
474#[test]
475#[cfg(feature = "random")]
476fn test_randomized_encoded_len() {
477    fn roundtrip(buf: &mut [u8], payload: Payload, round: usize) {
478        let len = payload.encoded_len();
479        let encoded = payload.encode(buf);
480
481        assert!(encoded == len, format!("Bad roundtrip! encoded={:?}, len={:?}, payload={:#?}, round={:?}",
482                                        encoded, len, payload, round))
483    }
484
485    let mut buf = vec![0; 5000];
486    for round in 0..1000 {
487        roundtrip(&mut buf, ::rand::random(), round)
488    }
489}
490
491#[test]
492#[cfg(feature = "random")]
493fn test_randomized_encode() {
494    fn roundtrip(buf: &mut [u8], payload: Payload) {
495        payload.encode(buf);
496
497        assert_eq!(payload, Payload::parse(::frame::rand_for_payload(&payload), &buf).unwrap());
498    }
499
500    let mut buf = vec![0; 5000];
501    for _ in 0..1000 {
502        roundtrip(&mut buf, ::rand::random())
503    }
504}
505
506#[test]
507#[cfg(not(feature = "random"))]
508fn no_test_encoded_len_because_no_rand() {}
509
510#[test]
511#[cfg(not(feature = "random"))]
512fn no_test_encode_because_no_rand() {}
513