• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // Copyright 2023 Google LLC
2  //
3  // Licensed under the Apache License, Version 2.0 (the "License");
4  // you may not use this file except in compliance with the License.
5  // You may obtain a copy of the License at
6  //
7  //     https://www.apache.org/licenses/LICENSE-2.0
8  //
9  // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  //! Request library for micro HTTP server.
16  //!
17  //! This library implements the basic parts of Request Message from
18  //! (RFC 5322)[ https://www.rfc-editor.org/rfc/rfc5322.html] "HTTP
19  //! Message Format."
20  //!
21  //! This library is only used for serving the netsim client and is not
22  //! meant to implement all aspects of RFC 5322. In particular,
23  //! this library does not implement the following:
24  //! * header field body with multiple lines (section 3.2.2)
25  //! * limits on the lengths of the header section or header field
26  //!
27  //! The main function is `HttpRequest::parse` which can be called
28  //! repeatedly.
29  
30  use http::Request;
31  use http::Version;
32  use std::io::BufRead;
33  use std::io::BufReader;
34  use std::io::Read;
35  
36  #[allow(clippy::read_zero_byte_vec)]
parse_http_request<T: std::io::Read>( reader: &mut BufReader<T>, ) -> Result<Request<Vec<u8>>, String>37  pub fn parse_http_request<T: std::io::Read>(
38      reader: &mut BufReader<T>,
39  ) -> Result<Request<Vec<u8>>, String> {
40      let mut line = String::new();
41      reader.read_line(&mut line).map_err(|e| format!("Failed to read request line: {e}"))?;
42      let mut parts = line.split_whitespace();
43      let method = parts.next().ok_or("Invalid request line, missing method")?;
44      let uri = parts.next().ok_or("Invalid request line, missing uri")?;
45      let version_str = parts.next().ok_or("Invalid request line, missing version")?;
46      let version = match version_str {
47          "HTTP/0.9" => Version::HTTP_09,
48          "HTTP/1.0" => Version::HTTP_10,
49          "HTTP/1.1" => Version::HTTP_11,
50          "HTTP/2.0" => Version::HTTP_2,
51          "HTTP/3.0" => Version::HTTP_3,
52          _ => return Err("Invalid HTTP version".to_string()),
53      };
54  
55      let mut headers = Vec::new();
56      for line in reader.lines() {
57          let line = line.map_err(|e| format!("Failed to parse headers: {e}"))?;
58          if let Some((name, value)) = line.split_once(':') {
59              headers.push((name.to_string(), value.trim().to_string()));
60          } else if line.len() > 1 {
61              // no colon in a header line
62              return Err(format!("Invalid header line: {line}"));
63          } else {
64              // empty line marks the end of headers
65              break;
66          }
67      }
68  
69      let mut builder = Request::builder().method(method).uri(uri).version(version);
70      let mut body_length: Option<usize> = None;
71      for (key, value) in headers {
72          builder = builder.header(key.clone(), value.clone());
73          if key == "Content-Length" {
74              body_length = match value.parse() {
75                  Ok(size) => Some(size),
76                  Err(err) => return Err(format!("{err:?}")),
77              }
78          }
79      }
80      let mut body = Vec::new();
81      if let Some(len) = body_length {
82          body.resize(len, 0);
83          reader.read_exact(&mut body).map_err(|e| format!("Failed to read body: {e}"))?;
84      }
85      match builder.body(body) {
86          Ok(request) => Ok(request),
87          Err(err) => Err(format!("{err:?}")),
88      }
89  }
90  
91  #[cfg(test)]
92  mod tests {
93      use super::*;
94  
95      #[test]
test_parse()96      fn test_parse() {
97          let request = concat!(
98              "GET /index.html HTTP/1.1\r\n",
99              "Host: example.com\r\nContent-Length: 13\r\n\r\n",
100              "Hello World\r\n"
101          );
102          let mut reader = BufReader::new(request.as_bytes());
103          let http_request = parse_http_request::<&[u8]>(&mut reader).unwrap();
104          assert_eq!(http_request.method(), "GET");
105          assert_eq!(http_request.uri().to_string(), "/index.html");
106          assert_eq!(http_request.version(), Version::HTTP_11);
107          let mut headers = http::HeaderMap::new();
108          headers.insert("Host", http::HeaderValue::from_static("example.com"));
109          headers.insert("Content-Length", http::HeaderValue::from_static("13"));
110          assert_eq!(http_request.headers().to_owned(), headers);
111          assert_eq!(http_request.body().to_owned(), b"Hello World\r\n".to_vec());
112      }
113  
114      #[test]
test_parse_without_body()115      fn test_parse_without_body() {
116          let request = concat!("GET /index.html HTTP/1.1\r\n", "Host: example.com\r\n\r\n");
117          let mut reader = BufReader::new(request.as_bytes());
118          let http_request = parse_http_request::<&[u8]>(&mut reader).unwrap();
119          assert_eq!(http_request.method(), "GET");
120          assert_eq!(http_request.uri().to_string(), "/index.html");
121          assert_eq!(http_request.version(), Version::HTTP_11);
122          let mut headers = http::HeaderMap::new();
123          headers.insert("Host", http::HeaderValue::from_static("example.com"));
124          assert_eq!(http_request.headers().to_owned(), headers);
125          assert_eq!(http_request.body().to_owned(), Vec::<u8>::new());
126      }
127  
128      #[test]
test_parse_without_content_length()129      fn test_parse_without_content_length() {
130          let request =
131              concat!("GET /index.html HTTP/1.1\r\n", "Host: example.com\r\n\r\n", "Hello World\r\n");
132          let mut reader = BufReader::new(request.as_bytes());
133          let http_request = parse_http_request::<&[u8]>(&mut reader).unwrap();
134          assert_eq!(http_request.method(), "GET");
135          assert_eq!(http_request.uri(), "/index.html");
136          assert_eq!(http_request.version(), Version::HTTP_11);
137          let mut headers = http::HeaderMap::new();
138          headers.insert("Host", http::HeaderValue::from_static("example.com"));
139          assert_eq!(http_request.headers().to_owned(), headers);
140          assert_eq!(http_request.body().to_owned(), Vec::<u8>::new());
141      }
142  }
143