Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
// 正确性检查在计时外覆盖凭据、Provider、角色、路由及严格输入,不能用空 200 掩盖漏做。
fn check_requests(connection: &mut HttpConnection, input: &AuthInput) {
for request in &input.requests[..16] {
check_reply(&connection.request(&request_bytes(request)), 200);
}
check_reply(
&connection.request(&request_bytes(&input.requests[16])),
401,
);
let valid = &input.requests[0];
let mut missing = valid.clone();
missing.headers_mut().remove("cookie");
let mut invalid = valid.clone();
invalid
.headers_mut()
.insert("cookie", "session=v1.invalid-jwt".parse().unwrap());
let mut host = valid.clone();
host.headers_mut()
.insert("host", "other.test".parse().unwrap());
let mut path = valid.clone();
*path.uri_mut() = format!("{}-missing", path.uri()).parse().unwrap();
let mut query = valid.clone();
*query.uri_mut() = format!("{}?unexpected=1", query.uri()).parse().unwrap();
for (request, status) in [
(missing, 401),
(invalid, 401),
(host, 404),
(path, 404),
(query, 400),
] {
check_reply(&connection.request(&request_bytes(&request)), status);
}
}
fn membership(runtime: &Runtime, registry: &Arc<Registry>, input: &AuthInput, grant: bool) {
runtime
.run(async |scope| {
let (mut context, claims) = input
.service
.prepare("admin", &input.requests[0], false, input.now)
.unwrap();
rust_verify(&mut context, claims.unwrap(), scope, registry)
.await
.map_err(|error| error.0)
.unwrap();
let mut database = DbContext::new(registry.clone());
let executor = database.on(AUTH_BINDING, scope).await.unwrap();
if grant {
authorization::grant(executor, scope, &context, 16, "reader")
.await
.unwrap();
} else {
authorization::revoke(executor, scope, &context, 16, "reader")
.await
.unwrap();
}
})
.unwrap();
}
fn check(
runtime: &Runtime,
registry: &Arc<Registry>,
config: &Arc<api::Config>,
input: &AuthInput,
) {
for generated in [true, false] {
with_server(runtime, registry, config, input, generated, |port| {
check_requests(&mut HttpConnection::connect(port), input);
});
}
membership(runtime, registry, input, false);
for generated in [true, false] {
with_server(runtime, registry, config, input, generated, |port| {
let mut connection = HttpConnection::connect(port);
check_reply(
&connection.request(&request_bytes(&input.requests[15])),
403,
);
});
}
membership(runtime, registry, input, true);
}
+91
View File
@@ -0,0 +1,91 @@
// 客户端只连接本轮持有的回环监听器,使用同一 HTTP/1.1 长连接顺序发送请求。
use std::{
io::{BufRead, BufReader, Read, Write},
net::TcpStream,
time::Duration,
};
const ROUTE: &str = "/bench/account/admin/permissions";
const CONTENT_TYPE: &str = "application/json; charset=utf-8";
const SUCCESS: &str = "{\"code\":0,\"message\":\"ok\",\"data\":[{\"key\":\"bench.account.admin.permissions\",\"component\":\"bench\",\"domain\":\"account\",\"site\":\"admin\",\"action\":\"permissions\",\"method\":\"GET\",\"kind\":\"http\"}]}";
struct HttpReply {
status: u16,
content_type: String,
body: Vec<u8>,
}
struct HttpConnection(BufReader<TcpStream>);
impl HttpConnection {
fn connect(port: u16) -> Self {
let socket = TcpStream::connect(("127.0.0.1", port)).unwrap();
socket.set_nodelay(true).unwrap();
socket
.set_read_timeout(Some(Duration::from_secs(5)))
.unwrap();
socket
.set_write_timeout(Some(Duration::from_secs(5)))
.unwrap();
Self(BufReader::new(socket))
}
fn request(&mut self, request: &[u8]) -> HttpReply {
self.0.get_mut().write_all(request).unwrap();
let mut line = String::new();
self.0.read_line(&mut line).unwrap();
assert!(line.starts_with("HTTP/1.1 "));
let status = line.split_whitespace().nth(1).unwrap().parse().unwrap();
let mut length = None;
let mut content_type = String::new();
loop {
line.clear();
assert!(self.0.read_line(&mut line).unwrap() > 0);
if line == "\r\n" {
break;
}
let (name, value) = line.trim_end().split_once(':').unwrap();
match name.to_ascii_lowercase().as_str() {
"content-length" => {
assert!(length.is_none());
length = Some(value.trim().parse::<usize>().unwrap());
}
"content-type" => content_type = value.trim().into(),
"connection" => assert_ne!(value.trim(), "close"),
"transfer-encoding" | "set-cookie" => panic!("unexpected response header"),
_ => (),
}
}
let mut body = vec![0; length.unwrap()];
self.0.read_exact(&mut body).unwrap();
HttpReply {
status,
content_type,
body,
}
}
}
fn request_bytes(request: &Request) -> Vec<u8> {
assert!(request.body().is_empty());
let mut bytes = format!("{} {} HTTP/1.1\r\n", request.method(), request.uri()).into_bytes();
for (name, value) in request.headers() {
bytes.extend_from_slice(name.as_str().as_bytes());
bytes.extend_from_slice(b": ");
bytes.extend_from_slice(value.as_bytes());
bytes.extend_from_slice(b"\r\n");
}
bytes.extend_from_slice(b"Connection: keep-alive\r\nContent-Length: 0\r\n\r\n");
bytes
}
fn check_reply(reply: &HttpReply, status: u16) {
assert_eq!(reply.status, status);
assert_eq!(reply.content_type, CONTENT_TYPE);
let expected = if status == 200 {
SUCCESS.as_bytes().to_vec()
} else {
api::error(status).body().to_vec()
};
assert_eq!(reply.body, expected);
}
+123
View File
@@ -0,0 +1,123 @@
// 两侧复用相同 HTTP 引擎、限额和调度策略;计时包含真实 JWT 校验、三次数据库读取及响应。
fn with_server<Value>(
runtime: &Runtime,
registry: &Arc<Registry>,
config: &Arc<api::Config>,
input: &AuthInput,
generated: bool,
client: impl FnOnce(u16) -> Value,
) -> Value {
let registry = registry.clone();
let config = config.clone();
let authentication = input.service.clone();
std::thread::scope(|threads| {
let (started, port) = std::sync::mpsc::sync_channel(0);
let (finished, completion) = tokio::sync::oneshot::channel();
let serving = threads.spawn(move || {
runtime
.run(async move |scope| {
let listener = dever_runtime::net::listen("127.0.0.1", 0, scope)
.await
.unwrap();
let port = listener.port().unwrap() as u16;
let incoming = listener.clone();
let server = scope
.spawn(move |child| async move {
let limits = dever_runtime::http::Limits {
connections: 1,
..Default::default()
};
api::serve::<_, _, true>(
&incoming,
&limits,
&child,
None,
move |request, scope, peer| {
let config = config.clone();
let registry = registry.clone();
let authentication = authentication.clone();
async move {
let path = request.uri().path();
let response = match (request.method().as_str(), path) {
("GET", ROUTE) if config.accepts("admin", &request) => {
if generated {
GENERATED_HTTP(
&request,
peer,
&scope,
&registry,
&authentication,
)
.await
} else {
rust_http(
&request,
peer,
&scope,
&registry,
&authentication,
)
.await
}
}
_ => api::error(404),
};
Ok(response)
}
},
)
.await
})
.unwrap();
// 阻塞客户端独立于运行时线程,也不占用数据库的阻塞池;交接在计时外。
started.send(port).unwrap();
completion.await.unwrap();
listener.close().unwrap();
match server.timeout(5000).await.unwrap() {
dever_runtime::task::Timed::Ready(result) => result.unwrap(),
_ => panic!("owned HTTP benchmark server failed to drain"),
}
})
.unwrap()
});
let result = client(port.recv().unwrap());
finished.send(()).unwrap();
serving.join().unwrap();
result
})
}
pub(super) fn run(
runtime: &Runtime,
registry: &Arc<Registry>,
config: &Arc<api::Config>,
input: &AuthInput,
) {
check(runtime, registry, config, input);
eprintln!(
"HTTP/1.1 loopback; one persistent connection; rotating 16 JWT cookies; JWT + Provider + role gate + permission list + JSON response included; TCP connect and response assertions excluded; no TLS/proxy/concurrent-load claim"
);
let requests = input.requests[..16]
.iter()
.map(request_bytes)
.collect::<Vec<_>>();
samples("http_jwt_provider_roles", |generated, count| {
with_server(runtime, registry, config, input, generated, |port| {
let mut connection = HttpConnection::connect(port);
check_reply(&connection.request(&requests[0]), 200);
let mut replies = Vec::with_capacity(count);
let start = Instant::now();
for index in 0..count {
replies.push(connection.request(black_box(&requests[index % requests.len()])));
}
let elapsed = start.elapsed().as_nanos();
let mut checksum = 0u64;
for reply in &replies {
check_reply(reply, 200);
checksum += black_box(reply.body.iter().map(|byte| u64::from(*byte)).sum::<u64>());
}
(elapsed, checksum)
})
});
check(runtime, registry, config, input);
}
@@ -0,0 +1,102 @@
// 手写 Rust 完成同样的请求边界、Provider、权限门禁和业务返回,不调用生成 API。
use dever_runtime::{api, authorization, wire};
use wire::serde::{self, Deserialize, Serialize};
#[derive(Serialize)]
#[serde(crate = "dever_runtime::wire::serde")]
struct RustPermission {
key: String,
component: String,
domain: String,
site: String,
action: String,
method: String,
kind: String,
}
#[derive(Deserialize)]
#[serde(crate = "dever_runtime::wire::serde", deny_unknown_fields)]
struct EmptyFields {}
struct EmptyInput;
impl<'input> Deserialize<'input> for EmptyInput {
fn deserialize<Decoder: serde::Deserializer<'input>>(
decoder: Decoder,
) -> Result<Self, Decoder::Error> {
let _: EmptyFields = wire::object(decoder)?;
Ok(Self)
}
}
fn access_failure(error: authorization::Failure) -> ApiFailure {
match error {
authorization::Failure::Access(status) => ApiFailure(status),
authorization::Failure::Database(_) => ApiFailure(500),
}
}
async fn rust_http(
request: &Request,
peer: std::net::SocketAddr,
scope: &Scope<'_>,
registry: &Arc<Registry>,
authentication: &Arc<auth::Service>,
) -> Response {
let now = match auth::now() {
Ok(now) => now,
Err(error) => return api::error(error.status()),
};
let (mut context, claims) = match authentication.prepare_at("admin", request, false, now, peer)
{
Ok(prepared) => prepared,
Err(error) => return api::error(error.status()),
};
if let Some(claims) = claims {
if let Err(error) = rust_verify(&mut context, claims, scope, registry).await {
return error.response();
}
}
let mut database = DbContext::new(registry.clone());
let outcome = async {
authorization::authorize(
&mut database,
AUTH_BINDING,
scope,
&context,
"bench",
"account",
"permissions",
)
.await
.map_err(access_failure)?;
let input = api::input(request).map_err(ApiFailure)?;
let _: EmptyInput = input
.decode(dever_runtime::wire::decode)
.map_err(|_| ApiFailure(400))?;
let values = authorization::permissions(&mut database, AUTH_BINDING, scope, &context, true)
.await
.map_err(access_failure)?
.into_iter()
.map(|value| RustPermission {
key: value.key,
component: value.component,
domain: value.domain,
site: value.site,
action: value.action,
method: value.method,
kind: value.kind,
})
.collect::<Vec<_>>();
wire::response(&values).map_err(ApiFailure::from)
}
.await;
match outcome {
Ok(body) => {
let mut response = api::response(body);
context.publish(&mut response);
response
}
Err(error) => error.response(),
}
}