93 lines
2.4 KiB
Rust
93 lines
2.4 KiB
Rust
//! A simple echo server that echoes the body of a POST request, and returns a
|
|
//! 405 for any other method
|
|
//!
|
|
//! Usage:
|
|
//! cargo run --example echo -- <host> <port>
|
|
|
|
use std::{error::Error, io::Write, net::TcpListener};
|
|
|
|
use httplz::Lift;
|
|
|
|
fn main() -> Result<(), Box<dyn Error>> {
|
|
let mut args = std::env::args().skip(1);
|
|
let (host, port) = args
|
|
.next()
|
|
.and_then(|h| Some((h, args.next()?)))
|
|
.ok_or_else(|| Box::<dyn Error>::from(String::from("Missing required argument")))?;
|
|
|
|
let listener = TcpListener::bind((host, port.parse()?))?;
|
|
loop {
|
|
let (mut stream, _) = listener.accept()?;
|
|
let mut conn = httplz::Connection::new(httplz::Role::Server);
|
|
|
|
let mut body: Vec<u8> = Vec::new();
|
|
let mut buf = vec![0; 1024].into_boxed_slice();
|
|
let mut buf = httplz_ext::Buf::new(&mut buf);
|
|
|
|
let mut method_not_allowed = false;
|
|
|
|
loop {
|
|
let data = buf.filled();
|
|
let (remaining, r) = conn.poll_recv(data).lift();
|
|
match r.map_err(|e| e.kind) {
|
|
Err(httplz::ErrorKind::NeedMoreData) => {
|
|
buf.read_from(&mut stream)?;
|
|
continue;
|
|
},
|
|
Err(e) => panic!("{e:?}"),
|
|
Ok(event) => {
|
|
match event {
|
|
httplz::Event::RequestLine(r) => {
|
|
if !r.method.eq_ignore_ascii_case("post") {
|
|
method_not_allowed = true;
|
|
}
|
|
},
|
|
httplz::Event::RecvDone => break,
|
|
httplz::Event::BodyChunk(b) => body.extend_from_slice(b),
|
|
_ => (),
|
|
};
|
|
},
|
|
};
|
|
|
|
let len = data.len() - remaining.len();
|
|
buf.pop_front(len);
|
|
}
|
|
|
|
let parts: &[httplz::Event] = if method_not_allowed {
|
|
&[
|
|
httplz::Event::StatusLine(httplz::StatusLine {
|
|
version: httplz::Version::HTTP1_1,
|
|
status_code: 405,
|
|
status_text: "Method not allowed",
|
|
}),
|
|
httplz::Event::HeadersDone,
|
|
httplz::Event::SendDone,
|
|
]
|
|
} else {
|
|
&[
|
|
httplz::Event::StatusLine(httplz::StatusLine {
|
|
version: httplz::Version::HTTP1_1,
|
|
status_code: 200,
|
|
status_text: "OK",
|
|
}),
|
|
httplz::Event::Header(httplz::Header::Special(
|
|
httplz::HeaderSpecial::ContentLength(body.len()),
|
|
)),
|
|
httplz::Event::HeadersDone,
|
|
httplz::Event::BodyChunk(body.as_slice()),
|
|
httplz::Event::SendDone,
|
|
]
|
|
};
|
|
|
|
let buf = vec![0; 1024];
|
|
let mut cursor = httplz::WriteCursor::new(buf);
|
|
for p in parts {
|
|
if let Err(e) = conn.handle_send(p, &mut cursor) {
|
|
panic!("{e:?}")
|
|
};
|
|
stream.write_all(cursor.written())?;
|
|
cursor.reset();
|
|
}
|
|
}
|
|
}
|