httpcodec/
request_target.rs

1use bytecodec::{ByteCount, Decode, Eos, ErrorKind, Result};
2use std::fmt;
3
4use util;
5
6/// Request target.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
8pub struct RequestTarget<'a>(&'a str);
9impl<'a> RequestTarget<'a> {
10    /// Makes a new `RequestTarget` instance.
11    ///
12    /// # Errors
13    ///
14    /// `target` must be composed of "VCHAR" characters that defined in [RFC 7230].
15    /// If it contains any other characters,
16    /// an `ErrorKind::InvalidInput` error will be returned.
17    ///
18    /// [RFC 7230]: https://tools.ietf.org/html/rfc7230
19    pub fn new(target: &'a str) -> Result<Self> {
20        track_assert!(target.bytes().all(util::is_vchar), ErrorKind::InvalidInput);
21        Ok(RequestTarget(target))
22    }
23
24    /// Makes a new `RequestTarget` instance without any validation.
25    pub unsafe fn new_unchecked(target: &'a str) -> Self {
26        RequestTarget(target)
27    }
28
29    /// Returns a reference to the inner string of the method.
30    pub fn as_str(&self) -> &'a str {
31        self.0
32    }
33}
34impl<'a> AsRef<str> for RequestTarget<'a> {
35    fn as_ref(&self) -> &str {
36        self.0
37    }
38}
39impl<'a> fmt::Display for RequestTarget<'a> {
40    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41        self.0.fmt(f)
42    }
43}
44
45#[derive(Debug, Default)]
46pub struct RequestTargetDecoder {
47    size: usize,
48    idle: bool,
49}
50impl Decode for RequestTargetDecoder {
51    type Item = usize;
52
53    fn decode(&mut self, buf: &[u8], eos: Eos) -> Result<usize> {
54        if self.idle {
55            Ok(0)
56        } else if let Some(n) = buf.iter().position(|b| !util::is_vchar(*b)) {
57            track_assert_eq!(buf[n], b' ', ErrorKind::InvalidInput);
58            self.size += n;
59            self.idle = true;
60            Ok(n + 1)
61        } else {
62            track_assert!(!eos.is_reached(), ErrorKind::UnexpectedEos);
63            self.size += buf.len();
64            Ok(buf.len())
65        }
66    }
67
68    fn finish_decoding(&mut self) -> Result<Self::Item> {
69        track_assert!(self.idle, ErrorKind::IncompleteDecoding);
70        let size = self.size;
71        self.size = 0;
72        self.idle = false;
73        Ok(size)
74    }
75
76    fn requiring_bytes(&self) -> ByteCount {
77        if self.idle {
78            ByteCount::Finite(0)
79        } else {
80            ByteCount::Unknown
81        }
82    }
83
84    fn is_idle(&self) -> bool {
85        self.idle
86    }
87}
88
89#[cfg(test)]
90mod test {
91    use bytecodec::io::IoDecodeExt;
92    use bytecodec::ErrorKind;
93
94    use super::*;
95
96    #[test]
97    fn request_target_decoder_works() {
98        let mut decoder = RequestTargetDecoder::default();
99        let item = track_try_unwrap!(decoder.decode_exact(b"/foo/bar HTTP/1.1".as_ref()));
100        assert_eq!(item, 8);
101
102        assert_eq!(
103            decoder
104                .decode_exact(b"/f\too".as_ref())
105                .err()
106                .map(|e| *e.kind()),
107            Some(ErrorKind::InvalidInput)
108        )
109    }
110}