Skip to content

Guard header copy against committed response in NettyRoutingFilter - #4272

Open
adityaanikam wants to merge 1 commit into
spring-cloud:mainfrom
adityaanikam:fix-readonly-headers-4270
Open

Guard header copy against committed response in NettyRoutingFilter#4272
adityaanikam wants to merge 1 commit into
spring-cloud:mainfrom
adityaanikam:fix-readonly-headers-4270

Conversation

@adityaanikam

Copy link
Copy Markdown

Fixes gh-4270

Problem

NettyRoutingFilter copies filtered response headers back onto the
client response near the end of filter():

response.getHeaders().remove(HttpHeaders.TRANSFER_ENCODING);
...
response.getHeaders().addAll(filteredResponseHeaders);

If the response has already been committed elsewhere in the filter
chain before routing completes, AbstractServerHttpResponse#getHeaders()
returns a cached ReadOnlyHttpHeaders wrapper instead of the mutable
headers map. Calling remove(...) or addAll(...) on that wrapper
throws UnsupportedOperationException, which surfaces as an error
signal on the filter chain instead of the response completing
normally.

Fix

Guard the header-copy step with response.isCommitted(). Once a
response is committed, headers can no longer reach the client
regardless, so skipping the copy is safe and matches an existing
precedent already in the test codebase
(BaseWebClientTests#modifyResponseFilter, which uses the same
isCommitted() check before touching response headers).

Testing

  • Added NettyRoutingFilterTests#routingAfterResponseAlreadyCommittedDoesNotThrow,
    which pre-commits a MockServerWebExchange and asserts
    nettyRoutingFilter.filter(...) completes normally instead of
    erroring.
  • Full NettyRoutingFilterTests suite passes.
  • Verified with a negative control: reverting only the fix (keeping
    the new test) reproduces the exact reported
    UnsupportedOperationException at
    ReadOnlyHttpHeaders.remove(ReadOnlyHttpHeaders.java:166), matching
    the original issue's stack trace. Restoring the fix passes cleanly.

NettyRoutingFilter unconditionally called response.getHeaders()
.remove(...) and .addAll(...) when copying the filtered response
headers onto the client response. Once a response is committed,
AbstractServerHttpResponse#getHeaders() returns a cached
ReadOnlyHttpHeaders wrapper, and mutating it throws
UnsupportedOperationException.

Guard the header-copy step with response.isCommitted(), matching
the same check already used elsewhere in this codebase (see
BaseWebClientTests#modifyResponseFilter). Headers can no longer
reach the client past that point regardless, so skipping is safe.

Fixes spring-cloudgh-4270

Signed-off-by: adityaanikam <adityanikam9502@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UnsupportedOperationException in NettyRoutingFilter when handling immutable ReadOnlyHttpHeaders

2 participants