sozu_lib/protocol/h2/
parser.rs

1use std::convert::From;
2
3use nom::{
4    bytes::streaming::{tag, take},
5    combinator::{complete, map, map_opt},
6    error::{ErrorKind, ParseError},
7    multi::many0,
8    number::streaming::{be_u16, be_u24, be_u32, be_u8},
9    sequence::tuple,
10    Err, HexDisplay, IResult, Offset,
11};
12
13#[derive(Clone, Debug, PartialEq)]
14pub struct FrameHeader {
15    pub payload_len: u32,
16    pub frame_type: FrameType,
17    pub flags: u8,
18    pub stream_id: u32,
19}
20
21#[derive(Clone, Debug, PartialEq)]
22pub enum FrameType {
23    Data,
24    Headers,
25    Priority,
26    RstStream,
27    Settings,
28    PushPromise,
29    Ping,
30    GoAway,
31    WindowUpdate,
32    Continuation,
33}
34
35/*
36const NO_ERROR: u32 = 0x0;
37const PROTOCOL_ERROR: u32 = 0x1;
38const INTERNAL_ERROR: u32 = 0x2;
39const FLOW_CONTROL_ERROR: u32 = 0x3;
40const SETTINGS_TIMEOUT: u32 = 0x4;
41const STREAM_CLOSED: u32 = 0x5;
42const FRAME_SIZE_ERROR: u32 = 0x6;
43const REFUSED_STREAM: u32 = 0x7;
44const CANCEL: u32 = 0x8;
45const COMPRESSION_ERROR: u32 = 0x9;
46const CONNECT_ERROR: u32 = 0xa;
47const ENHANCE_YOUR_CALM: u32 = 0xb;
48const INADEQUATE_SECURITY: u32 = 0xc;
49const HTTP_1_1_REQUIRED: u32 = 0xd;
50*/
51
52#[derive(Clone, Debug, PartialEq)]
53pub struct Error<'a> {
54    pub input: &'a [u8],
55    pub error: InnerError,
56}
57
58#[derive(Clone, Debug, PartialEq)]
59pub enum InnerError {
60    Nom(ErrorKind),
61    NoError,
62    ProtocolError,
63    InternalError,
64    FlowControlError,
65    SettingsTimeout,
66    StreamClosed,
67    FrameSizeError,
68    RefusedStream,
69    Cancel,
70    CompressionError,
71    ConnectError,
72    EnhanceYourCalm,
73    InadequateSecurity,
74    HTTP11Required,
75}
76
77impl<'a> Error<'a> {
78    pub fn new(input: &'a [u8], error: InnerError) -> Error<'a> {
79        Error { input, error }
80    }
81}
82
83impl<'a> ParseError<&'a [u8]> for Error<'a> {
84    fn from_error_kind(input: &'a [u8], kind: ErrorKind) -> Self {
85        Error {
86            input,
87            error: InnerError::Nom(kind),
88        }
89    }
90
91    fn append(input: &'a [u8], kind: ErrorKind, other: Self) -> Self {
92        Error {
93            input,
94            error: InnerError::Nom(kind),
95        }
96    }
97}
98
99impl<'a> From<(&'a [u8], ErrorKind)> for Error<'a> {
100    fn from((input, kind): (&'a [u8], ErrorKind)) -> Self {
101        Error {
102            input,
103            error: InnerError::Nom(kind),
104        }
105    }
106}
107
108pub fn preface(i: &[u8]) -> IResult<&[u8], &[u8]> {
109    tag(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")(i)
110}
111
112// https://httpwg.org/specs/rfc7540.html#rfc.section.4.1
113/*named!(pub frame_header<FrameHeader>,
114  do_parse!(
115    payload_len: dbg_dmp!(be_u24) >>
116    frame_type: map_opt!(be_u8, convert_frame_type) >>
117    flags: dbg_dmp!(be_u8) >>
118    stream_id: dbg_dmp!(verify!(be_u32, |id| {
119      match frame_type {
120
121      }
122    }) >>
123    (FrameHeader { payload_len, frame_type, flags, stream_id })
124  )
125);
126  */
127
128pub fn frame_header(input: &[u8]) -> IResult<&[u8], FrameHeader, Error> {
129    let (i1, payload_len) = be_u24(input)?;
130    let (i2, frame_type) = map_opt(be_u8, convert_frame_type)(i1)?;
131    let (i3, flags) = be_u8(i2)?;
132    let (i4, stream_id) = be_u32(i3)?;
133
134    Ok((
135        i4,
136        FrameHeader {
137            payload_len,
138            frame_type,
139            flags,
140            stream_id,
141        },
142    ))
143}
144
145fn convert_frame_type(t: u8) -> Option<FrameType> {
146    info!("got frame type: {}", t);
147    match t {
148        0 => Some(FrameType::Data),
149        1 => Some(FrameType::Headers),
150        2 => Some(FrameType::Priority),
151        3 => Some(FrameType::RstStream),
152        4 => Some(FrameType::Settings),
153        5 => Some(FrameType::PushPromise),
154        6 => Some(FrameType::Ping),
155        7 => Some(FrameType::GoAway),
156        8 => Some(FrameType::WindowUpdate),
157        9 => Some(FrameType::Continuation),
158        _ => None,
159    }
160}
161
162#[derive(Clone, Debug, PartialEq)]
163pub enum Frame<'a> {
164    Data(Data<'a>),
165    Headers(Headers<'a>),
166    Priority,
167    RstStream(RstStream),
168    Settings(Settings),
169    PushPromise,
170    Ping(Ping),
171    GoAway,
172    WindowUpdate(WindowUpdate),
173    Continuation,
174}
175
176impl<'a> Frame<'a> {
177    pub fn is_stream_specific(&self) -> bool {
178        match self {
179            Frame::Data(_)
180            | Frame::Headers(_)
181            | Frame::Priority
182            | Frame::RstStream(_)
183            | Frame::PushPromise
184            | Frame::Continuation => true,
185            Frame::Settings(_) | Frame::Ping(_) | Frame::GoAway => false,
186            Frame::WindowUpdate(w) => w.stream_id != 0,
187        }
188    }
189
190    pub fn stream_id(&self) -> u32 {
191        match self {
192            Frame::Data(d) => d.stream_id,
193            Frame::Headers(h) => h.stream_id,
194            Frame::Priority => unimplemented!(),
195            Frame::RstStream(r) => r.stream_id,
196            Frame::PushPromise => unimplemented!(),
197            Frame::Continuation => unimplemented!(),
198            Frame::Settings(_) | Frame::Ping(_) | Frame::GoAway => 0,
199            Frame::WindowUpdate(w) => w.stream_id,
200        }
201    }
202}
203
204pub fn frame<'a>(input: &'a [u8], max_frame_size: u32) -> IResult<&'a [u8], Frame<'a>, Error<'a>> {
205    let (i, header) = frame_header(input)?;
206
207    info!("got frame header: {:?}", header);
208
209    if header.payload_len > max_frame_size {
210        return Err(Err::Failure(Error::new(input, InnerError::FrameSizeError)));
211    }
212
213    let valid_stream_id = match header.frame_type {
214        FrameType::Data
215        | FrameType::Headers
216        | FrameType::Priority
217        | FrameType::RstStream
218        | FrameType::PushPromise
219        | FrameType::Continuation => header.stream_id != 0,
220        FrameType::Settings | FrameType::Ping | FrameType::GoAway => header.stream_id == 0,
221        FrameType::WindowUpdate => true,
222    };
223
224    if !valid_stream_id {
225        return Err(Err::Failure(Error::new(input, InnerError::ProtocolError)));
226    }
227
228    let f = match header.frame_type {
229        FrameType::Data => data_frame(i, &header)?,
230        FrameType::Headers => headers_frame(i, &header)?,
231        FrameType::Priority => {
232            if header.payload_len != 5 {
233                return Err(Err::Failure(Error::new(input, InnerError::FrameSizeError)));
234            }
235            unimplemented!();
236        }
237        FrameType::RstStream => {
238            if header.payload_len != 4 {
239                return Err(Err::Failure(Error::new(input, InnerError::FrameSizeError)));
240            }
241            rst_stream_frame(i, &header)?
242        }
243        FrameType::PushPromise => {
244            unimplemented!();
245        }
246        FrameType::Continuation => {
247            unimplemented!();
248        }
249        FrameType::Settings => {
250            if header.payload_len % 6 != 0 {
251                return Err(Err::Failure(Error::new(input, InnerError::FrameSizeError)));
252            }
253            settings_frame(i, &header)?
254        }
255        FrameType::Ping => {
256            if header.payload_len != 8 {
257                return Err(Err::Failure(Error::new(input, InnerError::FrameSizeError)));
258            }
259            ping_frame(i, &header)?
260        }
261        FrameType::GoAway => {
262            unimplemented!();
263        }
264        FrameType::WindowUpdate => {
265            if header.payload_len != 4 {
266                return Err(Err::Failure(Error::new(input, InnerError::FrameSizeError)));
267            }
268            window_update_frame(i, &header)?
269        }
270    };
271
272    Ok(f)
273}
274
275#[derive(Clone, Debug, PartialEq)]
276pub struct Data<'a> {
277    pub stream_id: u32,
278    pub payload: &'a [u8],
279    pub end_stream: bool,
280}
281
282pub fn data_frame<'a, 'b>(
283    input: &'a [u8],
284    header: &'b FrameHeader,
285) -> IResult<&'a [u8], Frame<'a>, Error<'a>> {
286    let (remaining, i) = take(header.payload_len)(input)?;
287
288    let (i1, pad_length) = if header.flags & 0x8 != 0 {
289        let (i, pad_length) = be_u8(i)?;
290        (i, Some(pad_length))
291    } else {
292        (i, None)
293    };
294
295    if pad_length.is_some() && i1.len() <= pad_length.unwrap() as usize {
296        return Err(Err::Failure(Error::new(input, InnerError::ProtocolError)));
297    }
298
299    let (_, payload) = take(i1.len() - pad_length.unwrap_or(0) as usize)(i1)?;
300
301    Ok((
302        remaining,
303        Frame::Data(Data {
304            stream_id: header.stream_id,
305            payload,
306            end_stream: header.flags & 0x1 != 0,
307        }),
308    ))
309}
310
311#[derive(Clone, Debug, PartialEq)]
312pub struct Headers<'a> {
313    pub stream_id: u32,
314    pub stream_dependency: Option<StreamDependency>,
315    pub weight: Option<u8>,
316    pub header_block_fragment: &'a [u8],
317    pub end_stream: bool,
318    pub end_headers: bool,
319    pub priority: bool,
320}
321
322#[derive(Clone, Debug, PartialEq)]
323pub struct StreamDependency {
324    pub exclusive: bool,
325    pub stream_id: u32,
326}
327
328pub fn headers_frame<'a, 'b>(
329    input: &'a [u8],
330    header: &'b FrameHeader,
331) -> IResult<&'a [u8], Frame<'a>, Error<'a>> {
332    let (remaining, i) = take(header.payload_len)(input)?;
333
334    let (i1, pad_length) = if header.flags & 0x8 != 0 {
335        let (i, pad_length) = be_u8(i)?;
336        (i, Some(pad_length))
337    } else {
338        (i, None)
339    };
340
341    let (i2, stream_dependency) = if header.flags & 0x20 != 0 {
342        let (i, stream) = map(be_u32, |i| StreamDependency {
343            exclusive: i & 0x8000 != 0,
344            stream_id: i & 0x7FFF,
345        })(i1)?;
346        (i, Some(stream))
347    } else {
348        (i1, None)
349    };
350
351    let (i3, weight) = if header.flags & 0x20 != 0 {
352        let (i, weight) = be_u8(i2)?;
353        (i, Some(weight))
354    } else {
355        (i2, None)
356    };
357
358    if pad_length.is_some() && i3.len() <= pad_length.unwrap() as usize {
359        return Err(Err::Failure(Error::new(input, InnerError::ProtocolError)));
360    }
361
362    let (_, header_block_fragment) = take(i3.len() - pad_length.unwrap_or(0) as usize)(i3)?;
363
364    Ok((
365        remaining,
366        Frame::Headers(Headers {
367            stream_id: header.stream_id,
368            stream_dependency,
369            weight,
370            header_block_fragment,
371            end_stream: header.flags & 0x1 != 0,
372            end_headers: header.flags & 0x4 != 0,
373            priority: header.flags & 0x20 != 0,
374        }),
375    ))
376}
377
378#[derive(Clone, Debug, PartialEq)]
379pub struct RstStream {
380    pub stream_id: u32,
381    pub error_code: u32,
382}
383
384pub fn rst_stream_frame<'a, 'b>(
385    input: &'a [u8],
386    header: &'b FrameHeader,
387) -> IResult<&'a [u8], Frame<'a>, Error<'a>> {
388    let (i, error_code) = be_u32(input)?;
389    Ok((
390        i,
391        Frame::RstStream(RstStream {
392            stream_id: header.stream_id,
393            error_code,
394        }),
395    ))
396}
397
398#[derive(Clone, Debug, PartialEq)]
399pub struct Settings {
400    pub settings: Vec<Setting>,
401}
402
403#[derive(Clone, Debug, PartialEq)]
404pub struct Setting {
405    pub identifier: u16,
406    pub value: u32,
407}
408
409pub fn settings_frame<'a, 'b>(
410    input: &'a [u8],
411    header: &'b FrameHeader,
412) -> IResult<&'a [u8], Frame<'a>, Error<'a>> {
413    let (i, data) = take(header.payload_len)(input)?;
414
415    let (_, settings) = many0(map(
416        complete(tuple((be_u16, be_u32))),
417        |(identifier, value)| Setting { identifier, value },
418    ))(data)?;
419
420    Ok((i, Frame::Settings(Settings { settings })))
421}
422
423#[derive(Clone, Debug, PartialEq)]
424pub struct Ping {
425    pub payload: [u8; 8],
426}
427
428pub fn ping_frame<'a, 'b>(
429    input: &'a [u8],
430    header: &'b FrameHeader,
431) -> IResult<&'a [u8], Frame<'a>, Error<'a>> {
432    let (i, data) = take(8usize)(input)?;
433
434    let mut p = Ping { payload: [0; 8] };
435
436    for i in 0..8 {
437        p.payload[i] = data[i];
438    }
439
440    Ok((i, Frame::Ping(p)))
441}
442
443#[derive(Clone, Debug, PartialEq)]
444pub struct WindowUpdate {
445    pub stream_id: u32,
446    pub increment: u32,
447}
448
449pub fn window_update_frame<'a, 'b>(
450    input: &'a [u8],
451    header: &'b FrameHeader,
452) -> IResult<&'a [u8], Frame<'a>, Error<'a>> {
453    let (i, increment) = be_u32(input)?;
454    let increment = increment & 0x7FFF;
455
456    //FIXME: if stream id is 0, trat it as connection error?
457    if increment == 0 {
458        return Err(Err::Failure(Error::new(input, InnerError::ProtocolError)));
459    }
460
461    Ok((
462        i,
463        Frame::WindowUpdate(WindowUpdate {
464            stream_id: header.stream_id,
465            increment,
466        }),
467    ))
468}
469
470#[macro_export]
471macro_rules! map_err(
472  (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
473    ($submac!($i, $($args)*)).map_err(|e| {
474      $g(e)
475    })
476  );
477);