diff --git a/apollo-router/src/axum_factory/axum_http_server_factory.rs b/apollo-router/src/axum_factory/axum_http_server_factory.rs index b49d5e7918..4077ddc057 100644 --- a/apollo-router/src/axum_factory/axum_http_server_factory.rs +++ b/apollo-router/src/axum_factory/axum_http_server_factory.rs @@ -306,6 +306,9 @@ impl HttpServerFactory for AxumHttpServerFactory { if let Some(max_headers) = configuration.supergraph.experimental_http1_max_headers { http_config.http1_max_headers(max_headers); } + if let Some(max_buf_size) = configuration.supergraph.experimental_http1_max_buf_size { + http_config.max_buf_size(max_buf_size); + } let (main_server, main_shutdown_sender) = serve_router_on_listen_addr( main_listener, diff --git a/apollo-router/src/configuration/mod.rs b/apollo-router/src/configuration/mod.rs index b744cf9df9..bc685cf634 100644 --- a/apollo-router/src/configuration/mod.rs +++ b/apollo-router/src/configuration/mod.rs @@ -707,6 +707,11 @@ pub(crate) struct Supergraph { /// /// Default is 100. pub(crate) experimental_http1_max_headers: Option, + + /// Set the maximum buffer size for the HTTP1 connection. + /// + /// Default is ~400kb. + pub(crate) experimental_http1_max_buf_size: Option, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)] @@ -746,6 +751,7 @@ impl Supergraph { early_cancel: Option, experimental_log_on_broken_pipe: Option, experimental_http1_max_headers: Option, + experimental_http1_max_buf_size: Option, ) -> Self { Self { listen: listen.unwrap_or_else(default_graphql_listen), @@ -766,6 +772,7 @@ impl Supergraph { early_cancel: early_cancel.unwrap_or_default(), experimental_log_on_broken_pipe: experimental_log_on_broken_pipe.unwrap_or_default(), experimental_http1_max_headers, + experimental_http1_max_buf_size, } } } @@ -785,6 +792,7 @@ impl Supergraph { early_cancel: Option, experimental_log_on_broken_pipe: Option, experimental_http1_max_headers: Option, + experimental_http1_max_buf_size: Option, ) -> Self { Self { listen: listen.unwrap_or_else(test_listen), @@ -805,6 +813,7 @@ impl Supergraph { early_cancel: early_cancel.unwrap_or_default(), experimental_log_on_broken_pipe: experimental_log_on_broken_pipe.unwrap_or_default(), experimental_http1_max_headers, + experimental_http1_max_buf_size, } } } diff --git a/apollo-router/tests/integration/supergraph.rs b/apollo-router/tests/integration/supergraph.rs index 8dc48a16dc..bd1672c44a 100644 --- a/apollo-router/tests/integration/supergraph.rs +++ b/apollo-router/tests/integration/supergraph.rs @@ -62,3 +62,59 @@ async fn test_supergraph_allow_to_change_http1_max_headers() -> Result<(), BoxEr ); Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn test_supergraph_allow_to_change_http1_max_buf_size( +) -> Result<(), BoxError> { + let mut router = IntegrationTest::builder() + .config( + r#" + supergraph: + experimental_http1_max_buf_size: 1000000 + "#, + ) + .build() + .await; + + router.start().await; + router.assert_started().await; + + let mut headers = HashMap::new(); + headers.insert(format!("test-header"), "x".repeat(1048576 + 1)); + + let (_trace_id, response) = router + .execute_query_with_headers(&json!({ "query": "{ __typename }"}), headers) + .await; + assert_eq!(response.status(), 431); + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_supergraph_errors_on_http1_header_that_does_not_fit_inside_buffer( +) -> Result<(), BoxError> { + let mut router = IntegrationTest::builder() + .config( + r#" + supergraph: + experimental_http1_max_buf_size: 2000000 + "#, + ) + .build() + .await; + + router.start().await; + router.assert_started().await; + + let mut headers = HashMap::new(); + headers.insert(format!("test-header"), "x".repeat(1048576 + 1)); + + let (_trace_id, response) = router + .execute_query_with_headers(&json!({ "query": "{ __typename }"}), headers) + .await; + assert_eq!(response.status(), 200); + assert_eq!( + response.json::().await?, + json!({ "data": { "__typename": "Query" } }) + ); + Ok(()) +}