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 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 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#[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