Skip to content

Add HTTP/2 support for the Reactor Netty integration - #2325

Open
sri-adarsh-kumar wants to merge 6 commits into
zalando:mainfrom
sri-adarsh-kumar:add-http2-support-squashed
Open

sri-adarsh-kumar wants to merge 6 commits into
zalando:mainfrom
sri-adarsh-kumar:add-http2-support-squashed

Conversation

@sri-adarsh-kumar

@sri-adarsh-kumar sri-adarsh-kumar commented May 31, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #961

Summary

  • add Http2AwareHandlerRegistrar so Logbook handlers are installed on the right Reactor Netty lifecycle hooks for both HTTP/1.1 and HTTP/2 streams
  • normalize netty request/response logging for HTTP/2 by reporting HTTP/2.0, resolving the scheme from the parent TLS channel, and stripping synthetic HTTP/2 conversion headers from logged headers
  • wire Spring WebFlux auto-configuration and README examples to the new registrar and add focused coverage for registrar behavior, request/response adaptation, and client customization

Motivation

The previous doOnConnected/doOnConnection registration pattern works for HTTP/1.1 but misses HTTP/2 stream channels, so Logbook does not reliably instrument multiplexed Reactor Netty traffic. This change makes the recommended integration path HTTP/2-aware without regressing HTTP/1.1.

Test Plan

  • ./mvnw test -pl logbook-netty -am

@kasmarian kasmarian added the major Major feature changes or updates label Jun 8, 2026

@kasmarian kasmarian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! I like that Logbook will have a good HTTP2 support with it.

Comment thread logbook-netty/pom.xml
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http2</artifactId>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't adding it as not an optional dependency mean that every consumer of logbook-netty, including the overwhelming majority who only use HTTP/1.1, will get netty-codec-http2 added to their transitive dependency tree unconditionally. This is unnecessary classpath bloat and breaks the principle
that optional features should not be forced on all users.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. netty-codec-http2 is now optional, and HTTP/2-only type access is isolated behind a lazy boundary. An isolated HTTP/1.1 regression test also verifies logging works when the HTTP/2 codec and Reactor Netty are physically absent.

Comment thread README.md Outdated
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class Http2AwareHandlerRegistrarTest {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but this test doesn't seem to test that HTTP2 works as expected. Which is the main point to ensure to have no regression afterwards. Please add tests that'd use and show "HTTP/2.0" protocol in log assertions. Could be done in a separate set of test files, if needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The suite now runs real H2C client/server exchanges and asserts HTTP/2.0 in request and response logs on both sides, including bodies, preserved user headers, and removed synthetic headers.

*/
public static HttpServer installOnServer(final HttpServer httpServer, final Logbook logbook) {
return httpServer.observe((connection, state) -> {
if (state == ConnectionObserver.State.CONFIGURED) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of the client, you also check if state == HttpClientState.STREAM_CONFIGURED, why is it not needed here to check if state == HttpServerState.CONFIGURED? I'm unfamiliar with this level of netty internals, please excuse me if it's something obvious.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reactor Netty has no HttpServerState.CONFIGURED; its server-specific states are request-level states. Generic ConnectionObserver.State.CONFIGURED is emitted for both HTTP/1.1 channels and HTTP/2 stream channels. The implementation uses childObserve, retains the duplicate-handler guard, and covers this with focused and real-traffic tests.

Comment thread logbook-netty/src/main/java/org/zalando/logbook/netty/SyntheticHttp2Headers.java Outdated
Comment on lines 33 to +37

@Test
void shouldBeDefaultRequest() {

HttpRequest req = mock(HttpRequest.class);
when(req.uri()).thenReturn("/test?a=b");
when(req.headers()).thenReturn(new DefaultHttpHeaders().add(CONTENT_TYPE, "text/plain"));
when(req.method()).thenReturn(HttpMethod.GET);
when(req.protocolVersion()).thenReturn(HttpVersion.HTTP_1_1);

ChannelHandlerContext context = mockChannelHandlerContext();
HttpRequest req = request("/test?a=b", headers(CONTENT_TYPE.toString(), "text/plain"));
EmbeddedChannel channel = channel(null, LocalAddress.ANY, sslHandler());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have concerns with the change in the logic of getScheme() implementation. Now it's first check if the parent channel exist and take the SslHandler of it. Can it be a breaking change for HTTP1.1 clients that have parent channel without the SslHandler?
A test to simulate this would be

@Test
    void shouldReturnHttpsSchemeForHttp11ServerTlsWhereOnlyChildChannelHasSslHandler() {
        EmbeddedChannel parent = channel(null, null);             
        EmbeddedChannel child  = channel(parent, LocalAddress.ANY, sslHandler());
        Request request = new Request(context(child), REMOTE, request("/", new DefaultHttpHeaders()));

        assertThat(request.getScheme()).isEqualTo("https");
    }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And while we're at it, maybe worth having a dedicated test for HTTP2 flow as well

 @Test
    void shouldReturnHttpsSchemeForHttp2StreamChannelWhoseParentHasSslHandler() {
        EmbeddedChannel parent = channel(null, null, sslHandler());
        EmbeddedChannel h2stream = http2Channel(parent, LocalAddress.ANY); 
        Request request = new Request(context(h2stream), REMOTE, request("/", new DefaultHttpHeaders()));

        assertThat(request.getScheme()).isEqualTo("https");
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. getScheme() now checks the current channel first, preserving HTTP/1.1 child-channel TLS. I've also added a dedicated HTTP/2 stream test with TLS on the parent channel, matching Reactor Netty's topology.

sri-adarsh-kumar and others added 4 commits July 12, 2026 21:50
Add isolated optional-dependency regressions, real H2C acceptance coverage, complete synthetic-header cleanup, TLS scheme preservation, and integration guidance.

Co-Authored-By: gpt-5.6-sol <noreply@anthropic.com>
Co-Authored-By: github-copilot/gpt-5.6-sol <noreply@anthropic.com>
@sri-adarsh-kumar

Copy link
Copy Markdown
Contributor Author

@kasmarian small reminder to resume review here

@kasmarian

Copy link
Copy Markdown
Collaborator

Sorry for not answering, I've also asked my colleagues to have a look at it to

@sri-adarsh-kumar

Copy link
Copy Markdown
Contributor Author

@kasmarian Reminder for this review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

major Major feature changes or updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Logbook Netty: Support HTTP/2

2 participants