Skip to content

Commit f758077

Browse files
committed
make http2 parameters configurable
1 parent bf82c66 commit f758077

File tree

5 files changed

+101
-13
lines changed

5 files changed

+101
-13
lines changed

ext/http/http_next.rs

+85-10
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ use std::io;
7070
use std::pin::Pin;
7171
use std::ptr::null;
7272
use std::rc::Rc;
73+
use std::time::Duration;
7374

7475
use super::fly_accept_encoding;
7576
use fly_accept_encoding::Encoding;
@@ -165,6 +166,25 @@ pub enum HttpNextError {
165166
UpgradeUnavailable(#[from] crate::service::UpgradeUnavailableError),
166167
}
167168

169+
/// A set of configuration parameters for HTTP/2.
170+
/// If a field is `None`, the default value from the hyper crate will be used.
171+
/// The default values may change in future versions.
172+
#[derive(Default, Clone, Copy)]
173+
pub struct Http2Config {
174+
pub max_pending_accept_reset_streams: Option<usize>,
175+
pub max_local_error_reset_streams: Option<usize>,
176+
pub initial_stream_window_size: Option<u32>,
177+
pub initial_connection_window_size: Option<u32>,
178+
pub adaptive_window: Option<bool>,
179+
pub max_frame_size: Option<u32>,
180+
pub max_concurrent_streams: Option<u32>,
181+
pub keep_alive_interval: Option<Duration>,
182+
pub keep_alive_timeout: Option<Duration>,
183+
pub max_send_buf_size: Option<usize>,
184+
pub max_header_list_size: Option<u32>,
185+
pub auto_date_header: Option<bool>,
186+
}
187+
168188
#[op2(fast)]
169189
#[smi]
170190
pub fn op_http_upgrade_raw(
@@ -829,9 +849,48 @@ fn serve_http2_unconditional(
829849
io: impl HttpServeStream,
830850
svc: impl HttpService<Incoming, ResBody = HttpRecordResponse> + 'static,
831851
cancel: Rc<CancelHandle>,
852+
h2_config: Http2Config,
832853
) -> impl Future<Output = Result<(), hyper::Error>> + 'static {
833-
let conn =
834-
http2::Builder::new(LocalExecutor).serve_connection(TokioIo::new(io), svc);
854+
let mut builder = http2::Builder::new(LocalExecutor);
855+
856+
if let Some(v) = h2_config.max_pending_accept_reset_streams {
857+
builder.max_pending_accept_reset_streams(v);
858+
}
859+
if let Some(v) = h2_config.max_local_error_reset_streams {
860+
builder = builder.max_local_error_reset_streams(v);
861+
}
862+
if let Some(v) = h2_config.initial_stream_window_size {
863+
builder.initial_stream_window_size(v);
864+
}
865+
if let Some(v) = h2_config.initial_connection_window_size {
866+
builder.initial_connection_window_size(v);
867+
}
868+
if let Some(v) = h2_config.adaptive_window {
869+
builder.adaptive_window(v);
870+
}
871+
if let Some(v) = h2_config.max_frame_size {
872+
builder.max_frame_size(v);
873+
}
874+
if let Some(v) = h2_config.max_concurrent_streams {
875+
builder.max_concurrent_streams(v);
876+
}
877+
if let Some(v) = h2_config.keep_alive_interval {
878+
builder.keep_alive_interval(v);
879+
}
880+
if let Some(v) = h2_config.keep_alive_timeout {
881+
builder.keep_alive_timeout(v);
882+
}
883+
if let Some(v) = h2_config.max_send_buf_size {
884+
builder.max_send_buf_size(v);
885+
}
886+
if let Some(v) = h2_config.max_header_list_size {
887+
builder.max_header_list_size(v);
888+
}
889+
if let Some(v) = h2_config.auto_date_header {
890+
builder.auto_date_header(v);
891+
}
892+
893+
let conn = builder.serve_connection(TokioIo::new(io), svc);
835894
async {
836895
match conn.or_abort(cancel).await {
837896
Err(mut conn) => {
@@ -847,11 +906,12 @@ async fn serve_http2_autodetect(
847906
io: impl HttpServeStream,
848907
svc: impl HttpService<Incoming, ResBody = HttpRecordResponse> + 'static,
849908
cancel: Rc<CancelHandle>,
909+
h2_config: Http2Config,
850910
) -> Result<(), HttpNextError> {
851911
let prefix = NetworkStreamPrefixCheck::new(io, HTTP2_PREFIX);
852912
let (matches, io) = prefix.match_prefix().await?;
853913
if matches {
854-
serve_http2_unconditional(io, svc, cancel)
914+
serve_http2_unconditional(io, svc, cancel, h2_config)
855915
.await
856916
.map_err(HttpNextError::Hyper)
857917
} else {
@@ -866,6 +926,7 @@ fn serve_https(
866926
request_info: HttpConnectionProperties,
867927
lifetime: HttpLifetime,
868928
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
929+
h2_config: Http2Config,
869930
) -> JoinHandle<Result<(), HttpNextError>> {
870931
let HttpLifetime {
871932
server_state,
@@ -877,21 +938,21 @@ fn serve_https(
877938
handle_request(req, request_info.clone(), server_state.clone(), tx.clone())
878939
});
879940
spawn(
880-
async {
941+
async move {
881942
let handshake = io.handshake().await?;
882943
// If the client specifically negotiates a protocol, we will use it. If not, we'll auto-detect
883944
// based on the prefix bytes
884945
let handshake = handshake.alpn;
885946
if Some(TLS_ALPN_HTTP_2) == handshake.as_deref() {
886-
serve_http2_unconditional(io, svc, listen_cancel_handle)
947+
serve_http2_unconditional(io, svc, listen_cancel_handle, h2_config)
887948
.await
888949
.map_err(HttpNextError::Hyper)
889950
} else if Some(TLS_ALPN_HTTP_11) == handshake.as_deref() {
890951
serve_http11_unconditional(io, svc, listen_cancel_handle)
891952
.await
892953
.map_err(HttpNextError::Hyper)
893954
} else {
894-
serve_http2_autodetect(io, svc, listen_cancel_handle).await
955+
serve_http2_autodetect(io, svc, listen_cancel_handle, h2_config).await
895956
}
896957
}
897958
.try_or_cancel(connection_cancel_handle),
@@ -903,6 +964,7 @@ fn serve_http(
903964
request_info: HttpConnectionProperties,
904965
lifetime: HttpLifetime,
905966
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
967+
h2_config: Http2Config,
906968
) -> JoinHandle<Result<(), HttpNextError>> {
907969
let HttpLifetime {
908970
server_state,
@@ -914,7 +976,7 @@ fn serve_http(
914976
handle_request(req, request_info.clone(), server_state.clone(), tx.clone())
915977
});
916978
spawn(
917-
serve_http2_autodetect(io, svc, listen_cancel_handle)
979+
serve_http2_autodetect(io, svc, listen_cancel_handle, h2_config)
918980
.try_or_cancel(connection_cancel_handle),
919981
)
920982
}
@@ -924,6 +986,7 @@ fn serve_http_on<HTTP>(
924986
listen_properties: &HttpListenProperties,
925987
lifetime: HttpLifetime,
926988
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
989+
h2_config: Http2Config,
927990
) -> JoinHandle<Result<(), HttpNextError>>
928991
where
929992
HTTP: HttpPropertyExtractor,
@@ -935,14 +998,14 @@ where
935998

936999
match network_stream {
9371000
NetworkStream::Tcp(conn) => {
938-
serve_http(conn, connection_properties, lifetime, tx)
1001+
serve_http(conn, connection_properties, lifetime, tx, h2_config)
9391002
}
9401003
NetworkStream::Tls(conn) => {
941-
serve_https(conn, connection_properties, lifetime, tx)
1004+
serve_https(conn, connection_properties, lifetime, tx, h2_config)
9421005
}
9431006
#[cfg(unix)]
9441007
NetworkStream::Unix(conn) => {
945-
serve_http(conn, connection_properties, lifetime, tx)
1008+
serve_http(conn, connection_properties, lifetime, tx, h2_config)
9461009
}
9471010
}
9481011
}
@@ -1031,6 +1094,11 @@ where
10311094

10321095
let lifetime = resource.lifetime();
10331096

1097+
let h2_config = {
1098+
let state = state.borrow();
1099+
*state.borrow::<Http2Config>()
1100+
};
1101+
10341102
let listen_properties_clone: HttpListenProperties = listen_properties.clone();
10351103
let handle = spawn(async move {
10361104
loop {
@@ -1043,6 +1111,7 @@ where
10431111
&listen_properties_clone,
10441112
lifetime.clone(),
10451113
tx.clone(),
1114+
h2_config,
10461115
);
10471116
}
10481117
#[allow(unreachable_code)]
@@ -1079,11 +1148,17 @@ where
10791148
let (tx, rx) = tokio::sync::mpsc::channel(10);
10801149
let resource: Rc<HttpJoinHandle> = Rc::new(HttpJoinHandle::new(rx));
10811150

1151+
let h2_config = {
1152+
let state = state.borrow();
1153+
*state.borrow::<Http2Config>()
1154+
};
1155+
10821156
let handle = serve_http_on::<HTTP>(
10831157
connection,
10841158
&listen_properties,
10851159
resource.lifetime(),
10861160
tx,
1161+
h2_config,
10871162
);
10881163

10891164
// Set the handle after we start the future

ext/http/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ mod service;
8787
mod websocket_upgrade;
8888

8989
use fly_accept_encoding::Encoding;
90+
pub use http_next::Http2Config;
9091
pub use http_next::HttpNextError;
9192
pub use request_properties::DefaultHttpPropertyExtractor;
9293
pub use request_properties::HttpConnectionProperties;
@@ -134,6 +135,12 @@ deno_core::extension!(
134135
http_next::op_http_cancel,
135136
],
136137
esm = ["00_serve.ts", "01_http.js", "02_websocket.ts"],
138+
options = {
139+
h2_config: Http2Config,
140+
},
141+
state = |state, options| {
142+
state.put(options.h2_config);
143+
}
137144
);
138145

139146
#[derive(Debug, thiserror::Error)]

runtime/snapshot.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,9 @@ pub fn create_runtime_snapshot(
300300
deno_cron::local::LocalCronHandler::new(),
301301
),
302302
deno_napi::deno_napi::init_ops_and_esm::<Permissions>(),
303-
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(),
303+
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(
304+
deno_http::Http2Config::default(),
305+
),
304306
deno_io::deno_io::init_ops_and_esm(Default::default()),
305307
deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
306308
deno_node::deno_node::init_ops_and_esm::<Permissions>(None, fs.clone()),

runtime/web_worker.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,9 @@ impl WebWorker {
488488
),
489489
deno_cron::deno_cron::init_ops_and_esm(LocalCronHandler::new()),
490490
deno_napi::deno_napi::init_ops_and_esm::<PermissionsContainer>(),
491-
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(),
491+
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(
492+
deno_http::Http2Config::default(),
493+
),
492494
deno_io::deno_io::init_ops_and_esm(Some(options.stdio)),
493495
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
494496
services.fs.clone(),

runtime/worker.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,9 @@ impl MainWorker {
405405
),
406406
deno_cron::deno_cron::init_ops_and_esm(LocalCronHandler::new()),
407407
deno_napi::deno_napi::init_ops_and_esm::<PermissionsContainer>(),
408-
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(),
408+
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(
409+
deno_http::Http2Config::default(),
410+
),
409411
deno_io::deno_io::init_ops_and_esm(Some(options.stdio)),
410412
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
411413
services.fs.clone(),

0 commit comments

Comments
 (0)