Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,145 @@
|
||||
use dever_runtime::{
|
||||
http::{self, Header, Limits, Request, Response},
|
||||
net,
|
||||
task::{Runtime, Scope},
|
||||
};
|
||||
use std::{
|
||||
io::{BufRead, BufReader, Read, Write},
|
||||
net::TcpStream,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
mod http2;
|
||||
mod lifecycle;
|
||||
mod limits;
|
||||
mod live;
|
||||
mod pool;
|
||||
mod streaming;
|
||||
mod tls;
|
||||
mod websocket;
|
||||
|
||||
fn runtime() -> Runtime {
|
||||
Runtime::new(dever_runtime::task::Limits {
|
||||
threads: 2,
|
||||
workers: 2,
|
||||
tasks: 32,
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn request(target: &str, body: &[u8]) -> Request {
|
||||
Request {
|
||||
method: "POST".into(),
|
||||
target: target.into(),
|
||||
headers: vec![Header {
|
||||
name: "Host".into(),
|
||||
value: b"fixture.test".to_vec().into(),
|
||||
}],
|
||||
body: body.to_vec().into(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn route(request: Request, _: Arc<Scope<'static>>) -> Result<Response, String> {
|
||||
if request.target == "/fail" {
|
||||
return Err("owned fixture failure".into());
|
||||
}
|
||||
if request.target == "/wait" {
|
||||
tokio::time::sleep(Duration::from_secs(60)).await;
|
||||
}
|
||||
Ok(Response {
|
||||
status: 200,
|
||||
headers: vec![
|
||||
Header {
|
||||
name: "x-data".into(),
|
||||
value: vec![0x80].into(),
|
||||
},
|
||||
Header {
|
||||
name: "x-data".into(),
|
||||
value: b"second".to_vec().into(),
|
||||
},
|
||||
],
|
||||
body: request.body,
|
||||
})
|
||||
}
|
||||
|
||||
fn connect(port: i64) -> BufReader<TcpStream> {
|
||||
let stream = TcpStream::connect(("127.0.0.1", port as u16)).unwrap();
|
||||
stream
|
||||
.set_read_timeout(Some(Duration::from_secs(3)))
|
||||
.unwrap();
|
||||
stream
|
||||
.set_write_timeout(Some(Duration::from_secs(3)))
|
||||
.unwrap();
|
||||
BufReader::new(stream)
|
||||
}
|
||||
|
||||
fn read_response(stream: &mut BufReader<TcpStream>, head: bool) -> (u16, Vec<u8>) {
|
||||
let mut line = Vec::new();
|
||||
stream.read_until(b'\n', &mut line).unwrap();
|
||||
let status = std::str::from_utf8(&line)
|
||||
.unwrap()
|
||||
.split_whitespace()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap();
|
||||
let mut size = 0;
|
||||
loop {
|
||||
line.clear();
|
||||
assert!(stream.read_until(b'\n', &mut line).unwrap() > 0);
|
||||
if line == b"\r\n" {
|
||||
break;
|
||||
}
|
||||
if line.to_ascii_lowercase().starts_with(b"content-length:") {
|
||||
size = std::str::from_utf8(&line[15..])
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
let mut body = vec![0; if head { 0 } else { size }];
|
||||
stream.read_exact(&mut body).unwrap();
|
||||
(status, body)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_and_independent_peer_cover_keepalive_chunking_and_request_isolation() {
|
||||
runtime().run(async |scope| {
|
||||
let listener = net::listen("127.0.0.1", 0, scope).await.unwrap();
|
||||
let port = listener.port().unwrap();
|
||||
let incoming = listener.clone();
|
||||
let server = scope.spawn(move |child| async move { http::serve::<_, _, false>(&incoming, &Limits::default(), &child, route).await }).unwrap();
|
||||
let response = http::send("127.0.0.1", port, request("/echo", b"owned body"), &Limits::default()).await.unwrap();
|
||||
assert_eq!(response.body.as_ref(), b"owned body");
|
||||
let headers = response.headers.iter().filter(|value| value.name == "x-data").map(|value| value.value.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(headers, vec![vec![0x80], b"second".to_vec()]);
|
||||
scope.blocking(move || {
|
||||
let mut stream = connect(port);
|
||||
for message in [
|
||||
&b"GET /echo HTTP/1.1\r\nHost: fixture.test\r\n\r\n"[..],
|
||||
&b"POST /echo HTTP/1.1\r\nHost: fixture.test\r\nContent-Length: 0\r\n\r\n"[..],
|
||||
&b"POST /echo HTTP/1.1\r\nHost: fixture.test\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n"[..],
|
||||
] {
|
||||
stream.get_mut().write_all(message).unwrap();
|
||||
assert_eq!(read_response(&mut stream, false), (200, vec![]));
|
||||
}
|
||||
for (path, status) in [("/echo", 200), ("/fail", 500), ("/echo", 200)] {
|
||||
write!(stream.get_mut(), "POST {path} HTTP/1.1\r\nHost: fixture.test\r\nContent-Length: 3\r\n\r\nabc").unwrap();
|
||||
let (actual, body) = read_response(&mut stream, false);
|
||||
assert_eq!(actual, status);
|
||||
if status == 200 { assert_eq!(body, b"abc"); }
|
||||
}
|
||||
stream.get_mut().write_all(b"HEAD /echo HTTP/1.1\r\nHost: fixture.test\r\nContent-Length: 3\r\n\r\nabc").unwrap();
|
||||
assert_eq!(read_response(&mut stream, true), (200, vec![]));
|
||||
stream.get_mut().write_all(b"POST /echo HTTP/1.1\r\nHost: fixture.test\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n3\r\none\r\n3\r\ntwo\r\n0\r\n\r\n").unwrap();
|
||||
assert_eq!(read_response(&mut stream, false), (200, b"onetwo".to_vec()));
|
||||
let mut tail = Vec::new();
|
||||
stream.read_to_end(&mut tail).unwrap();
|
||||
assert!(tail.is_empty());
|
||||
}).await.unwrap();
|
||||
listener.close().unwrap();
|
||||
server.wait().await.unwrap().unwrap();
|
||||
}).unwrap();
|
||||
}
|
||||
Reference in new issue
Block a user