v0.26.1
This commit is contained in:
1 parent
ddc5c6593f
commit
b9d137eee1
63 files changed
+1232
-445
No files matched your search
+75
-16
@@ -28,7 +28,6 @@ use tokio::{
|
||||
task::JoinSet,
|
||||
};
|
||||
use tower::ServiceExt;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Settings {
|
||||
@@ -191,6 +190,63 @@ impl Drop for Lease {
|
||||
.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn log_protocol_error(
|
||||
state: &App,
|
||||
kind: &'static str,
|
||||
detail: impl std::fmt::Display,
|
||||
peer: SocketAddr,
|
||||
local: SocketAddr,
|
||||
status: u16,
|
||||
authority: Option<String>,
|
||||
host: Option<String>,
|
||||
sni: Option<String>,
|
||||
) {
|
||||
let resolved = state.config.load().resolve_logging_vhost(
|
||||
local,
|
||||
true,
|
||||
None,
|
||||
authority.as_deref(),
|
||||
host.as_deref(),
|
||||
sni.as_deref(),
|
||||
);
|
||||
let (vhost, matched_by) = resolved
|
||||
.map(|resolved| (Some(resolved.vhost), resolved.matched_by))
|
||||
.unwrap_or((None, "none"));
|
||||
state.logs.push_protocol_error_attributed(
|
||||
kind,
|
||||
detail,
|
||||
peer,
|
||||
local,
|
||||
"quic",
|
||||
"3",
|
||||
status,
|
||||
sni,
|
||||
authority.or(host),
|
||||
vhost,
|
||||
matched_by,
|
||||
);
|
||||
}
|
||||
fn request_identity<B>(request: &http::Request<B>) -> (Option<String>, Option<String>) {
|
||||
let authority = request
|
||||
.uri()
|
||||
.authority()
|
||||
.map(|value| value.as_str().to_owned());
|
||||
let host = request
|
||||
.headers()
|
||||
.get(http::header::HOST)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.map(str::to_owned);
|
||||
(authority, host)
|
||||
}
|
||||
fn connection_sni(connection: &quinn::Connection) -> Option<String> {
|
||||
connection
|
||||
.handshake_data()?
|
||||
.downcast::<quinn::crypto::rustls::HandshakeData>()
|
||||
.ok()?
|
||||
.server_name
|
||||
.and_then(|name| crate::config::request_host(&name).ok())
|
||||
}
|
||||
pub async fn serve(bound: Bound, router: Router, state: Arc<App>, grace: Duration) -> Result<()> {
|
||||
let slots = Arc::new(Semaphore::new(
|
||||
bound.settings.max_concurrent_connections as usize,
|
||||
@@ -258,15 +314,16 @@ pub async fn serve(bound: Bound, router: Router, state: Arc<App>, grace: Duratio
|
||||
None if !address.ip().is_unspecified()=>address,
|
||||
None=>{connection.close(0x102u32.into(),b"local destination unavailable");return;},
|
||||
};
|
||||
let tls_sni=connection_sni(&connection);
|
||||
state.metrics.connections.fetch_add(1,Ordering::Relaxed);
|
||||
state.metrics.active_connections.fetch_add(1,Ordering::Relaxed);
|
||||
state.metrics.http3_connections.fetch_add(1,Ordering::Relaxed);
|
||||
state.metrics.http3_active_connections.fetch_add(1,Ordering::Relaxed);
|
||||
state.metrics.tls_connections.fetch_add(1,Ordering::Relaxed);
|
||||
let _lease=Lease {_permit:permit,metrics:state.metrics.clone()};
|
||||
if let Err(error)=connection_loop(connection,local,router,state.clone(),limit,grace).await {
|
||||
state.logs.push_protocol_error(
|
||||
"http3_connection_error", &error, peer, local, "quic", "3", 0, None,
|
||||
if let Err(error)=connection_loop(connection,local,router,state.clone(),limit,grace,tls_sni.clone()).await {
|
||||
log_protocol_error(
|
||||
&state, "http3_connection_error", &error, peer, local, 0, None, None, tls_sni,
|
||||
);
|
||||
tracing::debug!(%error,"HTTP/3 connection ended");
|
||||
}
|
||||
@@ -290,6 +347,7 @@ async fn connection_loop(
|
||||
state: Arc<App>,
|
||||
limit: usize,
|
||||
grace: Duration,
|
||||
tls_sni: Option<String>,
|
||||
) -> Result<()> {
|
||||
let mut builder = h3::server::builder();
|
||||
builder.max_field_section_size(32 * 1024);
|
||||
@@ -316,27 +374,27 @@ async fn connection_loop(
|
||||
Ok(Some(resolver))=>{
|
||||
// Completed JoinSet entries are drained before accepting more.
|
||||
if requests.len()>=limit {
|
||||
state.logs.push_protocol_error(
|
||||
"http3_stream_limit_rejected", "HTTP/3 concurrent request stream limit reached",
|
||||
connection.remote_address(), local, "quic", "3", 0, None,
|
||||
log_protocol_error(
|
||||
&state, "http3_stream_limit_rejected", "HTTP/3 concurrent request stream limit reached",
|
||||
connection.remote_address(), local, 0, None, None, tls_sni.clone(),
|
||||
);
|
||||
drop(resolver);continue;
|
||||
}
|
||||
let router=router.clone();let state=state.clone();let peer=connection.remote_address();
|
||||
let router=router.clone();let state=state.clone();let peer=connection.remote_address();let tls_sni=tls_sni.clone();
|
||||
requests.spawn(async move {
|
||||
let resolved=tokio::time::timeout(state.header_timeout,resolver.resolve_request()).await;
|
||||
let (mut request,stream)=match resolved {
|
||||
Ok(Ok(request))=>request,
|
||||
Ok(Err(error))=>{
|
||||
state.logs.push_protocol_error(
|
||||
"http3_request_error", error, peer, local, "quic", "3", 400, None,
|
||||
log_protocol_error(
|
||||
&state, "http3_request_error", error, peer, local, 400, None, None, tls_sni.clone(),
|
||||
);
|
||||
return;
|
||||
},
|
||||
Err(_)=>{
|
||||
state.logs.push_protocol_error(
|
||||
"http3_header_timeout", "HTTP/3 request header timeout",
|
||||
peer, local, "quic", "3", 408, None,
|
||||
log_protocol_error(
|
||||
&state, "http3_header_timeout", "HTTP/3 request header timeout",
|
||||
peer, local, 408, None, None, tls_sni.clone(),
|
||||
);
|
||||
return;
|
||||
},
|
||||
@@ -347,9 +405,10 @@ async fn connection_loop(
|
||||
let websocket=extended_connect && protocol.as_deref()==Some("websocket");
|
||||
let (mut send,receive)=stream.split();
|
||||
if invalid_headers(request.headers()) {
|
||||
state.logs.push_protocol_error(
|
||||
"http3_invalid_headers", "HTTP/3 request contains forbidden connection-specific headers",
|
||||
peer, local, "quic", "3", 400, None,
|
||||
let (authority, host) = request_identity(&request);
|
||||
log_protocol_error(
|
||||
&state, "http3_invalid_headers", "HTTP/3 request contains forbidden connection-specific headers",
|
||||
peer, local, 400, authority, host, tls_sni.clone(),
|
||||
);
|
||||
send.stop_stream(Code::H3_MESSAGE_ERROR);return;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user