WEB Debug + Trace

Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
Alexey
2026-08-25 12:59:41 +03:00
parent 0779cd0901
commit e774bc8c9a
48 changed files with 3744 additions and 435 deletions
+106
View File
@@ -0,0 +1,106 @@
use std::sync::Arc;
use hyper::header::{self, HeaderName, HeaderValue};
use hyper::{Request, StatusCode};
use super::body::{CollectBodyError, CollectedBody, RequestBody, collect_body};
use super::decoy::serve_decoy;
use super::request::canonical_u64_header;
use super::{
HttpResponse, carrier_empty, carrier_headers, carrier_lane, full_response, insert_header,
request_trace, service_unavailable,
};
use crate::config::WebRuntimeVhost;
use crate::web::manager::{ManagerError, TokenHash, WebProcessRuntime};
use crate::web::trace::{TraceDirection, TraceRoute};
/// Handles one authenticated long-poll downlink exchange.
pub(super) async fn handle_down(
request: Request<RequestBody>,
runtime: Arc<WebProcessRuntime>,
vhost: Arc<WebRuntimeVhost>,
token_hash: TokenHash,
) -> HttpResponse {
if request.method() != hyper::Method::POST
|| request.headers().contains_key(header::CONTENT_TYPE)
{
return serve_decoy(request, vhost, true, &runtime).await;
}
let Some(cursor) = canonical_u64_header(&request, "x-down-cursor") else {
return serve_decoy(request, vhost, true, &runtime).await;
};
let Ok(session) = runtime.get_session(token_hash, &vhost.host) else {
return serve_decoy(request, vhost, true, &runtime).await;
};
if let Some(trace) = request_trace(&request) {
trace.set_route(TraceRoute::Downlink);
trace.bind_identity(session.trace_identity());
}
let Some(lane_id) = carrier_lane(&request, session.carrier()) else {
return serve_decoy(request, vhost, true, &runtime).await;
};
let CollectedBody {
request,
body,
_body_budget,
} = match collect_body(request, &runtime, 1, true).await {
Ok(result) => result,
Err(CollectBodyError::Limit) => return service_unavailable(),
Err(CollectBodyError::Invalid(request)) => {
return serve_decoy(request, vhost, true, &runtime).await;
}
};
if !body.is_empty() {
return serve_decoy(request, vhost, true, &runtime).await;
}
let _lane_poll = if lane_id.is_some() {
let Some(permit) = runtime.try_lane_poll() else {
return service_unavailable();
};
Some(permit)
} else {
None
};
let result = match lane_id {
Some(lane_id) => session.poll_down_lane(lane_id, cursor).await,
None => session.poll_down(cursor).await,
};
match result {
Ok(result) if result.body.is_empty() => {
let mut response = carrier_empty(StatusCode::NO_CONTENT);
insert_header(
&mut response,
HeaderName::from_static("x-down-cursor"),
&result.next_cursor.to_string(),
);
if result.lane_closed {
response.headers_mut().insert(
HeaderName::from_static("x-lane-closed"),
HeaderValue::from_static("1"),
);
}
response
}
Ok(result) => {
if let Some(trace) = request_trace(&request) {
trace.record_frames(
TraceDirection::Response,
&result.body,
&runtime.active_generation().config().web.limits,
);
}
let mut response = full_response(StatusCode::OK, result.body);
carrier_headers(&mut response);
insert_header(
&mut response,
HeaderName::from_static("x-down-cursor"),
&result.next_cursor.to_string(),
);
response
}
Err(ManagerError::Concurrent | ManagerError::Backpressure | ManagerError::Limit) => {
service_unavailable()
}
Err(_) => serve_decoy(request, vhost, true, &runtime).await,
}
}