1use 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 b.iter(|| decode())
123 }
124}