1use anyhow::Error;
6use fuchsia_async as fasync;
7use futures::prelude::*;
8use std::net::SocketAddr;
9
10#[derive(Debug, PartialEq, Eq)]
12enum HttpError {
13 NotFound,
14 BadRequest,
15}
16
17fn verify_raw_http_request(buf: &[u8], msg_size: usize) -> Result<(), HttpError> {
19 if let Some(first_line) =
20 std::str::from_utf8(&buf[..msg_size]).ok().and_then(|s| s.lines().next())
21 {
22 let mut parts = first_line.split_whitespace();
23 if parts.next() == Some("GET") && parts.next() == Some("/") {
24 Ok(())
25 } else {
26 Err(HttpError::NotFound)
27 }
28 } else {
29 Err(HttpError::BadRequest)
30 }
31}
32
33pub async fn run_http_server() -> Result<(), Error> {
38 log::info!("Setting up http server for authorized_keys");
39 let addr = SocketAddr::from((std::net::Ipv6Addr::UNSPECIFIED, 9797));
40 let listener = fasync::net::TcpListener::bind(&addr)?;
41 let mut task_group = fasync::TaskGroup::new();
42 let mut stream = listener.accept_stream();
43 log::info!("Trying to load file from /data/ssh/authorized_keys");
44 let response =
45 match fuchsia_fs::file::read_in_namespace_to_string("/data/ssh/authorized_keys").await {
46 Ok(c) => format!("HTTP/1.0 200 OK\r\n\r\n{c}"),
47 Err(e) => {
48 log::warn!("Unable to load file from /data/ssh/authorized_keys: {e}");
49 format!("HTTP/1.0 500 Internal Server Error\r\n\r\nUnable to read file: {e}")
50 }
51 };
52 while let Some(r) = stream.try_next().await? {
53 let (mut sock, _addr) = r;
54 let response_clone = response.clone();
55 task_group.spawn(async move {
56 let mut buf = [0u8; 1024];
57 let response = match sock.read(&mut buf).await {
58 Ok(n) => match verify_raw_http_request(&buf, n) {
59 Ok(()) => response_clone,
60 Err(HttpError::NotFound) => "HTTP/1.0 404 Not Found\r\n\r\n".to_owned(),
61 Err(HttpError::BadRequest) => "HTTP/1.0 400 Bad Request\r\n\r\n".to_owned(),
62 },
63 Err(e) => {
64 log::error!("error reading from socket: {e:?}");
65 return;
66 }
67 };
68 if let Err(e) = sock.write_all(response.as_bytes()).await {
69 log::error!("error writing to socket: {e:?}");
70 }
71 });
72 }
73 task_group.join().await;
74 Ok(())
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_verify_raw_http_request_valid() {
83 let req = "GET / HTTP/1.1\r\n\r\n";
84 assert!(verify_raw_http_request(req.as_bytes(), req.len()).is_ok());
85 }
86
87 #[test]
88 fn test_verify_raw_http_request_not_found() {
89 let req = "GET /foo HTTP/1.1\r\n\r\n";
90 assert_eq!(verify_raw_http_request(req.as_bytes(), req.len()), Err(HttpError::NotFound));
91 }
92
93 #[test]
94 fn test_verify_raw_http_request_bad_request() {
95 let req = &[0, 1, 2, 3];
96 assert_eq!(verify_raw_http_request(req, req.len()), Err(HttpError::NotFound));
97 }
98}