From 4784da15a24a8207fbad3a876fa7baee5ca19754 Mon Sep 17 00:00:00 2001 From: greymoth-jp Date: Fri, 26 Jun 2026 16:46:37 +0900 Subject: [PATCH] fix(http1): use append for repeat trailer values in encoder The chunked trailer encoder built allowed_trailers with HeaderMap::insert, which overwrites prior values for the same name. When a user sets the same trailer field multiple times, only the last value was written to the wire. This mirrors the decode-side fix (#4107): use append so duplicate trailer values are preserved on encode, matching how regular headers are emitted. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/proto/h1/encode.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/proto/h1/encode.rs b/src/proto/h1/encode.rs index fcf7940b16..690d7e8452 100644 --- a/src/proto/h1/encode.rs +++ b/src/proto/h1/encode.rs @@ -181,7 +181,7 @@ impl Encoder { if allowed_set.contains(name) { if is_valid_trailer_field(name) { - allowed_trailers.insert(name, value); + allowed_trailers.append(name, value); } else { debug!("trailer field is not valid: {}", &name); } @@ -567,6 +567,32 @@ mod tests { ); } + #[test] + fn chunked_with_duplicate_trailer_values() { + let encoder = Encoder::chunked(); + let trailers = vec![HeaderName::from_static("chunky-trailer")]; + let encoder = encoder.into_chunked_with_trailing_fields(trailers); + + let mut headers = HeaderMap::new(); + headers.append( + HeaderName::from_static("chunky-trailer"), + HeaderValue::from_static("first"), + ); + headers.append( + HeaderName::from_static("chunky-trailer"), + HeaderValue::from_static("second"), + ); + + let buf1 = encoder.encode_trailers::<&[u8]>(headers, false).unwrap(); + + let mut dst = Vec::new(); + dst.put(buf1); + assert_eq!( + dst, + b"0\r\nchunky-trailer: first\r\nchunky-trailer: second\r\n\r\n" + ); + } + #[test] fn chunked_with_no_trailer_header() { let encoder = Encoder::chunked();