Skip to content

Commit 6bf1fcb

Browse files
authored
Fix recursive call leading to stack overflow when tracing level filter is TRACE (#3312)
1 parent 1599569 commit 6bf1fcb

File tree

3 files changed

+45
-3
lines changed

3 files changed

+45
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

axum-extra/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ multipart = ["dep:multer", "dep:fastrand"]
3838
protobuf = ["dep:prost"]
3939
scheme = []
4040
query = ["dep:form_urlencoded", "dep:serde_html_form", "dep:serde_path_to_error"]
41-
tracing = ["axum-core/tracing", "axum/tracing"]
41+
tracing = ["axum-core/tracing", "axum/tracing", "dep:tracing"]
4242
typed-header = ["dep:headers"]
4343
typed-routing = ["dep:axum-macros", "dep:percent-encoding", "dep:serde_html_form", "dep:form_urlencoded"]
4444

@@ -92,6 +92,7 @@ serde_json = "1.0.71"
9292
tokio = { version = "1.14", features = ["full"] }
9393
tower = { version = "0.5.2", features = ["util"] }
9494
tower-http = { version = "0.6.0", features = ["map-response-body", "timeout"] }
95+
tracing-subscriber = "0.3.19"
9596

9697
[lints]
9798
workspace = true

axum-extra/src/extract/multipart.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,13 @@ impl MultipartError {
243243

244244
/// Get the response body text used for this rejection.
245245
pub fn body_text(&self) -> String {
246+
let body = self.source.to_string();
246247
axum_core::__log_rejection!(
247248
rejection_type = Self,
248-
body_text = self.body_text(),
249+
body_text = body,
249250
status = self.status(),
250251
);
251-
self.source.to_string()
252+
body
252253
}
253254

254255
/// Get the status code used for this rejection.
@@ -398,4 +399,43 @@ mod tests {
398399
let res = client.post("/").multipart(form).await;
399400
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
400401
}
402+
403+
#[tokio::test]
404+
#[cfg(feature = "tracing")]
405+
async fn body_too_large_with_tracing() {
406+
const BYTES: &[u8] = "<!doctype html><title>🦀</title>".as_bytes();
407+
408+
async fn handle(mut multipart: Multipart) -> impl IntoResponse {
409+
let result: Result<(), MultipartError> = async {
410+
while let Some(field) = multipart.next_field().await? {
411+
field.bytes().await?;
412+
}
413+
Ok(())
414+
}
415+
.await;
416+
417+
let subscriber = tracing_subscriber::FmtSubscriber::builder()
418+
.with_max_level(tracing::level_filters::LevelFilter::TRACE)
419+
.with_writer(std::io::sink)
420+
.finish();
421+
422+
let guard = tracing::subscriber::set_default(subscriber);
423+
let response = result.into_response();
424+
drop(guard);
425+
426+
response
427+
}
428+
429+
let app = Router::new()
430+
.route("/", post(handle))
431+
.layer(DefaultBodyLimit::max(BYTES.len() - 1));
432+
433+
let client = TestClient::new(app);
434+
435+
let form =
436+
reqwest::multipart::Form::new().part("file", reqwest::multipart::Part::bytes(BYTES));
437+
438+
let res = client.post("/").multipart(form).await;
439+
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
440+
}
401441
}

0 commit comments

Comments
 (0)