HTTP server #44
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -111,6 +111,7 @@ dependencies = [
|
|||||||
"criterion",
|
"criterion",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"exitcode",
|
"exitcode",
|
||||||
|
"httparse",
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -289,6 +290,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -25,6 +25,9 @@ tempfile = "3.3"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
|
|
||||||
|
# examples/tls
|
||||||
|
httparse = "1"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "clone3"
|
name = "clone3"
|
||||||
harness = false
|
harness = false
|
||||||
|
61
examples/tls/http.rs
Normal file
61
examples/tls/http.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub(super) fn handler(mut stream: TcpStream) -> i32 {
|
||||||
|
println!("entered http handler");
|
||||||
|
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
loop {
|
||||||
|
let buf_len = buf.len();
|
||||||
|
buf.resize_with(buf_len + 1024, Default::default);
|
||||||
|
|
||||||
|
if stream.read(&mut buf[buf_len..]).unwrap() == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut headers = [httparse::EMPTY_HEADER; 64];
|
||||||
|
let mut req = httparse::Request::new(&mut headers);
|
||||||
|
let result = req.parse(&buf).unwrap();
|
||||||
|
|
||||||
|
if result.is_partial() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let filename = if req.method != Some("GET") {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
req.path
|
||||||
|
};
|
||||||
|
|
||||||
|
let status_line = if filename.is_some() {
|
||||||
|
"HTTP/1.1 200 OK"
|
||||||
|
} else {
|
||||||
|
"HTTP/1.1 404 NOT FOUND"
|
||||||
|
};
|
||||||
|
|
||||||
|
let contents = if let Some(filename) = filename {
|
||||||
|
fs::read_to_string(
|
||||||
|
PathBuf::from("/var/www/html/")
|
||||||
|
.join(filename.strip_prefix('/').unwrap_or(filename)),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
"content not found\n".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let response_header = format!(
|
||||||
|
"{}\r\nContent-Length: {}\r\n\r\n",
|
||||||
|
status_line,
|
||||||
|
contents.len(),
|
||||||
|
);
|
||||||
|
|
||||||
|
stream.write_all(response_header.as_bytes()).unwrap();
|
||||||
|
stream.write_all(contents.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exitcode::OK
|
||||||
|
}
|
109
examples/tls/main.rs
Normal file
109
examples/tls/main.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
mod http;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args = std::env::args();
|
||||||
|
|
||||||
|
let _bin = args.next();
|
||||||
|
let entrypoint = args.next();
|
||||||
|
|
||||||
|
match entrypoint {
|
||||||
|
Some(s) => match s.as_str() {
|
||||||
|
"connection_listener" => connection_listener_entrypoint(),
|
||||||
|
"http_handler" => http_handler_entrypoint(),
|
||||||
|
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
None => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connection_listener_entrypoint() {
|
||||||
|
// imports
|
||||||
|
use std::os::unix::io::{FromRawFd, RawFd};
|
||||||
|
|
||||||
|
// argument parsing
|
||||||
|
let mut args = std::env::args();
|
||||||
|
|
||||||
|
let _bin = args.next();
|
||||||
|
let _entrypoint = args.next();
|
||||||
|
|
||||||
|
let http_handler_trigger = args.next();
|
||||||
|
let http_handler_trigger: RawFd = http_handler_trigger
|
||||||
|
.expect("request handler required")
|
||||||
|
.parse()
|
||||||
|
.expect("tcp listener should be a file descriptor");
|
||||||
|
let http_handler_trigger = unsafe { File::from_raw_fd(http_handler_trigger) };
|
||||||
|
|
||||||
|
let tcp_listener = args.next();
|
||||||
|
let tcp_listener: RawFd = tcp_listener
|
||||||
|
.expect("tcp listener required")
|
||||||
|
.parse()
|
||||||
|
.expect("tcp listener should be a file descriptor");
|
||||||
|
let tcp_listener = unsafe { TcpListener::from_raw_fd(tcp_listener) };
|
||||||
|
|
||||||
|
// actual function body
|
||||||
|
fn connection_listener(http_handler_trigger: File, tcp_listener: TcpListener) -> i32 {
|
||||||
|
println!("connection_listener entered");
|
||||||
|
|
||||||
|
// handle incoming connections
|
||||||
|
for stream in tcp_listener.incoming() {
|
||||||
|
let stream = match stream {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
println!("connection listener: error: {}", e);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("received a new connection");
|
||||||
|
http_handler(&http_handler_trigger, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
exitcode::OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// run function
|
||||||
|
std::process::exit(connection_listener(http_handler_trigger, tcp_listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn http_handler(trigger_socket: &File, stream: TcpStream) {
|
||||||
|
// imports
|
||||||
|
use nix::sys::socket::{sendmsg, ControlMessage, MsgFlags};
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
// send file descriptor(s)
|
||||||
|
let sockfd = trigger_socket.as_raw_fd();
|
||||||
|
let fds = [stream.as_raw_fd()];
|
||||||
|
|
||||||
|
sendmsg::<()>(
|
||||||
|
sockfd,
|
||||||
|
&[],
|
||||||
|
&[ControlMessage::ScmRights(&fds)],
|
||||||
|
MsgFlags::empty(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn http_handler_entrypoint() {
|
||||||
|
// imports
|
||||||
|
use std::os::unix::io::{FromRawFd, RawFd};
|
||||||
|
|
||||||
|
// argument parsing
|
||||||
|
let mut args = std::env::args();
|
||||||
|
|
||||||
|
let _bin = args.next();
|
||||||
|
let _entrypoint = args.next();
|
||||||
|
|
||||||
|
let stream = args.next();
|
||||||
|
let stream: RawFd = stream
|
||||||
|
.expect("request stream required")
|
||||||
|
.parse()
|
||||||
|
.expect("request stream should be a file descriptor");
|
||||||
|
let stream = unsafe { TcpStream::from_raw_fd(stream) };
|
||||||
|
|
||||||
|
std::process::exit(http::handler(stream));
|
||||||
|
}
|
76
examples/tls/spec.json
Normal file
76
examples/tls/spec.json
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"entrypoints": {
|
||||||
|
"connection_listener": {
|
||||||
|
"args": [
|
||||||
|
"BinaryName",
|
||||||
|
"Entrypoint",
|
||||||
|
{
|
||||||
|
"FileSocket": {
|
||||||
|
"Tx": "http"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TcpListener": {
|
||||||
|
"addr": "0.0.0.0:8443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"environment": [
|
||||||
|
{
|
||||||
|
"Filesystem": {
|
||||||
|
"host_path": "/lib/x86_64-linux-gnu/libgcc_s.so.1",
|
||||||
|
"environment_path": "/lib/libgcc_s.so.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Filesystem": {
|
||||||
|
"host_path": "/lib/x86_64-linux-gnu/libc.so.6",
|
||||||
|
"environment_path": "/lib/libc.so.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Filesystem": {
|
||||||
|
"host_path": "/lib64/ld-linux-x86-64.so.2",
|
||||||
|
"environment_path": "/lib64/ld-linux-x86-64.so.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"http_handler": {
|
||||||
|
"trigger": {
|
||||||
|
"FileSocket": "http"
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"BinaryName",
|
||||||
|
"Entrypoint",
|
||||||
|
"Trigger"
|
||||||
|
],
|
||||||
|
"environment": [
|
||||||
|
{
|
||||||
|
"Filesystem": {
|
||||||
|
"host_path": "/var/www/html",
|
||||||
|
"environment_path": "/var/www/html"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Filesystem": {
|
||||||
|
"host_path": "/lib/x86_64-linux-gnu/libgcc_s.so.1",
|
||||||
|
"environment_path": "/lib/libgcc_s.so.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Filesystem": {
|
||||||
|
"host_path": "/lib/x86_64-linux-gnu/libc.so.6",
|
||||||
|
"environment_path": "/lib/libc.so.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Filesystem": {
|
||||||
|
"host_path": "/lib64/ld-linux-x86-64.so.2",
|
||||||
|
"environment_path": "/lib64/ld-linux-x86-64.so.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -135,14 +135,6 @@ impl VoidBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug!("cloned child: {}", child);
|
debug!("cloned child: {}", child);
|
||||||
|
|
||||||
// Leak the child function's resources in the parent process.
|
|
||||||
// This avoids closing files that have been "moved" into the child.
|
|
||||||
// It is also an over-approximation, and may cause actual memory leaks.
|
|
||||||
// As the spawning process is normally short lived, this shouldn't
|
|
||||||
// be a problem.
|
|
||||||
std::mem::forget(child_fn);
|
|
||||||
|
|
||||||
Ok(VoidHandle { pid: child })
|
Ok(VoidHandle { pid: child })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user