Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Http2 flags for advanced configurations #365

Merged
merged 1 commit into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion cas/cas_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,46 @@ async fn inner_main(cfg: CasConfig, server_start_timestamp: u64) -> Result<(), B

let socket_addr = server_cfg.listen_address.parse::<SocketAddr>()?;
let tcp_listener = TcpListener::bind(&socket_addr).await?;
let http = Http::new();
let mut http = Http::new();
let http_config = &server_cfg.advanced_http;
if let Some(value) = http_config.http2_max_pending_accept_reset_streams {
http.http2_max_pending_accept_reset_streams(
usize::try_from(value).err_tip(|| "Could not convert http2_max_pending_accept_reset_streams")?,
);
}
if let Some(value) = http_config.http2_initial_stream_window_size {
http.http2_initial_stream_window_size(value);
}
if let Some(value) = http_config.http2_initial_connection_window_size {
http.http2_initial_connection_window_size(value);
}
if let Some(value) = http_config.http2_adaptive_window {
http.http2_adaptive_window(value);
}
if let Some(value) = http_config.http2_max_frame_size {
http.http2_max_frame_size(value);
}
if let Some(value) = http_config.http2_max_concurrent_streams {
http.http2_max_concurrent_streams(value);
}
if let Some(value) = http_config.http2_keep_alive_interval {
http.http2_keep_alive_interval(Duration::from_secs(u64::from(value)));
}
if let Some(value) = http_config.http2_keep_alive_timeout {
http.http2_keep_alive_timeout(Duration::from_secs(u64::from(value)));
}
if let Some(value) = http_config.http2_max_send_buf_size {
http.http2_max_send_buf_size(
usize::try_from(value).err_tip(|| "Could not convert http2_max_send_buf_size")?,
);
}
if let Some(true) = http_config.http2_enable_connect_protocol {
http.http2_enable_connect_protocol();
}
if let Some(value) = http_config.http2_max_header_list_size {
http.http2_max_header_list_size(value);
}

log::warn!("Ready, listening on {}", socket_addr);
root_futures.push(Box::pin(async move {
loop {
Expand Down
40 changes: 39 additions & 1 deletion config/cas_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
use std::collections::HashMap;

use serde::Deserialize;
use serde_utils::{convert_numeric_with_shellexpand, convert_string_with_shellexpand};
use serde_utils::{
convert_numeric_with_shellexpand, convert_optinoal_numeric_with_shellexpand, convert_string_with_shellexpand,
};

use crate::schedulers::SchedulerConfig;
use crate::stores::{StoreConfig, StoreRefName};
Expand Down Expand Up @@ -200,6 +202,38 @@ pub struct TlsConfig {
pub key_file: String,
}

/// Advanced Http configurations. These are generally should not be set.
/// For documentation on what each of these do, see the hyper documentation:
/// See: https://docs.rs/hyper/latest/hyper/server/conn/struct.Http.html
///
/// Note: All of these default to hyper's default values unless otherwise
/// specified.
#[derive(Deserialize, Debug, Default)]
pub struct HttpServerConfig {
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_max_pending_accept_reset_streams: Option<u32>,
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_initial_stream_window_size: Option<u32>,
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_initial_connection_window_size: Option<u32>,
pub http2_adaptive_window: Option<bool>,
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_max_frame_size: Option<u32>,
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_max_concurrent_streams: Option<u32>,
/// Note: This is in seconds.
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_keep_alive_interval: Option<u32>,
/// Note: This is in seconds.
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_keep_alive_timeout: Option<u32>,
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_max_send_buf_size: Option<u32>,
pub http2_enable_connect_protocol: Option<bool>,
#[serde(deserialize_with = "convert_optinoal_numeric_with_shellexpand")]
pub http2_max_header_list_size: Option<u32>,
}

#[derive(Deserialize, Debug)]
pub struct ServerConfig {
/// Name of the server. This is used to help identify the service
Expand All @@ -218,6 +252,10 @@ pub struct ServerConfig {
#[serde(default)]
pub compression: CompressionConfig,

/// Advanced Http server configuration.
#[serde(default)]
pub advanced_http: HttpServerConfig,

/// Services to attach to server.
pub services: Option<ServicesConfig>,

Expand Down
43 changes: 43 additions & 0 deletions util/serde_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,49 @@ where
deserializer.deserialize_any(USizeVisitor::<T>(PhantomData::<T> {}))
}

/// Same as convert_numeric_with_shellexpand, but supports Option<T>.
pub fn convert_optinoal_numeric_with_shellexpand<'de, D, T, E>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
E: fmt::Display,
T: TryFrom<i64> + FromStr<Err = E>,
<T as TryFrom<i64>>::Error: fmt::Display,
{
// define a visitor that deserializes
// `ActualData` encoded as json within a string
struct USizeVisitor<T: TryFrom<i64>>(PhantomData<T>);

impl<'de, T, FromStrErr> de::Visitor<'de> for USizeVisitor<T>
where
FromStrErr: fmt::Display,
T: TryFrom<i64> + FromStr<Err = FromStrErr>,
<T as TryFrom<i64>>::Error: fmt::Display,
{
type Value = Option<T>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string containing json data")
}

fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
Ok(Some(v.try_into().map_err(de::Error::custom)?))
}

fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
if v.is_empty() {
return Ok(None);
}
Ok(Some(
(*shellexpand::env(v).map_err(de::Error::custom)?)
.parse::<T>()
.map_err(de::Error::custom)?,
))
}
}

deserializer.deserialize_any(USizeVisitor::<T>(PhantomData::<T> {}))
}

/// Helper for serde macro so you can use shellexpand variables in the json configuration
/// files when the number is a numeric type.
pub fn convert_string_with_shellexpand<'de, D: Deserializer<'de>>(deserializer: D) -> Result<String, D::Error> {
Expand Down