From 60aebc247ecd9fae8d676705422db8f282c2b590 Mon Sep 17 00:00:00 2001 From: NianJiuZst <3235467914@qq.com> Date: Sat, 5 Sep 2026 00:14:08 +0800 Subject: [PATCH] servlet: Register response trailers before stream writes Register the trailer supplier while creating the servlet stream, before a peer reset can cause the container to commit the response. This removes the race where Jetty throws IllegalStateException from writeHeaders after receiving RST_STREAM. Fixes #12777 --- servlet/src/main/java/io/grpc/servlet/ServletServerStream.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/servlet/src/main/java/io/grpc/servlet/ServletServerStream.java b/servlet/src/main/java/io/grpc/servlet/ServletServerStream.java index 0182f302698..63415f87472 100644 --- a/servlet/src/main/java/io/grpc/servlet/ServletServerStream.java +++ b/servlet/src/main/java/io/grpc/servlet/ServletServerStream.java @@ -82,6 +82,8 @@ final class ServletServerStream extends AbstractServerStream { this.resp = (HttpServletResponse) asyncCtx.getResponse(); this.writer = new AsyncServletOutputStreamWriter( asyncCtx, transportState, logId); + // Register before the peer can reset the stream and cause the container to commit the response. + resp.setTrailerFields(sink.trailerSupplier); resp.getOutputStream().setWriteListener(new GrpcWriteListener()); } @@ -231,7 +233,6 @@ private final class Sink implements AbstractServerStream.Sink { @Override public void writeHeaders(Metadata headers, boolean flush) { writeHeadersToServletResponse(headers); - resp.setTrailerFields(trailerSupplier); try { writer.flush(); } catch (IOException e) {