change handling of maximum capable request number, max streams
This commit is contained in:
parent
548fb77c31
commit
36c8ebcb54
12 changed files with 138 additions and 89 deletions
|
|
@ -1,5 +1,5 @@
|
|||
use super::Proxy;
|
||||
use crate::{backend::ServerNameLC, constants::*, error::*, log::*};
|
||||
use crate::{backend::ServerNameLC, error::*, log::*};
|
||||
use bytes::{Buf, Bytes};
|
||||
use h3::{quic::BidiStream, server::RequestStream};
|
||||
use hyper::{client::connect::Connect, Body, Request, Response};
|
||||
|
|
@ -10,12 +10,7 @@ impl<T> Proxy<T>
|
|||
where
|
||||
T: Connect + Clone + Sync + Send + 'static,
|
||||
{
|
||||
pub(super) fn client_serve_h3(&self, conn: quinn::Connecting, tls_server_name: &[u8]) {
|
||||
let clients_count = self.globals.clients_count.clone();
|
||||
if clients_count.increment() > self.globals.max_clients {
|
||||
clients_count.decrement();
|
||||
return;
|
||||
}
|
||||
pub(super) fn connection_serve_h3(&self, conn: quinn::Connecting, tls_server_name: &[u8]) {
|
||||
let fut = self
|
||||
.clone()
|
||||
.handle_connection_h3(conn, tls_server_name.to_vec());
|
||||
|
|
@ -24,8 +19,6 @@ where
|
|||
if let Err(e) = fut.await {
|
||||
warn!("QUIC or HTTP/3 connection failed: {}", e)
|
||||
}
|
||||
clients_count.decrement();
|
||||
debug!("Client #: {}", clients_count.current());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -45,40 +38,37 @@ where
|
|||
"QUIC/HTTP3 connection established from {:?} {:?}",
|
||||
client_addr, tls_server_name
|
||||
);
|
||||
|
||||
// Does this work enough?
|
||||
// while let Some((req, stream)) = h3_conn
|
||||
// .accept()
|
||||
// .await
|
||||
// .map_err(|e| anyhow!("HTTP/3 accept failed: {}", e))?
|
||||
// TODO: Is here enough to fetch server_name from NewConnection?
|
||||
// to avoid deep nested call from listener_service_h3
|
||||
while let Some((req, stream)) = match h3_conn.accept().await {
|
||||
Ok(opt_req) => opt_req,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"HTTP/3 failed to accept incoming connection (likely timeout): {}",
|
||||
e
|
||||
);
|
||||
warn!("HTTP/3 failed to accept incoming connection: {}", e);
|
||||
return Ok(h3_conn.shutdown(0).await?);
|
||||
}
|
||||
} {
|
||||
debug!(
|
||||
"HTTP/3 new request from {}: {} {}",
|
||||
client_addr,
|
||||
req.method(),
|
||||
req.uri()
|
||||
);
|
||||
// We consider the connection count separately from the stream count.
|
||||
// Max clients for h1/h2 = max 'stream' for h3.
|
||||
let request_count = self.globals.request_count.clone();
|
||||
if request_count.increment() > self.globals.max_clients {
|
||||
request_count.decrement();
|
||||
return Ok(h3_conn.shutdown(0).await?);
|
||||
}
|
||||
debug!("Request incoming: current # {}", request_count.current());
|
||||
|
||||
let self_inner = self.clone();
|
||||
let tls_server_name_inner = tls_server_name.clone();
|
||||
self.globals.runtime_handle.spawn(async move {
|
||||
if let Err(e) = timeout(
|
||||
self_inner.globals.proxy_timeout + Duration::from_secs(1), // timeout per stream are considered as same as one in http2
|
||||
self_inner.handle_stream_h3(req, stream, client_addr, tls_server_name_inner),
|
||||
self_inner.stream_serve_h3(req, stream, client_addr, tls_server_name_inner),
|
||||
)
|
||||
.await
|
||||
{
|
||||
error!("HTTP/3 failed to process stream: {}", e);
|
||||
}
|
||||
request_count.decrement();
|
||||
debug!("Request processed: current # {}", request_count.current());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +81,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_stream_h3<S>(
|
||||
async fn stream_serve_h3<S>(
|
||||
self,
|
||||
req: Request<()>,
|
||||
stream: RequestStream<S, Bytes>,
|
||||
|
|
@ -111,13 +101,14 @@ where
|
|||
|
||||
// Buffering and sending body through channel for protocol conversion like h3 -> h2/http1.1
|
||||
// The underling buffering, i.e., buffer given by the API recv_data.await?, is handled by quinn.
|
||||
let max_body_size = self.globals.h3_request_max_body_size;
|
||||
self.globals.runtime_handle.spawn(async move {
|
||||
let mut sender = body_sender;
|
||||
let mut size = 0usize;
|
||||
while let Some(mut body) = recv_stream.recv_data().await? {
|
||||
debug!("HTTP/3 incoming request body");
|
||||
size += body.remaining();
|
||||
if size > H3_REQUEST_MAX_BODY_SIZE {
|
||||
if size > max_body_size {
|
||||
error!("Exceeds max request body size for HTTP/3");
|
||||
return Err(anyhow!("Exceeds max request body size for HTTP/3"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,11 +56,12 @@ where
|
|||
) where
|
||||
I: AsyncRead + AsyncWrite + Send + Unpin + 'static,
|
||||
{
|
||||
let clients_count = self.globals.clients_count.clone();
|
||||
if clients_count.increment() > self.globals.max_clients {
|
||||
clients_count.decrement();
|
||||
let request_count = self.globals.request_count.clone();
|
||||
if request_count.increment() > self.globals.max_clients {
|
||||
request_count.decrement();
|
||||
return;
|
||||
}
|
||||
debug!("Request incoming: current # {}", request_count.current());
|
||||
|
||||
// let inner = tls_server_name.map_or_else(|| None, |v| Some(v.as_bytes().to_ascii_lowercase()));
|
||||
self.globals.runtime_handle.clone().spawn(async move {
|
||||
|
|
@ -84,8 +85,8 @@ where
|
|||
.await
|
||||
.ok();
|
||||
|
||||
clients_count.decrement();
|
||||
debug!("Client #: {}", clients_count.current());
|
||||
request_count.decrement();
|
||||
debug!("Request processed: current # {}", request_count.current());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use futures::{future::FutureExt, select};
|
|||
use hyper::{client::connect::Connect, server::conn::Http};
|
||||
use rustls::ServerConfig;
|
||||
use std::sync::Arc;
|
||||
use tokio::{net::TcpListener, sync::watch, time::Duration};
|
||||
use tokio::{
|
||||
net::TcpListener,
|
||||
sync::watch,
|
||||
time::{sleep, Duration},
|
||||
};
|
||||
use tokio_rustls::TlsAcceptor;
|
||||
|
||||
impl<T> Proxy<T>
|
||||
|
|
@ -29,7 +33,7 @@ where
|
|||
} else {
|
||||
error!("Failed to update certs");
|
||||
}
|
||||
tokio::time::sleep(Duration::from_secs(CERTS_WATCH_DELAY_SECS.into())).await;
|
||||
sleep(Duration::from_secs(CERTS_WATCH_DELAY_SECS.into())).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +54,7 @@ where
|
|||
if tls_acceptor.is_none() || tcp_cnx.is_err() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let (raw_stream, _client_addr) = tcp_cnx.unwrap();
|
||||
let (raw_stream, client_addr) = tcp_cnx.unwrap();
|
||||
|
||||
if let Ok(stream) = tls_acceptor.as_ref().unwrap().accept(raw_stream).await {
|
||||
// Retrieve SNI
|
||||
|
|
@ -62,7 +65,7 @@ where
|
|||
if server_name.is_none(){
|
||||
continue;
|
||||
}
|
||||
self.clone().client_serve(stream, server.clone(), _client_addr, server_name); // TODO: don't want to pass copied value...
|
||||
self.clone().client_serve(stream, server.clone(), client_addr, server_name); // TODO: don't want to pass copied value...
|
||||
}
|
||||
}
|
||||
_ = server_crypto_rx.changed().fuse() => {
|
||||
|
|
@ -83,13 +86,20 @@ where
|
|||
&self,
|
||||
mut server_crypto_rx: watch::Receiver<Option<Arc<ServerConfig>>>,
|
||||
) -> Result<()> {
|
||||
let mut transport_config_quic = quinn::TransportConfig::default();
|
||||
transport_config_quic
|
||||
.max_concurrent_bidi_streams(self.globals.h3_max_concurrent_bidistream)
|
||||
.max_concurrent_uni_streams(self.globals.h3_max_concurrent_unistream);
|
||||
|
||||
let server_crypto = self
|
||||
.globals
|
||||
.backends
|
||||
.generate_server_crypto_with_cert_resolver()
|
||||
.await?;
|
||||
|
||||
let server_config_h3 = quinn::ServerConfig::with_crypto(Arc::new(server_crypto));
|
||||
let mut server_config_h3 = quinn::ServerConfig::with_crypto(Arc::new(server_crypto));
|
||||
server_config_h3.transport = Arc::new(transport_config_quic);
|
||||
server_config_h3.concurrent_connections(self.globals.h3_max_concurrent_connections);
|
||||
let (endpoint, mut incoming) = quinn::Endpoint::server(server_config_h3, self.listening_on)?;
|
||||
info!("Start UDP proxy serving with HTTP/3 request for configured host names");
|
||||
|
||||
|
|
@ -121,7 +131,9 @@ where
|
|||
"HTTP/3 connection incoming (SNI {:?})",
|
||||
new_server_name
|
||||
);
|
||||
self.clone().client_serve_h3(conn, new_server_name.as_ref());
|
||||
// TODO: server_nameをここで出してどんどん深く投げていくのは効率が悪い。connecting -> connectionsの後でいいのでは?
|
||||
// TODO: 通常のTLSと同じenumか何かにまとめたい
|
||||
self.clone().connection_serve_h3(conn, new_server_name.as_ref());
|
||||
}
|
||||
_ = server_crypto_rx.changed().fuse() => {
|
||||
if server_crypto_rx.borrow().is_none() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue