-
Notifications
You must be signed in to change notification settings - Fork 691
Description
HTTP/2 doesn't recommend adding Trailer header for trailer HEADERS frame.
But HttpServerOperations::onOutboundComplete mandates it.
HttpServerOperations::onOutboundComplete is RECOMMENDED in HTTP/1.1.
But it's not true for HTTP/2.
HTTP/1.1 recommends it.
HTTP/2 do not recommend it.
Please do not force Trailer header for trailer fields.
I have problems due to this reactor-netty's behavior. 😢
I'm making a proxy server with reactor-netty.
Proxy server must know all the trailer fields before actually reading it.
But HTTP/2 proxy clients don't use the Trailer header because it's not recommended by HTTP/2 spec.
So, it's impossible to make a proxy server with reactor-netty that deals with trailer fields properly.
Expected Behavior
Do not mandate Trailer header for trailer field(HTTP/1.1 : chunked, HTTP/2: trailer frame).
Actual Behavior
Do manadate Trailer header for trailer fields(HTTP/1.1: chunked, HTTP/2: trailer frame).
Steps to Reproduce
Following code snippet is a part of HttpServerOperations::onOutboundComplete.
@Override
protected void onOutboundComplete() {
if (isWebsocket()) {
// There is no need to proceed for 'HTTP/1.1 101 Switching Protocols',
// a full response has been sent
return;
}
final ChannelFuture f;
if (log.isDebugEnabled()) {
log.debug(format(channel(), "Last HTTP response frame"));
}
if (markSentHeaderAndBody()) {
if (log.isDebugEnabled()) {
log.debug(format(channel(), "Headers are not sent before onComplete()."));
}
f = channel().writeAndFlush(fullHttpResponse != null ? fullHttpResponse : newFullBodyMessage(EMPTY_BUFFER));
}
else if (markSentBody()) {
HttpHeaders trailerHeaders = null;
// https://datatracker.ietf.org/doc/html/rfc7230#section-4.1.2
// A trailer allows the sender to include additional fields at the end
// of a chunked message in order to supply metadata that might be
// dynamically generated while the message body is sent, such as a
// message integrity check, digital signature, or post-processing
// status.
if (trailerHeadersConsumer != null && isTransferEncodingChunked(nettyResponse)) {
// https://datatracker.ietf.org/doc/html/rfc7230#section-4.4
// When a message includes a message body encoded with the chunked
// transfer coding and the sender desires to send metadata in the form
// of trailer fields at the end of the message, the sender SHOULD
// generate a Trailer header field before the message body to indicate
// which fields will be present in the trailers.
String declaredHeaderNames = responseHeaders.get(HttpHeaderNames.TRAILER);
if (declaredHeaderNames != null) {
trailerHeaders = new TrailerHeaders(declaredHeaderNames);
try {
trailerHeadersConsumer.accept(trailerHeaders);
}
catch (IllegalArgumentException e) {
// A sender MUST NOT generate a trailer when header names are
// HttpServerOperations.TrailerHeaders.DISALLOWED_TRAILER_HEADER_NAMES
log.error(format(channel(), "Cannot apply trailer headers [{}]"), declaredHeaderNames, e);
}
}
}
f = channel().writeAndFlush(trailerHeaders != null && !trailerHeaders.isEmpty() ?
new DefaultLastHttpContent(Unpooled.buffer(0), trailerHeaders) :
EMPTY_LAST_CONTENT);
}
else {
discard();
terminate();
return;
}
f.addListener(this);
}Possible Solution
Do not force Trailer header.
Your Environment
- Reactor version(s) used:
io.projectreactor.netty:reactor-netty-http:1.2.4 - Other relevant libraries versions (eg.
netty, ...): - JVM version (
java -version): 17
openjdk version "17.0.15" 2025-04-15 LTS
OpenJDK Runtime Environment Zulu17.58+21-CA (build 17.0.15+6-LTS)
OpenJDK 64-Bit Server VM Zulu17.58+21-CA (build 17.0.15+6-LTS, mixed mode, sharing)
- OS and version (eg.
uname -a):Linux 6.11.0-26-generic #26~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Apr 17 19:20:47 UTC 2 x86_64 x86_64 x86_64 GNU/Linux