1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
use std::{net::SocketAddr, sync::Arc};
use httparse::{Request, Status};
use smol::{
LocalExecutor, future,
io::{AsyncReadExt, AsyncWriteExt},
net::{TcpListener, TcpStream},
};
fn main() {
let exec = LocalExecutor::new();
let arxc = Arc::new(exec);
let moving_arxc = Arc::clone(&arxc);
future::block_on(arxc.run(async move { async_main(moving_arxc).await }));
}
async fn async_main(ex: Arc<LocalExecutor<'_>>) {
let addr = SocketAddr::from(([0, 0, 0, 0], 12345));
let listen = TcpListener::bind(addr).await.unwrap();
loop {
let (stream, caddr) = listen.accept().await.unwrap();
println!("accepted!");
ex.spawn(async move { handle_request(stream, caddr).await })
.detach();
}
}
async fn handle_request(mut stream: TcpStream, caddr: SocketAddr) {
let mut buffer = vec![0; 1024];
let mut data_end = 0;
loop {
println!("Waiting on read");
match stream.read(&mut buffer[data_end..]).await {
Err(_err) => {
eprintln!("Error in handle_request during read. Bailing.");
return;
}
Ok(bytes_read) => {
data_end += bytes_read;
println!("read {bytes_read}");
}
}
let mut headers = [httparse::EMPTY_HEADER; 64];
let mut req = Request::new(&mut headers);
match req.parse(&buffer[..data_end]) {
Err(err) => {
eprintln!("Error in handle_request during parsing. Bailing.\nerror: {err}");
return;
}
Ok(Status::Partial) => {
// Going around again.
// Make sure we have room in the buffer. 512 seems good :)
if buffer.len() == data_end {
buffer.resize(buffer.len() + 512, 0);
}
println!("partial!");
continue;
}
Ok(Status::Complete(body_offset)) => {
println!("Got entire request!");
println!("method: {}", req.method.unwrap());
println!("path: {}", req.path.unwrap());
println!("body_offset: {body_offset}");
}
}
let minor = req.version.unwrap();
let status = 200;
let message = "Gotcha";
// Fall through the match. We should guarantee that, if we end up here,
// we got a Status::Complete from the parser
let mut response = format!("HTTP/1.{minor} {status} {message}\n");
let body = format!("{}", caddr.ip());
let length = body.len();
macro_rules! header {
($content:expr) => {
response.push_str(&format!($content));
response.push('\n');
};
}
header!("Content-Length: {length}");
header!("Content-Type: text/plain");
header!("Cache-Control: no-store");
response.push('\n');
response.push_str(&body);
if let Err(err) = stream.write_all(response.as_bytes()).await {
eprintln!("Error in handle_request sending response back. Bailing.\nError: {err}");
return;
} else {
return;
}
}
}
|