http_rs/
codec.rs

1//! [RFC 2616](https://tools.ietf.org/html/rfc2616#section-5.1)
2//!
3//! Request
4//! =======
5//! Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
6//! Request-URI    = "*" | absoluteURI | abs_path | authority
7//!
8//! Response
9//! ========
10
11use bytes::{ BytesMut, Buf };
12
13use crate::{
14    HttpResult,
15    HttpError,
16    Request,
17};
18
19use tokio_util::codec::{
20    Decoder,
21};
22
23#[derive(Debug, Default)]
24pub struct HttpCodec {
25    pub pos_n: Vec<usize>,
26    pub payload: BytesMut,
27}
28
29impl HttpCodec {
30    #[inline(always)]
31    fn _parse(&mut self, buf: &mut BytesMut) -> Option<Request> {
32        for (i, c) in buf.iter().enumerate() {
33            if *c == 0x0A {
34                let i = self.payload.len() + i;
35
36                self.pos_n.push(i);
37
38                if self.pos_n.len() >= 2 && (i - 2 == self.pos_n[self.pos_n.len() - 2]) {
39                    self._advance(buf);
40                    return self._build_request();
41                }
42            }
43        }
44
45        self._advance(buf);
46        None
47    }
48
49    #[inline(always)]
50    fn _advance(&mut self, buf: &mut BytesMut) {
51        self.payload.extend_from_slice(&buf[..]);
52        buf.advance(buf.len());
53    }
54
55    #[inline(always)]
56    fn _build_request(&self) -> Option<Request> {
57        Some(Request::new(&self.payload, &self.pos_n))
58    }
59}
60
61impl HttpCodec {
62
63}
64
65impl Decoder for HttpCodec {
66    type Item = Request;
67    type Error = HttpError;
68
69    fn decode(&mut self, buf: &mut BytesMut) -> HttpResult<Option<Self::Item>> {
70        if let Some(request) = self._parse(buf) {
71            return Ok(Some(request))
72        }
73
74        Ok(None)
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    extern crate test;
81
82    use bytes::{ BytesMut, BufMut };
83    use super::*;
84    use crate::Method;
85    use test::Bencher;
86
87    #[test]
88    fn decode() {
89        let mut codec = HttpCodec::default();
90        let mut buf = BytesMut::from(&b"GET "[..]);
91        let res = codec.decode(&mut buf);
92        assert!(res.unwrap().is_none());
93
94        buf.put_slice(&b"/ws/terminal HTTP/"[..]);
95        let res = codec.decode(&mut buf);
96        assert!(res.unwrap().is_none());
97
98        buf.put_slice(&b"1.1\r\nHost: hawk.local\r"[..]);
99        let res = codec.decode(&mut buf);
100        assert!(res.unwrap().is_none());
101
102        buf.put_slice(&b"\nUpgrade:websocket\r"[..]);
103        let res = codec.decode(&mut buf);
104        assert!(res.unwrap().is_none());
105
106        buf.put_slice(&b"\n\r\n"[..]);
107        let res = codec.decode(&mut buf);
108        let req = res.unwrap().unwrap();
109
110        assert_eq!("https://hawk.local/ws/terminal", req.url.as_str());
111        assert_eq!(Method::GET, req.method);
112        assert_eq!(1, req.version);
113        assert_eq!("hawk.local", req.headers.get("host").unwrap());
114        assert_eq!("websocket", req.headers.get("upgrade").unwrap());
115    }
116
117    #[bench]
118    fn bench_decode(b: &mut Bencher) {
119        // 7,760 ns/iter (+/- 185)
120        // 7,848 ns/iter (+/- 587)
121        // 7,938 ns/iter (+/- 617)
122        b.iter(|| decode())
123    }
124}