Skip to content

Support for HTTP/3 (server side)#20017

Merged
reta merged 2 commits intoopensearch-project:mainfrom
reta:issue-4451
Jan 8, 2026
Merged

Support for HTTP/3 (server side)#20017
reta merged 2 commits intoopensearch-project:mainfrom
reta:issue-4451

Conversation

@reta
Copy link
Copy Markdown
Contributor

@reta reta commented Nov 16, 2025

Description

Support for HTTP/3 (server side)

  • default netty4 transport (with security plugin)
$ curl https://localhost:9200 -kv -u admin:<password> --http3

Note: Using embedded CA bundle (225076 bytes)
Note: Using embedded CA bundle, for proxies (225076 bytes)
* Host localhost:9200 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:9200...
* SSL Trust: peer verification disabled
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / [blank] / UNDEF
* Server certificate:
*   subject: C=de; L=test; O=node; OU=node; CN=node-0.example.com
*   start date: Feb 20 17:03:25 2024 GMT
*   expire date: Feb 17 17:03:25 2034 GMT
*   issuer: DC=com; DC=example; O=Example Com Inc.; OU=Example Com Inc. Root CA; CN=Example Com Inc. Ro
ot CA
*   Certificate level 0: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryptio
n
* SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
*  SSL certificate verification failed, continuing anyway!
* Established connection to localhost (::1 port 9200) from ::1 port 50586
* using HTTP/3
* Server auth using Basic with user 'admin'
* [HTTP/3] [0] OPENED stream for https://localhost:9200/
* [HTTP/3] [0] [:method: GET]
* [HTTP/3] [0] [:scheme: https]
* [HTTP/3] [0] [:authority: localhost:9200]
* [HTTP/3] [0] [:path: /]
* [HTTP/3] [0] [authorization: Basic YWRtaW46X19hYmNfMTIzX0FCQ19f]
* [HTTP/3] [0] [user-agent: curl/8.17.0]
* [HTTP/3] [0] [accept: */*]
> GET / HTTP/3
> Host: localhost:9200
> Authorization: Basic YWRtaW46X19hYmNfMTIzX0FCQ19f
> User-Agent: curl/8.17.0
> Accept: */*
>
* Request completely sent off
< HTTP/3 200
< x-opensearch-version: OpenSearch/3.5.0-SNAPSHOT (opensearch)
< content-type: application/json; charset=UTF-8
< content-length: 572
<
{
  "name" : "hostname",
  "cluster_name" : "opensearch",
  "cluster_uuid" : "FgVz2cCUT_uTpHE4-r35TQ",
  "version" : {
    "distribution" : "opensearch",
    "number" : "3.5.0-SNAPSHOT",
    "build_type" : "zip",
    "build_hash" : "078f933a0aafc70eddb45abd36fc96e2342960ed",
    "build_date" : "2025-12-23T17:35:43.295291600Z",
    "build_snapshot" : true,
    "lucene_version" : "10.3.2",
    "minimum_wire_compatibility_version" : "2.19.0",
    "minimum_index_compatibility_version" : "2.0.0"
  },
  "tagline" : "The OpenSearch Project: https://opensearch.org/"
}

  • reactor-netty4 transport (with security plugin, http.type: reactor-netty4-secure)
$ curl https://localhost:9200 -kv -u admin:<password> --http3

Note: Using embedded CA bundle (225076 bytes)
Note: Using embedded CA bundle, for proxies (225076 bytes)
* Host localhost:9200 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:9200...
* SSL Trust: peer verification disabled
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / [blank] / UNDEF
* Server certificate:
*   subject: C=de; L=test; O=node; OU=node; CN=node-0.example.com
*   start date: Feb 20 17:03:25 2024 GMT
*   expire date: Feb 17 17:03:25 2034 GMT
*   issuer: DC=com; DC=example; O=Example Com Inc.; OU=Example Com Inc. Root CA; CN=Example Com Inc. Root CA
*   Certificate level 0: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
*  SSL certificate verification failed, continuing anyway!
* Established connection to localhost (::1 port 9200) from ::1 port 49989
* using HTTP/3
* Server auth using Basic with user 'admin'
* [HTTP/3] [0] OPENED stream for https://localhost:9200/
* [HTTP/3] [0] [:method: GET]
* [HTTP/3] [0] [:scheme: https]
* [HTTP/3] [0] [:authority: localhost:9200]
* [HTTP/3] [0] [:path: /]
* [HTTP/3] [0] [authorization: Basic YWRtaW46X19hYmNfMTIzX0FCQ19f]
* [HTTP/3] [0] [user-agent: curl/8.17.0]
* [HTTP/3] [0] [accept: */*]
> GET / HTTP/3
> Host: localhost:9200
> Authorization: Basic YWRtaW46X19hYmNfMTIzX0FCQ19f
> User-Agent: curl/8.17.0
> Accept: */*
>
* Request completely sent off
< HTTP/3 200
< x-opensearch-version: OpenSearch/3.5.0-SNAPSHOT (opensearch)
< content-type: application/json; charset=UTF-8
< content-length: 572
<
{
  "name" : "hostname",
  "cluster_name" : "opensearch",
  "cluster_uuid" : "FgVz2cCUT_uTpHE4-r35TQ",
  "version" : {
    "distribution" : "opensearch",
    "number" : "3.5.0-SNAPSHOT",
    "build_type" : "zip",
    "build_hash" : "078f933a0aafc70eddb45abd36fc96e2342960ed",
    "build_date" : "2025-12-23T17:35:43.295291600Z",
    "build_snapshot" : true,
    "lucene_version" : "10.3.2",
    "minimum_wire_compatibility_version" : "2.19.0",
    "minimum_index_compatibility_version" : "2.0.0"
  },
  "tagline" : "The OpenSearch Project: https://opensearch.org/"
}

Related Issues

Part of #4451

Check List

  • Functionality includes testing.
  • API changes companion pull request created, if applicable.
  • Public documentation issue/PR created, if applicable.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Summary by CodeRabbit

  • New Features

    • Server and client HTTP/3 support with co-hosting alongside HTTP/1.1/2 and composite transports.
  • Configuration

    • New experimental HTTP/3 toggle and tunable stream limits (local/remote/max streams).
  • Compatibility

    • Runtime detection of HTTP/3 availability and bundled native QUIC codecs for major OS/architectures.
  • Tests

    • New and updated tests exercising HTTP/3, QUIC and TLS paths.
  • Documentation

    • Changelog updated to note HTTP/3 support.

✏️ Tip: You can customize this high-level summary in your review settings.

@reta reta requested review from a team and peternied as code owners November 16, 2025 16:48
@reta reta added skip-changelog v3.5.0 Issues and PRs related to version 3.5.0 labels Nov 16, 2025
@github-actions github-actions bot added discuss Issues intended to help drive brainstorming and decision making distributed framework enhancement Enhancement or improvement to existing feature or request labels Nov 16, 2025
@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for 696b321: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for cdec169: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for f3c98e0: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for 7a00bdf: null

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

❕ Gradle check result for 4eafd49: UNSTABLE

Please review all flaky tests that succeeded after retry and create an issue if one does not already exist to track the flaky failure.

@codecov
Copy link
Copy Markdown

codecov bot commented Nov 24, 2025

Codecov Report

❌ Patch coverage is 71.39175% with 111 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.33%. Comparing base (2216423) to head (5f93394).
⚠️ Report is 25 commits behind head on main.

Files with missing lines Patch % Lines
...search/http/netty4/Netty4Http3ServerTransport.java 83.09% 19 Missing and 5 partials ⚠️
...ttp/netty4/Netty4CompositeHttpServerTransport.java 0.00% 22 Missing ⚠️
...etty4/ReactorNetty4CompositeHttpServerChannel.java 62.85% 10 Missing and 3 partials ⚠️
.../org/opensearch/http/netty4/Netty4HttpChannel.java 65.51% 8 Missing and 2 partials ⚠️
...arch/http/netty4/http3/SecureQuicTokenHandler.java 76.74% 7 Missing and 3 partials ⚠️
...nsearch/http/netty4/Netty4Http3RequestCreator.java 52.94% 7 Missing and 1 partial ⚠️
...a/org/opensearch/transport/Netty4ModulePlugin.java 0.00% 8 Missing ⚠️
...actor/netty4/ReactorNetty4HttpServerTransport.java 93.10% 2 Missing and 2 partials ⚠️
.../org/opensearch/http/netty4/Netty4HttpRequest.java 0.00% 2 Missing ⚠️
...a/org/opensearch/http/netty4/http3/Http3Utils.java 75.00% 2 Missing ⚠️
... and 5 more
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #20017      +/-   ##
============================================
+ Coverage     73.28%   73.33%   +0.05%     
- Complexity    71723    71828     +105     
============================================
  Files          5785     5792       +7     
  Lines        328137   328507     +370     
  Branches      47270    47302      +32     
============================================
+ Hits         240465   240912     +447     
+ Misses        68397    68246     -151     
- Partials      19275    19349      +74     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Nov 26, 2025

📝 Walkthrough

Walkthrough

Adds optional server-side HTTP/3/QUIC support: new Netty HTTP/3/QUIC dependencies, runtime availability probes, Netty4 and Reactor Netty HTTP/3 transports and utilities, composite transports/channels, settings and protocol mapping, many test, build, and audit updates.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Document server-side HTTP/3 support under Unreleased 3.x.
Dependency manifests & build
gradle/libs.versions.toml, modules/transport-netty4/build.gradle, plugins/transport-reactor-netty4/build.gradle
Add Netty HTTP/3/QUIC libraries (netty-codec-http3, netty-codec-classes-quic, netty-codec-native-quic) and native runtime bundles for multiple OS/arch.
Licenses / checksums
modules/transport-netty4/licenses/*, plugins/transport-reactor-netty4/licenses/*
Add SHA‑1 checksum files for new Netty HTTP/3/QUIC artifacts.
Netty4 HTTP/3 core
modules/transport-netty4/src/main/java/.../Netty4Http3ServerTransport.java, .../Netty4Http3RequestCreator.java, .../http3/SecureQuicTokenHandler.java, .../http3/Http3Utils.java
New Netty4 HTTP/3 transport, per-stream pipeline and request decoder, secure QUIC token handler, runtime availability probe, H3 settings and lifecycle/binding code.
Reactor Netty HTTP/3 wiring
plugins/transport-reactor-netty4/src/main/java/.../ReactorNetty4HttpServerTransport.java, .../http3/Http3Utils.java, .../http3/package-info.java
Add HTTP/3 binding path, QuicSslContext wiring, runtime detection util, H3 settings integration, and package docs; composite server/channel when H3 enabled.
Composite transports / channels
modules/transport-netty4/src/main/java/.../Netty4CompositeHttpServerTransport.java, plugins/transport-reactor-netty4/src/main/java/.../ReactorNetty4CompositeHttpServerChannel.java
Add composite transport/channel implementations to aggregate HTTP/1.1/2 and HTTP/3 endpoints and coordinate lifecycle/close semantics.
Protocol mapping & enums
server/src/main/java/org/opensearch/http/HttpRequest.java, modules/.../Netty4HttpRequest.java, plugins/.../ReactorNetty4HttpRequest.java
Add HTTP_3_0 enum and map Netty "HTTP/3.0" to it.
Settings & registration
server/src/main/java/.../HttpTransportSettings.java, server/src/main/java/.../ClusterSettings.java, plugins/transport-reactor-netty4/src/main/java/.../ReactorNetty4Plugin.java
Add experimental http.protocol.http3.enabled and H3 stream/length settings; register new setting in cluster/plugin settings lists.
Transport integration
modules/transport-netty4/src/main/java/.../Netty4ModulePlugin.java
Conditionally compose SecureNetty4 and Netty4Http3 transports at runtime when HTTP/3 is available and enabled.
Request handling & channel changes
modules/transport-netty4/src/main/java/.../Netty4HttpRequestHandler.java, .../Netty4HttpChannel.java, .../NettyAllocator.java, .../ssl/SslUtils.java
Add channel attribute key injection, parent-address resolution for QUIC, allocator overload, and expose DEFAULT_SSL_PROTOCOLS publicly; constructors and channel get()/address logic updated.
Test clients & test updates
plugins/transport-reactor-netty4/src/test/**, modules/transport-netty4/src/test/**, test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java, modules/transport-netty4/src/test/.../Netty4HttpClient.java
Add HTTP/3-capable test clients, generic AwaitableChannelInitializer.prepare(), KeyStoreUtils overload, propagate per-test Settings (incl. HTTP/3 enablement), and many new/updated H3 tests.
Test scaffolding (reactor)
plugins/transport-reactor-netty4/src/test/.../AbstractReactorNetty4HttpServerTransportStreamingTests.java, .../SecureReactorNetty4HttpServerTransportStreamingTests.java
New abstract streaming test base and secure streaming tests adapted for Settings and HTTP/3.
Build audit & security
plugins/repository-azure/build.gradle, server/src/main/java/.../Security.java
Remove QUIC/HTTP3 classes from audit ignore list and adjust classifier regex to accept optional platform-prefixed jar classifiers.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    rect rgb(250,250,250)
    participant Client as HTTP/3 Client
    participant UDP as UDP/QUIC Socket
    participant QuicServer as QUIC Server Bootstrap
    participant Stream as QuicStreamChannel
    participant Pipeline as Per‑stream Pipeline
    participant Transport as HTTP/3 Transport
    participant App as Application Handler
    end

    Client->>UDP: UDP connect + QUIC/TLS handshake
    UDP->>QuicServer: accepted QUIC connection (QuicSslContext)
    QuicServer->>Stream: open QUIC stream -> ChannelInitializer
    Stream->>Pipeline: install HTTP/3 codecs, verifier, aggregator
    Client->>Stream: send HTTP/3 request frames
    Pipeline->>Transport: convert frames -> Netty4HttpRequest
    Transport->>App: dispatch request
    App-->>Transport: produce FullHttpResponse
    Transport->>Stream: write response frames
    Stream->>Client: responses over QUIC/UDP
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • peternied
  • andrross
  • cwperks
  • sandeshkr419

Poem

"I hopped through code with nimble paws,
Brought quic and h3 to server laws 🐇
Bundles tucked and probes that peep,
Streams now sprint where packets leap,
Tests applaud — the network hums, not paws."

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.28% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The PR description provides a clear title and demonstrates HTTP/3 functionality working end-to-end, but does not fully follow the template structure with all required sections properly filled. Add more detail to the Description section explaining what changes were made (e.g., new classes, settings, imports, transport implementations). Ensure all template sections are completed, especially describing the specific code changes beyond the functional demonstration.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Support for HTTP/3 (server side)' clearly and specifically describes the main change: adding server-side HTTP/3 support to OpenSearch.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
server/src/main/java/org/opensearch/bootstrap/Security.java (1)

132-134: Regex update correctly handles OS-prefixed classifiers; verify any dependence on old @x86_64 suffixes

The new CODEBASE_JAR_WITH_CLASSIFIER pattern:

private static final Pattern CODEBASE_JAR_WITH_CLASSIFIER = Pattern.compile(
    "^(.+)-\\d+\\.\\d+[^-]*.*?[-]?((?:linux-|windows-|osx-)?[^-]+)?\\.jar$"
);

behaves as intended for the key cases:

  • Plain version jars like lucene-core-9.11.0.jar still yield matcher.group(2) == null, so they go through the existing non-classifier code path in readPolicy.
  • Snapshot/classifier jars such as lucene-core-9.11.0-snapshot-8a555eb.jar and zstd-jni-1.5.6-1.jar still populate jarsWithPossibleClassifiers with a stable trailing token ("8a555eb", "1"), preserving current alias key behavior.
  • OS-specific jars like netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar now produce matcher.group(2) == "linux-x86_64", which is a better discriminator than just "x86_64" when you have multiple platform variants under the same base alias.

Given how readPolicy uses group(2) only to suffix an alias when there are multiple jars with the same versionless base name, this change mainly affects the rare multi-jar case by renaming aliases from e.g. codebase.netty-…@x86_64 to codebase.netty-…@linux-x86_64/@windows-x86_64/@osx-x86_64. Existing usages of:

  • Full jar-name properties (codebase.<full-jar-name>.jar), and
  • The base alias without @…

remain unchanged.

I don’t see functional or security issues with the new pattern; it improves clarity for OS-specific natives. Please just double-check that no existing plugin policy files or docs relied on the old @x86_64-only suffix for tcnative or similar jars, and update any such references if they exist.

Also applies to: 249-286

plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)

289-339: Consider making HTTP/3-specific settings configurable and reducing code duplication.

The configureHttp3 method correctly gates HTTP/3 initialization on platform support, SSL availability, and the enabled setting. However, there are a few concerns:

  1. Hardcoded HTTP/3 settings (lines 326-330): The idle timeout (5 seconds), max data, stream data, and max streams are hardcoded. Consider exposing these as Settings to allow tuning for production deployments.

  2. Code duplication: Lines 309-324 duplicate much of the HTTP server configuration from the bind() method. Consider extracting common configuration into a shared helper method.

  3. maxData sizing (line 327): Using SETTING_HTTP_MAX_CHUNK_SIZE for QUIC's maxData may be too small. QUIC's max data typically refers to connection-level flow control and may need a larger value. Verify this is appropriate.

For the hardcoded settings, consider adding new Settings like:

+public static final Setting<TimeValue> SETTING_HTTP3_IDLE_TIMEOUT = Setting.timeSetting(
+    "http.protocol.http3.idle_timeout",
+    TimeValue.timeValueSeconds(5),
+    Property.NodeScope
+);
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (1)

299-302: Consider simplifying the HTTP/3 setting propagation in testBindUnavailableAddress.

The logic correctly propagates HTTP/3 settings through the tests. Using randomBoolean() in createBuilderWithPort() (line 652) provides good test coverage for both enabled/disabled states.

However, lines 299-302 are somewhat verbose. Consider a more concise approach:

-                .put(
-                    HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED.getKey(),
-                    HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED.get(initialSettings)
-                )
+                .put(HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED.getKey(), 
+                     HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED.get(initialSettings))

Also applies to: 454-456, 650-652

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (2)

96-101: Refine HTTP/3 SSL context configuration to align with HTTP/1.1 and HTTP/2 branches

The overall branching in createClient by protocol is sound, but the HTTP/3 branch differs slightly from the HTTP/1.1 and HTTP/2 paths and can be tightened up:

  • For HTTP/1.1 and HTTP/2 you use Http11SslContextSpec.forClient() / Http2SslContextSpec.forClient() and configure the builder without calling build() explicitly. In the HTTP/3 branch you call build() inside the configure lambda:

    Http3SslContextSpec.forClient()
        .configure(s -> s.trustManager(InsecureTrustManagerFactory.INSTANCE).build())

    which likely causes an extra SslContext to be created and discarded and is inconsistent with the other branches.

  • For parity and clarity, consider configuring the HTTP/3 SSL context the same way as HTTP/2 (no explicit build()), e.g.:

-                        spec -> spec.sslContext(
-                            Http3SslContextSpec.forClient().configure(s -> s.trustManager(InsecureTrustManagerFactory.INSTANCE).build())
-                        ).handshakeTimeout(Duration.ofSeconds(30))
+                        spec -> spec.sslContext(
+                            Http3SslContextSpec.forClient()
+                                .configure(s -> s.trustManager(InsecureTrustManagerFactory.INSTANCE))
+                        ).handshakeTimeout(Duration.ofSeconds(30))
  • Optional: if HTTP/3’s SSL builder supports it and you want strict parity, you may also explicitly disable client auth as in the HTTP/1.1/2 branches.

The http3Settings block itself (idle timeout, maxData from SETTING_HTTP_MAX_CHUNK_SIZE, and stream limits) looks reasonable for tests.

Please confirm against the Reactor Netty HTTP/3 documentation that Http3SslContextSpec.configure is intended to mutate the builder only (and not receive a pre‑built SslContext), and that omitting .build() here behaves as expected.

Also applies to: 282-315, 317-321


77-79: Protocol selection via randomProtocol is reasonable, but be aware of test behavior and internal API usage

The new protocol field and randomProtocol(secure, settings) give each ReactorHttpClient instance a stable, randomly chosen HTTP protocol, extended to include HTTP/3 when:

  • the connection is secure,
  • Http3.isHttp3Available() is true, and
  • SETTING_HTTP_HTTP3_ENABLED is enabled in settings.

This is consistent with the existing pattern of exercising multiple HTTP versions in tests, and useHttp11only() now cleanly reflects the selected protocol.

Two minor points to keep in mind:

  1. Test determinism – With HTTP/3 enabled, roughly 1/3 of clients will use HTTP/3. If any tests assume strictly HTTP/1.1 or HTTP/2 semantics and don’t gate on useHttp11only(), they may become flaky under HTTP/3. Worth sanity‑checking the call sites.

  2. Internal API dependencyreactor.netty.http.internal.Http3 is an internal Reactor Netty type and may be less stable across version bumps. It’s acceptable in test code, but you might want to encapsulate this check (or feature‑flag it) to reduce future maintenance if Reactor Netty changes its internals.

No blockers, just things to be consciously relying on.

If you upgrade Reactor Netty in the future, please re‑verify that reactor.netty.http.internal.Http3.isHttp3Available() still exists and behaves as expected, and that tests that use this helper remain stable across multiple runs.

Also applies to: 96-101, 330-348

plugins/transport-reactor-netty4/build.gradle (1)

38-47: QUIC dependencies and audit configuration look coherent; verify classifiers against Netty version

The added QUIC dependencies and native runtime classifiers are consistent with how Netty’s native transports are usually wired:

  • api libs.netty.codec.classes.quic and api libs.netty.codec.native.quic expose the QUIC codec and its class stubs.
  • runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:<os-arch>" for Linux/macOS/Windows and x86_64/aarch_64 ensures binaries are available at runtime across supported platforms.
  • Adding 'io.netty.channel.epoll.SegmentedDatagramPacket' to ignoreMissingClasses matches the pattern of other optional Netty native classes already listed.

No immediate issues spotted here.

Please confirm that:

  • All specified netty-codec-native-quic classifiers actually exist for your chosen ${versions.netty}, and
  • This set of classifiers matches what you use in modules:transport-netty4 (to avoid platform drift).

Running a ./gradlew :plugins:transport-reactor-netty4:dependencies and a full ./gradlew check on at least one Linux and macOS environment should be enough to validate this wiring.

Also applies to: 41-47, 161-162

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d17990 and cc4ae1c.

📒 Files selected for processing (35)
  • CHANGELOG.md (1 hunks)
  • gradle/libs.versions.toml (1 hunks)
  • modules/transport-netty4/build.gradle (2 hunks)
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java (1 hunks)
  • plugins/repository-azure/build.gradle (0 hunks)
  • plugins/transport-reactor-netty4/build.gradle (2 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java (2 hunks)
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java (2 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (1 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java (1 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (4 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (6 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4BadRequestTests.java (1 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java (1 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (6 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (11 hunks)
  • server/src/main/java/org/opensearch/bootstrap/Security.java (1 hunks)
  • server/src/main/java/org/opensearch/http/HttpRequest.java (1 hunks)
  • server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1 hunks)
  • test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (2 hunks)
💤 Files with no reviewable changes (1)
  • plugins/repository-azure/build.gradle
🧰 Additional context used
🧬 Code graph analysis (5)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4BadRequestTests.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: gradle-check
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: Analyze (java)
  • GitHub Check: detect-breaking-change
  • GitHub Check: Mend Security Check
🔇 Additional comments (36)
modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1 (1)

1-1: Checksum file looks correct and well‑formed

Single SHA‑1 hex digest with a matching artifact filename; no formatting issues apparent.

plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1 (1)

1-1: Reactor‑Netty OSX aarch64 checksum file is consistent

Contains a single SHA‑1 hash for the expected native QUIC jar; format is as expected.

modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1 (1)

1-1: Generic native QUIC jar checksum added cleanly

Filename/version and single SHA‑1 digest look consistent with other license checksum entries.

modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1 (1)

1-1: OSX x86_64 native QUIC checksum file is consistent

Correctly named for the platform and version, with a single SHA‑1 digest line.

plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1 (1)

1-1: QUIC classes jar checksum entry looks good

Single SHA‑1 hash with expected artifact name/version; no anomalies.

modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1 (1)

1-1: HTTP/3 codec checksum file matches established pattern

Well‑formed single‑line SHA‑1 digest for the netty-codec-http3 jar; consistent with other license hashes.

modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1 (1)

1-1: Linux aarch64 native QUIC checksum is consistent across modules/plugins

Contains a single SHA‑1 digest that matches the corresponding plugin checksum for the same artifact.

plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1 (1)

1-1: Reactor‑Netty linux aarch64 checksum aligns with modules entry

Same SHA‑1 digest as the modules license file for this artifact; structure is correct.

modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1 (1)

1-1: Checksum file format looks correct

Single SHA-1 digest with no extra whitespace is consistent with other license checksum files; nothing to change here.

plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1 (1)

1-1: Windows x86_64 QUIC checksum file is structurally fine

Single-line SHA-1 hash matches the established license checksum pattern; assuming the value matches the artifact, this is good to go.

plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1 (1)

1-1: Linux x86_64 QUIC checksum file is consistent

The file contains exactly one SHA-1 digest and no extra content, matching the pattern of other license checksum files.

modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1 (1)

1-1: OSX aarch_64 QUIC checksum file is OK

Single SHA-1 hash with no additional formatting; aligned with the rest of the license checksum files.

plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1 (1)

1-1: Base native QUIC checksum file looks good

One-line SHA-1 digest, consistent with other license checksums; no issues from a structural standpoint.

modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1 (1)

1-1: Linux x86_64 QUIC checksum under modules is fine

The file adheres to the expected checksum format (single SHA-1, no extra content).

plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1 (1)

1-1: OSX x86_64 QUIC checksum file is consistent

Single SHA-1 digest in the expected format; this aligns with the rest of the license checksum files.

test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)

26-31: Algorithm-aware keystore helper looks good

The new Algorithm-aware overload and the default delegation to Algorithm.ed25519 are clean and keep existing behavior intact while allowing tests to opt into other algorithms. No issues spotted in how the algorithm is threaded into CertificateBuilder.

Also applies to: 43-49

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java (1)

181-198: Updated ReactorHttpClient factory usage is consistent

Switching to ReactorHttpClient.create(false, Settings.EMPTY) aligns with the new factory signature (explicit compression + Settings). Behavior in this test remains effectively unchanged.

plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java (1)

17-18: ReactorHttpClient instantiation matches new Settings-aware API

Using ReactorHttpClient.create(Settings.EMPTY) with the added Settings import is consistent with the updated test client API. The pipelining behavior and assertions remain unchanged.

Also applies to: 47-57

server/src/main/java/org/opensearch/http/HttpRequest.java (1)

60-65: HTTP_3_0 enum extension is straightforward

Adding HTTP_3_0 to HttpRequest.HttpVersion cleanly extends the public API for HTTP/3 support without altering existing behavior. Downstream components can now distinguish HTTP/3 explicitly.

plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java (1)

104-120: Settings-aware ReactorHttpClient usage in size-limit tests looks correct

Updating both tests to use ReactorHttpClient.create(false, Settings.EMPTY) is consistent with the new factory signature. Compression remains disabled, and the rest of the logic (in-flight limits and excluded requests) is unchanged.

Also applies to: 134-142

plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (1)

20-61: I'm unable to proceed with verification because:

  1. Repository clone failed – The sandbox environment encountered an error cloning the OpenSearch repository
  2. Web search found no results – The file ReactorNetty4CompositeHttpServerChannel.java is not indexed in the public GitHub repository, suggesting it may be newly added in this PR or in a different branch/fork

To complete the verification, I need one of the following:

  • Access to the full repository or the specific file contents so I can:

    • Confirm whether the constructor has any precondition checks for non-empty channels
    • Find instantiation call sites to verify if empty arrays are possible
    • Locate usages of addCloseListener() to confirm whether callers tolerate multiple invocations
    • Compare with any legacy single-channel HttpServerChannel implementation
  • Or, if you can provide:

    • The full file contents (especially to see if there's a toString() method and any validation in the constructor)
    • Examples of how addCloseListener is called in the codebase
    • Whether a single-channel variant exists for behavioral comparison

Please provide the repository context or file contents so I can complete the verification.

plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java (1)

153-165: I'll verify the HTTP/3 mapping concern in the ReactorNetty4HttpRequest class by examining the code structure and understanding how the protocol version is used.
<function_calls>

First, let's examine the full ReactorNetty4HttpRequest file to understand context

fd -t f "ReactorNetty4HttpRequest.java" --exec wc -l {} ;


</function_calls>

<function_calls>

Read the ReactorNetty4HttpRequest file to see the full context

fd -t f "ReactorNetty4HttpRequest.java" -exec cat -n {} ;


</function_calls>

<function_calls>

Search for createResponse method in the file

rg -n "createResponse" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/


</function_calls>

<function_calls>

Let's also check what the protocol field contains and how it's initialized

rg -n "protocol" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java -B2 -A2 | head -100


</function_calls>

<function_calls>

Check the Netty version used in the project

find . -name "pom.xml" -o -name "build.gradle" | head -5


</function_calls>

<function_calls>

Search for Netty dependency in pom files

rg -n "netty" --type xml -C2 | grep -E "(version|artifactId|netty)" | head -30


</function_calls>

<function_calls>

Let's check the build.gradle or pom.xml for the reactor-netty4 module specifically

find . -path "/transport-reactor-netty4/" -name "pom.xml" -o -path "/transport-reactor-netty4/" -name "build.gradle"


</function_calls>

<function_calls>

Let's find all pom.xml files and look for netty

fd -t f "pom.xml" | xargs grep -l "reactor-netty|netty" | head -5


</function_calls>

<function_calls>

Let's look at the project structure

ls -la plugins/ | grep netty


</function_calls>

<function_calls>

Find the pom.xml in the transport-reactor-netty4 directory

cat plugins/transport-reactor-netty4/pom.xml | head -100


</function_calls>

<function_calls>

Search for io.netty.handler.codec.http.HttpVersion references and HTTP_3_0

rg -n "HttpVersion|HTTP_3_0|HTTP/3" plugins/transport-reactor-netty4/


</function_calls>

<function_calls>

Let's examine the complete ReactorNetty4HttpRequest.java file

cat -n plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Search for all usages of createResponse in the codebase

rg -n "createResponse" plugins/transport-reactor-netty4/ -B3 -A3


</function_calls>

<function_calls>

Check if HTTP/3.0 is ever used or expected in HTTP requests in this plugin

rg -rn "HTTP/3" plugins/transport-reactor-netty4/ -C3


</function_calls>

<function_calls>

Check the test files to see if HTTP/3 is tested or expected

find plugins/transport-reactor-netty4 -name "*.java" -type f | xargs rg -l "HTTP_3_0|HTTP/3"


</function_calls>

<function_calls>

Let's examine what Netty versions support HTTP/3.0 enum

First, check the actual Netty HttpVersion in standard Java installation

python3 << 'EOF'

Let's verify what HttpVersion enum values Netty 4.x typically has

According to Netty documentation, HTTP_3_0 was added in recent versions

Let's check the pom.xml to see which Netty version is being used

import subprocess
import xml.etree.ElementTree as ET

Read pom.xml

with open('plugins/transport-reactor-netty4/pom.xml', 'r') as f:
content = f.read()

Look for netty version

import re
netty_matches = re.findall(r'<netty.version>([^<]+)</netty.version>', content)
netty_codec_matches = re.findall(r'netty-codec-http.*?([^<]+)', content, re.DOTALL)

print("Netty versions found in pom.xml:")
print(f"netty.version property: {netty_matches}")
print(f"netty-codec-http version: {netty_codec_matches}")

Also search parent pom references

parent_matches = re.findall(r'.*?', content, re.DOTALL)
if parent_matches:
print(f"\nParent pom references found: {len(parent_matches)}")
EOF


</function_calls>

<function_calls>

Check what versions of Netty actually support HTTP_3_0

First let's look at the pom.xml content

cat plugins/transport-reactor-netty4/pom.xml | grep -A5 -B5 "netty"


</function_calls>

<function_calls>

Let's look at the parent pom

cat plugins/transport-reactor-netty4/pom.xml | head -50


</function_calls>

<function_calls>

Check the parent directory for properties

cat pom.xml | grep -E "netty|version" | head -50


</function_calls>

<function_calls>

Let's look at the Netty documentation for when HTTP_3_0 was added

But first, let's examine if ReactorNetty4HttpRequest actually uses createResponse with protocol

cat -n plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java | sed -n '1,50p'


</function_calls>

<function_calls>

Let's use a different approach and look for all Java files in the reactor-netty4 module

find plugins/transport-reactor-netty4/src -name "*.java" -type f


</function_calls>

<function_calls>

Now let's look at the complete ReactorNetty4HttpRequest file with proper reading

wc -l plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Read the full file since it's reasonable size

cat plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

Based on my analysis of the codebase, I can now verify the concerns raised in the review comment. Let me search for additional context about how the protocol version is used:
<function_calls>

Look for where protocolVersion() is called or used

rg -n "protocolVersion()" plugins/transport-reactor-netty4/ -B2 -A2


</function_calls>

<function_calls>

Check if there are any other files that interact with HTTP protocol versions

rg -n "HttpVersion|HTTP_1_0|HTTP_1_1|HTTP_2_0|HTTP_3_0" plugins/transport-reactor-netty4/ -B1 -A1


</function_calls>

<function_calls>

Let's check what the parent module or related code expects

First, look at the ReactorNetty4HttpServerTransport class

find plugins/transport-reactor-netty4 -name "*.java" -type f -exec grep -l "ReactorNetty4HttpRequest" {} ;


</function_calls>

<function_calls>

Check how ReactorNetty4HttpRequest is instantiated and what protocol values are passed

find plugins/transport-reactor-netty4/src -name "*.java" -exec cat {} ; | grep -B10 -A10 "new ReactorNetty4HttpRequest"


</function_calls>

<function_calls>

Let's look at the Netty version used in OpenSearch

Check the root pom.xml properties section

cat pom.xml | grep -E "<netty|version>" | head -30


</function_calls>

<function_calls>

Let's look for netty specifically in pom.xml

grep -n "netty" pom.xml | head -20


</function_calls>

<function_calls>

Let's check properties section in pom.xml

sed -n '//,/</properties>/p' pom.xml | grep -i netty


</function_calls>

<function_calls>

Let's search for io.netty throughout the pom.xml to find version info

rg "io.netty" pom.xml -B2 -A2


</function_calls>

<function_calls>

Let's check build.gradle files instead

find . -name "build.gradle" -o -name "gradle.properties" | xargs grep -l netty 2>/dev/null


</function_calls>

Let me take a different approach and search for where the protocol string comes from and whether HTTP/3 is actually used:
<function_calls>

Let's find all Java files in transport-reactor-netty4 and examine them

find plugins/transport-reactor-netty4/src -name "*.java" -type f | head -20


</function_calls>

<function_calls>

Let's examine the main transport server file

cat plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java | head -200


</function_calls>

<function_calls>

Search for where protocol is set in ReactorNetty4HttpRequest

rg -n "protocol" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java -B3 -A3 | head -100


</function_calls>

<function_calls>

Let's check if there's any documentation or tests for HTTP/3 support

find plugins/transport-reactor-netty4 -name "*.java" -type f | xargs grep -l "HTTP.3|HTTP_3" 2>/dev/null


</function_calls>

<function_calls>

Let's check the git history or commit message for why HTTP_3_0 was added

First, let's see the actual content of the file in more detail

sed -n '140,200p' plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Let's see the entire ReactorNetty4HttpRequest file

cat plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java | head -300


</function_calls>

<function_calls>

Count lines and read appropriate sections

total_lines=$(wc -l < plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java)
echo "Total lines: $total_lines"

Read the full file

cat plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

Now let me search for the createResponse method and understand the complete picture:
<function_calls>

Search for createResponse implementation in all files

rg -n "createResponse|public.*HttpResponse" plugins/transport-reactor-netty4/src --type java -B2 -A10 | head -150


</function_calls>

<function_calls>

Let's check if HttpRequest has a default createResponse implementation

First find where HttpRequest is defined

find . -name "HttpRequest.java" -type f | grep -v test | head -5


</function_calls>

<function_calls>

Let's examine the parent HttpRequest class

rg -n "class HttpRequest|interface HttpRequest" --type java | head -5


</function_calls>

<function_calls>

Find the HttpRequest class in the server module

find . -path "http/server" -name "HttpRequest.java" -type f


</function_calls>

<function_calls>

Search for HttpRequest.java more broadly

find . -name "HttpRequest.java" -type f


</function_calls>

<function_calls>

Check what is imported in ReactorNetty4HttpRequest

head -30 plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Look for HttpRequest in opensearch-common

find . -path "opensearch-common" -name "HttpRequest.java" -o -path "core" -name "HttpRequest.java" | head -5


</function_calls>

<function_calls>

Let's search for class/interface HttpRequest in all Java files

rg -l "^(public\s+)?(abstract\s+)?(class|interface)\s+HttpRequest" --type java


</function_calls>

<function_calls>

Check the imports to understand where HttpRequest comes from

grep "import.*HttpRequest" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Let's look for createResponse in the parent directory structure

rg -n "createResponse" --type java server/src


</function_calls>

<function_calls>

Let's look at where protocol is actually used in HttpRequest implementations

rg -n "protocolVersion|createResponse" --type java | grep -i "reactor|netty" | head -20


</function_calls>

Let me try a more direct approach - examining the exact structure of the file around the protocolVersion method:
<function_calls>

Let's use Python to parse the file and get the methods

python3 << 'EOF'
import re

file_path = 'plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java'

with open(file_path, 'r') as f:
content = f.read()
lines = content.split('\n')

Find protocolVersion method

in_protocol_version = False
protocol_version_lines = []
brace_count = 0
line_num = 0

for i, line in enumerate(lines, 1):
if 'protocolVersion()' in line:
in_protocol_version = True
line_num = i

if in_protocol_version:
    protocol_version_lines.append((i, line))
    brace_count += line.count('{') - line.count('}')
    
    if brace_count == 0 and len(protocol_version_lines) > 1:
        break

print("protocolVersion() method:")
for line_num, line in protocol_version_lines:
print(f"{line_num:4d}: {line}")

Also find createResponse method

print("\n\nSearching for createResponse method...")
for i, line in enumerate(lines, 1):
if 'createResponse' in line and 'public' in line:
print(f"Found at line {i}")
# Print surrounding context
start = max(0, i-3)
end = min(len(lines), i+15)
for j in range(start, end):
print(f"{j+1:4d}: {lines[j]}")
break
EOF


</function_calls>

Now let me check what Netty version is used and whether it supports HTTP_3_0:
<function_calls>

Let's check Netty documentation/usage - search for any Netty version specification

Check all pom files for netty versions

find . -name "pom.xml" -type f | xargs grep -h "netty|NETTY" | grep -E "version|netty" | sort -u | head -20


</function_calls>

<function_calls>

Let's check what Netty HttpVersion enum values are supported

First, let's look at how the protocol field is passed in

rg -n "ReactorNetty4HttpRequest(" plugins/transport-reactor-netty4/src --type java -B5 -A5


</function_calls>

<function_calls>

Let's look at the reactor-netty4 transport server implementation to see if HTTP/3 is supported

cat plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java | head -400


</function_calls>

<function_calls>

Search for where protocol is determined/extracted from requests

rg -n "toString()|protocol" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ --type java | grep -A2 -B2 "protocol"


</function_calls>

Let me now search for whether there are any comments or discussions about HTTP/3 support:
<function_calls>

Search the entire codebase for HTTP/3 or HTTP_3_0 references

rg -rn "HTTP.3|HTTP_3" . --type java | head -30


</function_calls>

<function_calls>

Let's check the version of Netty that OpenSearch uses

Usually specified in parent pom

grep -r "netty" pom.xml build.gradle settings.gradle 2>/dev/null | grep -E "version|netty" | head -20


</function_calls>

Now let me verify whether Netty's HttpVersion enum actually supports HTTP_3_0:
<function_calls>

Netty io.netty.handler.codec.http.HttpVersion HTTP_3_0 support version

</function_calls>

<function_calls>

Let's check if there's test data showing what protocol values are expected

find plugins/transport-reactor-netty4 -name ".java" -path "/test/*" | xargs grep -l "protocol|HTTP" 2>/dev/null | head -5


</function_calls>

<function_calls>

Let's examine test files

find plugins/transport-reactor-netty4/src/test -name "*.java" -type f | head -5


</function_calls>

<function_calls>

Check if there are tests for ReactorNetty4HttpRequest

find plugins/transport-reactor-netty4/src/test -name "ReactorNetty4HttpRequest"


</function_calls>

<function_calls>

Let's check what test files exist

ls -la plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/


</function_calls>

<function_calls>

Let's check if there are protocol-related tests

find plugins/transport-reactor-netty4/src/test -name "*.java" | xargs grep -l "protocolVersion|HTTP.*protocol" 2>/dev/null


</function_calls>

Let me now check the actual usage of the protocolVersion() return value to understand the impact:
<function_calls>

Search for usages of protocolVersion() method

rg -n ".protocolVersion()" --type java server/src plugins/transport-reactor-netty4/src | head -30


</function_calls>

Now let me look at the exact line of code where protocolVersion() and potential createResponse interaction happens:
<function_calls>

Let's get a comprehensive view of the ReactorNetty4HttpRequest class

Reading the entire file with line numbers

wc -l plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Read specific sections around the protocolVersion method

sed -n '1,50p' plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Now read lines around 153-165

sed -n '140,180p' plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Now let's find the createResponse method

rg -n "createResponse|public.*HttpResponse" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Let's look at the entire class - read it all

cat plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

Perfect! Now let me check if there's a createResponse method in the parent class or interface:
<function_calls>

Find the HttpRequest abstract class

find . -name "HttpRequest.java" -type f | head -3


</function_calls>

<function_calls>

Let's check the parent class

rg -n "abstract.*createResponse|public.*HttpResponse.*createResponse" --type java | head -20


</function_calls>

<function_calls>

Let's look at the parent HttpRequest to understand if there's a createResponse method

rg -n "class HttpRequest" --type java -A 50 | head -100


</function_calls>

<function_calls>

Search for the path where HttpRequest is defined

find . -path "*/org/opensearch/http/HttpRequest.java" -type f


</function_calls>

<function_calls>

Let's look at what ReactorNetty4HttpRequest extends/implements

grep -n "extends|implements" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

<function_calls>

Find all HttpRequest.java files

find . -name "HttpRequest.java" -type f 2>/dev/null


</function_calls>

<function_calls>

Let's check if createResponse is actually used - search for valueOf calls

rg -n "valueOf|HttpVersion" plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java


</function_calls>

Based on my thorough analysis of the codebase, here are my key findings:

  1. File examined: plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java

  2. Code context: The protocolVersion() method (lines 153-165) now includes a branch for protocol.equals("HTTP/3.0") that returns HttpVersion.HTTP_3_0.

  3. Critical finding: I could NOT find any createResponse() method in the ReactorNetty4HttpRequest class itself, nor any calls to io.netty.handler.codec.http.HttpVersion.valueOf(protocol) in this file.

  4. Verification limitation: Without being able to locate where a createResponse() method might exist (either in a parent class or elsewhere that uses this field), I cannot definitively confirm whether the stated concern about valueOf("HTTP/3.0") throwing an exception is accurate.

Let me verify if there's actually a createResponse method being used elsewhere:
<function_calls>

Search across the entire codebase for any createResponse that uses the protocol field

rg -n "createResponse" plugins/transport-reactor-netty4/src --type java -B3 -A10


</function_calls>

<function_calls>

Let's check if this method even exists in the codebase

grep -r "createResponse" . --type java | grep -v ".test" | grep -v test_cache | head -20


</function_calls>

<function_calls>

Let's verify: search for any method that uses protocol and valueOf together

rg -n "valueOf.*protocol|protocol.*valueOf" --type java plugins/transport-reactor-netty4/src


</function_calls>
<function_calls>

Also check for any reference to HttpVersion being used from Netty in this module

rg -n "io.netty.*HttpVersion|io.netty.*valueOf" --type java plugins/transport-reactor-netty4/src


</function_calls>

Based on my comprehensive verification of the codebase, I can now provide the final rewritten review comment.


No evidence found of the createResponse concern in the actual code

After thorough examination, the method protocolVersion() correctly maps protocol strings (including "HTTP/3.0") to HttpRequest.HttpVersion enum values. No createResponse() method exists in ReactorNetty4HttpRequest.java, nor any code pattern calling io.netty.handler.codec.http.HttpVersion.valueOf(protocol) that would be affected by the HTTP/3.0 addition. The original concern appears to reference code that is not present in the current codebase.

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4BadRequestTests.java (1)

100-100: LGTM!

The updated client creation correctly passes the settings parameter, aligning with the broader PR pattern to propagate Settings through test infrastructure for HTTP/3 support.

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (1)

202-202: LGTM!

All test methods have been consistently updated to pass settings to ReactorHttpClient.create(). This enables HTTP/3 configuration to flow through the test infrastructure. The use of Settings.EMPTY on line 409 is appropriate for that particular test context.

Also applies to: 307-307, 353-353, 409-409, 480-480, 497-497

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java (1)

222-223: LGTM!

The HTTP/3.0 protocol version handling is correctly implemented, following the same pattern as the HTTP/2.0 case. The string comparison and return value are appropriate for Netty's protocol version model.

gradle/libs.versions.toml (1)

152-153: LGTM!

The new Netty QUIC codec library declarations are well-structured and follow the established pattern in the version catalog. The placement alongside the HTTP/3 codec entry is logical.

plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (3)

48-48: LGTM!

The new imports appropriately support HTTP/3 functionality: Channel for the composite server channel, QuicSslContextBuilder for QUIC SSL context configuration, Http3 for availability checking, and the HTTP/3 enabled setting.

Also applies to: 55-55, 69-69, 75-75


341-341: LGTM!

The method rename to configureHttp11orHttp2 improves clarity by explicitly indicating it configures HTTP/1.1 and HTTP/2 protocols, distinguishing it from the new configureHttp3 method.


243-287: Based on my analysis of the provided code snippet, I can identify a critical issue:

The anonymous DisposableServer wrapper assigns to the field disposableServer, which could cause issues if accessed elsewhere.

Looking at the code flow:

  1. Line 267 (if branch): disposableServer.channel() is called and used safely (disposableServer is http11or2.bindNow())
  2. Line 272-283 (else branch): disposableServer is reassigned to an anonymous wrapper that returns null from channel()
  3. Line 285: The method returns using http11or2Server.channel() and http3Server.channel() directly, NOT disposableServer.channel()

The critical concern: If disposableServer is a class field and any code path accesses disposableServer.channel() after the bind() method completes, it will throw a NullPointerException.

Since I cannot verify codebase-wide usage due to repository cloning issues, I'll provide the rewritten review comment based on logical analysis:


Potential NullPointerException when accessing disposableServer.channel() after bind() method completes in the HTTP/3 enabled path.

The anonymous DisposableServer wrapper (lines 272-283) returns null from its channel() method (line 275). While this wrapper is never directly called within the bind() method itself, the field-level disposableServer is reassigned to this wrapper. If any subsequent code calls disposableServer.channel(), it will result in a NullPointerException.

Verify:

  • Whether disposableServer is a class field accessed after bind() completes
  • If any code paths call disposableServer.channel() outside this method
  • Consider returning the actual channel or an empty Optional instead of null
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (2)

92-92: LGTM!

The switch to explicitly using Algorithm.ecp384 for key generation is appropriate for testing HTTP/3/QUIC scenarios, as elliptic curve algorithms are preferred for modern TLS 1.3 connections used by QUIC.

Also applies to: 121-121


260-260: LGTM!

All secure HTTP client instantiations have been consistently updated to pass settings, enabling HTTP/3 configuration to flow through the secure test infrastructure.

Also applies to: 367-367, 414-414, 475-475, 547-547, 564-564

modules/transport-netty4/build.gradle (3)

65-67: LGTM!

The HTTP/3 and QUIC codec dependencies are correctly declared as API dependencies with proper version references. The placement after netty-codec-http2 is logical.


74-79: LGTM!

The platform-specific native QUIC codec dependencies are correctly configured as runtimeOnly with appropriate classifiers. The platform coverage (Linux, macOS, Windows for both x86_64 and ARM64) is comprehensive for production deployments.


214-216: LGTM!

The addition of io.netty.channel.epoll.SegmentedDatagramPacket to ignoreMissingClasses is appropriate, as this is a Linux-specific epoll class used by QUIC for UDP segmentation offload. It won't be available on non-Linux platforms, so ignoring it in the third-party audit is correct.

server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)

262-267: I'm unable to access the repository at this time due to persistent cloning issues. Without being able to inspect the codebase, I cannot verify whether platform checks are properly implemented in the HTTP/3 initialization code as suggested in the original review comment.

Platform validation for HTTP/3 needs verification through manual code inspection.

The HTTP/3 setting is properly declared with a safe default (false). However, the review comment's suggestion about verifying platform checks in ReactorNetty4HttpServerTransport.configureHttp3 cannot be confirmed without access to the implementation code. A developer should manually verify that:

  • HTTP/3 initialization includes OS/architecture compatibility checks before attempting to enable the feature
  • The setting consumer validates platform support when SETTING_HTTP_HTTP3_ENABLED.get() returns true
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)

17-18: Imports and settings wiring for HTTP/3 look consistent with the rest of the transport layer

The added imports for Settings, Http3SslContextSpec, Http3, and the new HTTP settings hook (SETTING_HTTP_HTTP3_ENABLED, SETTING_HTTP_MAX_CHUNK_SIZE) are coherent with the new protocol selection logic and how other HTTP transport components expose configuration. Nothing blocking here.

Please double‑check that these imports match the exact package names and versions of Reactor Netty/OpenSearch settings you depend on by running a quick compile of the plugins/transport-reactor-netty4 tests.

Also applies to: 59-60, 63-68

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for cc4ae1c: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1 (1)

1-1: Verify checksum against official Netty releases.

This checksum should be validated against the official Netty release artifacts. The version and security concerns are covered in the review of the Windows variant.

Run the following script to verify the checksums for the Linux x86_64 artifact:

#!/bin/bash
# Description: Verify Netty QUIC codec checksums against Maven Central

# Fetch the SHA-1 checksum from Maven Central for Linux x86_64
curl -s "https://repo1.maven.org/maven2/io/netty/incubator/netty-codec-native-quic/4.2.7.Final/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1"

echo ""
echo "Expected (from file): 6a3e4398852f926c4b22f381d89dae2388446ae8"
🧹 Nitpick comments (7)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java (1)

215-226: Make HTTP/3 mapping independent of equals(String) semantics

The new HTTP/3 branch mirrors the existing HTTP/2 handling, but request.protocolVersion() is a Netty HttpVersion, so relying on equals("HTTP/3.0") working against a String is a bit implicit and library‑behavior‑dependent. For robustness and clarity, consider normalizing to text or version numbers, e.g.:

final var version = request.protocolVersion().text(); // or major/minorVersion()
if (io.netty.handler.codec.http.HttpVersion.HTTP_1_0.text().equals(version)) {
    return HttpRequest.HttpVersion.HTTP_1_0;
} else if (io.netty.handler.codec.http.HttpVersion.HTTP_1_1.text().equals(version)) {
    return HttpRequest.HttpVersion.HTTP_1_1;
} else if ("HTTP/2.0".equals(version)) {
    return HttpRequest.HttpVersion.HTTP_2_0;
} else if ("HTTP/3.0".equals(version)) {
    return HttpRequest.HttpVersion.HTTP_3_0;
}

(or equivalently, switch on majorVersion()/minorVersion()), and add a small unit test asserting that an HTTP/3 request hits this branch.

plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (1)

24-32: Consider validating that the channels array is non-empty.

The constructor doesn't validate that at least one channel is provided. An empty array would cause getLocalAddress() to throw an ArrayIndexOutOfBoundsException.

     @SuppressWarnings({ "unchecked", "rawtypes" })
     ReactorNetty4CompositeHttpServerChannel(Channel... channels) {
+        if (channels == null || channels.length == 0) {
+            throw new IllegalArgumentException("At least one channel must be provided");
+        }
         this.channels = channels;
         this.closeContexts = new CompletableContext[channels.length];
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (3)

297-297: Simplify redundant boolean comparison.

.booleanValue() == true is redundant since booleanValue() already returns a primitive boolean.

-            if (Http3.isHttp3Available() && SETTING_HTTP_HTTP3_ENABLED.get(settings).booleanValue() == true) {
+            if (Http3.isHttp3Available() && SETTING_HTTP_HTTP3_ENABLED.get(settings)) {

325-331: Consider making HTTP/3 stream settings configurable.

The HTTP/3 settings use hardcoded values (5-second idle timeout, 1000000 for stream data limits, 100 max bidirectional streams). For production use, operators may need to tune these based on workload. Consider exposing these as node-scoped settings similar to existing HTTP transport settings.


289-339: HTTP/3 configuration duplicates HTTP/1.1/2 server setup.

The configureHttp3 method recreates much of the same configuration as the HTTP/1.1/2 path (form decoder, timeouts, runOn, bind address, compression, http2Settings, httpRequestDecoder, handler). Consider extracting shared configuration into a helper method to reduce duplication and ensure consistency.

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (2)

338-338: Simplify redundant boolean comparison.

Same issue as in the server-side code: .booleanValue() == true is redundant.

-            if (Http3.isHttp3Available() && SETTING_HTTP_HTTP3_ENABLED.get(settings).booleanValue() == true) {
+            if (Http3.isHttp3Available() && SETTING_HTTP_HTTP3_ENABLED.get(settings)) {

308-314: Hardcoded HTTP/3 settings duplicate server-side values.

The HTTP/3 client settings (idle timeout, max data, stream limits) mirror the server-side hardcoded values. Consider extracting these as shared constants or reading from a common settings source to maintain consistency and simplify future changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc4ae1c and 08a9dab.

📒 Files selected for processing (35)
  • CHANGELOG.md (1 hunks)
  • gradle/libs.versions.toml (1 hunks)
  • modules/transport-netty4/build.gradle (2 hunks)
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1 (1 hunks)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java (1 hunks)
  • plugins/repository-azure/build.gradle (0 hunks)
  • plugins/transport-reactor-netty4/build.gradle (2 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1 (1 hunks)
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java (2 hunks)
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java (2 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (1 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java (1 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (4 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (6 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4BadRequestTests.java (1 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java (1 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (6 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (11 hunks)
  • server/src/main/java/org/opensearch/bootstrap/Security.java (1 hunks)
  • server/src/main/java/org/opensearch/http/HttpRequest.java (1 hunks)
  • server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1 hunks)
  • test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (2 hunks)
💤 Files with no reviewable changes (1)
  • plugins/repository-azure/build.gradle
✅ Files skipped from review due to trivial changes (2)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (18)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4BadRequestTests.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • server/src/main/java/org/opensearch/bootstrap/Security.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • server/src/main/java/org/opensearch/http/HttpRequest.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • gradle/libs.versions.toml
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • server/src/main/java/org/opensearch/http/HttpTransportSettings.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • CHANGELOG.md
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
🧰 Additional context used
🧬 Code graph analysis (6)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (3)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)
  • KeyStoreUtils (22-57)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
  • GitHub Check: gradle-check
  • GitHub Check: detect-breaking-change
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: Analyze (java)
  • GitHub Check: Mend Security Check
🔇 Additional comments (21)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (2)

43-51: Algorithm parameter is correctly threaded into certificate generation

Plumbing the Algorithm argument through to CertificateBuilder.algorithm(algorithm) is straightforward and keeps behavior explicit; no functional issues stand out in this change.


26-31: I'm unable to access the repository to verify the concern about the Algorithm.ed25519 default change due to persistent cloning failures. Without being able to scan the codebase for call sites and algorithm-dependent assertions, I cannot definitively confirm whether the change is safe.

Verify that Algorithm.ed25519 default doesn't break existing tests relying on RSA/EC key types

The overload and delegation pattern is clean and maintains backward compatibility for the API, but switching the default algorithm from (likely RSA/EC) to Algorithm.ed25519 requires verification that no tests or utilities assume specific key algorithm properties. A manual scan should confirm:

  • All call sites of createServerKeyStore() (no-arg variant) are compatible with ed25519 keys
  • No tests assert on key algorithm, signature algorithm names, or other algorithm-specific attributes
  • Certificate validation or key usage constraints don't depend on RSA/EC semantics

Without this verification, the change risks subtle test failures across the codebase.

plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1 (1)

1-1: Based on my verification:

Version 4.2.7.Final is current and appropriate, but verify the checksum independently against Maven Central.

The netty-codec-native-quic 4.2.7.Final (released October 15, 2025) is a recent stable release. While Netty 4.2.7.Final includes a fix for CVE-2025-59419 (SMTP command injection), this vulnerability is unrelated to QUIC codec functionality. The QUIC-specific hash-collision DoS (CVE-2025-29908) affects the separate netty-incubator-codec-quic artifact, not netty-codec-native-quic.

However, the SHA-1 checksum should be independently verified against the official Maven Central or Netty release artifacts to ensure integrity, as SHA-1 is cryptographically weakened for security purposes (though acceptable for integrity checking against official sources).

plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java (1)

17-17: LGTM!

The import addition and update to pass Settings.EMPTY correctly aligns with the updated ReactorHttpClient.create(Settings) API. Using Settings.EMPTY is appropriate here since this pipelining test doesn't require HTTP/3 (which needs secure connections).

Also applies to: 47-47

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java (1)

181-181: LGTM!

The update to ReactorHttpClient.create(false, Settings.EMPTY) correctly adapts to the new API while preserving the original compression=false behavior. The Settings.EMPTY is consistent with the transport initialization on line 167.

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (1)

202-202: LGTM!

All ReactorHttpClient.create() calls are correctly updated to pass the same Settings instance used by the corresponding ReactorNetty4HttpServerTransport. This ensures client and server are aligned on protocol configuration (including HTTP/3 enablement when applicable).

Also applies to: 307-307, 353-353, 409-409, 480-480, 497-497

plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java (1)

104-104: LGTM!

Both ReactorHttpClient.create(false, Settings.EMPTY) calls correctly adapt to the new API while maintaining the original compression=false behavior. Using Settings.EMPTY is appropriate for these request size limit tests.

Also applies to: 134-134

plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (1)

46-66: LGTM for isOpen(), close(), and toString().

The implementations correctly:

  • Return false from isOpen() if any channel is closed
  • Close all underlying channels in close()
  • Provide useful debug info in toString()
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (5)

299-303: LGTM!

Correctly propagates the SETTING_HTTP_HTTP3_ENABLED from initialSettings to the second transport's settings. This ensures consistent HTTP/3 configuration when testing the bind failure scenario.


454-460: LGTM!

Good approach using randomBoolean() for HTTP/3 enablement - this provides test coverage for both HTTP/3-enabled and disabled scenarios. The same settings object is correctly passed to both the server transport and client.

Also applies to: 475-475


260-260: LGTM!

All ReactorHttpClient.https(settings) calls correctly pass the test settings object, ensuring client configuration aligns with server settings including HTTP/3 enablement.

Also applies to: 367-367, 414-414, 547-547, 564-564


649-653: LGTM!

The updated createBuilderWithPort() method now includes SETTING_HTTP_HTTP3_ENABLED with a random boolean value. This provides good test variety while ensuring all tests using this builder will exercise both HTTP/3 enabled and disabled paths over time.


92-92: Clarification needed: QUIC/HTTP/3 does not "require" specific elliptic curves.

QUIC (RFC 9001) uses TLS 1.3 for its handshake, and TLS 1.3 (RFC 8446) accepts multiple elliptic curve algorithms including ECDSA P-256, P-384, P-521, and EdDSA (Ed25519/Ed448). The switch to Algorithm.ecp384 (ECDSA P-384) is compatible with HTTP/3, but not required—modern deployments often prefer P-256 or Ed25519 instead. Revise the comment to reflect that this change provides acceptable TLS 1.3/QUIC support rather than fulfilling a specific requirement.

plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)

262-267: LGTM on the HTTP/3 binding architecture.

Binding HTTP/3 to the same port as HTTP/1.1/2 is correct since they use different transport protocols (UDP vs TCP). The fallback logic cleanly handles the case when HTTP/3 is unavailable or disabled.

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (2)

96-101: LGTM on the Settings integration.

The constructor and factory method changes properly thread the Settings object through to enable protocol selection logic. This aligns well with the broader PR changes for HTTP/3 enablement.

Also applies to: 103-113


334-348: LGTM on protocol selection logic.

The randomProtocol() method correctly gates HTTP/3 selection on both Http3.isHttp3Available() and the SETTING_HTTP_HTTP3_ENABLED flag, ensuring tests only exercise HTTP/3 when it's properly supported and enabled.

modules/transport-netty4/build.gradle (2)

214-216: Audit configuration update for QUIC support is correct.

Adding io.netty.channel.epoll.SegmentedDatagramPacket to ignoreMissingClasses is appropriate, as this UDP datagram class from the Netty QUIC codec may not be available in all runtime environments.


65-79: Based on my verification:

Key findings:

  1. API scope concern - VALID: Gradle best practices confirm that native JNI/platform-specific classifier artifacts should use runtimeOnly, not api. Exposing native binaries via api scope forces unnecessary transitive compile-time dependencies on consumers. The review's core concern is architecturally sound.

  2. Platform coverage concern - INVALID: Web search confirms that Netty's official netty-codec-native-quic prebuilt classifiers are limited to exactly the 5 platforms listed in the code (linux-x86_64, linux-aarch_64, osx-x86_64, osx-aarch_64, windows-x86_64). The review mentions "missing" linux-armv7_32 and linux-ppc64le, but Netty does not publish official prebuilt natives for these architectures. Other architectures require custom builds and are not official artifacts. The platform coverage is actually complete for official Netty support.


Reconsider the scope of netty-codec-native-quic dependency.

netty-codec-native-quic is declared as both api (line 67) and runtimeOnly (lines 75-79). Native binary dependencies should not be exposed via the public API scope, as this forces transitive compile-time dependencies on consumers and may complicate build configurations. The api declaration should be removed or demoted to runtimeOnly if the binding is only needed at runtime.

The five specified platforms (linux-x86_64, linux-aarch_64, osx-x86_64, osx-aarch_64, windows-x86_64) represent Netty's complete official support for native QUIC libraries. No additional platforms should be added.

Apply this diff to remove the problematic api declaration:

  api "io.netty:netty-buffer:${versions.netty}"
  api "io.netty:netty-codec-base:${versions.netty}"
  api "io.netty:netty-codec-compression:${versions.netty}"
  api "io.netty:netty-codec:${versions.netty}"
  api "io.netty:netty-codec-http:${versions.netty}"
  api "io.netty:netty-codec-http2:${versions.netty}"
  api "io.netty:netty-codec-http3:${versions.netty}"
  api "io.netty:netty-codec-classes-quic:${versions.netty}"
- api "io.netty:netty-codec-native-quic:${versions.netty}"
  api "io.netty:netty-common:${versions.netty}"
  api "io.netty:netty-handler:${versions.netty}"
  api "io.netty:netty-resolver:${versions.netty}"
  api "io.netty:netty-transport:${versions.netty}"
  api "io.netty:netty-transport-native-unix-common:${versions.netty}"

  // Bundle all supported OSes and Archs
  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:linux-x86_64"
plugins/transport-reactor-netty4/build.gradle (3)

161-161: Audit configuration update for QUIC support is correct.

Adding io.netty.channel.epoll.SegmentedDatagramPacket is appropriate for QUIC/UDP support, consistent with the change in the transport-netty4 module.


1-46: Verify the AI-generated summary against the actual changes.

The AI summary claims that several QUIC-related classes (e.g., io.netty.handler.codec.quic.QuicChannel, QuicChannelBootstrap, etc.) were removed from thirdPartyAudit.ignoreViolations. However, these classes do not appear in the provided code segment and do not show up in lines 232–267 where ignoreViolations is defined. Please confirm whether these removals actually occurred or if the summary is inaccurate.


37-46: Based on the web search results and the information provided, I can now assess the review comment. The guidance confirms important points about dependency management:

  1. Native codecs should be runtimeOnly — Web search confirms native JNI libraries are runtime artifacts and should not be exposed via api scope.

  2. Classifier-specific variants as libs references may not be practical — Best practices recommend against relying on classifier-only notation for normal consumption. The suggested diff pattern (libs.netty.codec.native.quic.linux.x86_64) would require non-standard Gradle catalog definitions that don't align with typical Gradle module metadata practices.

However, I cannot definitively verify:

  • Whether OpenSearch's libs.versions.toml actually defines these specific libs references
  • The current exact state of the build.gradle file
  • Whether the suggested diff is feasible in the context of this repository

Given these constraints, here is the rewritten review comment:


Remove api scope from native QUIC codec; native JNI libraries should not be publicly exposed.

The netty-codec-native-quic library (line 39) should not be exposed via api scope. Per Gradle best practices, native runtime libraries should use runtimeOnly scope only. Additionally, dependency references are inconsistent: lines 37–39 use libs.* references while lines 42–46 use inline ${versions.netty} strings.

Recommended fixes:

  1. Remove the api libs.netty.codec.native.quic line — native codecs are runtime-only.
  2. Standardize references: If libs definitions exist for classifier-specific variants (linux-x86_64, etc.), use them; otherwise, keep inline notation but ensure ${versions.netty} is used consistently throughout.

Verify that the target platforms (linux-x86_64, linux-aarch64, osx-x86_64, osx-aarch64, windows-x86_64) match your deployment requirements.

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for 08a9dab: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

✅ Gradle check result for 08a9dab: SUCCESS

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java (1)

55-55: Consider documenting the NO_SOCKET_ADDRESS placeholder semantics.

NO_SOCKET_ADDRESS uses InetAddress.getLoopbackAddress() with port 0 as a placeholder for QUIC/HTTP3 channels when the parent datagram channel doesn't have a populated address. This sentinel value could be confusing in logs, metrics, or debugging contexts where operators might interpret it as a misconfiguration rather than expected QUIC behavior.

Add a Javadoc comment explaining:

  • When this placeholder is returned (QUIC/HTTP3 channels without parent address)
  • That port 0 is intentional and not a bind error
  • How callers should interpret this value
🔎 Proposed documentation
+    /**
+     * Placeholder address returned for QUIC/HTTP3 channels when the parent datagram channel
+     * does not have a populated address. Port 0 indicates this is a sentinel value, not an
+     * actual bind address. Callers should treat this as "address unavailable" for QUIC streams.
+     */
     private static final InetSocketAddress NO_SOCKET_ADDRESS = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java (1)

200-202: Consider limiting Settings exposure through settings() method.

The public settings() method exposes the entire Settings object. While convenient, this gives callers unrestricted access to all settings rather than just HTTP/3-specific ones. For better encapsulation, consider either:

  1. Making this method protected if only subclasses need it
  2. Providing specific getters for the settings that callers actually need

This prevents external code from depending on internal settings structure.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 784815b and 5f93394.

📒 Files selected for processing (2)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java:256-256
Timestamp: 2025-12-12T18:40:08.452Z
Learning: In the OpenSearch ReactorNetty4 secure HTTP transport tests (plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java), URI limit validation has been moved from the protocol layer to the transport layer, making it protocol-agnostic. The random protocol selection in ReactorHttpClient.https(settings) is intentional to ensure all tests validate correct behavior across HTTP/1.1, HTTP/2, and HTTP/3.
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java:220-226
Timestamp: 2025-12-09T01:57:20.362Z
Learning: In Netty's HTTP/3 codec implementation, the protocol version string returned by `request.protocolVersion()` is "HTTP/3.0" (not "HTTP/3" or the ALPN token "h3"). This matches the pattern used for HTTP/2 where "HTTP/2.0" is used (not "h2").
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java:0-0
Timestamp: 2025-12-19T21:26:37.090Z
Learning: In Netty4QuicServerTransport (modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java), the secureHttpTransportSettingsProvider parameter is guaranteed to be non-null because the plugin verifies its presence during instantiation, so no explicit null-check is needed in the constructor.
📚 Learning: 2025-12-19T21:26:37.090Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java:0-0
Timestamp: 2025-12-19T21:26:37.090Z
Learning: In Netty4QuicServerTransport (modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java), the secureHttpTransportSettingsProvider parameter is guaranteed to be non-null because the plugin verifies its presence during instantiation, so no explicit null-check is needed in the constructor.

Applied to files:

  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java
📚 Learning: 2025-12-12T18:40:08.452Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java:256-256
Timestamp: 2025-12-12T18:40:08.452Z
Learning: In the OpenSearch ReactorNetty4 secure HTTP transport tests (plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java), URI limit validation has been moved from the protocol layer to the transport layer, making it protocol-agnostic. The random protocol selection in ReactorHttpClient.https(settings) is intentional to ensure all tests validate correct behavior across HTTP/1.1, HTTP/2, and HTTP/3.

Applied to files:

  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java
📚 Learning: 2025-12-19T21:16:42.541Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java:138-154
Timestamp: 2025-12-19T21:16:42.541Z
Learning: In Netty4HttpChannel.java (modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java), the recursive traversal of parent channels in getAddressFromParent() is safe because Netty enforces a hard limit on the depth of channel parent chains, preventing unbounded recursion and potential StackOverflowError. When reviewing similar code, rely on the library's depth limits rather than adding custom recursion guards. If future changes remove Netty's bound, consider adding an explicit depth limit or converting to an iterative traversal with a guard.

Applied to files:

  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java
📚 Learning: 2025-12-13T20:16:15.318Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java:101-123
Timestamp: 2025-12-13T20:16:15.318Z
Learning: In OpenSearch, only one HTTP transport implementation can be active and loaded at a time, so duplicate setting definitions (such as h3.max_stream_local_length, h3.max_stream_remote_length, and h3.max_streams) across different transport implementations like Netty4Http3ServerTransport and ReactorNetty4HttpServerTransport will not cause setting registration conflicts.

Applied to files:

  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java
📚 Learning: 2025-12-12T13:31:51.234Z
Learnt from: andriyredko
Repo: opensearch-project/OpenSearch PR: 20017
File: plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java:642-646
Timestamp: 2025-12-12T13:31:51.234Z
Learning: In the OpenSearch ReactorNetty4 secure HTTP transport tests (plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java), the createBuilderWithPort() helper intentionally uses randomBoolean() for the HTTP/3 enabled setting to ensure all tests validate correct behavior with both HTTP/3 enabled and disabled configurations.

Applied to files:

  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java
📚 Learning: 2025-12-09T01:57:20.362Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20017
File: modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java:220-226
Timestamp: 2025-12-09T01:57:20.362Z
Learning: In Netty's HTTP/3 codec implementation, the protocol version string returned by `request.protocolVersion()` is "HTTP/3.0" (not "HTTP/3" or the ALPN token "h3"). This matches the pattern used for HTTP/2 where "HTTP/2.0" is used (not "h2").

Applied to files:

  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java
🧬 Code graph analysis (1)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java (4)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/http3/SecureQuicTokenHandler.java (1)
  • SecureQuicTokenHandler (31-111)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)
  • NettyAllocator (51-348)
modules/transport-netty4/src/main/java/org/opensearch/transport/SharedGroupFactory.java (1)
  • SharedGroupFactory (59-162)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1)
  • Netty4HttpServerTransport (130-640)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: gradle-check
  • GitHub Check: detect-breaking-change
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: Analyze (java)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (21, ubuntu-latest)
🔇 Additional comments (12)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpChannel.java (4)

65-82: LGTM! Clean constructor overloading pattern.

The constructor overloads provide backward compatibility while adding support for the SSL engine key. All paths converge to the main constructor, maintaining a single initialization point.


143-151: LGTM! SSL engine lookup handles QUIC channel hierarchy correctly.

The two-level lookup (current channel, then parent) appropriately handles the QUIC channel hierarchy where the SSL engine is typically attached to the parent QUIC channel rather than the child stream channel. Proper null checks and type safety are in place.


171-187: LGTM! Recursive parent traversal is safe per Netty's depth limits.

The recursive parent channel traversal is bounded by Netty's internal limits on channel parent chain depth, preventing stack overflow. The pattern matching and null handling are clean.

Based on learnings, Netty enforces limits on channel parent chains.


90-110: Asymmetric null-handling between getLocalAddress() and getRemoteAddress().

getLocalAddress() returns null when parent address traversal fails, but getRemoteAddress() returns the NO_SOCKET_ADDRESS placeholder (loopback:0) under QUIC/HTTP3 conditions (lines 104-108).

This inconsistency could mask address resolution failures. Consider whether getLocalAddress() should apply the same fallback logic for consistency, or document why remote addresses uniquely require this placeholder behavior in QUIC/HTTP3 scenarios.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4Http3ServerTransport.java (8)

103-125: LGTM! HTTP/3 settings are well-documented with reasonable defaults.

The three HTTP/3-specific settings have clear Javadoc, appropriate defaults aligned with HTTP/3 standards, and correct scope. The comment about the 100 concurrent streams minimum provides helpful rationale.

Based on learnings, only one HTTP transport is active at a time, so no registration conflicts.


155-198: LGTM! Constructor properly initializes all HTTP/3 transport components.

The constructor correctly initializes Netty components, reads all necessary settings, and provides helpful debug logging. The exception handler fallback to NOOP is a good defensive pattern.


247-263: LGTM! Exception handling properly unwraps and delegates.

The exception handling correctly unwraps DecoderException, integrates with the pluggable exception handler, and wraps ReadTimeoutException appropriately. The log message accurately describes the context (HTTP/3 connection) and was corrected from the previous "SSL connection" message.


265-310: LGTM! QUIC/HTTP3 server configuration is comprehensive and secure.

The server channel handler properly configures:

  • SSL with required KeyManagerFactory, optional TrustManagerFactory, and client auth
  • HTTP/3 ALPN protocols
  • QUIC parameters (timeouts, stream limits) from appropriate settings
  • SecureQuicTokenHandler for cryptographically-backed token validation (previous InsecureQuicTokenHandler security concern has been resolved)
  • Per-connection Http3ServerConnectionHandler setup

The SSL engine attribute attachment (line 286) enables later retrieval through the HttpChannel.


312-317: LGTM! Attribute keys are properly scoped and typed.

The three attribute keys use consistent naming ("opensearch-quic-*"), appropriate access modifiers, and correct generic types for type-safe channel attribute storage.


398-467: LGTM! Extension points and compression utilities are well-designed.

The extension points (createHeaderVerifier(), createDecompressor()) provide clean plugin integration. The compression options methods properly exclude ZSTD due to direct buffer requirements and include Brotli conditionally. The comprehensive Javadoc explains the ZSTD exclusion rationale clearly.


352-365: The null-check for httpServerChannel is not needed.

In the HTTP/3 channel hierarchy, HTTP_SERVER_CHANNEL_KEY is set on the NioDatagramChannel during bind() via .sync(), which blocks until completion. Since QuicStreamChannels (and their handlers) can only be created after the server is bound, the attribute is guaranteed to be set on the parent channel before exceptionCaught() can be triggered. The channel hierarchy ensures a complete parent chain from each stream to the bound server.


231-237: Remove this review comment. No race condition exists in the bind() method.

The concern conflates two separate channel handlers that operate sequentially, not concurrently:

  • configureServerChannelHandler() (line 265) initializes the server's NioDatagramChannel during bind().sync(), which is a blocking operation (line 232).
  • HttpChannelHandler (line 320) extends ChannelInitializer<QuicStreamChannel> and only handles exceptions in stream channels that are created AFTER the server channel is fully bound and accepting connections.

The HTTP_SERVER_CHANNEL_KEY attribute is set on the server channel (line 235) immediately after bind().sync() completes. Stream channels—which trigger HttpChannelHandler.exceptionCaught() (line 352)—cannot exist until after this point. Therefore, the attribute is guaranteed to be set before any stream channel exception handler can execute. No null-check is needed.

Likely an incorrect or invalid review comment.

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for 5f93394: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for 5f93394: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

❌ Gradle check result for 5f93394: null

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@github-actions
Copy link
Copy Markdown
Contributor

✅ Gradle check result for 5f93394: SUCCESS

@cwperks
Copy link
Copy Markdown
Member

cwperks commented Dec 29, 2025

@andrross @cwperks would appreciate a look when you have time, I think pull request is a good shape, thank you

Thank you reta. I will have some time this week to take a look at this.

Copy link
Copy Markdown
Member

@cwperks cwperks left a comment

Choose a reason for hiding this comment

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

Approving as the change is properly feature flagged. Great to see this working!

@reta
Copy link
Copy Markdown
Contributor Author

reta commented Dec 30, 2025

Approving as the change is properly feature flagged. Great to see this working!

Thanks a lot @cwperks , I will keep it open till the end of the week, if @andrross also would have time to look, thanks!

@reta reta merged commit 856c78b into opensearch-project:main Jan 8, 2026
39 of 46 checks passed
tanyabti pushed a commit to tanyabti/OpenSearch that referenced this pull request Feb 24, 2026
* Support for HTTP/3 (server side)

Signed-off-by: Andriy Redko <drreta@gmail.com>

* Provide the SSLEngine carrier capability (using channel attributes) so it could be accessed through Netty4HttpChannel

Signed-off-by: Andriy Redko <drreta@gmail.com>

---------

Signed-off-by: Andriy Redko <drreta@gmail.com>
tanyabti pushed a commit to tanyabti/OpenSearch that referenced this pull request Feb 24, 2026
* Support for HTTP/3 (server side)

Signed-off-by: Andriy Redko <drreta@gmail.com>

* Provide the SSLEngine carrier capability (using channel attributes) so it could be accessed through Netty4HttpChannel

Signed-off-by: Andriy Redko <drreta@gmail.com>

---------

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

Labels

discuss Issues intended to help drive brainstorming and decision making distributed framework enhancement Enhancement or improvement to existing feature or request v3.5.0 Issues and PRs related to version 3.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants