front_line_router/
method.rs1#[derive(Eq, PartialEq, Copy, Clone, Debug)]
6pub enum Method {
7 Get,
11
12 Post,
16
17 Put,
21
22 Delete,
26
27 Head,
31
32 Options,
36
37 Connect,
41
42 Trace,
46
47 Patch,
51}
52
53impl Method {
54 pub fn parse(request_line: &[u8]) -> Option<(Self, &[u8])> {
68 if request_line.len() < 14 {
71 return None;
72 }
73 if &request_line[..4] == b"GET " {
74 return Some((Method::Get, &request_line[4..]));
75 }
76 if &request_line[..4] == b"PUT " {
77 return Some((Method::Put, &request_line[4..]));
78 }
79 if request_line.len() < 15 {
80 return None;
81 }
82 if &request_line[..5] == b"POST " {
83 return Some((Method::Post, &request_line[5..]));
84 }
85 if &request_line[..5] == b"HEAD " {
86 return Some((Method::Head, &request_line[5..]));
87 }
88 if request_line.len() < 16 {
89 return None;
90 }
91 if &request_line[..6] == b"TRACE " {
92 return Some((Method::Trace, &request_line[6..]));
93 }
94 if &request_line[..6] == b"PATCH " {
95 return Some((Method::Patch, &request_line[6..]));
96 }
97 if request_line.len() < 17 {
98 return None;
99 }
100 if &request_line[..7] == b"DELETE " {
101 return Some((Method::Delete, &request_line[7..]));
102 }
103 if request_line.len() < 18 {
104 return None;
105 }
106 if &request_line[..8] == b"OPTIONS " {
107 return Some((Method::Options, &request_line[8..]));
108 }
109 if &request_line[..8] == b"CONNECT " {
110 return Some((Method::Connect, &request_line[8..]));
111 }
112 None
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::Method;
119 use rstest::rstest;
120
121 #[rstest]
122 #[case(b"GET / HTTP/1.1", Some((Method::Get, b"/ HTTP/1.1".as_slice())))]
123 #[case(b"PUT / HTTP/1.1", Some((Method::Put, b"/ HTTP/1.1".as_slice())))]
124 #[case(b"POST / HTTP/1.1", Some((Method::Post, b"/ HTTP/1.1".as_slice())))]
125 #[case(b"HEAD / HTTP/1.1", Some((Method::Head, b"/ HTTP/1.1".as_slice())))]
126 #[case(b"TRACE / HTTP/1.1", Some((Method::Trace, b"/ HTTP/1.1".as_slice())))]
127 #[case(b"PATCH / HTTP/1.1", Some((Method::Patch, b"/ HTTP/1.1".as_slice())))]
128 #[case(b"DELETE / HTTP/1.1", Some((Method::Delete, b"/ HTTP/1.1".as_slice())))]
129 #[case(b"OPTIONS / HTTP/1.1", Some((Method::Options, b"/ HTTP/1.1".as_slice())))]
130 #[case(b"CONNECT / HTTP/1.1", Some((Method::Connect, b"/ HTTP/1.1".as_slice())))]
131 #[case(b"INVALIDMETHOD / HTTP/1.1", None)]
132 fn test_parse_method(#[case] request: &[u8], #[case] expected: Option<(Method, &[u8])>) {
133 assert_eq!(Method::parse(request), expected);
134 }
135
136 #[test]
137 fn test_remaining_request_line() {
138 let request = b"GET /foo/bar HTTP/1.1".as_slice();
139 assert_eq!(
140 Method::parse(request),
141 Some((Method::Get, b"/foo/bar HTTP/1.1".as_slice()))
142 );
143 }
144
145 #[rstest]
146 #[case(b"GET/ HTTP/1.1")]
147 #[case(b"PUT/ HTTP/1.1")]
148 #[case(b"POST/ HTTP/1.1")]
149 #[case(b"HEAD/ HTTP/1.1")]
150 fn test_malformed_request(#[case] request: &[u8]) {
151 assert_eq!(Method::parse(request), None);
152 }
153
154 #[rstest]
155 #[case(b"GE")]
156 #[case(b"POS")]
157 #[case(b"TRAC")]
158 #[case(b"DELET")]
159 #[case(b"OPTION")]
160 #[case(b"GET / HTTP/1.")]
161 #[case(b"POST / HTTP/1.")]
162 #[case(b"TRACE / HTTP/1.")]
163 #[case(b"DELETE / HTTP/1.")]
164 #[case(b"OPTIONS / HTTP/1.")]
165 fn test_short_request(#[case] request: &[u8]) {
166 assert_eq!(Method::parse(request), None);
167 }
168}