httpcodec/
request_target.rs1use bytecodec::{ByteCount, Decode, Eos, ErrorKind, Result};
2use std::fmt;
3
4use util;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
8pub struct RequestTarget<'a>(&'a str);
9impl<'a> RequestTarget<'a> {
10 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 pub unsafe fn new_unchecked(target: &'a str) -> Self {
26 RequestTarget(target)
27 }
28
29 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}