Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,206 @@
|
||||
use super::*;
|
||||
use http_body_util::{BodyExt, Full};
|
||||
use hyper_util::rt::{TokioExecutor, TokioIo};
|
||||
use tokio::sync::Notify;
|
||||
|
||||
fn limits() -> Limits {
|
||||
Limits {
|
||||
http2: Some(http::Http2Limits::default()),
|
||||
..Limits::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn idle_http2_connection_releases_capacity_after_response() {
|
||||
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 limits = Limits {
|
||||
connections: 1,
|
||||
timeout_ms: 50,
|
||||
..limits()
|
||||
};
|
||||
let serving = limits.clone();
|
||||
let server = scope
|
||||
.spawn(move |child| async move {
|
||||
http::serve::<_, _, false>(&incoming, &serving, &child, route).await
|
||||
})
|
||||
.unwrap();
|
||||
let stream = tokio::net::TcpStream::connect(("127.0.0.1", port as u16))
|
||||
.await
|
||||
.unwrap();
|
||||
let (mut sender, connection) =
|
||||
hyper::client::conn::http2::Builder::new(TokioExecutor::new())
|
||||
.handshake::<_, Full<bytes::Bytes>>(TokioIo::new(stream))
|
||||
.await
|
||||
.unwrap();
|
||||
let driver = scope.spawn_leaf(move || connection).unwrap();
|
||||
let response = sender
|
||||
.send_request(
|
||||
hyper::Request::builder()
|
||||
.uri("http://fixture.test/echo")
|
||||
.body(Full::new(bytes::Bytes::from_static(b"first")))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
response.into_body().collect().await.unwrap().to_bytes(),
|
||||
b"first"[..]
|
||||
);
|
||||
tokio::time::timeout(Duration::from_secs(2), driver.wait())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
http::send("127.0.0.1", port, request("/echo", b"second"), &limits)
|
||||
.await
|
||||
.unwrap()
|
||||
.body
|
||||
.as_ref(),
|
||||
b"second"
|
||||
);
|
||||
listener.close().unwrap();
|
||||
server.wait().await.unwrap().unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn http2_single_request_preserves_body_headers_and_validates_protocol_options() {
|
||||
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(), &child, route).await
|
||||
})
|
||||
.unwrap();
|
||||
let response = http::send("127.0.0.1", port, request("/echo", b"http2"), &limits())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.body.as_ref(), b"http2");
|
||||
let headers = response
|
||||
.headers
|
||||
.iter()
|
||||
.filter(|header| header.name == "x-data")
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(headers.len(), 2);
|
||||
assert_eq!(headers[0].value.as_ref(), [0x80]);
|
||||
for header in ["Connection", "Keep-Alive", "Proxy-Connection", "TE"] {
|
||||
let mut message = request("/", b"");
|
||||
message.headers.push(Header {
|
||||
name: header.into(),
|
||||
value: b"invalid".to_vec().into(),
|
||||
});
|
||||
assert!(
|
||||
http::send("127.0.0.1", port, message, &limits())
|
||||
.await
|
||||
.unwrap_err()
|
||||
.contains("connection header")
|
||||
);
|
||||
}
|
||||
listener.close().unwrap();
|
||||
server.wait().await.unwrap().unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn http2_multiplexes_independent_streams_normalizes_authority_and_drains_goaway() {
|
||||
for threads in [1, 2] {
|
||||
let runtime = Runtime::new(dever_runtime::task::Limits {
|
||||
threads,
|
||||
workers: 2,
|
||||
tasks: 32,
|
||||
})
|
||||
.unwrap();
|
||||
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 started = Arc::new(Notify::new());
|
||||
let ready = started.clone();
|
||||
let release = Arc::new(Notify::new());
|
||||
let released = release.clone();
|
||||
let server = scope.spawn(move |child| async move {
|
||||
http::serve::<_, _, false>(&incoming, &limits(), &child, move |request, _| {
|
||||
let ready = ready.clone();
|
||||
let released = released.clone();
|
||||
async move {
|
||||
assert!(request.headers.iter().any(|header| header.name == "host" && header.value.as_ref() == b"fixture.test"));
|
||||
if request.target == "/slow" {
|
||||
ready.notify_one();
|
||||
released.notified().await;
|
||||
}
|
||||
Ok(Response { status: 200, headers: vec![], body: request.target.into_bytes().into() })
|
||||
}
|
||||
}).await
|
||||
}).unwrap();
|
||||
let stream = tokio::net::TcpStream::connect(("127.0.0.1", port as u16)).await.unwrap();
|
||||
let (mut sender, connection) = hyper::client::conn::http2::Builder::new(TokioExecutor::new())
|
||||
.handshake::<_, Full<bytes::Bytes>>(TokioIo::new(stream)).await.unwrap();
|
||||
let driver = scope.spawn_leaf(move || connection).unwrap();
|
||||
let message = |path: &str| hyper::Request::builder().uri(format!("http://fixture.test{path}"))
|
||||
.body(Full::new(bytes::Bytes::new())).unwrap();
|
||||
let slow = sender.send_request(message("/slow"));
|
||||
tokio::pin!(slow);
|
||||
tokio::select! {
|
||||
result = &mut slow => panic!("slow stream finished before release: {result:?}"),
|
||||
() = started.notified() => (),
|
||||
() = tokio::time::sleep(Duration::from_secs(3)) => panic!("slow stream did not start"),
|
||||
}
|
||||
let fast = tokio::time::timeout(Duration::from_secs(3), sender.send_request(message("/fast"))).await.unwrap().unwrap();
|
||||
assert_eq!(fast.into_body().collect().await.unwrap().to_bytes(), b"/fast"[..]);
|
||||
listener.close().unwrap();
|
||||
release.notify_one();
|
||||
let slow = slow.await.unwrap();
|
||||
assert_eq!(slow.into_body().collect().await.unwrap().to_bytes(), b"/slow"[..]);
|
||||
drop(sender);
|
||||
tokio::time::timeout(Duration::from_secs(3), server.wait()).await.unwrap().unwrap().unwrap();
|
||||
driver.stop().await.unwrap();
|
||||
}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn http2_limits_reject_invalid_windows_and_total_stream_capacity() {
|
||||
runtime()
|
||||
.run(async |_| {
|
||||
for http2 in [
|
||||
http::Http2Limits {
|
||||
streams: 2049,
|
||||
..http::Http2Limits::default()
|
||||
},
|
||||
http::Http2Limits {
|
||||
streams: 0,
|
||||
..http::Http2Limits::default()
|
||||
},
|
||||
http::Http2Limits {
|
||||
stream_window_bytes: 0,
|
||||
..http::Http2Limits::default()
|
||||
},
|
||||
http::Http2Limits {
|
||||
connection_window_bytes: 65534,
|
||||
..http::Http2Limits::default()
|
||||
},
|
||||
] {
|
||||
let limits = Limits {
|
||||
http2: Some(http2),
|
||||
..Limits::default()
|
||||
};
|
||||
assert!(
|
||||
http::send("127.0.0.1", 1, request("/", b""), &limits)
|
||||
.await
|
||||
.unwrap_err()
|
||||
.contains("HTTP/2 limits")
|
||||
);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
Reference in new issue
Block a user