Skip to content

Conversation

@reta
Copy link
Contributor

@reta reta commented Nov 16, 2025

Description

Support for HTTP/3 (server side)

Related Issues

Closes #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

    • Opt-in server-side HTTP/3 (QUIC) support; pull-based ingestion message mappers and raw payload support added.
  • HTTP Behavior

    • Servers can bind HTTP/3 alongside HTTP/1.1/2 and present a composite multi-protocol channel.
  • Settings

    • New per-node tunables for HTTP/3 stream sizes and max streams; HTTP/3 disabled by default.
  • Tests

    • Expanded HTTP/3/QUIC test coverage and updated test utilities to pass settings.
  • Chores

    • QUIC/HTTP/3 native codec packages and checksum artifacts bundled.
  • Bug Fixes

    • Fixed malformed trailing bracket in CHANGELOG entry.

✏️ 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.4.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
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
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
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
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
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

codecov bot commented Nov 24, 2025

Codecov Report

❌ Patch coverage is 85.00000% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.30%. Comparing base (97d3864) to head (c883a6e).
⚠️ Report is 14 commits behind head on main.

Files with missing lines Patch % Lines
...etty4/ReactorNetty4CompositeHttpServerChannel.java 73.68% 5 Missing ⚠️
.../org/opensearch/http/netty4/Netty4HttpRequest.java 0.00% 2 Missing ⚠️
.../http/reactor/netty4/ReactorNetty4HttpRequest.java 0.00% 2 Missing ⚠️
...actor/netty4/ReactorNetty4HttpServerTransport.java 96.15% 1 Missing and 1 partial ⚠️
...nsearch/transport/reactor/ReactorNetty4Plugin.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #20017      +/-   ##
============================================
- Coverage     73.33%   73.30%   -0.04%     
+ Complexity    71679    71657      -22     
============================================
  Files          5790     5787       -3     
  Lines        327549   327707     +158     
  Branches      47181    47212      +31     
============================================
+ Hits         240217   240218       +1     
- Misses        68080    68177      +97     
- Partials      19252    19312      +60     

☔ 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

coderabbitai bot commented Nov 26, 2025

Walkthrough

Adds server-side HTTP/3 (QUIC) support across transports, clients, tests, and build tooling: Netty QUIC libraries and checksums, HTTP/3 enum and settings, new Netty QUIC transport and Reactor composite binding, client/test APIs updated to accept Settings and select protocol, plus audit/build/runtime adjustments.

Changes

Cohort / File(s) Change Summary
Changelog & Versions
CHANGELOG.md, gradle/libs.versions.toml
Added Unreleased bullets (one contains a stray trailing bracket) and added Netty QUIC libraries (netty-codec-native-quic, netty-codec-classes-quic).
Build, Runtime & Audit
modules/transport-netty4/build.gradle, plugins/transport-reactor-netty4/build.gradle, plugins/repository-azure/build.gradle
Added API deps for Netty HTTP/3/QUIC, exposed platform-specific netty-codec-native-quic runtime binaries, and updated thirdPartyAudit ignore/violation lists (added io.netty.channel.epoll.SegmentedDatagramPacket, removed some QUIC classes from ignoreViolations in places).
Checksums / Licenses
modules/transport-netty4/licenses/*, plugins/transport-reactor-netty4/licenses/*
Added SHA‑1 checksum files for Netty HTTP/3/QUIC artifacts (generic and OS/arch-specific).
Core HTTP Types & Settings
server/src/main/java/org/opensearch/http/HttpRequest.java, server/src/main/java/org/opensearch/http/HttpTransportSettings.java, server/src/main/java/org/opensearch/common/settings/ClusterSettings.java
Added HTTP_3_0 enum constant; added SETTING_HTTP_HTTP3_ENABLED and registered it in built-in cluster settings.
Netty / Reactor Request Mapping
modules/transport-netty4/.../Netty4HttpRequest.java, plugins/transport-reactor-netty4/.../ReactorNetty4HttpRequest.java
protocolVersion() extended to recognize "HTTP/3.0"HTTP_3_0.
Reactor Netty Server Transport
plugins/transport-reactor-netty4/src/main/java/.../ReactorNetty4HttpServerTransport.java, .../ReactorNetty4CompositeHttpServerChannel.java
Added HTTP/3 configure/bind flow, QUIC SSL context wiring, composite server channel combining HTTP/1.1/2 and HTTP/3, new H3 settings, and safe disposal helpers.
New Netty QUIC Transport
modules/transport-netty4/src/main/java/.../Netty4QuicServerTransport.java
New Netty4 QUIC/HTTP/3 server transport class with H3 settings, QUIC pipeline and per-connection handling.
Client & Test Client Logic
modules/transport-netty4/src/test/.../Netty4HttpClient.java, plugins/transport-reactor-netty4/src/test/.../ReactorHttpClient.java
Added HTTP/3 client flows; Reactor test client APIs now accept Settings, protocol-selection is settings-driven; generic initializer types updated.
Tests Added / Updated
plugins/transport-reactor-netty4/src/test/..., modules/transport-netty4/src/test/.../Netty4QuicServerTransportTests.java
Updated tests to pass Settings and propagate HTTP/3 flags; added Netty4QuicServerTransportTests and other H3-aware tests.
Keystore & Test Helpers
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java
Added createServerKeyStore(Algorithm) overload and parameterized certificate generation.
Allocator & SSL Utils
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java, .../ssl/SslUtils.java
Added getAllocator(boolean directBuffers); made DEFAULT_SSL_PROTOCOLS public.
Bootstrap / Codebase Parsing
server/src/main/java/org/opensearch/bootstrap/Security.java
Broadened CODEBASE_JAR_WITH_CLASSIFIER regex to capture optional platform classifier suffixes.
Minor Type Generalization
modules/transport-netty4/src/main/java/.../Netty4HttpRequestHandler.java
Generalized serverTransport type to AbstractHttpServerTransport (field and constructor).
Misc Tests / Call-site updates
various plugins/transport-reactor-netty4/src/test/...
Replaced ReactorHttpClient.create() usages with new signatures accepting Settings; propagated HTTP/3 settings through test setup.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant ReactorTransport as ReactorNetty4HttpServerTransport
    participant Binder11 as HTTP/1.1-2 Binder
    participant Binder3 as HTTP/3 (QUIC) Binder
    participant Composite as CompositeServerChannel

    Client->>ReactorTransport: bind(address, settings)
    alt http3 enabled & available
        ReactorTransport->>Binder3: configureHttp3(address, ssl, h3-settings)
        Binder3-->>ReactorTransport: serverChannelH3
        ReactorTransport->>Binder11: configureHttp11orHttp2(address, ssl)
        Binder11-->>ReactorTransport: serverChannel11
        ReactorTransport->>Composite: createComposite(serverChannel11, serverChannelH3)
        Composite-->>ReactorTransport: compositeChannel
        ReactorTransport-->>Client: bound(compositeChannel)
    else http3 disabled/unavailable
        ReactorTransport->>Binder11: configureHttp11orHttp2(address, ssl)
        Binder11-->>ReactorTransport: serverChannel11
        ReactorTransport-->>Client: bound(serverChannel11)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Areas to focus:
    • ReactorNetty4HttpServerTransport — H3 initialization, composite bind correctness, QUIC SSL/context and disposal.
    • Netty4QuicServerTransport — QUIC/native artifact handling, per-connection stream lifecycle, exception translation.
    • Client/test changes — ReactorHttpClient signature/API changes, Settings propagation, generic initializer updates.
    • Build/audit — verify native artifact coordinates, checksum files, and thirdPartyAudit adjustments.

Possibly related PRs

Suggested labels

Other

Suggested reviewers

  • peternied
  • andrross
  • msfroh
  • owaiskazi19
  • kotwanikunal
  • cwperks

Poem

🐇 I hopped through TLS and QUIC tonight,
stitched channels old and new just right,
UDP drums and streams that leap,
HTTP/3 wakes from its sleep,
a rabbit cheers each packet's flight!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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 is minimal but covers the essential requirement: it states the objective ('Support for HTTP/3 (server side)'), references the related issue (#4451), and includes the standard checklist. However, detailed explanation of changes, testing status, and technical approach are largely absent. Provide more detailed description of the implementation approach, affected components, testing performed, and API changes made to support HTTP/3 server-side functionality.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title '[WIP] Support for HTTP/3 (server side)' clearly describes the main feature being added - server-side HTTP/3 support. The [WIP] prefix indicates work in progress status, which is appropriate for an enhancement.
Linked Issues check ✅ Passed The PR addresses the primary objective from issue #4451 by implementing server-side HTTP/3 support using Netty libraries. Changes include HTTP/3 server transport implementation, QUIC codec dependencies, protocol version support, and configuration settings.
Out of Scope Changes check ✅ Passed All changes appear focused on HTTP/3 server-side implementation. Minor updates include javadoc fixes, test client signature updates to support Settings, and security policy regex updates for JAR classifiers, all supporting the HTTP/3 feature.
✨ 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

@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

Comment on lines 34 to 41
- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765))
- Support dynamic consumer configuration update in pull-based ingestion ([#19963](https://github.com/opensearch-project/OpenSearch/pull/19963))
- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)]
- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017)]

Copy link

@coderabbitai coderabbitai bot Nov 26, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix duplicate entry and malformed links in the changelog

Here:

- Support pull-based ingestion message mappers and raw payload support ([#19765](...)]
- Support for HTTP/3 (server side) ([#20017](...)]

there are two issues:

  • The pull-based ingestion entry is duplicated (already listed on Line 34).
  • Both new lines have mismatched brackets (] instead of )) at the end of the link, which will break markdown parsing.

A minimal fix would be:

-- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)]
-- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017)]
+- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017))

This keeps the existing single ingestion entry and adds a clean HTTP/3 line.

🤖 Prompt for AI Agents
In CHANGELOG.md around lines 34 to 38, remove the duplicated "Support pull-based
ingestion message mappers and raw payload support" entry and correct the
malformed markdown links by replacing the trailing "]" with ")" on the two
affected lines so links are well-formed; ensure only one ingestion line remains
and the HTTP/3 line is preserved with a properly closed link.

Copy link
Member

Choose a reason for hiding this comment

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

@coderabbitai those are completely different change log entry, isnt it? Do you have any suggestions to the code itself in this PR?

Copy link

Choose a reason for hiding this comment

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

@peterzhuamazon Thank you for the clarification request! Let me address both points:

Regarding the changelog entries:

You're right to question this - let me clarify:

So the fix is to remove only the duplicate line 36 and correct the malformed bracket on line 37:

-- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)]
-- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017)]
+- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017))

Regarding code review:

Since this is a WIP PR, I'd be happy to review the HTTP/3 implementation itself. A few areas worth examining:

  1. Protocol detection and fallback - How the code handles HTTP/3 availability and falls back to HTTP/1.1/2.0
  2. QUIC/UDP configuration - Security settings, connection limits, timeouts
  3. Certificate handling - Especially the switch to ECC algorithms for HTTP/3
  4. Testing coverage - Integration tests for HTTP/3 scenarios
  5. Performance implications - Native QUIC library loading across platforms

Would you like me to provide detailed feedback on any specific aspect of the implementation?

@github-actions
Copy link
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

@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
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
Contributor

✅ Gradle check result for 08a9dab: SUCCESS

@github-actions
Copy link
Contributor

✅ Gradle check result for c883a6e: SUCCESS

Copy link

@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: 7

♻️ Duplicate comments (2)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)

66-67: Align HTTP/3 client flow-control limits with server-side H3 settings instead of SETTING_HTTP_MAX_CHUNK_SIZE.

On the HTTP/3 client path, http3Settings().maxData(...) currently uses SETTING_HTTP_MAX_CHUNK_SIZE, which is intended for HTTP message chunking, not QUIC connection-level flow control. The server-side HTTP/3 configuration has already been updated to use SETTING_HTTP_MAX_CONTENT_LENGTH and dedicated H3 settings for per-stream limits; keeping the client on SETTING_HTTP_MAX_CHUNK_SIZE creates an unrealistically small connection window and an asymmetry vs server configuration, even though this is test-only code.

Consider aligning the client with the server-side H3 settings, for example:

-import static org.opensearch.http.HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED;
-import static org.opensearch.http.HttpTransportSettings.SETTING_HTTP_MAX_CHUNK_SIZE;
+import static org.opensearch.http.HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED;
+import static org.opensearch.http.HttpTransportSettings.SETTING_HTTP_MAX_CONTENT_LENGTH;
+import static org.opensearch.http.reactor.netty4.ReactorNetty4HttpServerTransport.SETTING_H3_MAX_STREAM_LOCAL_LENGTH;
+import static org.opensearch.http.reactor.netty4.ReactorNetty4HttpServerTransport.SETTING_H3_MAX_STREAM_REMOTE_LENGTH;
+import static org.opensearch.http.reactor.netty4.ReactorNetty4HttpServerTransport.SETTING_H3_MAX_STREAMS;
@@
             } else {
                 return client.protocol(protocol)
                     .secure(
                         spec -> spec.sslContext(
                             Http3SslContextSpec.forClient().configure(s -> s.trustManager(InsecureTrustManagerFactory.INSTANCE))
                         ).handshakeTimeout(Duration.ofSeconds(30))
                     )
                     .http3Settings(
                         spec -> spec.idleTimeout(Duration.ofSeconds(5))
-                            .maxData(SETTING_HTTP_MAX_CHUNK_SIZE.get(settings).getBytes())
-                            .maxStreamDataBidirectionalLocal(1000000)
-                            .maxStreamDataBidirectionalRemote(1000000)
-                            .maxStreamsBidirectional(100)
+                            .maxData(SETTING_HTTP_MAX_CONTENT_LENGTH.get(settings).getBytes())
+                            .maxStreamDataBidirectionalLocal(SETTING_H3_MAX_STREAM_LOCAL_LENGTH.get(settings).getBytes())
+                            .maxStreamDataBidirectionalRemote(SETTING_H3_MAX_STREAM_REMOTE_LENGTH.get(settings).getBytes())
+                            .maxStreamsBidirectional(SETTING_H3_MAX_STREAMS.get(settings).longValue())
                     );
             }

This keeps test clients representative of the configured HTTP/3 behavior and avoids an overly restrictive default window.

Also applies to: 302-315

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

273-317: Clean up HTTP/3 server if HTTP/1.1/2 bind fails and avoid channel() returning null on the composite DisposableServer.

If HTTP/3 is enabled and configureHttp3(...).map(HttpServer::bindNow) succeeds, but http11or2.bindNow() throws, the HTTP/3 server is left running and disposableServer is never set, so stopInternal() cannot dispose it. Additionally, the anonymous DisposableServer implementation returns null from channel(), which is fragile even if currently unused.

Wrap the HTTP/1.1/2 bind in a try/catch and ensure http3Server is disposed on failure, and return a sensible channel from channel() (for example, the HTTP/1.1/2 channel):

-        final Optional<DisposableServer> http3Opt = configureHttp3(socketAddress).map(HttpServer::bindNow);
-        if (http3Opt.isEmpty()) {
-            disposableServer = http11or2.bindNow();
-            return new ReactorNetty4HttpServerChannel(disposableServer.channel());
-        } else {
-            final DisposableServer http3Server = http3Opt.get();
-            final DisposableServer http11or2Server = http11or2.bindNow();
-
-            disposableServer = new DisposableServer() {
-                @Override
-                public Channel channel() {
-                    return null; /* not implemented */
-                }
-
-                @Override
-                public void disposeNow() {
-                    http3Server.disposeNow();
-                    http11or2Server.disposeNow();
-                }
-            };
-
-            return new ReactorNetty4CompositeHttpServerChannel(http11or2Server.channel(), http3Server.channel());
-        }
+        final Optional<DisposableServer> http3Opt = configureHttp3(socketAddress).map(HttpServer::bindNow);
+        if (http3Opt.isEmpty()) {
+            disposableServer = http11or2.bindNow();
+            return new ReactorNetty4HttpServerChannel(disposableServer.channel());
+        } else {
+            final DisposableServer http3Server = http3Opt.get();
+            final DisposableServer http11or2Server;
+            try {
+                http11or2Server = http11or2.bindNow();
+            } catch (Exception e) {
+                http3Server.disposeNow();
+                throw e;
+            }
+
+            disposableServer = new DisposableServer() {
+                @Override
+                public Channel channel() {
+                    // Expose a representative channel; HTTP/1.1/2 is sufficient for callers that only need a single Channel
+                    return http11or2Server.channel();
+                }
+
+                @Override
+                public void disposeNow() {
+                    http3Server.disposeNow();
+                    http11or2Server.disposeNow();
+                }
+            };
+
+            return new ReactorNetty4CompositeHttpServerChannel(http11or2Server.channel(), http3Server.channel());
+        }
🧹 Nitpick comments (5)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)

160-166: Behavior looks correct; consider small style/encapsulation tweaks

The conditional correctly exposes the underlying allocator only when direct buffers are explicitly requested and the global allocator is the NoDirectBuffers wrapper, which matches the HTTP/3/QUIC requirement.

Two minor polish suggestions:

  • Drop the redundant comparison: if (directBuffers && ALLOCATOR instanceof NoDirectBuffers ndb) { ... }.
  • Prefer the accessor over direct field access to keep NoDirectBuffers encapsulated within its own API:
-    public static ByteBufAllocator getAllocator(boolean directBuffers) {
-        if (directBuffers == true && ALLOCATOR instanceof NoDirectBuffers ndb) {
-            return ndb.delegate; /* Http3/Quic only supports direct buffers */
-        } else {
-            return ALLOCATOR;
-        }
-    }
+    public static ByteBufAllocator getAllocator(boolean directBuffers) {
+        if (directBuffers && ALLOCATOR instanceof NoDirectBuffers ndb) {
+            return ndb.getDelegate(); /* Http3/Quic only supports direct buffers */
+        } else {
+            return ALLOCATOR;
+        }
+    }
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1)

360-379: Unused ServerChannelExceptionHandler class.

The ServerChannelExceptionHandler class is defined but never added to any pipeline in the current implementation. If this is intended for future use, consider adding a TODO comment. Otherwise, remove the dead code.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

382-389: Prefer StandardCharsets.UTF_8 over Charset.forName("UTF-8").

Lines 382 and 389 use Charset.forName("UTF-8") when StandardCharsets.UTF_8 is already imported (Line 54) and used elsewhere in the file (Lines 274, 453).

-                final String url = "/" + new String(new byte[maxInitialLineLength], Charset.forName("UTF-8"));
+                final String url = "/" + new String(new byte[maxInitialLineLength], StandardCharsets.UTF_8);
...
-                        new String(response.content().array(), Charset.forName("UTF-8")),
+                        new String(response.content().array(), StandardCharsets.UTF_8),

428-440: Test uses Settings.EMPTY which may cause port binding issues.

Unlike other tests that use createSettings() (which includes getPortRange()), this test passes Settings.EMPTY directly. This could lead to port conflicts if the default port range is already in use.

         try (
             Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
-                Settings.EMPTY,
+                createSettings(),
                 networkService,
                 bigArrays,
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (1)

295-299: Randomizing http.protocol.http3.enabled improves coverage; watch for protocol-specific flakiness.

Propagating and randomizing SETTING_HTTP_HTTP3_ENABLED across server and client settings is a reasonable way to exercise both HTTP/1.1+2 and HTTP/3 paths in these tests. If you see instability in tests that depend on very specific protocol behavior, consider pinning this flag for those tests or splitting dedicated HTTP/3 variants while leaving base tests on HTTP/1.1/2.

Also applies to: 450-452, 646-649

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c883a6e and 1ccdf5a.

📒 Files selected for processing (42)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (10 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 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 (6)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • CHANGELOG.md
  • plugins/transport-reactor-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-windows-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (17)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • server/src/main/java/org/opensearch/bootstrap/Security.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • modules/transport-netty4/build.gradle
  • gradle/libs.versions.toml
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java
🧰 Additional context used
🧬 Code graph analysis (6)
plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java (2)
server/src/main/java/org/opensearch/index/search/SimpleQueryStringQueryParser.java (1)
  • Settings (317-450)
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/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/ssl/SecureReactorNetty4HttpServerTransportTests.java (3)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)
  • KeyStoreUtils (26-83)
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)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (1)
server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java (1)
  • AbstractHttpServerTransport (93-507)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)
libs/core/src/main/java/org/opensearch/core/common/bytes/BytesArray.java (1)
  • BytesArray (48-151)
⏰ 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: 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-intel)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: detect-breaking-change
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: Analyze (java)
  • GitHub Check: Mend Security Check
🔇 Additional comments (15)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2)

36-36: Type generalization looks good.

The change from Netty4HttpServerTransport to AbstractHttpServerTransport is appropriate for supporting multiple HTTP transport implementations (HTTP/1.x/2 and HTTP/3). All methods invoked on serverTransport (incomingRequest and onException) are present in AbstractHttpServerTransport, making this a safe refactoring.

Also applies to: 46-46, 48-48


54-54: Verify if HTTP/3 support is included in this PR.

The review comment assumes HTTP/3/QUIC transport is being added, but OpenSearch currently ships only Netty4 (default) and experimental Reactor Netty transports—no HTTP/3/QUIC transport exists. If this PR does not introduce HTTP/3 transport, the static Netty4HttpServerTransport.HTTP_CHANNEL_KEY reference on lines 54 and 69 is correct for the current Netty4-only implementation. If HTTP/3 support is intended, confirm whether a separate HTTP/3 transport class is being added, or clarify the scope of the type generalization to AbstractHttpServerTransport.

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

50-65: Clean refactoring to support algorithm-parameterized keystore creation.

The delegation pattern preserves backward compatibility while enabling tests to specify different algorithms (e.g., Algorithm.ecp384 for HTTP/3/QUIC scenarios). The implementation correctly propagates the algorithm to the certificate builder.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

176-184: HTTP/3 client factory implementation looks correct.

The http3() method properly configures the bootstrap with NioDatagramChannel and uses NettyAllocator.getAllocator(true) to request direct buffers, which are required by QUIC.

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

17-17: LGTM!

The import addition and API migration to ReactorHttpClient.create(Settings.EMPTY) are consistent with the new Settings-aware client factory pattern introduced across the test suite for HTTP/3 support.

Also applies to: 47-47

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

60-65: LGTM!

The addition of HTTP_3_0 to the HttpVersion enum is a clean, backward-compatible extension to support the new HTTP/3 protocol. The enum maintains logical ordering by HTTP version.

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

122-122: LGTM!

The API migration to include Settings.EMPTY as a parameter is consistent with the updated ReactorHttpClient.create(boolean, Settings) signature. Since these tests explicitly use HttpVersion.HTTP_1_1, using Settings.EMPTY is appropriate.

Also applies to: 162-162

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

100-100: LGTM!

Good approach: this test appropriately propagates the same settings object (containing port configuration) to both the server transport and the client, ensuring consistent configuration. This aligns with the new Settings-aware client factory pattern.

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

262-267: LGTM!

The new SETTING_HTTP_HTTP3_ENABLED setting is well-structured:

  • Defaults to false, which is appropriate for a new, experimental feature
  • Uses Property.NodeScope correctly for node-level transport configuration
  • Follows existing naming conventions (http.protocol.*)
  • Includes a helpful comment about OS/architecture requirements

Ensure this setting is registered in the appropriate settings module so it's recognized by the cluster.

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

205-205: ReactorHttpClient factory migration looks correct and consistent.

All call sites correctly switched to ReactorHttpClient.create(settings) / create(Settings.EMPTY), keeping server/client settings aligned without changing the test semantics.

Also applies to: 310-310, 356-356, 412-412, 478-478, 541-541, 559-559

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

92-93: Key material generation and SSLEngine setup are appropriate for test SSL.

Using KeyStoreUtils.createServerKeyStore(Algorithm.ecp384) with a shared KeyManagerFactory and constructing the SSLEngine via SslContextBuilder.forServer(keyManagerFactory).trustManager(InsecureTrustManagerFactory.INSTANCE) is sound for these tests and keeps the setup concise.

Also applies to: 120-122, 165-171


256-256: HTTPS client creation correctly aligned with the new Settings-aware ReactorHttpClient API.

All secure tests now construct clients via ReactorHttpClient.https(settings), passing the same Settings used for the server transport so that HTTP/1.1, HTTP/2, and HTTP/3 selection stays consistent between client and server.

Also applies to: 363-363, 410-410, 471-471, 544-544, 560-560

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

18-18: Settings-aware client construction and protocol selection look coherent.

Requiring Settings in the constructor/factories, caching a per-instance HttpProtocol, and basing useHttp11only() on that protocol align well with the new HTTP/1.1–2–3 model. The secure/non-secure branches in createClient correctly choose between HTTP/1.1, H2/H2C, and HTTP/3 based on secure and randomProtocol.

Also applies to: 75-79, 96-113, 276-283, 317-323, 330-333, 334-348

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

48-49: HTTP/3 settings and configuration are well-scoped and gated.

The new H3 settings (SETTING_H3_MAX_STREAM_LOCAL_LENGTH, SETTING_H3_MAX_STREAM_REMOTE_LENGTH, SETTING_H3_MAX_STREAMS) with ~1 MB per stream and 100 concurrent bidirectional streams are reasonable defaults. The configureHttp3 method correctly:

  • Requires a SecureHttpTransportSettingsProvider and a KeyManagerFactory.
  • Gates on Http3.isHttp3Available() and SETTING_HTTP_HTTP3_ENABLED.
  • Aligns connection maxData with SETTING_HTTP_MAX_CONTENT_LENGTH and uses the H3 settings for stream limits.
  • Keeps HTTP/1.1/2 configuration isolated in configureHttp11orHttp2.

This structure gives a clear, opt-in HTTP/3 path without regressing existing HTTP/1.1/2 behavior.

Also applies to: 55-55, 69-69, 75-75, 110-136, 319-367, 370-370

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

38-47: QUIC dependencies and audit updates align with HTTP/3 support enablement.

The addition of netty-codec-classes-quic and netty-codec-native-quic APIs plus OS-specific runtimeOnly classifiers follows standard Gradle patterns and should not produce duplicate artifacts in the published POM/JAR. The SegmentedDatagramPacket audit exclusion is appropriate for platform-dependent availability. No actionable issues identified.

.initialMaxStreamDataBidirectionalRemote(SETTING_H3_MAX_STREAM_REMOTE_LENGTH.get(settings).getBytes())
.initialMaxStreamsBidirectional(SETTING_H3_MAX_STREAMS.get(settings).longValue())
.tokenHandler(InsecureQuicTokenHandler.INSTANCE)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Security: InsecureQuicTokenHandler should not be used in production.

The InsecureQuicTokenHandler.INSTANCE bypasses QUIC token validation, which is a security feature that helps prevent address spoofing attacks. While acceptable for initial development/testing, this should be replaced with a proper token handler before production use.

Consider adding a TODO or configuration option:

-                            .tokenHandler(InsecureQuicTokenHandler.INSTANCE)
+                            // TODO: Replace with secure token handler before production
+                            // See: https://www.rfc-editor.org/rfc/rfc9000.html#section-8
+                            .tokenHandler(InsecureQuicTokenHandler.INSTANCE)

Or introduce a setting to control this behavior for production deployments.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.initialMaxStreamDataBidirectionalRemote(SETTING_H3_MAX_STREAM_REMOTE_LENGTH.get(settings).getBytes())
.initialMaxStreamsBidirectional(SETTING_H3_MAX_STREAMS.get(settings).longValue())
.tokenHandler(InsecureQuicTokenHandler.INSTANCE)
.initialMaxStreamDataBidirectionalRemote(SETTING_H3_MAX_STREAM_REMOTE_LENGTH.get(settings).getBytes())
.initialMaxStreamsBidirectional(SETTING_H3_MAX_STREAMS.get(settings).longValue())
// TODO: Replace with secure token handler before production
// See: https://www.rfc-editor.org/rfc/rfc9000.html#section-8
.tokenHandler(InsecureQuicTokenHandler.INSTANCE)
🤖 Prompt for AI Agents
In
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java
around lines 274-276, the code uses InsecureQuicTokenHandler.INSTANCE which
disables QUIC token validation; replace this with a proper token handler
implementation that generates and validates stateless QUIC tokens (or integrates
with Netty/your existing token service) and remove the insecure instance from
production paths, and add a boolean cluster/transport setting (default false) to
allow the insecure handler only for dev/tests with a clear TODO and
documentation note; ensure the new setting is validated at startup and the
secure handler is used by default in production.

*/
public class SslUtils {
private static final String[] DEFAULT_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" };
public static final String[] DEFAULT_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" };
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid exposing mutable DEFAULT_SSL_PROTOCOLS array as public API

Changing DEFAULT_SSL_PROTOCOLS to public static final exposes a mutable array; any caller can modify its elements (e.g., DEFAULT_SSL_PROTOCOLS[0] = "TLSv1"), silently changing TLS behavior globally at runtime. That’s a security‑relevant configuration surface and breaks encapsulation just to share an implementation detail.

Prefer keeping the array private and exposing an immutable view or a defensive copy via an accessor:

-    public static final String[] DEFAULT_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" };
+    private static final String[] DEFAULT_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" };
+
+    public static String[] getDefaultSslProtocols() {
+        // Defensive copy so callers cannot mutate our internal array
+        return DEFAULT_SSL_PROTOCOLS.clone();
+    }

New HTTP/3 / QUIC code (or other callers) can then use SslUtils.getDefaultSslProtocols() instead of the field.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static final String[] DEFAULT_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" };
private static final String[] DEFAULT_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" };
public static String[] getDefaultSslProtocols() {
// Defensive copy so callers cannot mutate our internal array
return DEFAULT_SSL_PROTOCOLS.clone();
}
🤖 Prompt for AI Agents
In
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java
around line 27, the public static final DEFAULT_SSL_PROTOCOLS array is exposed
allowing callers to mutate its elements; make DEFAULT_SSL_PROTOCOLS private (or
package-private) and add a public accessor method getDefaultSslProtocols() that
returns either an immutable list/array copy or a defensive copy of the
protocols, and update all callers to use that accessor instead of the field to
prevent runtime mutation and preserve encapsulation.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

❌ Gradle check result for 1ccdf5a: 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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java (1)

153-165: HTTP/3 protocol string comparison is incorrect—will reject valid HTTP/3 requests

The code checks for "HTTP/3.0":

} else if (protocol.equals("HTTP/3.0")) {
    return HttpRequest.HttpVersion.HTTP_3_0;

However, Reactor Netty's HttpServerRequest.protocol() returns "HTTP/3" (not "HTTP/3.0") for HTTP/3 requests. This mismatch means the condition will never match and HTTP/3 requests will fall through to the IllegalArgumentException("Unexpected http protocol version: " + protocol) path, causing runtime failures.

Change the comparison to:

} else if (protocol.equals("HTTP/3")) {
    return HttpRequest.HttpVersion.HTTP_3_0;
}
♻️ Duplicate comments (8)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

553-597: testReadTimeout still uses TCP channel instead of QUIC/UDP, so it likely doesn’t exercise HTTP/3 behavior

This test bootstraps a NioSocketChannel (TCP) client and connects it to a server that is intended to speak QUIC/HTTP3. That TCP connection will not behave like an HTTP/3/QUIC client and is unlikely to validate the intended read-timeout behavior on the QUIC transport. This concern matches a previous review on an earlier revision of this test.

Consider reworking the test to use the existing HTTP/3 client helper, for example:

  • Replace the raw Bootstrap/NioSocketChannel client with try (Netty4HttpClient client = Netty4HttpClient.http3()) { ... } and send a request that intentionally stalls, or
  • If you need a lower-level check, use a UDP/NioDatagramChannel‑based QUIC client that mirrors how Netty4HttpClient.http3() sets up QUIC/HTTP3.

This will ensure the read-timeout logic is actually exercised in the HTTP/3/QUIC code path rather than via a mismatched TCP connection.

modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)

27-27: Security risk: Mutable array exposed as public API.

As flagged in a previous review, changing DEFAULT_SSL_PROTOCOLS to public static final exposes a mutable array. Callers can modify elements at runtime (e.g., DEFAULT_SSL_PROTOCOLS[0] = "TLSv1"), altering TLS behavior globally—a security configuration surface that must not be externally mutable.

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

39-44: Close listener will be invoked multiple times.

As previously noted, the listener is added to each closeContext, causing it to fire once per channel closure. If the caller expects a single notification when all channels have closed, this will cause unexpected behavior.


25-32: Validate constructor parameters.

The constructor does not validate that channels is non-null and non-empty. Line 36's getLocalAddress() will throw ArrayIndexOutOfBoundsException if an empty array is passed.

Add validation at the start of the constructor:

 ReactorNetty4CompositeHttpServerChannel(Channel... channels) {
+    if (channels == null || channels.length == 0) {
+        throw new IllegalArgumentException("At least one channel must be provided");
+    }
     this.channels = channels;
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (2)

304-306: Returning null from channel() may cause NPE.

As flagged previously, the anonymous DisposableServer returns null for channel(). Downstream code expecting a valid channel reference will encounter NullPointerException.


299-300: HTTP/3 server not cleaned up if HTTP/1.1/2 bind fails.

As noted in a previous review, if http11or2.bindNow() (Line 300) throws after http3Server has successfully bound (Line 299), the HTTP/3 server remains bound, leaking resources.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

273-273: Security: InsecureQuicTokenHandler bypasses QUIC token validation.

This handler disables address validation tokens, which protect against address spoofing attacks (RFC 9000 Section 8). This was previously flagged and should be addressed before production use.

Consider introducing a configuration setting to control token handler behavior, defaulting to a secure implementation for production.


331-332: Header verification and decompression are disabled.

These handlers are commented out, which means:

  1. createHeaderVerifier() is never invoked, so plugins cannot verify headers.
  2. createDecompressor() is never invoked, so compressed request bodies won't be decompressed.

This breaks feature parity with Netty4HttpServerTransport and could cause functional issues with compressed requests.

-            ch.pipeline().addLast(new Http3FrameToHttpObjectCodec(true));
-            // ch.pipeline().addLast("header_verifier", transport.createHeaderVerifier());
-            // ch.pipeline().addLast("decoder_compress", transport.createDecompressor());
+            ch.pipeline().addLast("http3_codec", new Http3FrameToHttpObjectCodec(true));
+            ch.pipeline().addLast("header_verifier", transport.createHeaderVerifier());
+            ch.pipeline().addLast("decoder_compress", transport.createDecompressor());
🧹 Nitpick comments (11)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (2)

54-55: Consider adding a brief Javadoc or null guard.

For a public API in the test framework, consider documenting the expected algorithm values or adding a null check. Since Algorithm is an enum, a null argument would cause a NullPointerException in generateCert. A brief Javadoc noting FIPS constraints (per the comment in generateCert) would help callers choose appropriate algorithms.

+    /**
+     * Creates a server keystore with a self-signed certificate using the specified algorithm.
+     * When FIPS mode is enabled, use FIPS-approved algorithms: rsa2048, rsa3072, rsa4096, rsa8192, ecp256, ecp384.
+     */
     public static KeyStore createServerKeyStore(Algorithm algorithm) throws Exception {
+        if (algorithm == null) {
+            throw new IllegalArgumentException("algorithm must not be null");
+        }
         var serverCred = generateCert(algorithm);

67-77: Update comment to reflect parameterized algorithm.

The comment on lines 71-72 states "must use FIPS-approved algorithms" but the method now accepts any Algorithm value from the caller. Consider updating the comment to clarify this is the caller's responsibility, or note that the BouncyCastleFipsProvider will reject non-approved algorithms at runtime when FIPS mode is enabled.

-            // must use FIPS-approved algorithms like rsa2048, rsa3072, rsa4096, rsa8192, ecp256, ecp384
-            // reference: https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4943
+            // When FIPS mode is enabled, callers must provide a FIPS-approved algorithm
+            // (e.g., rsa2048, rsa3072, rsa4096, rsa8192, ecp256, ecp384).
+            // Reference: https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4943
             return new CertificateBuilder().subject("CN=Test CA Certificate")
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (2)

161-161: Simplify the boolean comparison.

The comparison directBuffers == true is redundant. Simplify to just directBuffers for cleaner, more idiomatic code.

Apply this diff:

-        if (directBuffers == true && ALLOCATOR instanceof NoDirectBuffers ndb) {
+        if (directBuffers && ALLOCATOR instanceof NoDirectBuffers ndb) {

160-166: Consider adding Javadoc for this public API method.

The new method correctly handles HTTP/3/QUIC's direct buffer requirement by unwrapping the NoDirectBuffers delegate when needed. However, as a public API method, it would benefit from Javadoc explaining:

  • The purpose and use case (HTTP/3/QUIC support)
  • The directBuffers parameter behavior
  • Return value semantics (when delegate vs. ALLOCATOR is returned)

Example Javadoc:

/**
 * Returns a ByteBufAllocator that supports the specified buffer type.
 * 
 * @param directBuffers if true, returns an allocator capable of creating direct buffers.
 *                      This is required for HTTP/3 and QUIC protocols. If the current
 *                      allocator is wrapped with NoDirectBuffers, returns the underlying
 *                      delegate; otherwise returns the standard allocator.
 * @return a ByteBufAllocator instance
 */
public static ByteBufAllocator getAllocator(boolean directBuffers) {
plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java (1)

101-120: Client factory updates correctly reflect new Settings-based API

Using ReactorHttpClient.create(false, Settings.EMPTY) in these ITs matches the revised factory signature and keeps the client behavior explicit and isolated from cluster nodeSettings. If you later want to exercise HTTP/3 here, consider passing the same nodeSettings(int nodeOrdinal) instead of Settings.EMPTY.

Also applies to: 131-143

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

74-79: Random protocol selection may introduce unnecessary test nondeterminism

ReactorHttpClient now randomly chooses among HTTP/1.1, HTTP/2, and optionally HTTP/3 per instance via randomProtocol(secure, settings). This keeps tests covering multiple protocols, but as HTTP/3 gets enabled this randomness can make failures harder to reproduce and reason about.

Consider (optionally) exposing the chosen HttpProtocol or allowing tests to inject a fixed protocol, then retaining randomness only where you explicitly want multi‑protocol coverage.

Also applies to: 96-101, 330-348

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

384-390: Safer ByteBuf to String conversion in testBadRequest

new String(response.content().array(), Charset.forName("UTF-8")) assumes the buffer is backed by an accessible array, which may not always be true for Netty ByteBufs.

You already use ByteBufUtil.getBytes(..., StandardCharsets.UTF_8) elsewhere in this class; using the same here would be safer and more consistent:

-                    assertThat(
-                        new String(response.content().array(), Charset.forName("UTF-8")),
-                        containsString("you sent a bad request and you should feel bad")
-                    );
+                    byte[] bytes = ByteBufUtil.getBytes(response.content());
+                    assertThat(
+                        new String(bytes, StandardCharsets.UTF_8),
+                        containsString("you sent a bad request and you should feel bad")
+                    );
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)

327-327: Remove redundant boolean comparison.

The expression .booleanValue() == true is redundant. get(settings) returns a Boolean that auto-unboxes in the if condition.

Simplify to:

-            if (Http3.isHttp3Available() && SETTING_HTTP_HTTP3_ENABLED.get(settings).booleanValue() == true) {
+            if (Http3.isHttp3Available() && SETTING_HTTP_HTTP3_ENABLED.get(settings)) {
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (3)

119-119: Add validation bounds for h3.max_streams setting.

The setting lacks minimum value validation. Per RFC 9000 and the Javadoc comment on lines 113-117, HTTP/3 expects at least 100 concurrent bidirectional streams. A value of 0 or negative would cause unexpected behavior.

-    public static final Setting<Long> SETTING_H3_MAX_STREAMS = Setting.longSetting("h3.max_streams", 100L, Property.NodeScope);
+    public static final Setting<Long> SETTING_H3_MAX_STREAMS = Setting.longSetting("h3.max_streams", 100L, 1L, Property.NodeScope);

164-165: Unused exceptionHandler field.

The exceptionHandler is initialized but never used anywhere in the class. Either integrate it into exception handling paths (e.g., in onException() or HttpChannelHandler.exceptionCaught()) or remove the dead code.

If intended to delegate exception handling, consider integrating it:

 @Override
 public void onException(HttpChannel channel, Exception cause) {
+    exceptionHandler.onError(cause);
     if (cause instanceof ReadTimeoutException) {
         super.onException(channel, new HttpReadTimeoutException(readTimeoutMillis, cause));
     } else {
         super.onException(channel, cause);
     }
 }

308-310: Unused getRequestHandler() method.

This public accessor is defined but never called. Consider removing it if not needed, or document its intended use case for plugin extensibility.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ccdf5a and a37d345.

📒 Files selected for processing (43)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (10 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 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 (4)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (16)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • server/src/main/java/org/opensearch/http/HttpTransportSettings.java
  • server/src/main/java/org/opensearch/http/HttpRequest.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java
  • CHANGELOG.md
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
🧰 Additional context used
🧬 Code graph analysis (6)
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/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/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (1)
server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java (1)
  • AbstractHttpServerTransport (93-507)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (4)
server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java (1)
  • AbstractHttpServerTransport (93-507)
server/src/main/java/org/opensearch/bootstrap/Bootstrap.java (1)
  • Bootstrap (89-495)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (3)
  • ChannelHandler (543-562)
  • Netty4HttpServerTransport (130-635)
  • HttpChannelHandler (364-541)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (4)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
server/src/main/java/org/opensearch/rest/BytesRestResponse.java (1)
  • BytesRestResponse (59-219)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)
  • KeyStoreUtils (26-83)
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)
  • SslUtils (26-107)
⏰ 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-24.04-arm)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: detect-breaking-change
  • GitHub Check: Analyze (java)
  • GitHub Check: Mend Security Check
🔇 Additional comments (17)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1)

198-208: Javadoc typo fix is correct

The updated @param settings settings Javadoc is accurate and has no behavioral impact. Looks good to keep as-is.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2)

35-37: Importing AbstractHttpServerTransport is consistent with transport abstraction

Switching the dependency to the abstract base transport aligns this handler with the shared HTTP transport layer, which is a good fit given the methods it uses (incomingRequest, onException) are defined there.


46-50: Generalizing serverTransport to AbstractHttpServerTransport looks correct

The field and constructor now depend on AbstractHttpServerTransport while the handler still only calls methods provided by that base class, so behavior is unchanged while reducing coupling to Netty4HttpServerTransport. This will also ease reuse with additional HTTP transports (e.g., HTTP/3) that extend the abstract transport.

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

50-52: LGTM!

Clean backward-compatible delegation pattern. The default Algorithm.rsa2048 maintains the previous behavior and is FIPS-approved.

server/src/main/java/org/opensearch/bootstrap/Security.java (2)

259-286: Verify test coverage for classifier handling logic.

The two-pass approach for handling JARs with classifiers is sound: the first pass separates classified JARs, and the second pass processes them with conflict resolution via the "@" + classifier suffix.

Ensure that test coverage exists for:

  1. JARs with platform-specific classifiers (e.g., linux-x86_64, osx-aarch_64)
  2. Multiple JARs with the same base name but different classifiers
  3. The conflict resolution logic when aliasProperty already exists

132-134: The regex pattern correctly handles platform-specific classifier extraction for HTTP/3 dependency JARs. All provided examples match the pattern as intended, including netty-tcnative-boringssl-static artifacts with platform classifiers like linux-x86_64. The concern about compound classifiers like snapshot-8a555eb is based on a misunderstanding of classifier definitions—pre-release version metadata is distinct from classifiers and is not intended to be extracted by this pattern.

No action required; the implementation is sound.

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

1-1: Checksum file format looks correct

Single-line 40‑character hex digest matches expected .sha1 format; nothing to change.

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

1-1: Checksum entry is well-formed

SHA‑1 checksum line is correctly formatted; aligns with other license checksum artifacts.

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

83-118: Updated ReactorHttpClient.create(settings) usage is consistent with new API

Switching to ReactorHttpClient.create(settings) matches the updated factory signature and reuses the same settings used to configure the server transport; this keeps protocol selection (incl. HTTP/3 when enabled) consistent between client and server in this test.

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

96-113: HTTP/1.1 / HTTP/2 / HTTP/3 wiring in createClient looks aligned with Reactor Netty usage

The refactor to:

  • store a per-instance HttpProtocol protocol,
  • build HTTP/1.1 via Http11SslContextSpec.forClient(),
  • build HTTP/2 via Http2SslContextSpec.forClient() with {HTTP11, H2} protocols, and
  • build HTTP/3 via Http3SslContextSpec.forClient() plus http3Settings(...),

matches Reactor Netty’s documented patterns for enabling HTTP/3 and configuring QUIC settings (idle timeout, max data, streams). Using SETTING_HTTP_HTTP3_ENABLED together with Http3.isHttp3Available() to gate HTTP/3 is also a sensible guard.

Please double-check against the Reactor Netty version you use that:

  • Http3SslContextSpec.forClient().configure(...) is the recommended pattern, and
  • chaining .secure(...).http3Settings(...) on the client is supported for HttpProtocol.HTTP3.

If your version’s API differs, you may need to adjust the builder chaining accordingly.

Also applies to: 276-323

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

176-185: HTTP/3 client path and pipeline ordering look correct for test usage

The new HTTP/3 support in Netty4HttpClient:

  • Uses NioDatagramChannel and QUIC codecs on the datagram channel,
  • Bootstraps a QuicChannel and HTTP/3 request stream,
  • Installs Http3FrameToHttpObjectCodec(false) before the decompressor and aggregator, and
  • Reuses the familiar “copy content, add to list, count down latch” pattern,

which lines up with Netty’s guidance for HTTP/3 client pipelines and addresses earlier feedback about mixing HTTP/1.x codecs into an HTTP/3 pipeline. The AwaitableChannelInitializer<C> + prepare(...) hook also keeps the HTTP/1.1, HTTP/2, and HTTP/3 code paths unified without complicating the calling code.

If you upgrade Netty HTTP/3 in the future, it’s worth re-checking that:

  • Http3.newQuicClientCodecBuilder() and Http3.newRequestStream(...) remain the recommended entry points, and
  • Http3FrameToHttpObjectCodec(false) is still the appropriate adapter for client-side streams.

Also applies to: 234-263, 328-336, 469-533

gradle/libs.versions.toml (1)

152-153: LGTM!

The QUIC library entries follow the established pattern and correctly reference the Netty version.

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

122-122: LGTM!

The test updates correctly adapt to the new ReactorHttpClient.create(boolean, Settings) API signature by passing Settings.EMPTY.

Also applies to: 162-162

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

66-68: LGTM!

The QUIC/HTTP3 dependencies are correctly declared as api (exposing them to consumers) and native binaries are appropriately scoped as runtimeOnly for all supported platforms.

Also applies to: 79-84

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

38-39: LGTM!

The QUIC library dependencies mirror the transport-netty4 module's pattern and correctly expose codecs via api while bundling platform-specific native binaries as runtimeOnly.

Also applies to: 42-46

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

194-244: LGTM!

The lifecycle methods (doStart, bind, stopInternal, onException) follow established patterns from the existing HTTP/1.x transport. The proper cleanup in the finally block and ReadTimeoutException wrapping are well implemented.


387-439: LGTM!

The defaultCompressionOptions() implementation correctly excludes ZSTD due to direct buffer constraints and provides Brotli conditionally when available. This matches the behavior in Netty4HttpServerTransport.

Comment on lines +349 to +376
@ChannelHandler.Sharable
private static class ServerChannelExceptionHandler extends ChannelInboundHandlerAdapter {

private final Netty4QuicServerTransport transport;

private ServerChannelExceptionHandler(Netty4QuicServerTransport transport) {
this.transport = transport;
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ExceptionsHelper.maybeDieOnAnotherThread(cause);
Netty4HttpServerChannel httpServerChannel = ctx.channel().attr(HTTP_SERVER_CHANNEL_KEY).get();
if (cause instanceof Error) {
transport.onServerException(httpServerChannel, new Exception(cause));
} else {
transport.onServerException(httpServerChannel, (Exception) cause);
}
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

ServerChannelExceptionHandler is defined but never used.

This class is never instantiated or added to any pipeline. Either integrate it into configureServerChannelHandler() for proper server-level exception handling, or remove the dead code.

If this should handle server channel exceptions, add it to the QUIC server codec's parent channel:

// In configureServerChannelHandler(), after adding the QUIC server codec:
ch.pipeline().addLast("server_exception_handler", new ServerChannelExceptionHandler(Netty4QuicServerTransport.this));

@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

❌ Gradle check result for a37d345: 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

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

192-192: Scheme header logic is inverted.

The ternary is backwards: it sets scheme to "http" when secure is true, and "https" when false.

-            httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "http" : "https");
+            httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "https" : "http");
♻️ Duplicate comments (5)
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)

27-27: Mutable array exposure concern already flagged.

The previous review correctly identified the security concern with exposing DEFAULT_SSL_PROTOCOLS as a mutable public array. The suggested fix (making it private with a defensive copy accessor) should be applied.

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

272-317: Fix lifecycle coupling between HTTP/3 and HTTP/1.1/2 servers and avoid null channel()

Two issues remain in the combined bind path:

  1. Resource leak on HTTP/1.1/2 bind failure
    If http11or2.bindNow() throws after http3Server has already bound, the HTTP/3 server is left running with no reference in disposableServer, so stopInternal() will never dispose it.

  2. DisposableServer.channel() returns null
    Returning null from channel() in the composite DisposableServer can cause NPEs if any code assumes a non-null server channel (e.g., for logging or metrics).

You can address both by disposing HTTP/3 on HTTP/1.1/2 bind failure and having channel() delegate to one of the underlying servers (typically the TCP HTTP/1.1/2 server):

@@
-        } else {
-            final DisposableServer http3Server = http3Opt.get();
-            final DisposableServer http11or2Server = http11or2.bindNow();
-
-            disposableServer = new DisposableServer() {
-                @Override
-                public Channel channel() {
-                    return null; /* not implemented */
-                }
-
-                @Override
-                public void disposeNow() {
-                    http3Server.disposeNow();
-                    http11or2Server.disposeNow();
-                }
-            };
-
-            return new ReactorNetty4CompositeHttpServerChannel(http11or2Server.channel(), http3Server.channel());
-        }
+        } else {
+            final DisposableServer http3Server = http3Opt.get();
+            final DisposableServer http11or2Server;
+            try {
+                http11or2Server = http11or2.bindNow();
+            } catch (Exception e) {
+                http3Server.disposeNow();
+                throw e;
+            }
+
+            disposableServer = new DisposableServer() {
+                @Override
+                public Channel channel() {
+                    // Expose the TCP server channel for compatibility with existing usages.
+                    return http11or2Server.channel();
+                }
+
+                @Override
+                public void disposeNow() {
+                    http3Server.disposeNow();
+                    http11or2Server.disposeNow();
+                }
+            };
+
+            return new ReactorNetty4CompositeHttpServerChannel(http11or2Server.channel(), http3Server.channel());
+        }
#!/bin/bash
# Verify whether any code relies on disposableServer.channel()
rg -n "disposableServer\.channel\(" .
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (1)

20-44: Harden composite channel against empty input and avoid multi‑invoking close listeners

The current implementation has two issues:

  • No guard against channels.length == 0, which would break getLocalAddress() and loops if misused.
  • addCloseListener wires the same listener to every closeContext, so it fires once per underlying channel instead of once when the composite is fully closed.

Consider validating input and aggregating close completion so the listener runs exactly once when all channels are closed:

@@
-import java.net.InetSocketAddress;
+import java.net.InetSocketAddress;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
@@
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    ReactorNetty4CompositeHttpServerChannel(Channel... channels) {
-        this.channels = channels;
+    @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];
         for (int i = 0; i < channels.length; ++i) {
             closeContexts[i] = new CompletableContext<>();
             Netty4Utils.addListener(this.channels[i].closeFuture(), closeContexts[i]);
         }
     }
@@
     @Override
     public void addCloseListener(ActionListener<Void> listener) {
-        for (int i = 0; i < closeContexts.length; ++i) {
-            closeContexts[i].addListener(ActionListener.toBiConsumer(listener));
-        }
+        final AtomicInteger remaining = new AtomicInteger(closeContexts.length);
+        final AtomicReference<Exception> firstFailure = new AtomicReference<>();
+
+        final ActionListener<Void> composite = new ActionListener<>() {
+            @Override
+            public void onResponse(Void unused) {
+                if (remaining.decrementAndGet() == 0) {
+                    final Exception failure = firstFailure.get();
+                    if (failure != null) {
+                        listener.onFailure(failure);
+                    } else {
+                        listener.onResponse(null);
+                    }
+                }
+            }
+
+            @Override
+            public void onFailure(Exception e) {
+                firstFailure.compareAndSet(null, e);
+                if (remaining.decrementAndGet() == 0) {
+                    listener.onFailure(firstFailure.get());
+                }
+            }
+        };
+
+        for (int i = 0; i < closeContexts.length; ++i) {
+            closeContexts[i].addListener(ActionListener.toBiConsumer(composite));
+        }
     }
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

349-368: Remove unused ServerChannelExceptionHandler class.

This exception handler is defined but never instantiated or added to any pipeline. Either integrate it into the server channel setup or remove it as dead code.

If server-level exception handling is needed, add it in configureServerChannelHandler() around line 280:

                 ch.pipeline().remove(this);
+                ch.pipeline().addLast("server_exception_handler", new ServerChannelExceptionHandler(Netty4QuicServerTransport.this));
             }

Otherwise, delete lines 349-368.


271-273: Replace InsecureQuicTokenHandler with secure implementation before production.

InsecureQuicTokenHandler.INSTANCE bypasses QUIC's address validation token mechanism, making the server vulnerable to address spoofing and amplification attacks. This is unacceptable for production deployments.

Based on learnings from past reviews, this was previously flagged and remains unaddressed. Since this is marked as [WIP], ensure this is resolved before marking the PR ready for merge.

🧹 Nitpick comments (4)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)

160-166: Consider using the public accessor and simplifying the boolean check.

The logic is correct for enabling HTTP/3/QUIC which requires direct buffers. Two minor improvements:

  1. Use directBuffers instead of directBuffers == true for idiomatic boolean checks
  2. Consider using the public getDelegate() accessor instead of directly accessing the private delegate field for better encapsulation
 public static ByteBufAllocator getAllocator(boolean directBuffers) {
-    if (directBuffers == true && ALLOCATOR instanceof NoDirectBuffers ndb) {
-        return ndb.delegate; /* Http3/Quic only supports direct buffers */
+    if (directBuffers && ALLOCATOR instanceof NoDirectBuffers ndb) {
+        return ndb.getDelegate(); /* Http3/Quic only supports direct buffers */
     } else {
         return ALLOCATOR;
     }
 }
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)

67-81: Consider adding null check for algorithm parameter.

The generateCert method could throw an NPE if called with a null algorithm. Since this is test code, the risk is low, but a defensive check would be prudent.

 private static X509Bundle generateCert(Algorithm algorithm) throws Exception {
+    if (algorithm == null) {
+        throw new IllegalArgumentException("Algorithm must not be null");
+    }
     final Locale locale = Locale.getDefault();
gradle/libs.versions.toml (1)

152-153: QUIC library entries are consistent; bundle inclusion is optional

The new netty-codec-native-quic and netty-codec-classes-quic entries correctly reuse the shared netty version. If you expect these to be treated like the other Netty artifacts, consider adding them to the netty bundle; otherwise, explicit dependency wiring as in the module build files is fine.

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

319-367: HTTP/3 configuration gating is correct; enhance logging to detect both classpath and runtime native library issues

The configureHttp3 method correctly gates HTTP/3 on secureHttpTransportSettingsProvider, Http3.isHttp3Available() (classpath check), and SETTING_HTTP_HTTP3_ENABLED. However, Http3.isHttp3Available() only verifies that the Netty HTTP/3 codec artifact is present on the classpath—it does not verify that native QUIC libraries are available at runtime. For operators to diagnose missing or failed-to-load native libraries, consider adding structured logging at startup that checks both:

  • Http3.isHttp3Available() (classpath availability)
  • io.netty.incubator.codec.quic.Quic.isAvailable() and Quic.unavailabilityCause() (runtime native library status)

Additionally, enable SLF4J DEBUG/TRACE logging for reactor.netty and netty.* packages and consider calling warmup() on the HttpServer during initialization to force native library preloading before handling requests.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a37d345 and bddf29b.

📒 Files selected for processing (43)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (10 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 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 (4)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • CHANGELOG.md
  • plugins/transport-reactor-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-osx-x86_64.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (19)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java
  • server/src/main/java/org/opensearch/http/HttpRequest.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java
  • plugins/transport-reactor-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.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java
  • server/src/main/java/org/opensearch/bootstrap/Security.java
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
🧰 Additional context used
🧬 Code graph analysis (4)
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/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (9)
server/src/main/java/org/opensearch/index/search/SimpleQueryStringQueryParser.java (1)
  • Settings (317-450)
libs/core/src/main/java/org/opensearch/core/common/bytes/BytesArray.java (1)
  • BytesArray (48-151)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
server/src/main/java/org/opensearch/rest/BytesRestResponse.java (1)
  • BytesRestResponse (59-219)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)
  • KeyStoreUtils (26-83)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)
  • NettyAllocator (51-350)
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)
  • SslUtils (26-107)
server/src/main/java/org/opensearch/bootstrap/Bootstrap.java (1)
  • Bootstrap (89-495)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)
  • Netty4HttpClient (114-535)
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)
⏰ 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: Analyze (java)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: detect-breaking-change
  • GitHub Check: Mend Security Check
🔇 Additional comments (18)
plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1 (1)

1-1: LGTM!

SHA1 checksum file for the Netty QUIC native library (macOS aarch64) is correctly added as part of the HTTP/3 dependency additions.

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

50-65: Good backward-compatible refactoring for algorithm flexibility.

Clean approach: the no-arg createServerKeyStore() delegates to the parameterized overload with a sensible default (Algorithm.rsa2048), preserving backward compatibility while enabling algorithm flexibility for HTTP/3/QUIC testing.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (4)

176-184: HTTP/3 factory method looks correct.

Good additions:

  • Uses NioDatagramChannel for UDP transport (required for QUIC)
  • Uses NettyAllocator.getAllocator(true) to enable direct buffers (required for QUIC)
  • Properly wires CountDownLatchHandlerHttp3

Note: The secure=false parameter is somewhat misleading since HTTP/3 always uses TLS via QUIC, but this only affects the scheme header logic which has a separate issue (see below).


328-336: Good abstraction for channel preparation.

The generic AwaitableChannelInitializer<C extends Channel> with a prepare() hook is a clean way to support different transport protocols (TCP for HTTP/1.1 & HTTP/2, UDP+QUIC for HTTP/3) while maintaining a uniform request dispatch flow.


498-533: Verify HTTP/3 stream handling for multiple requests.

The prepare() method creates a single QuicStreamChannel which is then used to send all requests. In HTTP/3, each request typically uses its own stream for proper multiplexing. Sending multiple requests on a single stream may not work as expected with an HTTP/3 server.

For single-request tests this is fine, but for multi-request scenarios (e.g., the get(SocketAddress, String...) method with multiple URIs), this may need adjustment.

Consider whether multi-request tests are needed for HTTP/3, and if so, refactor to create a new stream per request:

// Alternative approach for multi-request support:
// Instead of returning one channel from prepare(), 
// could override the request dispatch logic for HTTP/3

507-531: Pipeline order is now correct.

The HTTP/3 pipeline follows the correct order:

  1. Http3FrameToHttpObjectCodec(false) - converts HTTP/3 frames to HTTP objects
  2. HttpContentDecompressor - handles content decompression
  3. HttpObjectAggregator - aggregates HTTP objects
  4. Response handler

This addresses the previous review feedback.

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

47-47: Client factory update is consistent with new API

Using ReactorHttpClient.create(Settings.EMPTY) correctly matches the new factory signature and preserves the existing test behavior.

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

83-101: Passing settings into ReactorHttpClient.create looks correct

Reusing the same settings object for both the server transport and ReactorHttpClient.create(settings) keeps test configuration coherent and matches the updated client API.

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

262-267: New HTTP/3 enable flag is well-scoped

SETTING_HTTP_HTTP3_ENABLED is a reasonable node-scoped boolean gate for HTTP/3; wiring to transports and documentation just needs to stay in sync with this key.

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

122-123: Streaming tests correctly adopt new client factory signature

Both tests now use ReactorHttpClient.create(false, Settings.EMPTY), which matches the updated API and maintains the intended non-secure streaming behavior.

Also applies to: 162-163

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

104-105: HTTP request size limit ITs use the new client factory correctly

Switching to ReactorHttpClient.create(false, Settings.EMPTY) in both tests aligns with the updated client API without changing the behavior of the in-flight request limiting checks.

Also applies to: 134-135

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

110-136: H3 stream/window settings and defaults look reasonable

The new SETTING_H3_MAX_STREAM_LOCAL_LENGTH, SETTING_H3_MAX_STREAM_REMOTE_LENGTH, and SETTING_H3_MAX_STREAMS provide explicit HTTP/3 flow-control tuning with sensible defaults (~1 MB per stream, 100 streams), which aligns connection limits in configureHttp3 with typical HTTP/3 expectations.

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

334-348: LGTM! Protocol selection logic is sound.

The randomProtocol method correctly:

  • Checks HTTP/3 availability via Http3.isHttp3Available()
  • Respects the SETTING_HTTP_HTTP3_ENABLED setting
  • Falls back to HTTP/1.1 and H2/H2C appropriately for secure/non-secure contexts
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1)

330-346: Pipeline configuration correctly adapted for HTTP/3.

The pipeline now properly uses Http3FrameToHttpObjectCodec as the first handler to convert QUIC/HTTP3 frames to HttpObjects before other handlers process them. The HTTP/1.x-specific codecs (HttpRequestDecoder, HttpResponseEncoder) have been correctly removed.

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

66-84: LGTM! QUIC/HTTP3 dependencies properly configured.

The build configuration correctly:

  • Adds QUIC codec dependencies (http3, classes-quic, native-quic)
  • Bundles native libraries for all major OS/architecture combinations
  • Uses runtimeOnly scope for platform-specific binaries
plugins/transport-reactor-netty4/build.gradle (1)

38-46: LGTM! Consistent QUIC dependency configuration.

The reactor-netty4 plugin build configuration mirrors the netty4 module's QUIC setup, ensuring consistent HTTP/3 support across transport implementations.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

187-285: Well-structured Expect header tests.

The test correctly validates:

  • 100-Continue support with valid content-length
  • 413 response for oversized payloads
  • 417 response for unsupported expectations

The continuation request pattern properly simulates real client behavior.


110-170: Proper TLS setup for HTTP/3 testing.

The test harness correctly:

  • Uses PKIX KeyManagerFactory with ECP384 algorithm
  • Provides SecureHttpTransportSettingsProvider with appropriate SSL configuration
  • Configures InsecureTrustManagerFactory for test purposes (acceptable in tests)

@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

❌ Gradle check result for bddf29b: 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

@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: 5

♻️ Duplicate comments (4)
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)

27-27: Exposing mutable DEFAULT_SSL_PROTOCOLS array remains a security concern.

This change still exposes a mutable array as public API, allowing any caller to modify TLS protocol versions at runtime (e.g., DEFAULT_SSL_PROTOCOLS[0] = "TLSv1"). The previous review comment correctly identified this as a security posture gap that breaks encapsulation.

The recommendation to keep the array private and provide a defensive-copy accessor (e.g., getDefaultSslProtocols()) should be implemented to prevent runtime mutation of security-critical TLS configuration.

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

273-317: Critical: Composite binding still has unresolved issues from previous review.

Two critical issues were flagged in previous reviews and appear unresolved:

  1. Lines 304-305: channel() returns null, which can cause NPE if callers invoke it
  2. Lines 269-270: If http11or2.bindNow() throws after http3Server binds successfully, the HTTP/3 server is not cleaned up, causing a resource leak

These issues remain from the previous review marked with ``.

Please address both issues:

  1. Return a valid channel from channel() (e.g., http11or2Server.channel()) or throw UnsupportedOperationException
  2. Wrap http11or2.bindNow() in try-catch to dispose http3Server on failure:
     final DisposableServer http3Server = http3Opt.get();
-    final DisposableServer http11or2Server = http11or2.bindNow();
+    final DisposableServer http11or2Server;
+    try {
+        http11or2Server = http11or2.bindNow();
+    } catch (Exception e) {
+        http3Server.disposeNow();
+        throw e;
+    }
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

349-368: Remove unused ServerChannelExceptionHandler class.

This class is defined but never instantiated or added to any pipeline. Either integrate it into configureServerChannelHandler() for proper server-level exception handling, or remove the dead code.

If this should handle server channel exceptions, add it to the QUIC codec's parent handler:

// In configureServerChannelHandler(), after building the QUIC codec:
ch.pipeline().addLast("server_exception_handler", new ServerChannelExceptionHandler(Netty4QuicServerTransport.this));

273-273: Security: InsecureQuicTokenHandler bypasses QUIC address validation.

This handler disables QUIC token validation which protects against address spoofing attacks (RFC 9000, Section 8). While acceptable for development, this must be replaced with a proper token handler before production use.

Consider adding a configuration option or TODO to track this:

+                            // TODO: Issue #XXXX - Replace with secure token handler before GA
+                            // InsecureQuicTokenHandler bypasses address validation (RFC 9000 Section 8)
                             .tokenHandler(InsecureQuicTokenHandler.INSTANCE)
🧹 Nitpick comments (4)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)

160-166: getAllocator(boolean) correctly unwraps NoDirectBuffers; consider clarifying API semantics

The conditional unwrapping of NoDirectBuffers to expose the underlying delegate when directBuffers is true looks correct and keeps existing callers (no-arg getAllocator()) unchanged, while enabling HTTP/3/QUIC to obtain a direct-buffer-capable allocator.

Two minor suggestions:

  • Consider renaming the parameter (e.g., requireDirectBuffers) and/or adding Javadoc to make it explicit that true will bypass the global “no direct buffers” choice, so future callers don’t pass true casually.
  • Optionally use the existing NoDirectBuffers#getDelegate() instead of accessing ndb.delegate directly, for consistency with the inner-class abstraction.

Please also confirm that overriding the “no direct buffers” behavior for HTTP/3 is acceptable in environments that explicitly configured heap-only buffers (or that HTTP/3 will be disabled there).

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

262-267: Consider enhancing the setting documentation.

The new SETTING_HTTP_HTTP3_ENABLED setting looks good with a safe default of false. However, the comment could be more informative about platform requirements and the QUIC protocol dependency.

Consider this enhancement to the comment:

-    // Enable HTTP/3 protocol if supported by the operating system and architecture
+    /**
+     * Enable HTTP/3 (QUIC) protocol support. HTTP/3 requires native QUIC libraries
+     * which are platform-dependent (check Netty QUIC documentation for supported OS/arch).
+     * Binds on UDP alongside TCP when enabled.
+     */
     public static final Setting<Boolean> SETTING_HTTP_HTTP3_ENABLED = Setting.boolSetting(
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1)

119-119: Add minimum value validation for SETTING_H3_MAX_STREAMS.

The setting allows any long value including 0 or negative numbers. Since HTTP/3 requires at least some concurrent streams to function, and the RFC recommends 100, consider adding a minimum bound.

-    public static final Setting<Long> SETTING_H3_MAX_STREAMS = Setting.longSetting("h3.max_streams", 100L, Property.NodeScope);
+    public static final Setting<Long> SETTING_H3_MAX_STREAMS = Setting.longSetting("h3.max_streams", 100L, 1L, Property.NodeScope);
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

577-597: Test validates UDP channel close but may not exercise QUIC-level timeout.

The test creates a raw UDP channel without performing a QUIC handshake. While it validates that the server closes idle connections, it doesn't test HTTP/3-specific read timeout behavior since no QUIC connection is established.

Consider using Netty4HttpClient.http3() with a delayed request to test read timeout at the HTTP/3 layer for more comprehensive coverage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bddf29b and 8a90e43.

📒 Files selected for processing (43)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (10 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 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)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (15)
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • 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-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java
  • modules/transport-netty4/build.gradle
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • CHANGELOG.md
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
🧰 Additional context used
🧬 Code graph analysis (7)
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/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/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/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/ssl/SecureReactorNetty4HttpServerTransportTests.java (3)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)
  • KeyStoreUtils (26-83)
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)
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/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1)
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)
  • ReactorNetty4HttpServerTransport (93-582)
⏰ 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-24.04-arm)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: detect-breaking-change
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: Analyze (java)
  • GitHub Check: Mend Security Check
🔇 Additional comments (32)
modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1 (1)

1-1: Checksum format looks correct

The file contains a single 40-character hex SHA-1 string with no extra whitespace, matching the expected format for these license checksum entries.

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

1-1: Verify the SHA-1 hash and dependency version against official sources.

Ensure this hash matches the official Netty distribution from Maven Central and confirm that version 4.2.7.Final is appropriate and free from known vulnerabilities.

Run the following script to verify the latest version and check for security advisories:

#!/bin/bash
# Check Maven Central for the latest version of netty-incubator-codec-native-quic
curl -s 'https://search.maven.org/solrsearch/select?q=g:io.netty.incubator+AND+a:netty-incubator-codec-native-quic&rows=1&wt=json' | jq -r '.response.docs[0].latestVersion'

# Check for Netty security advisories
gh api graphql -f query='
{
  securityVulnerabilities(first: 10, ecosystem: MAVEN, package: "io.netty.incubator:netty-incubator-codec-native-quic") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Additionally, verify the SHA-1 hash by downloading the JAR from Maven Central and computing its checksum:

#!/bin/bash
# Download the JAR and verify SHA-1
curl -L -o /tmp/netty-codec-native-quic.jar \
  'https://repo1.maven.org/maven2/io/netty/incubator/netty-incubator-codec-native-quic/4.2.7.Final/netty-incubator-codec-native-quic-4.2.7.Final-osx-x86_64.jar'

# Compute SHA-1
sha1sum /tmp/netty-codec-native-quic.jar | awk '{print $1}'

# Expected: f3679a6cc103292931098b1dc835ffb831e27368
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (2)

50-55: Good backward-compatible overload pattern.

The delegation to the new algorithm-parameterized overload with rsa2048 as default maintains existing behavior while enabling flexibility for HTTP/3 testing scenarios.


67-81: Algorithm parameter properly propagated to CertificateBuilder.

The implementation correctly passes the Algorithm parameter to the certificate builder and uses BouncyCastleFipsProvider consistently. The inline comment documenting required FIPS-approved algorithms (rsa2048, rsa3072, rsa4096, rsa8192, ecp256, ecp384) serves as clear guidance for callers of this method.

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

36-50: LGTM! Clean type generalization to support multiple transport implementations.

The refactoring from Netty4HttpServerTransport to AbstractHttpServerTransport enables this handler to work with both the existing Netty4 transport and the new QUIC/HTTP3 transport, which aligns well with the HTTP/3 support objectives.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (4)

176-184: LGTM! HTTP/3 client factory properly configured.

The HTTP/3 factory uses NioDatagramChannel (since QUIC runs over UDP) and enables buffer allocation, which is appropriate for datagram-based transport.


328-336: LGTM! Generic channel initializer supports multiple transport types.

The type parameter <C extends Channel> and the prepare() method enable proper handling of HTTP/3's two-phase channel setup (DatagramChannel → QuicChannel → QuicStreamChannel) while maintaining compatibility with HTTP/1.x and HTTP/2 transports.


483-496: Verify QUIC timeout and buffer sizes align with production requirements.

The QUIC client codec uses:

  • maxIdleTimeout: 5000ms
  • initialMaxData: 10MB
  • initialMaxStreamDataBidirectionalLocal: 1MB

These values appear suitable for testing, but ensure they align with expected production load and latency requirements.


507-532: LGTM! HTTP/3 request stream pipeline is correctly ordered.

The pipeline properly sequences:

  1. Http3FrameToHttpObjectCodec(false) — converts HTTP/3 frames to HttpObject
  2. HttpContentDecompressor — handles compression
  3. HttpObjectAggregator — aggregates chunks
  4. Response handler — processes FullHttpResponse

This addresses the past review concern about HTTP/1.x codecs being incorrectly placed in the HTTP/3 pipeline.

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

60-65: LGTM! HTTP/3 settings properly exposed.

The plugin correctly exposes HTTP/3 configuration settings (stream local/remote lengths and max streams) alongside the existing HTTP/2 cleartext setting, enabling runtime configuration of QUIC transport parameters.

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

47-47: LGTM! Test updated for Settings-based client API.

Passing Settings.EMPTY is appropriate for this test since it doesn't require custom HTTP/3 or transport configuration.

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

63-64: LGTM! HTTP/3 enum constant added.

The HTTP_3_0 addition follows the established pattern and enables HTTP/3 protocol version representation across the transport layer.

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

100-100: LGTM! API update correctly propagates settings.

The change correctly updates the client creation to pass the per-test settings (which includes HTTP port configuration) into the new ReactorHttpClient.create(Settings) API. This aligns with the HTTP/3 integration work and maintains proper test behavior.

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

122-122: LGTM! Streaming test client creation correctly updated.

Both client instantiations properly update to ReactorHttpClient.create(false, Settings.EMPTY), maintaining the compression-disabled behavior while adapting to the new Settings-aware API.

Also applies to: 162-162

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

104-104: LGTM! Integration test client creation properly updated.

Both test methods correctly update to the new API signature while preserving the compression-disabled configuration appropriate for these request size limit tests.

Also applies to: 134-134

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (4)

92-92: LGTM! ECC P-384 algorithm appropriate for test certificates.

The addition of Algorithm.ecp384 for test certificate generation uses elliptic curve cryptography with the P-384 curve, which provides strong security suitable for testing TLS connections.

Also applies to: 121-121


166-170: LGTM! Simplified SSLEngine creation is cleaner.

The refactored SSL engine creation directly builds the context and engine without the try-catch block. Since the method signature declares throws SSLException, exceptions will still propagate correctly to callers.


256-256: LGTM! HTTPS client creation correctly updated with settings.

All ReactorHttpClient.https() calls now properly pass the settings parameter, ensuring the secure client receives proper configuration including HTTP/3 enablement where applicable.

Also applies to: 363-363, 410-410, 471-471, 543-543, 560-560


295-298: LGTM! HTTP/3 test coverage properly integrated.

The changes correctly propagate HTTP/3 enablement through test scaffolding:

  • testBindUnavailableAddress preserves the HTTP/3 setting from the initial transport when creating the conflicting transport
  • testLargeCompressedResponse randomizes HTTP/3 to test both modes
  • createBuilderWithPort adds random HTTP/3 enablement for general test coverage

This ensures HTTP/3 paths are exercised during testing.

Also applies to: 450-452, 646-648

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

110-135: Verify the stream limit fix from previous review.

Past review comments indicated that stream limits of 1,000,000 KB were too large and should be 1 MB. The current code shows:

new ByteSizeValue(1000000, ByteSizeUnit.BYTES)

This is ~976 KB, which is close to the recommended 1 MB range. However, it would be clearer to use new ByteSizeValue(1, ByteSizeUnit.MB) as suggested in the previous review to avoid confusion about the unit.

Based on previous review feedback, please confirm whether the current values (1,000,000 BYTES ≈ 976 KB) are intentional or if they should be exactly 1 MB as originally suggested.


319-368: Verify maxData setting change from previous review.

Previous review indicated that using SETTING_HTTP_MAX_CHUNK_SIZE for QUIC's maxData was incorrect (8 KB is too small for connection-level flow control). Line 356 now shows:

.maxData(SETTING_HTTP_MAX_CONTENT_LENGTH.get(settings).getBytes())

This uses SETTING_HTTP_MAX_CONTENT_LENGTH (default 100 MB), which is much better than the previous 8 KB. However, this may still not be ideal since:

  • Connection-level maxData and max content length serve different purposes
  • The previous review suggested a dedicated QUIC-specific setting

Since the PR is marked [WIP] and this is an improvement over the original, it's reasonable to defer to a dedicated setting in a future iteration.

Please confirm whether using SETTING_HTTP_MAX_CONTENT_LENGTH for maxData is the intended final approach, or if a dedicated HTTP/3 setting is planned for a future commit.


48-48: LGTM! Imports correctly added for HTTP/3 support.

The new imports for Channel, QuicSslContextBuilder, Http3, and the static import of SETTING_HTTP_HTTP3_ENABLED are all necessary and correctly placed for the HTTP/3 integration.

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


370-370: LGTM! Method rename clarifies purpose.

Renaming configure() to configureHttp11orHttp2() makes the method's scope explicit and distinguishes it from the new configureHttp3() method.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

290-346: LGTM!

The HTTP/3 pipeline configuration is correctly structured with Http3FrameToHttpObjectCodec as the first handler to convert HTTP/3 frames to HTTP objects before other handlers process them.


370-439: LGTM!

The extension points and compression configuration are well-designed. The ZSTD exclusion is properly documented with clear rationale regarding NettyAllocator's direct buffer limitations.

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

162-162: LGTM!

Adding SegmentedDatagramPacket to ignoreMissingClasses is appropriate as this epoll-specific class is used for UDP GSO (Generic Segmentation Offload) and is only available on Linux with native epoll support.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (4)

109-180: LGTM!

The test setup and teardown are well-structured. Using InsecureTrustManagerFactory is acceptable for test scenarios, and the cleanup properly shuts down resources.


186-284: LGTM!

The Expect header tests are comprehensive, covering 100-continue, content-length limits, and unsupported expectations. Resource management with try-with-resources and explicit release() in finally blocks is correct.


286-326: LGTM!

The duplicate bind test correctly validates that attempting to bind to an already-used address throws BindHttpException with an appropriate message.


459-530: LGTM!

The CORS test comprehensively validates both pre-flight OPTIONS request handling and origin rejection for non-allowed origins.

server/src/main/java/org/opensearch/bootstrap/Security.java (1)

132-134: Verify the regex pattern handles all platform-specific Netty QUIC/HTTP3 native library JAR names.

The updated pattern now captures optional classifiers, which is necessary for platform-specific JARs. However, verify that the hardcoded platform prefixes cover all cases:

  1. Platform prefix coverage: The pattern only recognizes linux-, windows-, and osx- prefixes. If Netty QUIC native libraries use additional platform identifiers (e.g., macos-, darwin-, or aarch64- in the classifier), they may not be correctly parsed and could fail to load.

  2. Classifier matching limitation: The pattern [^-]+ assumes classifiers don't contain internal dashes (except for the platform prefix). While this works for most cases, it could break with unusual classifier formats.

  3. Impact on security policy: When group(1) is extracted (line 244), the filename is reconstructed and routed to a special codebase handling path. If the pattern fails to match JAR names with unknown platform identifiers, they may not receive the correct security permissions, potentially causing runtime failures.

Add unit tests with actual Netty QUIC native library JAR names to verify the pattern correctly matches all expected platform variants. Additionally, document which platform identifiers are supported and why others are excluded.

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

205-205: Settings-aware ReactorHttpClient usage is consistent and correct

All updated call sites now use ReactorHttpClient.create(settings) or ReactorHttpClient.create(Settings.EMPTY) and keep the client settings aligned with the server transport configuration. Lifecycle management via try‑with‑resources is intact, and the changes are a straightforward adaptation to the new factory API with no apparent behavioral regressions in these tests.

Also applies to: 310-310, 356-356, 412-412, 478-478, 541-541, 558-558

Comment on lines +386 to +388
assertThat(
new String(response.content().array(), Charset.forName("UTF-8")),
containsString("you sent a bad request and you should feel bad")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential UnsupportedOperationException if buffer is not array-backed.

Calling response.content().array() assumes the ByteBuf is heap-backed. If the allocator returns a direct buffer, this will throw UnsupportedOperationException.

Consider using ByteBufUtil.getBytes() which handles both heap and direct buffers:

-                    assertThat(
-                        new String(response.content().array(), Charset.forName("UTF-8")),
-                        containsString("you sent a bad request and you should feel bad")
-                    );
+                    assertThat(
+                        new String(ByteBufUtil.getBytes(response.content()), StandardCharsets.UTF_8),
+                        containsString("you sent a bad request and you should feel bad")
+                    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assertThat(
new String(response.content().array(), Charset.forName("UTF-8")),
containsString("you sent a bad request and you should feel bad")
assertThat(
new String(ByteBufUtil.getBytes(response.content()), StandardCharsets.UTF_8),
containsString("you sent a bad request and you should feel bad")
);
🤖 Prompt for AI Agents
In
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java
around lines 386 to 388, the test calls response.content().array() which can
throw UnsupportedOperationException for direct ByteBufs; replace that usage by
extracting bytes via ByteBufUtil.getBytes(response.content()) and construct the
String with StandardCharsets.UTF_8 so both heap and direct buffers are handled
safely and charset handling is explicit.

Comment on lines +426 to +438
try (
Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
Settings.EMPTY,
networkService,
bigArrays,
threadPool,
xContentRegistry(),
dispatcher,
clusterSettings,
new SharedGroupFactory(Settings.EMPTY),
secureHttpTransportSettingsProvider,
NoopTracer.INSTANCE
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Test uses Settings.EMPTY which may cause port binding issues.

Unlike other tests that use createSettings() to configure a random port range, this test passes Settings.EMPTY which relies on default port binding. This could cause flaky failures in CI environments due to port conflicts.

         try (
             Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
-                Settings.EMPTY,
+                createSettings(),
                 networkService,
                 bigArrays,
                 threadPool,
                 xContentRegistry(),
                 dispatcher,
                 clusterSettings,
-                new SharedGroupFactory(Settings.EMPTY),
+                new SharedGroupFactory(createSettings()),
                 secureHttpTransportSettingsProvider,
                 NoopTracer.INSTANCE
             )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try (
Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
Settings.EMPTY,
networkService,
bigArrays,
threadPool,
xContentRegistry(),
dispatcher,
clusterSettings,
new SharedGroupFactory(Settings.EMPTY),
secureHttpTransportSettingsProvider,
NoopTracer.INSTANCE
)
try (
Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
createSettings(),
networkService,
bigArrays,
threadPool,
xContentRegistry(),
dispatcher,
clusterSettings,
new SharedGroupFactory(createSettings()),
secureHttpTransportSettingsProvider,
NoopTracer.INSTANCE
)
🤖 Prompt for AI Agents
In
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java
around lines 426 to 438, the test constructs Netty4QuicServerTransport with
Settings.EMPTY which can cause port binding conflicts in CI; replace
Settings.EMPTY with a test settings instance that uses the same randomized port
range as other tests (e.g. call createSettings() or build Settings with the
ephemeral network port range used elsewhere) so the transport binds to a random
available port; update the constructor invocation to pass that settings object.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 3, 2025

❌ Gradle check result for 8a90e43: 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

@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

♻️ Duplicate comments (9)
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java (1)

161-162: Fix HTTP/3 protocol string to match Reactor Netty's format.

Reactor Netty's HttpServerRequest.protocol() returns "HTTP/3" (without the .0 suffix), so the condition protocol.equals("HTTP/3.0") will never match HTTP/3 requests. This causes the HTTP/3 branch to be unreachable.

-        } else if (protocol.equals("HTTP/3.0")) {
+        } else if (protocol.equals("HTTP/3")) {
             return HttpRequest.HttpVersion.HTTP_3_0;
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (2)

39-44: Close listener will be invoked multiple times.

The listener is attached to each closeContext, so it fires once per channel close rather than once when all channels have closed. If callers expect a single callback (e.g., for cleanup), this leads to duplicate operations.

Consider using CompletableFuture.allOf() to aggregate and trigger the listener only once when all channels are closed.


25-32: Add validation for null or empty channels array.

The constructor doesn't validate the input array. If channels is null, lines 27-30 will throw NullPointerException. If empty, getLocalAddress() at line 36 will throw 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 (2)

298-316: HTTP/3 server not cleaned up if HTTP/1.1/2 bind fails.

If http11or2.bindNow() (line 300) throws an exception after http3Server has successfully bound (line 299), the HTTP/3 server remains open, causing a resource leak and potentially blocking the port.

         final DisposableServer http3Server = http3Opt.get();
-        final DisposableServer http11or2Server = http11or2.bindNow();
+        final DisposableServer http11or2Server;
+        try {
+            http11or2Server = http11or2.bindNow();
+        } catch (Exception e) {
+            http3Server.disposeNow();
+            throw e;
+        }

         disposableServer = new DisposableServer() {

302-313: Returning null from channel() may cause NPE.

If any caller (logging, monitoring, or parent class methods) invokes channel() expecting a valid reference, this will result in a NullPointerException.

                 @Override
                 public Channel channel() {
-                    return null; /* not implemented */
+                    return http11or2Server.channel();
                 }
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)

308-314: Reconsider the setting used for HTTP/3 maxData.

The maxData parameter represents the connection-level flow-control limit for HTTP/3 (QUIC initial_max_data per RFC 9000), which is the aggregate maximum bytes permitted across all streams on the connection. Using SETTING_HTTP_MAX_CHUNK_SIZE here is semantically incorrect—this setting represents per-chunk size limits, not connection-level aggregates.

Consider using SETTING_HTTP_MAX_CONTENT_LENGTH or introducing a dedicated connection-level setting instead.

Based on past review comments, this issue was previously flagged but remains unresolved.

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

357-376: ServerChannelExceptionHandler is still defined but never used.

This class was flagged in a previous review as dead code. It's never instantiated or added to any pipeline. Either integrate it into the QUIC server channel pipeline for proper exception handling, or remove it entirely.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

386-390: Potential UnsupportedOperationException for direct buffers.

Using response.content().array() assumes the buffer is heap-backed. Use ByteBufUtil.getBytes() for compatibility with both heap and direct buffers, consistent with line 273.

                     assertThat(response.status(), equalTo(HttpResponseStatus.BAD_REQUEST));
                     assertThat(
-                        new String(response.content().array(), Charset.forName("UTF-8")),
+                        new String(ByteBufUtil.getBytes(response.content()), StandardCharsets.UTF_8),
                         containsString("you sent a bad request and you should feel bad")
                     );

427-439: Test uses Settings.EMPTY which may cause port binding issues.

This test passes Settings.EMPTY which relies on default port binding. Use createSettings() to configure a random port range and avoid flaky failures in CI due to port conflicts.

+        final Settings settings = createSettings();
         try (
             Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
-                Settings.EMPTY,
+                settings,
                 networkService,
                 bigArrays,
                 threadPool,
                 xContentRegistry(),
                 dispatcher,
                 clusterSettings,
-                new SharedGroupFactory(Settings.EMPTY),
+                new SharedGroupFactory(settings),
                 secureHttpTransportSettingsProvider,
                 NoopTracer.INSTANCE
             )
🧹 Nitpick comments (7)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)

160-166: New getAllocator(boolean directBuffers) looks correct; consider minor style/encapsulation tweaks

The behavior—returning the underlying allocator only when directBuffers is explicitly requested and ALLOCATOR is NoDirectBuffers—is a clean way to opt into direct buffers for HTTP/3/QUIC while preserving existing behavior for all other callers. No functional issues stand out.

A couple of small, optional refinements:

  • You can simplify the condition and avoid the explicit comparison:
if (directBuffers && ALLOCATOR instanceof NoDirectBuffers ndb) {
    return ndb.delegate; // Http3/Quic only supports direct buffers
}
  • Since NoDirectBuffers already exposes getDelegate(), you might prefer to use that instead of accessing the private field from the outer class, which keeps encapsulation a bit clearer:
if (directBuffers && ALLOCATOR instanceof NoDirectBuffers ndb) {
    return ndb.getDelegate();
}

Both are non‑blocking suggestions; the current implementation is fine as is.

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

54-76: Validate algorithm and align the contract with the FIPS comment

Because createServerKeyStore(Algorithm) is public in the test framework, a null or otherwise invalid algorithm will currently fail deeper in the stack with a less clear error. A small guard here would make misuse easier to diagnose:

-    public static KeyStore createServerKeyStore(Algorithm algorithm) throws Exception {
-        var serverCred = generateCert(algorithm);
+    public static KeyStore createServerKeyStore(Algorithm algorithm) throws Exception {
+        Objects.requireNonNull(algorithm, "algorithm must not be null");
+        var serverCred = generateCert(algorithm);

and add:

import java.util.Objects;

You might also consider documenting (or asserting in tests) that only FIPS‑approved algorithms are expected here, to match the comment in generateCert.

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

121-121: Consider making the keystore algorithm configurable or document the choice.

The keystore is now initialized with a hardcoded Algorithm.ecp384. While ECC P-384 is a valid choice for HTTP/3, consider whether this should be randomized or parameterized in tests to ensure broader algorithm coverage, especially since HTTP/3 may support different cipher suites.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

316-318: Unused method getRequestHandler().

This method is defined but never called anywhere in the codebase. Consider removing it or documenting its intended use as an extension point.


378-447: Code duplication with Netty4HttpServerTransport.

The createHeaderVerifier(), createDecompressor(), and defaultCompressionOptions() methods are duplicated from Netty4HttpServerTransport. Consider extracting these to a shared utility class or abstract base class to reduce maintenance burden.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

298-298: Inconsistent Settings usage in SharedGroupFactory.

The transport is created with initialSettings, but SharedGroupFactory uses Settings.EMPTY. For consistency, use initialSettings for both.

-                new SharedGroupFactory(Settings.EMPTY),
+                new SharedGroupFactory(initialSettings),
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

132-144: Generic AwaitableChannelInitializer wiring looks correct; prepare signature could be simplified later.

The change to have handlerFactory return AwaitableChannelInitializer<?> and to drive everything through await() + prepare(...) is consistent and keeps HTTP/1.1 and HTTP/2 behavior intact while enabling HTTP/3’s extra setup.

Right now prepare(Bootstrap clientBootstrap, Channel channel) ignores the clientBootstrap parameter in all implementations. If you don’t foresee a concrete need for it, you could drop that argument to keep the hook minimal and easier to maintain (or at least document its intended future use).

Also applies to: 328-336

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a90e43 and 07f5199.

📒 Files selected for processing (44)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (10 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 hunks)
  • server/src/main/java/org/opensearch/bootstrap/Security.java (1 hunks)
  • server/src/main/java/org/opensearch/common/settings/ClusterSettings.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 (3)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (23)
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • server/src/main/java/org/opensearch/http/HttpTransportSettings.java
  • server/src/main/java/org/opensearch/http/HttpRequest.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4BadRequestTests.java
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-classes-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-linux-aarch_64.jar.sha1
  • CHANGELOG.md
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • modules/transport-netty4/build.gradle
🧰 Additional context used
🧬 Code graph analysis (6)
server/src/main/java/org/opensearch/common/settings/ClusterSettings.java (1)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
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/ReactorNetty4HttpRequestSizeLimitIT.java (1)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
  • ReactorHttpClient (74-350)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (3)
  • ChannelHandler (543-562)
  • Netty4HttpServerTransport (130-635)
  • HttpChannelHandler (364-541)
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/test/java/org/opensearch/http/reactor/netty4/ReactorHttpClient.java (1)
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: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: detect-breaking-change
  • GitHub Check: Analyze (java)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: Mend Security Check
🔇 Additional comments (26)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)

50-52: Delegation to the new overload preserves existing behavior

Using createServerKeyStore(Algorithm.rsa2048) as the default keeps the previous RSA‑2048 behavior while exposing a more flexible overload; this looks good.

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

110-136: HTTP/3 stream settings look reasonable.

The settings now use ByteSizeUnit.BYTES with 1,000,000 bytes (~1 MB) per stream, which aligns with typical QUIC implementations (1–10 MB range). The max streams default of 100 matches HTTP/3 recommendations.


319-368: HTTP/3 configuration looks well-structured.

The method properly:

  • Checks both runtime availability (Http3.isHttp3Available()) and the setting toggle
  • Reuses the existing SecureHttpTransportSettingsProvider infrastructure
  • Applies appropriate QUIC/HTTP3 settings including flow control limits
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java (2)

122-122: LGTM!

The test correctly adapts to the new ReactorHttpClient.create(boolean, Settings) API signature.


162-162: LGTM!

Consistent with the API change for ReactorHttpClient.

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

104-104: LGTM!

The test correctly adapts to the new ReactorHttpClient.create(boolean, Settings) API signature.


134-134: LGTM!

Consistent API usage with Settings.EMPTY for non-HTTP/3 testing scenarios.

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

205-205: LGTM! API alignment looks correct.

All test client instantiation calls have been updated to pass the required Settings parameter, correctly using either the test-specific settings or Settings.EMPTY as appropriate.

Also applies to: 310-310, 356-356, 412-412, 478-478, 541-541, 558-558

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (3)

256-256: LGTM! HTTPS client creation updated correctly.

All secure client instantiations properly use ReactorHttpClient.https(settings), aligning with the new API that requires Settings for protocol selection.

Also applies to: 363-363, 410-410, 471-471, 543-543, 560-560


295-298: Good practice: Preserving HTTP/3 setting for consistent test behavior.

Copying the SETTING_HTTP_HTTP3_ENABLED value from initialSettings ensures both transport instances have the same protocol configuration, which is essential for reproducing the bind conflict correctly.


646-648: Appropriate test randomization for HTTP/3 coverage.

Randomly enabling HTTP/3 in the test settings builder ensures tests exercise both HTTP/3-enabled and HTTP/3-disabled code paths, improving coverage.

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

96-113: LGTM! API updated to support Settings-driven protocol selection.

The constructor and factory methods correctly propagate Settings through the client initialization, enabling deterministic protocol selection based on configuration rather than per-instance randomization.


284-292: LGTM! HTTP/1.1 SSL context configured correctly.

The HTTP/1.1 secure path properly uses Http11SslContextSpec.forClient() with appropriate trust manager configuration and handshake timeout.


293-300: LGTM! HTTP/2 SSL context configured correctly.

The HTTP/2 secure path properly uses Http2SslContextSpec.forClient() with protocol array [HTTP11, H2] for ALPN negotiation, appropriate trust manager, and handshake timeout.


317-322: LGTM! Non-secure protocol selection is correct.

The cleartext path appropriately uses HTTP11 for HTTP/1.1-only mode and [HTTP11, H2C] for HTTP/2 cleartext with HTTP/1.1 fallback.


330-332: LGTM! Protocol check correctly refactored.

The useHttp11only() method now correctly checks the protocol field state rather than a separate boolean flag, maintaining consistency with the Settings-driven protocol selection.


334-348: LGTM! Protocol randomization correctly accounts for HTTP/3 availability and settings.

The random protocol selection appropriately:

  • Checks both HTTP/3 availability (Http3.isHttp3Available()) and configuration (SETTING_HTTP_HTTP3_ENABLED)
  • Provides appropriate protocol arrays for secure (HTTP11/H2/HTTP3) and non-secure (HTTP11/H2C) scenarios
  • Uses test randomization for coverage
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (4)

186-285: LGTM!

The expect header tests are well-structured with proper use of createSettings() for random port binding and Netty4HttpClient.http3() for HTTP/3 client testing.


461-531: LGTM!

The CORS test properly exercises both pre-flight and forbidden origin scenarios with correct settings configuration.


601-607: LGTM!

The helper methods follow established patterns for test port configuration.


577-594: Read timeout test may not properly exercise QUIC server timeout.

This test creates a raw UDP socket to the QUIC server without performing a QUIC handshake. Since UDP is connectionless and the QUIC protocol requires a handshake to establish streams, the server-side read timeout may not trigger as expected. Consider establishing a proper QUIC connection first (if Netty4HttpClient.http3() or similar is available) and then not sending requests, or verify this test intentionally validates server behavior against non-QUIC UDP packets.

server/src/main/java/org/opensearch/common/settings/ClusterSettings.java (1)

390-428: HTTP/3 enablement setting correctly wired into cluster settings.

Adding HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED to BUILT_IN_CLUSTER_SETTINGS is consistent with how other HTTP transport settings are exposed and should allow cluster‑level toggling without issues.

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

162-162: Verify consistency of SegmentedDatagramPacket in ignoreMissingClasses configuration.

Adding io.netty.channel.epoll.SegmentedDatagramPacket to ignoreMissingClasses should match how other optional, platform-specific Netty epoll/kqueue/uring classes are handled to avoid false positives when native implementations aren't available. Confirm this pattern is consistently applied across similar optional classes in the configuration.


36-46: Verify classifier naming for QUIC native artifacts.

Maven Central confirms io.netty:netty-codec-native-quic:4.2.7.Final exists with platform-specific classifiers, but the web search results show Maven Central uses linux-aarch64 and osx-aarch64 (no underscore), whereas the build.gradle snippet shows linux-aarch_64 and osx-aarch_64 (with underscore). Confirm that Gradle's dependency resolution correctly handles the classifier names as specified in lines 36–46; if the underscore format is incorrect, artifact resolution may fail at runtime.

The remaining aspects—API dependencies on libs.netty.codec.classes.quic and libs.netty.codec.native.quic, and the audit ignore entry for io.netty.channel.epoll.SegmentedDatagramPacket—could not be verified against the actual codebase due to repository access constraints.

gradle/libs.versions.toml (1)

152-153: Netty QUIC version wiring looks correct and consistent.

Both io.netty:netty-codec-native-quic:4.2.7.Final and io.netty:netty-codec-classes-quic:4.2.7.Final are published artifacts and are used by other projects at this version, so pointing them at version.ref = "netty" (4.2.7.Final) is appropriate and keeps the Netty stack aligned.

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

1-1: Verify SHA‑1 matches the actual netty-codec-native-quic JAR.

The format looks correct, but please confirm this hash was generated from the exact netty-codec-native-quic-4.2.7.Final.jar file you ship, to keep license/audit checks reliable.

You can verify with:

JAR="netty-codec-native-quic-4.2.7.Final.jar"
EXPECTED="d6a7141d5fab45c8d2f6c646965f2dd53a43b41e"
ACTUAL=$(sha1sum "$JAR" | awk '{print $1}')
test "$ACTUAL" = "$EXPECTED" && echo "SHA1 OK" || echo "SHA1 MISMATCH"

@github-actions
Copy link
Contributor

github-actions bot commented Dec 5, 2025

❌ Gradle check result for 07f5199: 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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

197-197: Inverted scheme header logic—sets "http" when secure is true.

The ternary condition is backwards. When secure is true, the scheme should be "https".

-            httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "http" : "https");
+            httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "https" : "http");
♻️ Duplicate comments (12)
CHANGELOG.md (1)

39-40: ** Fix duplicate entry and malformed markdown links in CHANGELOG.**

Line 39 duplicates line 35 (identical text and PR number for pull-based ingestion). Additionally, both lines 39–40 have malformed markdown: they end with mismatched brackets ] instead of ).

Apply this diff:

- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)]
- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017)]
+ Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017))

This removes the duplicate ingestion line and corrects the HTTP/3 link syntax.

gradle/libs.versions.toml (1)

152-153: ** Fix netty-codec-classes-quic version mismatch — artifact unavailable at 4.2.7.Final.**

The artifact io.netty:netty-codec-classes-quic is not published at version 4.2.7.Final on Maven Central; the latest available release is 4.2.6.Final. Line 153 must use a concrete version to avoid dependency resolution failure.

Apply this diff:

  netty-codec-native-quic = { group = "io.netty", name = "netty-codec-native-quic", version.ref = "netty" }
- netty-codec-classes-quic = { group = "io.netty", name = "netty-codec-classes-quic", version.ref = "netty" }
+ netty-codec-classes-quic = { group = "io.netty", name = "netty-codec-classes-quic", version = "4.2.6.Final" }
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java (2)

39-44: Listener invoked multiple times; use composite approach.

The same listener is added to every closeContext, so it will be called once for each channel that closes rather than once when all channels have closed. This violates the expected contract of a composite channel.

As noted in the previous review, consider using an aggregate close context that completes only when all channels are closed, or use atomic counters to invoke the listener exactly once.


24-32: Add input validation to prevent runtime exceptions.

The constructor does not validate the channels parameter. If channels is null or empty, subsequent calls to getLocalAddress() (line 36) or toString() (line 65) will throw exceptions.

Apply this diff to add validation:

 @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;
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

181-189: HTTP/3 still only supports a single request per client instance due to single-stream reuse.

The prepare() method returns one QuicStreamChannel, but sendRequests() iterates all requests over it. Per RFC 9114, each HTTP/3 request requires its own stream. The past review suggested adding a guard or opening new streams per request.

This remains unaddressed—tests passing multiple requests via http3() would violate the spec.

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

161-162: Fix the HTTP/3 protocol string to match Reactor Netty's format.

The protocol check uses "HTTP/3.0", but Reactor Netty's HttpServerRequest.protocol() returns "HTTP/3" (without the ".0" suffix). This causes the HTTP/3 branch to never execute.

Based on past review findings (web search confirmed), change the string to:

-        } else if (protocol.equals("HTTP/3.0")) {
+        } else if (protocol.equals("HTTP/3")) {
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (2)

302-313: Returning null from channel() may cause NPE.

The anonymous DisposableServer returns null for channel(). If any downstream code invokes channel() expecting a valid reference (for logging, monitoring, or internal operations), it will result in a NullPointerException.

Consider returning one of the underlying channels or throwing UnsupportedOperationException:

 @Override
 public Channel channel() {
-    return null; /* not implemented */
+    return http11or2Server.channel(); // or throw UnsupportedOperationException
 }

294-317: Exception handling issue: HTTP/3 server not cleaned up if HTTP/1.1/2 bind fails.

If http11or2.bindNow() (line 300) throws an exception after http3Server has successfully bound (line 299), the HTTP/3 server remains bound and is not cleaned up, leading to a resource leak.

Wrap the second bind in a try-catch:

 final DisposableServer http3Server = http3Opt.get();
-final DisposableServer http11or2Server = http11or2.bindNow();
+final DisposableServer http11or2Server;
+try {
+    http11or2Server = http11or2.bindNow();
+} catch (Exception e) {
+    http3Server.disposeNow();
+    throw e;
+}
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

357-376: Remove or integrate unused ServerChannelExceptionHandler.

This class is never instantiated or added to any pipeline, making it dead code. If server-channel-level exception handling is needed, integrate it into configureServerChannelHandler(). Otherwise, remove it to reduce maintenance burden.

If integration is intended, consider adding it to the parent channel in configureServerChannelHandler():

// After adding the QUIC server codec:
ch.pipeline().addLast("server_exception_handler", new ServerChannelExceptionHandler(Netty4QuicServerTransport.this));

266-288: Security: InsecureQuicTokenHandler remains a production risk.

Line 274 still uses InsecureQuicTokenHandler.INSTANCE, which was flagged in previous reviews. QUIC token validation helps prevent address spoofing and amplification attacks. While acceptable for development, this should be replaced with a proper token handler before production use.

Consider implementing a secure token handler or adding a configuration flag:

+                           // TODO: Implement secure token handler for production (RFC 9000 §8)
+                           // Current insecure handler acceptable only for development/testing
                            .tokenHandler(InsecureQuicTokenHandler.INSTANCE)

Alternatively, introduce a node-scoped boolean setting to control this behavior, defaulting to a secure implementation in production.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

386-389: Potential UnsupportedOperationException with direct buffers.

Line 387 uses response.content().array() which assumes a heap-backed ByteBuf. If the allocator returns a direct buffer, this throws UnsupportedOperationException.

Apply this fix to handle both heap and direct buffers:

-                   assertThat(
-                       new String(response.content().array(), Charset.forName("UTF-8")),
-                       containsString("you sent a bad request and you should feel bad")
-                   );
+                   assertThat(
+                       new String(ByteBufUtil.getBytes(response.content()), StandardCharsets.UTF_8),
+                       containsString("you sent a bad request and you should feel bad")
+                   );

426-438: Potential port binding conflicts in CI environments.

Lines 428 and 435 use Settings.EMPTY, which relies on default port binding and can cause flaky test failures due to port conflicts. Other tests use createSettings() to bind to random available ports.

Apply this fix to use randomized port ranges:

        try (
            Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
-               Settings.EMPTY,
+               createSettings(),
                networkService,
                bigArrays,
                threadPool,
                xContentRegistry(),
                dispatcher,
                clusterSettings,
-               new SharedGroupFactory(Settings.EMPTY),
+               new SharedGroupFactory(createSettings()),
                secureHttpTransportSettingsProvider,
                NoopTracer.INSTANCE
            )
🧹 Nitpick comments (6)
plugins/transport-reactor-netty4/build.gradle (1)

42-46: Fix inconsistent dependency declaration — use library references instead of hardcoded coordinates.

Lines 42–46 use hardcoded artifact coordinates for platform-specific native binaries instead of referencing the library catalog. For consistency and maintainability, these should reference the library definition from libs.versions.toml (similar to lines 38–39) by using a library reference with appropriate classifiers, or define a separate library entry for each platform variant.

Additionally, verify that the io.netty groupId is correct (previous feedback suggests io.netty.incubator may be the correct namespace for QUIC artifacts).

One option is to avoid the platform-specific runtimeOnly declarations entirely if Gradle can automatically select the correct classifier based on the build platform. Alternatively, consider using Gradle's built-in platform resolution or a custom configuration that selects the artifact dynamically.

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

46-54: Consider enhanced for-loop for readability.

The logic correctly returns false if any channel is closed. You may simplify with an enhanced for-loop:

 @Override
 public boolean isOpen() {
-    for (int i = 0; i < channels.length; ++i) {
-        if (channels[i].isOpen() == false) {
+    for (Channel channel : channels) {
+        if (!channel.isOpen()) {
             return false;
         }
     }
     return true;
 }

56-61: Consider enhanced for-loop for readability.

The close logic is correct. For consistency and readability, consider using an enhanced for-loop:

 @Override
 public void close() {
-    for (int i = 0; i < channels.length; ++i) {
-        channels[i].close();
+    for (Channel channel : channels) {
+        channel.close();
     }
 }
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

523-540: Consider moving latch.countDown() inside the if block for consistency.

The latch.countDown() at line 532 executes for all HttpObject messages, not just FullHttpResponse. While HttpObjectAggregator should only emit FullHttpResponse, if any other message type slips through, the latch would decrement without adding a response to the collection—potentially causing the test to complete prematurely with missing responses.

For defensive consistency (and to match the expected 1:1 relationship between requests and responses):

                     ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpObject>() {
                         @Override
                         protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
                             if (msg instanceof FullHttpResponse ht) {
                                 // We copy the buffer manually to avoid a huge allocation on a pooled allocator. We have
                                 // a test that tracks huge allocations, so we want to avoid them in this test code.
                                 ByteBuf newContent = Unpooled.copiedBuffer(ht.content());
                                 content.add(ht.replace(newContent));
+                                latch.countDown();
                             }
-                            latch.countDown();
                         }
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)

354-360: HTTP/3 settings configuration looks good, but consider a dedicated maxData setting.

The HTTP/3 QUIC settings are properly configured. Using SETTING_HTTP_MAX_CONTENT_LENGTH for maxData is semantically reasonable, as both are connection-level limits. However, maxData is a QUIC flow-control parameter (aggregate byte limit across all streams), while MAX_CONTENT_LENGTH is an HTTP message size limit. They serve different purposes.

Consider introducing a dedicated setting like SETTING_HTTP3_MAX_CONNECTION_DATA with a default in the 10–25 MB range (typical for QUIC implementations) to independently tune flow control without coupling it to content length limits.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

577-592: Consider testing HTTP/3 read timeout at the application layer.

The test creates a raw UDP datagram channel and waits for closure without performing any HTTP/3/QUIC handshake. This tests UDP-level timeout behavior but may not properly exercise the HTTP/3 application-layer read timeout logic.

For more realistic HTTP/3 testing, consider using Netty4HttpClient.http3() to establish a proper QUIC connection and then let it idle:

try (Netty4HttpClient client = Netty4HttpClient.http3()) {
    // Connect but don't send any data to trigger read timeout
    // Monitor for connection closure or timeout exception
}

Alternatively, if low-level UDP timeout testing is intended, add a comment explaining the rationale.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07f5199 and 36cda04.

📒 Files selected for processing (44)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (13 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 hunks)
  • server/src/main/java/org/opensearch/bootstrap/Security.java (1 hunks)
  • server/src/main/java/org/opensearch/common/settings/ClusterSettings.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)
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-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 (24)
  • server/src/main/java/org/opensearch/common/settings/ClusterSettings.java
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • server/src/main/java/org/opensearch/http/HttpRequest.java
  • 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-osx-aarch_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • server/src/main/java/org/opensearch/http/HttpTransportSettings.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • server/src/main/java/org/opensearch/bootstrap/Security.java
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java
  • plugins/transport-reactor-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.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
🧰 Additional context used
🧬 Code graph analysis (3)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (3)
libs/core/src/main/java/org/opensearch/core/common/bytes/BytesArray.java (1)
  • BytesArray (48-151)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)
  • KeyStoreUtils (26-83)
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)
  • SslUtils (26-107)
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 (77-353)
plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1)
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)
  • ReactorNetty4HttpServerTransport (93-582)
⏰ 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-24.04-arm)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, macos-15)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (25, macos-15-intel)
  • 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, macos-15)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: detect-breaking-change
  • GitHub Check: Analyze (java)
  • GitHub Check: Mend Security Check
🔇 Additional comments (34)
modules/transport-netty4/build.gradle (2)

66-68: Verify Netty QUIC artifact coordinates are correct.

The dependencies reference io.netty:netty-codec-native-quic and io.netty:netty-codec-classes-quic. Previous feedback noted that Netty QUIC artifacts may be published under io.netty.incubator with different naming (e.g., io.netty.incubator:netty-incubator-codec-native-quic). Confirm that the io.netty groupId coordinates are valid and resolve correctly on Maven Central, or update to use the incubator coordinates if necessary.


80-84: Verify native QUIC artifact classifier resolution.

The platform-specific runtimeOnly declarations reference standard platform classifiers. Confirm these match the published artifacts on Maven Central and that the build system correctly selects the appropriate classifier for each target platform during dependency resolution.

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

38-39: Approve QUIC library API dependencies (subject to artifact coordinate verification).

The use of library references from libs.versions.toml is correct and maintains consistency with the dependency catalog pattern.

Confirm that the artifact coordinates and versions defined in libs.versions.toml (lines 152–153) resolve correctly on Maven Central.


162-162: Approve addition of missing QUIC-related class to audit configuration.

The inclusion of io.netty.channel.epoll.SegmentedDatagramPacket in the missing classes list is appropriate for QUIC support and aligns with similar additions in the netty4 transport module.

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

34-37: Delegation to first channel's address is reasonable for composite binding.

The method returns the local address of the first channel, which is appropriate for a composite server channel where all channels share the same logical bind address (but may differ by protocol, e.g., HTTP/2 vs HTTP/3).


63-66: String representation is clear and useful.

The toString method provides a concise representation of the composite channel, delegating to the first channel's address as expected.

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

50-52: LGTM! Good backward compatibility pattern.

The delegation to the new overload with a sensible default (Algorithm.rsa2048) maintains backward compatibility while enabling algorithm customization.


67-67: LGTM! Signature correctly updated.

The signature change properly enables algorithm parameterization for certificate generation.


75-75: LGTM! Algorithm parameter correctly applied.

The certificate builder now uses the provided algorithm parameter, enabling the intended customization for different certificate types (e.g., RSA vs. ECC for HTTP/3 support).


54-65: Validate algorithm compliance in FIPS mode.

When FIPS mode is enabled (line 56), the provided algorithm must be FIPS-approved. The comment on lines 71-72 explicitly lists approved algorithms (rsa2048, rsa3072, rsa4096, rsa8192, ecp256, ecp384), but there is no runtime validation to ensure the caller respects this constraint. Passing a non-compliant algorithm in FIPS mode could violate security requirements.

Consider adding validation to ensure only FIPS-approved algorithms are used when FIPS mode is enabled.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (4)

108-114: LGTM!

The imports for HTTP/3, QUIC, and H3 settings are appropriate for the new functionality.


234-234: Scheme logic is correct here.

Note: This correctly uses secure ? "https" : "http", which confirms the inverted logic at lines 197 and 210 are bugs.


335-343: Clean abstraction for protocol-specific channel preparation.

The prepare() hook allows HTTP/3 to set up QUIC channels before sending, while HTTP/1.1 and HTTP/2 use the default pass-through behavior.


488-505: LGTM!

Using Settings.EMPTY to obtain default values is appropriate for test code. The QUIC client codec configuration correctly applies the H3 stream settings from the server transport's constants.

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

60-65: LGTM! HTTP/3 settings properly exposed.

The plugin correctly exposes the new H2C and HTTP/3-related settings through getSettings(), following the standard plugin pattern. The settings are properly scoped and align with the HTTP/3 integration.

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

17-17: LGTM! Test updated to match new API signature.

The test correctly updates the ReactorHttpClient.create() call to accept a Settings parameter, using Settings.EMPTY as a sensible default. This aligns with the broader API changes enabling Settings-driven HTTP/3 configuration.

Also applies to: 47-47

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

104-104: LGTM! Test correctly updated for new API.

Both test methods properly use ReactorHttpClient.create(false, Settings.EMPTY) to create the HTTP client with compression disabled and default settings. The change is consistent with the new Settings-aware API.

Also applies to: 134-134

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

205-205: LGTM! Comprehensive test updates for Settings-aware API.

All test methods correctly propagate Settings through ReactorHttpClient construction. The tests appropriately use either test-specific settings (from createSettings()) or Settings.EMPTY when no custom configuration is needed. This enables proper HTTP/3 testing when enabled via settings.

Also applies to: 310-310, 356-356, 412-412, 478-478, 541-541, 558-558

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (4)

92-92: LGTM! ECC P-384 certificate appropriate for HTTP/3 testing.

Using Algorithm.ecp384 (ECC P-384) for test certificate generation is a good choice, providing strong security and compatibility with HTTP/3/QUIC requirements.

Also applies to: 121-121


166-170: LGTM! SSL engine construction follows correct pattern.

The SSL context and engine initialization properly chains SslContextBuilder.forServer() with the key manager factory and trust manager, then creates the engine with the appropriate allocator. This is the correct approach for secure transport setup in tests.


295-298: LGTM! HTTP/3 settings properly integrated into secure transport tests.

The tests correctly propagate HTTP/3 enablement settings:

  • testBindUnavailableAddress ensures consistent HTTP/3 configuration across transport instances
  • testLargeCompressedResponse randomly enables HTTP/3 for coverage
  • createBuilderWithPort() helper randomizes HTTP/3 by default, providing comprehensive test coverage

Also applies to: 450-452, 646-648


256-256: LGTM! Secure client creation properly updated.

All secure test scenarios correctly use ReactorHttpClient.https(settings), ensuring the HTTPS client is configured with the appropriate settings for each test context. This enables proper HTTP/3-over-TLS testing when configured.

Also applies to: 363-363, 410-410, 471-471, 543-543, 560-560

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

110-135: LGTM! HTTP/3 stream settings have reasonable defaults.

The HTTP/3 settings are properly configured:

  • Stream local/remote lengths: 1,000,000 bytes (~1 MB per stream)
  • Max concurrent streams: 100

These values align with typical QUIC implementations (1–10 MB per stream) and the HTTP/3 standard's recommendation of at least 100 concurrent bidirectional streams for performance.


370-454: LGTM! Method renamed for clarity.

Renaming configure() to configureHttp11orHttp2() improves code clarity by explicitly distinguishing it from the new configureHttp3() method. The functionality remains unchanged and correct.


48-48: LGTM! Necessary imports added for HTTP/3 support.

The new imports properly support HTTP/3 integration:

  • Channel for composite server channel handling
  • QuicSslContextBuilder for HTTP/3 SSL configuration
  • Http3 for availability checking
  • SETTING_HTTP_HTTP3_ENABLED for feature gating

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

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

17-17: LGTM! Settings-based state properly introduced.

Adding the Settings field and protocol field enables deterministic, Settings-driven configuration instead of per-instance randomization. This is a good architectural improvement.

Also applies to: 80-81


99-116: LGTM! Constructor and factory methods properly refactored.

The new API surface correctly requires Settings for all client construction paths:

  • Constructor initializes protocol via randomProtocol(secure, settings)
  • Factory methods (create, https) consistently propagate Settings
  • Clear separation between secure and non-secure variants

337-351: LGTM! Protocol selection logic is well-designed.

The randomProtocol() method properly:

  • Gates HTTP/3 on both availability (Http3.isHttp3Available()) and configuration (SETTING_HTTP_HTTP3_ENABLED)
  • Selects appropriate protocols for secure (HTTP/1.1, H2, HTTP/3) vs. non-secure (HTTP/1.1, H2C) contexts
  • Provides randomized test coverage across protocols

59-59: LGTM! HTTP/3 dependencies properly imported.

The necessary imports for HTTP/3 client support are in place:

  • Http3SslContextSpec for HTTP/3 SSL configuration
  • Http3 for availability checks
  • HTTP/3 settings constants for configuration

Also applies to: 63-63, 66-70


279-326: LGTM! HTTP/3 client configuration correctly implemented.

The createClient() method properly handles protocol-specific configuration:

HTTP/3 SSL context fixed: Line 308 correctly uses configure(s -> s.trustManager(...)) without calling .build() inside the lambda (past issue resolved).

maxData setting fixed: Line 313 now uses SETTING_HTTP_MAX_CONTENT_LENGTH instead of the incorrect SETTING_HTTP_MAX_CHUNK_SIZE (past issue resolved).

The protocol branching (HTTP/1.1, H2, HTTP/3) is clean, and each path configures the appropriate SSL context spec and protocol settings.


333-335: LGTM! Method updated to reflect protocol state.

The useHttp11only() method correctly checks whether the current protocol is HTTP/1.1, replacing the old field-based approach with protocol-aware logic.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

98-120: LGTM: HTTP/3 settings are well-defined.

The three HTTP/3-specific settings (max stream local/remote length and max streams) have reasonable defaults aligned with HTTP/3 specifications. The documentation clearly explains their purpose.


337-354: LGTM: HTTP/3 pipeline correctly configured.

The pipeline properly places Http3FrameToHttpObjectCodec first to convert HTTP/3 frames before other handlers process them. The subsequent handlers (aggregator, compression, request/response handling) are correctly ordered.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

109-180: LGTM: Test setup properly configured for HTTP/3/QUIC.

The setup correctly initializes SSL/TLS infrastructure with an ecp384 certificate (FIPS-approved algorithm) and provides appropriate test fixtures. Teardown properly cleans up all resources.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 5, 2025

❌ Gradle check result for 36cda04: 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

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java (1)

215-226: Fix HTTP/2/HTTP/3 detection – current equals("HTTP/2.0") / equals("HTTP/3.0") never match.

request.protocolVersion() is a Netty HttpVersion; its equals method returns false unless the argument is another HttpVersion instance. Comparing to String literals is always false, so HTTP/2 or HTTP/3 requests will incorrectly fall through to the "Unexpected http protocol version" exception.

Use protocolName() and majorVersion() instead:

     @Override
     public HttpVersion protocolVersion() {
-        if (request.protocolVersion().equals(io.netty.handler.codec.http.HttpVersion.HTTP_1_0)) {
+        io.netty.handler.codec.http.HttpVersion v = request.protocolVersion();
+        if (v.equals(io.netty.handler.codec.http.HttpVersion.HTTP_1_0)) {
             return HttpRequest.HttpVersion.HTTP_1_0;
-        } else if (request.protocolVersion().equals(io.netty.handler.codec.http.HttpVersion.HTTP_1_1)) {
+        } else if (v.equals(io.netty.handler.codec.http.HttpVersion.HTTP_1_1)) {
             return HttpRequest.HttpVersion.HTTP_1_1;
-        } else if (request.protocolVersion().equals("HTTP/2.0")) {
-            return HttpRequest.HttpVersion.HTTP_2_0;
-        } else if (request.protocolVersion().equals("HTTP/3.0")) {
-            return HttpRequest.HttpVersion.HTTP_3_0;
+        } else if ("HTTP".equals(v.protocolName()) && v.majorVersion() == 2) {
+            return HttpRequest.HttpVersion.HTTP_2_0;
+        } else if ("HTTP".equals(v.protocolName()) && v.majorVersion() == 3) {
+            return HttpRequest.HttpVersion.HTTP_3_0;
         } else {
             throw new IllegalArgumentException("Unexpected http protocol version: " + request.protocolVersion());
         }
     }
plugins/transport-reactor-netty4/build.gradle (1)

32-55: QUIC native dependency coordinates are incorrect and will not resolve.

The runtimeOnly declarations use wrong Maven coordinates. The actual Netty QUIC artifacts use io.netty.incubator as groupId:

// Incorrect (will not resolve):
runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:linux-x86_64"

// Should be:
runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.netty}:linux-x86_64"

The same applies to all platform classifiers. Also verify that the api dependencies (libs.netty.codec.classes.quic, libs.netty.codec.native.quic) in the version catalog point to the correct io.netty.incubator group and artifact names (netty-incubator-codec-classes-quic, netty-incubator-codec-native-quic), as Netty QUIC is maintained as an incubator project separate from core Netty.

♻️ Duplicate comments (9)
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)

27-27: Previous security concern remains unaddressed: mutable array exposed as public API.

The issue flagged in the previous review has not been resolved. Exposing DEFAULT_SSL_PROTOCOLS as a public static final array still allows any caller to mutate the array elements (e.g., DEFAULT_SSL_PROTOCOLS[0] = "TLSv1"), which can silently compromise TLS security globally at runtime.

With the addition of HTTP/3/QUIC support increasing the surface area of SSL/TLS configuration usage, this security risk becomes more critical. Please apply the previously suggested fix to keep the array private and expose an immutable accessor method instead.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (2)

191-199: Fix inverted SCHEME header when secure is true (GET and send()).

In both get(...) and send(...) you currently set:

httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "http" : "https");

while the body‑request path correctly uses:

request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "https" : "http");

So when secure == true you end up advertising "http" instead of "https" on GET and send(...).

Align all three call sites to the same correct ternary:

- httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "http" : "https");
+ httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "https" : "http");

- httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "http" : "https");
+ httpRequest.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), secure ? "https" : "http");

Also applies to: 208-211, 221-237


241-270: HTTP/3: avoid sending multiple requests on a single QuicStreamChannel.

sendRequests(...) calls:

final Channel channel = handler.prepare(clientBootstrap, channelFuture.channel());
for (HttpRequest request : requests) {
    channel.writeAndFlush(request);
}

For HTTP/3, CountDownLatchHandlerHttp3.prepare(...) returns a single QuicStreamChannel created via Http3.newRequestStream(...). Per RFC 9114, each request/response must use its own bidirectional stream; a client MUST NOT send multiple requests on the same stream. Reusing one QuicStreamChannel for multiple entries in requests is therefore spec‑invalid if any caller passes more than one request when using http3().

If multi‑request support isn’t required for the HTTP/3 test client, the minimal and safe change is to fail fast:

-        final Channel channel = handler.prepare(clientBootstrap, channelFuture.channel());
-        for (HttpRequest request : requests) {
-            channel.writeAndFlush(request);
-        }
+        final Channel channel = handler.prepare(clientBootstrap, channelFuture.channel());
+
+        // HTTP/3: one request per QUIC stream; enforce this for the test client.
+        if (channel instanceof QuicStreamChannel && requests.size() > 1) {
+            throw new IllegalStateException(
+                "HTTP/3 test client only supports a single request per QUIC stream; got " + requests.size()
+            );
+        }
+
+        for (HttpRequest request : requests) {
+            channel.writeAndFlush(request);
+        }

If you want multi‑request support, instead open a new Http3.newRequestStream(...) (and thus a fresh QuicStreamChannel) per request while reusing the same QuicChannel.

Does HTTP/3 (RFC 9114) allow multiple requests to be sent sequentially on a single bidirectional QUIC stream, or must each request/response use its own stream?

Also applies to: 507-543

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

155-165: Make HTTP/2/HTTP/3 protocol checks resilient to Reactor’s actual protocol string.

protocol here is whatever HttpServerRequest.protocol() returns, and hard‑coding "HTTP/2.0" / "HTTP/3.0" is brittle: if Reactor returns "HTTP/2" or "HTTP/3" (or changes formatting), these branches will never match and HTTP/2 or HTTP/3 requests will fall into the IllegalArgumentException.

I’d suggest relaxing the comparison to handle both formats:

-        } else if (protocol.equals("HTTP/2.0")) {
-            return HttpRequest.HttpVersion.HTTP_2_0;
-        } else if (protocol.equals("HTTP/3.0")) {
-            return HttpRequest.HttpVersion.HTTP_3_0;
+        } else if (protocol.startsWith("HTTP/2")) {
+            return HttpRequest.HttpVersion.HTTP_2_0;
+        } else if (protocol.startsWith("HTTP/3")) {
+            return HttpRequest.HttpVersion.HTTP_3_0;

and ideally add a small test that logs request.protocol() for an HTTP/3 request to confirm the exact value Reactor is using.

CHANGELOG.md (1)

39-40: Deduplicate ingestion entry and fix malformed link.

Line 39 repeats the existing pull‑based ingestion changelog entry from line 35, and its link ends with ] instead of ), which breaks markdown.

A minimal clean-up:

-- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)]
-- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017))
+- Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017))
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)

272-317: Clean up HTTP/3 server on HTTP/1.1/2 bind failure and return a non-null channel.

In the dual-server case:

final DisposableServer http3Server = http3Opt.get();
final DisposableServer http11or2Server = http11or2.bindNow();
disposableServer = new DisposableServer() {
    @Override
    public Channel channel() { return null; }
    @Override
    public void disposeNow() { ... }
};
return new ReactorNetty4CompositeHttpServerChannel(http11or2Server.channel(), http3Server.channel());

there are two issues:

  1. Resource leak on bind failure – if http11or2.bindNow() throws after http3Server has bound, the HTTP/3 server stays running.
  2. channel() returns null – any code calling disposableServer.channel() will NPE.

Suggested fix:

final DisposableServer http3Server = http3Opt.get();
final DisposableServer http11or2Server;
try {
    http11or2Server = http11or2.bindNow();
} catch (Exception e) {
    http3Server.disposeNow();
    throw e;
}

disposableServer = new DisposableServer() {
    @Override
    public Channel channel() {
        // e.g. delegate to primary HTTP/1.1/2 channel
        return http11or2Server.channel();
    }

    @Override
    public void disposeNow() {
        http3Server.disposeNow();
        http11or2Server.disposeNow();
    }
};

to ensure both servers are cleaned up on failure and channel() is safe to call.

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

39-44: Clarify/combine close-listener semantics to avoid multiple invocations.

addCloseListener currently registers the same listener on every closeContexts[i], so it will be invoked once per underlying channel close. For a “composite” server channel, callers are likely to expect a single callback when the whole composite is closed.

You can instead aggregate completion over all contexts (e.g., via an AtomicInteger counter or a shared CompletableContext<Void>) and invoke the listener exactly once when all channels complete, propagating the first failure if any.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

328-398: Avoid response.content().array(); handle direct buffers safely.

In testBadRequest:

assertThat(
    new String(response.content().array(), Charset.forName("UTF-8")),
    containsString("you sent a bad request and you should feel bad")
);

assumes the ByteBuf is heap-backed; if a direct buffer is returned, this will throw UnsupportedOperationException.

You’re already using ByteBufUtil.getBytes(...) elsewhere in this class. Consider:

assertThat(
    new String(ByteBufUtil.getBytes(response.content()), StandardCharsets.UTF_8),
    containsString("you sent a bad request and you should feel bad")
);

for compatibility with both heap and direct buffers and consistent charset usage.


426-457: Use randomized test settings instead of Settings.EMPTY to avoid port conflicts.

testLargeCompressedResponse constructs the transport with:

Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
    Settings.EMPTY,
    ...,
    new SharedGroupFactory(Settings.EMPTY),
    ...
);

Unlike other tests that use createSettings() (which randomizes the HTTP port), relying on defaults here risks binding to fixed ports and causing flaky failures in CI.

Recommend switching to:

final Settings settings = createSettings();
try (Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
    settings,
    ...,
    new SharedGroupFactory(settings),
    ...
)) {
    ...
}

to keep port selection consistent across tests.

🧹 Nitpick comments (9)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (2)

50-65: Overload design keeps behavior while adding flexibility; consider null-safety and docs

The delegation from createServerKeyStore() to createServerKeyStore(Algorithm.rsa2048) is a clean way to preserve existing behavior while enabling algorithm selection in tests.

To make this a bit more robust and self-documenting:

  • Add an explicit null check on the algorithm parameter so failures are immediate and clear (rather than a later NPE inside the builder).
  • Optionally add brief Javadoc on the new overload describing what Algorithm values are expected/valid in this context and that the no‑arg overload uses rsa2048 by default.

For example:

-    public static KeyStore createServerKeyStore(Algorithm algorithm) throws Exception {
-        var serverCred = generateCert(algorithm);
+    public static KeyStore createServerKeyStore(Algorithm algorithm) throws Exception {
+        Objects.requireNonNull(algorithm, "algorithm");
+        var serverCred = generateCert(algorithm);

(plus the corresponding import java.util.Objects;).


67-76: Clarify FIPS expectations for caller-supplied algorithms (and optionally enforce in FIPS mode)

Now that generateCert takes a caller-provided Algorithm, the comment:

// must use FIPS-approved algorithms like rsa2048, rsa3072, rsa4096, rsa8192, ecp256, ecp384

is more of a guideline than a guarantee. If Algorithm contains non‑FIPS options, a caller could now pass something incompatible with BouncyCastleFipsProvider, especially when FipsMode.CHECK.isFipsEnabled() returns true.

Two suggestions:

  • Update the comment to make it clear this requirement applies when running in FIPS mode (and that callers are responsible for choosing a FIPS‑approved algorithm in that case).
  • Optionally, in FIPS mode, validate algorithm against the allowed set and fail fast with a descriptive exception instead of relying on provider/builder failures.

This would make test failures more targeted and avoid confusion if a non‑approved algorithm is accidentally used in a FIPS run.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (2)

335-417: New AwaitableChannelInitializer abstraction for HTTP/1/2 looks correct.

The AwaitableChannelInitializer<C extends Channel> base plus the HTTP/2 override of await() neatly separates “handshake/readiness” concerns from the common send logic. CountDownLatchHandlerHttp and CountDownLatchHandlerHttp2 wiring both look sound, and the HTTP/2 settings wait in await() is correctly placed before sending requests.

You might optionally add @Override on CountDownLatchHandlerHttp2.await() for clarity, but functionally this block is good as‑is.


476-544: HTTP/3 client pipeline is well‑structured; consider tightening latch semantics.

The HTTP/3 handler sets up:

  • QUIC client codec with H3‑related settings,
  • an HTTP/3 request stream whose pipeline is Http3FrameToHttpObjectCodec(false)HttpContentDecompressorHttpObjectAggregatorSimpleChannelInboundHandler<HttpObject>,

and in channelRead0 it copies the FullHttpResponse body into a new buffer before adding to content, matching the allocation behavior of the HTTP/1/2 paths. This wiring looks correct and consistent.

Minor robustness nit: latch.countDown() is called unconditionally, even when msg is not a FullHttpResponse. Today the aggregator ensures only FullHttpResponse arrives, but to make the code future‑proof you could tie the latch strictly to responses (and failures) only:

-                        protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
-                            if (msg instanceof FullHttpResponse ht) {
-                                // copy buffer...
-                                ByteBuf newContent = Unpooled.copiedBuffer(ht.content());
-                                content.add(ht.replace(newContent));
-                            }
-                            latch.countDown();
-                        }
+                        protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
+                            if (msg instanceof FullHttpResponse ht) {
+                                ByteBuf newContent = Unpooled.copiedBuffer(ht.content());
+                                content.add(ht.replace(newContent));
+                                latch.countDown();
+                            }
+                        }

(and keep the latch.countDown() in exceptionCaught as you already do).

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

110-136: Consider centralizing HTTP/3 flow-control settings instead of duplicating them here.

SETTING_H3_MAX_STREAM_LOCAL_LENGTH, SETTING_H3_MAX_STREAM_REMOTE_LENGTH, and SETTING_H3_MAX_STREAMS are also defined in Netty4QuicServerTransport with identical keys and defaults. Duplicating these settings in two classes increases the risk of drift later.

Consider moving the H3 settings into a shared location (e.g., HttpTransportSettings or a dedicated helper) and referencing them from both transports.


319-363: Align HTTP/3 timeout and flow-control tuning with existing HTTP settings.

The HTTP/3 configuration hard-codes:

.http3Settings(spec -> spec.idleTimeout(Duration.ofSeconds(5))
    .maxData(SETTING_HTTP_MAX_CONTENT_LENGTH.get(settings).getBytes())
    .maxStreamDataBidirectionalLocal(SETTING_H3_MAX_STREAM_LOCAL_LENGTH.get(settings).getBytes())
    .maxStreamDataBidirectionalRemote(SETTING_H3_MAX_STREAM_REMOTE_LENGTH.get(settings).getBytes())
    .maxStreamsBidirectional(SETTING_H3_MAX_STREAMS.get(settings).longValue())
)

Two observations:

  • Using SETTING_HTTP_MAX_CONTENT_LENGTH as the connection-level maxData is serviceable but conflates message size with transport flow-control; some deployments might want different connection budgets than per-request max content length.
  • The idle timeout is hard-coded to 5 seconds instead of reusing or deriving from SETTING_HTTP_READ_TIMEOUT.

Not blocking, but consider:

  • Introducing an HTTP/3-specific connection maxData setting (or at least documenting its coupling to max content length), and
  • Tying idleTimeout to existing timeout settings (or exposing it via a dedicated setting) for consistent tuning.
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

95-121: Avoid duplicating HTTP/3 flow-control settings across transports.

The H3 settings:

public static final Setting<ByteSizeValue> SETTING_H3_MAX_STREAM_LOCAL_LENGTH = ...
public static final Setting<ByteSizeValue> SETTING_H3_MAX_STREAM_REMOTE_LENGTH = ...
public static final Setting<Long> SETTING_H3_MAX_STREAMS = ...

are defined here with the same keys and defaults as in ReactorNetty4HttpServerTransport. Keeping two independent definitions increases the chance of divergence over time.

Consider extracting these into a shared settings holder (e.g., HttpTransportSettings or a dedicated Http3TransportSettings) and reusing them from both transports.


357-376: ServerChannelExceptionHandler is never used; either wire it or remove it.

ServerChannelExceptionHandler is defined but not added to any pipeline, so it’s currently dead code. If you intend to surface server-channel exceptions through onServerException, you probably want to attach it in configureServerChannelHandler():

ch.pipeline()
    .addLast("quic_server_codec", Http3.newQuicServerCodecBuilder()....build())
    .addLast("server_exception_handler", new ServerChannelExceptionHandler(Netty4QuicServerTransport.this));

Otherwise, consider removing this class to reduce noise.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

532-597: Read-timeout test uses raw UDP; consider exercising actual HTTP/3 traffic.

testReadTimeout now uses NioDatagramChannel with a bare pipeline to connect to the QUIC server and waits for the client channel to close. This validates “something” causes the UDP channel to close, but it doesn’t clearly exercise the HTTP/3 stream-level ReadTimeoutHandler that’s on QuicStreamChannel.

Not a blocker, but for stronger coverage you might consider:

  • Using Netty4HttpClient.http3() to open an HTTP/3 request that deliberately stalls, then asserting the connection/stream is closed due to read timeout, or
  • At least adding a brief comment explaining the intent of this raw UDP approach.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36cda04 and 0593761.

📒 Files selected for processing (44)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (13 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 hunks)
  • server/src/main/java/org/opensearch/bootstrap/Security.java (1 hunks)
  • server/src/main/java/org/opensearch/common/settings/ClusterSettings.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 (3)
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.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-aarch_64.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (19)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • modules/transport-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-osx-x86_64.jar.sha1
  • plugins/transport-reactor-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/ssl/SecureReactorNetty4HttpServerTransportTests.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java
  • server/src/main/java/org/opensearch/http/HttpRequest.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-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-windows-x86_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
🧰 Additional context used
🧬 Code graph analysis (9)
server/src/main/java/org/opensearch/common/settings/ClusterSettings.java (1)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (8)
libs/core/src/main/java/org/opensearch/core/common/bytes/BytesArray.java (1)
  • BytesArray (48-151)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
server/src/main/java/org/opensearch/rest/BytesRestResponse.java (1)
  • BytesRestResponse (59-219)
test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java (1)
  • KeyStoreUtils (26-83)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)
  • NettyAllocator (51-350)
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)
  • SslUtils (26-107)
server/src/main/java/org/opensearch/bootstrap/Bootstrap.java (1)
  • Bootstrap (89-495)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)
  • Netty4HttpClient (119-545)
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 (77-353)
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 (77-353)
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)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (6)
libs/core/src/main/java/org/opensearch/ExceptionsHelper.java (1)
  • ExceptionsHelper (76-476)
server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java (1)
  • AbstractHttpServerTransport (93-507)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)
  • NettyAllocator (51-350)
server/src/main/java/org/opensearch/bootstrap/Bootstrap.java (1)
  • Bootstrap (89-495)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1)
  • Netty4HttpServerTransport (130-635)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (3)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)
  • ChannelHandler (357-376)
  • Netty4QuicServerTransport (92-449)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)
  • NettyAllocator (51-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/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 (77-353)
⏰ 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: precommit (25, macos-15)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: Mend Security Check
  • GitHub Check: Analyze (java)
  • GitHub Check: detect-breaking-change
🔇 Additional comments (21)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1)

200-200: LGTM! Documentation typo fixed.

The Javadoc parameter name is now correctly spelled.

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

1-1: Verify checksum matches the committed JAR and is consistent with peer files.

Ensure the recorded SHA-1 hash is computed correctly against the corresponding netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar and verify formatting is consistent with other netty-codec-native-quic-4.2.7.*.jar.sha1 files in the same directory.

server/src/main/java/org/opensearch/bootstrap/Security.java (1)

132-134: Verify the regex pattern correctly matches all classifier variants and add unit tests.

The updated regex pattern is complex with non-greedy matching (.*?) and multiple optional groups that create potential for ambiguous or incorrect capture group assignments. For example, with lucene-core-9.11.0-snapshot-8a555eb.jar, it is unclear whether group 2 (classifier) captures the final segment, multiple segments, or requires specific boundaries.

Since this affects security policy grants for HTTP/3 dependencies with platform-specific classifiers, incorrect matching could result in missing permissions or runtime failures. Verify the regex against all example JAR names in the comments and add unit tests to ensure correct behavior for edge cases (multiple dashes, absent classifiers, various platform prefixes).

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (2)

35-112: Imports and HTTP/3/QUIC settings wiring look consistent.

The additional imports (Settings, Datagram/QUIC/HTTP3 classes, and static H3 settings) are coherent with the new HTTP/3 client logic and are used appropriately below; no issues from this block.


137-189: Verify allocator settings for HTTP/3 client bootstrap.

The http3() factory differs from http(), http2(), and https() by calling NettyAllocator.getAllocator(true) instead of NettyAllocator.getAllocator(). Confirm whether this boolean flag relates to direct buffer allocation and whether the resulting configuration is appropriate for Netty QUIC expectations. If direct buffers should be enabled for HTTP/3, consider aligning with the default allocator used in the other factory methods.

gradle/libs.versions.toml (1)

152-153: Netty QUIC dependencies look consistent with published artifacts.

Both io.netty:netty-codec-native-quic and io.netty:netty-codec-classes-quic are now available at 4.2.7.Final on Maven Central, so using version.ref = "netty" here is valid and keeps them aligned with the rest of the Netty stack. (mvnrepository.com)

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

83-101: Client creation update to create(settings) looks correct.

Passing the same Settings used to configure the server into ReactorHttpClient.create(settings) keeps this bad‑request test aligned with the new client API and future protocol selection logic, without changing test semantics.

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

106-140: Streaming tests correctly updated to the new ReactorHttpClient.create(boolean, Settings) API.

Using ReactorHttpClient.create(false, Settings.EMPTY) in both streaming tests preserves the existing behavior (no compression, HTTP/1.1) while wiring in the required Settings parameter; the extra blank line at the end is harmless.

Also applies to: 150-180, 243-244

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

191-225: Settings-aware ReactorHttpClient.create(...) usage is consistent across tests.

Each test now instantiates ReactorHttpClient with the same Settings used to configure its ReactorNetty4HttpServerTransport (or Settings.EMPTY when appropriate), which aligns client behavior with server configuration and the new factory signature without changing the underlying test logic.

Also applies to: 294-322, 341-367, 396-427, 467-498, 520-556

server/src/main/java/org/opensearch/common/settings/ClusterSettings.java (1)

390-428: HTTP/3 enablement setting correctly added to built-in cluster settings.

Including HttpTransportSettings.SETTING_HTTP_HTTP3_ENABLED in BUILT_IN_CLUSTER_SETTINGS alongside the other HTTP transport settings makes the new http.protocol.http3.enabled flag visible to cluster settings infrastructure and consistent with how other HTTP options are exposed.

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

78-116: Settings-driven protocol selection for tests looks reasonable.

Using a Settings argument and the randomProtocol(secure, settings) helper to select among HTTP/1.1, H2, and HTTP/3 (when enabled and available) gives good coverage without complicating call sites. The new create(Settings) / https(Settings) factories are straightforward.

No changes needed here.


333-351: useHttp11only() and randomProtocol behavior are consistent.

useHttp11only() now simply checks protocol == HttpProtocol.HTTP11, and randomProtocol limits HTTP/3 selection to secure == true plus SETTING_HTTP_HTTP3_ENABLED and runtime availability, falling back to HTTP/1.1/H2 otherwise. For insecure clients, only HTTP/1.1/H2C are considered.

This matches expectations and gives tests a clear way to detect the chosen protocol.


279-325: HTTP/3 client SSL context configuration aligns with Reactor Netty APIs.

The secure HTTP/3 branch correctly uses Http3SslContextSpec.forClient().configure(...) followed by .sslContext() to obtain the SSL context, matching the recommended Reactor Netty pattern. The configuration properly applies HTTP/3/QUIC-specific defaults before the customize callback runs.

Note: The HTTP/3 branch omits the explicit clientAuth(ClientAuth.NONE) configuration present in the HTTP/1.1 and H2 branches. While this is acceptable (client SSL contexts do not require explicit client auth settings), the inconsistency across protocol branches may warrant a comment explaining the intentional difference.

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

141-222: Audit ignore list additions for QUIC-related classes look appropriate.

Adding:

'io.netty.pkitesting.X509Bundle',
'io.netty.channel.epoll.SegmentedDatagramPacket',

to ignoreMissingClasses matches the new Netty QUIC/PKI helper classes and epoll datagram support; it prevents false positives when those classes are absent on some platforms.

No changes needed here.


58-85: Validate QUIC/HTTP3 dependency coordinates and consider centralizing runtime native classifiers.

Verify that:

  • versions.netty corresponds to a Netty release that publishes netty-codec-http3, netty-codec-classes-quic, and platform-specific netty-codec-native-quic classifiers (linux-x86_64, linux-aarch_64, osx-x86_64, osx-aarch_64, windows-x86_64)
  • Gradle successfully resolves these artifacts on all supported platforms

Consider defining the netty-codec-native-quic runtime natives through the version catalog (e.g., libs.netty.codec.native.quic) to centralize coordinates and reduce duplication across modules.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (4)

148-189: Constructor wiring and logging are consistent with existing Netty HTTP transports.

The constructor sets up:

  • processors (Netty4Utils.setAvailableProcessors),
  • allocator logging (NettyAllocator.logAllocatorDescriptionIfNeeded),
  • HTTP handling settings (maxChunkSize, maxHeaderSize, maxInitialLineLength),
  • composite buffer components, read timeout, and receive predictor.

The debug log mirrors the existing Netty HTTP transport and should be useful for diagnosing misconfiguration.

Looks good.


195-219: Server startup path matches existing transport lifecycle.

doStart() initializes the shared group, Bootstrap with NioDatagramChannel, allocator, receive buffer allocator, and handler, then calls bindServer() with proper failure cleanup.

Assuming SharedGroupFactory#getHttpGroup() is QUIC-compatible, this is consistent with other transports’ lifecycle and doesn’t introduce obvious leaks.


298-355: HTTP/3 stream pipeline configuration looks correct and HTTP/1.x-free.

HttpChannelHandler.configurePipeline:

ch.pipeline().addLast(new Http3FrameToHttpObjectCodec(true));
ch.pipeline().addLast("header_verifier", transport.createHeaderVerifier());
ch.pipeline().addLast("decoder_compress", transport.createDecompressor());
HttpObjectAggregator aggregator = new HttpObjectAggregator(handlingSettings.getMaxContentLength());
aggregator.setMaxCumulationBufferComponents(transport.maxCompositeBufferComponents);
ch.pipeline().addLast("aggregator", aggregator);
...
ch.pipeline().addLast("request_creator", requestCreator);
ch.pipeline().addLast("response_creator", responseCreator);
ch.pipeline().addLast("handler", requestHandler);

avoids HTTP/1.x codecs and places Http3FrameToHttpObjectCodec at the front, which matches the expected HTTP/3 pipeline. The aggregator and compression handlers mirror the existing Netty HTTP transport behavior.

Looks good.


381-393: Header verifier and decompressor extension points match existing HTTP transport.

createHeaderVerifier() and createDecompressor() provide the same extension hooks as the existing Netty HTTP server transport, allowing plugins to inject custom logic.

No issues here.

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

91-183: New audit ignore for SegmentedDatagramPacket is aligned with QUIC UDP usage.

Adding io.netty.channel.epoll.SegmentedDatagramPacket to ignoreMissingClasses is appropriate given the new UDP/QUIC support and platform-specific presence of epoll classes.

No issues here.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (1)

182-284: HTTP/3 “Expect: 100-continue” tests look solid and consistent.

The testExpectContinueHeader* tests and runExpectHeaderTest(...) helper correctly:

  • Configure the transport with appropriate http.max_content_length values,
  • Use HTTP/3 client (Netty4HttpClient.http3()) against the QUIC server,
  • Assert status codes for 100-continue, 413, and 417, and
  • Verify follow-up request behavior for the successful 100-continue case.

This is a good coverage of edge cases around Expect handling on the HTTP/3 path.

Comment on lines +247 to +291
public ChannelHandler configureServerChannelHandler() {
return new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
final Optional<SecureHttpTransportParameters> parameters = secureHttpTransportSettingsProvider.parameters(settings);

final KeyManagerFactory keyManagerFactory = parameters.flatMap(SecureHttpTransportParameters::keyManagerFactory)
.orElseThrow(() -> new OpenSearchException("The KeyManagerFactory instance is not provided"));

final QuicSslContextBuilder sslContextBuilder = QuicSslContextBuilder.forServer(keyManagerFactory, null);

parameters.flatMap(SecureHttpTransportParameters::trustManagerFactory).ifPresent(sslContextBuilder::trustManager);
parameters.flatMap(SecureHttpTransportParameters::clientAuth)
.ifPresent(clientAuth -> sslContextBuilder.clientAuth(ClientAuth.valueOf(clientAuth)));

final QuicSslContext sslContext = sslContextBuilder.applicationProtocols(
io.netty.handler.codec.http3.Http3.supportedApplicationProtocols()
).build();

ch.pipeline()
.addLast(
Http3.newQuicServerCodecBuilder()
.sslContext(sslContext)
.initialMaxData(SETTING_HTTP_MAX_CONTENT_LENGTH.get(settings).getBytes())
.initialMaxStreamDataBidirectionalLocal(SETTING_H3_MAX_STREAM_LOCAL_LENGTH.get(settings).getBytes())
.initialMaxStreamDataBidirectionalRemote(SETTING_H3_MAX_STREAM_REMOTE_LENGTH.get(settings).getBytes())
.initialMaxStreamsBidirectional(SETTING_H3_MAX_STREAMS.get(settings).longValue())
.tokenHandler(InsecureQuicTokenHandler.INSTANCE)
.handler(new ChannelInitializer<QuicChannel>() {
@Override
protected void initChannel(QuicChannel ch) {
// Called for each connection
ch.pipeline()
.addLast(
new Http3ServerConnectionHandler(
new HttpChannelHandler(Netty4QuicServerTransport.this, handlingSettings)
)
);
}
})
.build()
);
}
};
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Netty InsecureQuicTokenHandler QUIC token validation security

💡 Result:

Short answer: InsecureQuicTokenHandler in Netty performs token generation/validation without cryptographic integrity or secrecy and is explicitly documented as "shouldn't be used in production." That makes it unsafe for QUIC address-validation tokens (tokens can be guessed/forged/replayed), which can enable address‑spoofing, replay/amplification or linkage attacks and violates RFC 9000's requirement that address‑validation tokens be integrity‑protected. Use a crypto-backed QuicTokenHandler (AEAD/HMAC with server-only keys, include client IP and expiry, key rotation) or disable token-based validation. Sources: Netty docs and the QUIC RFC. (netty.io)

Citations:


🌐 Web query:

Netty HTTP/3 QUIC server token handler best practices production

💡 Result:

Short checklist of production best practices for a Netty HTTP/3 (QUIC) server token handler:

  1. Use authenticated, integrity-protected tokens (AEAD) that encode only what’s needed for address validation (client address, issue timestamp, token type). RFC recommends integrity protection and distinguishable token types. [2]

  2. Treat Retry vs NEW_TOKEN differently: accept Retry tokens only briefly and validate strictly; NEW_TOKEN may live longer but avoid unlimited reuse. Prefer single‑use when practical. [2]

  3. Keep tokens stateless on server side (encrypt/signed payload) so you can scale/rotate without stored state; include timestamp/nonce to limit replay. RFC and stateless designs advise this. [2]

  4. Rotate and protect token keys: use key rotation, maintain short TTL for keys, and securely store keys (HSM/KMS) to limit exposure if leaked.

  5. Bind token contents to transport address (and optionally connection-id) to prove client ownership; include version/party tag to prevent cross-purpose reuse. RFC recommends enabling server to verify client transport address and distinguish token purpose. [2]

  6. Enforce short acceptance windows for tokens used for address validation (Retry) to avoid DDoS amplification/replay; rate-limit token validation work and fallback to sending Retry when uncertain. [2]

  7. Graceful handling of unreadable/unknown-format tokens: treat as “no token” (don’t abort) and proceed with address validation/fallback per RFC to avoid false drops. [2]

  8. Implement metrics, logging and alarms around token validation failures, token replay rates, and Retry issuance to detect attacks or misconfiguration.

  9. Use Netty’s QuicTokenHandler API (set via QuicServerCodecBuilder.tokenHandler) and follow examples; pay attention to max connection-id length and endianness fixes in recent releases. Test with the incubator codec releases. [1][3]

  10. Test at scale (connection spikes, migration, loss) and validate interoperability with clients; ensure NEW_TOKEN issuance for 0-RTT use-cases is consistent with privacy/linkability guidance in RFC. [2]

References:

  • Netty QuicServer/QuicTokenHandler API (QuicServerCodecBuilder). [1]
  • RFC 9000 (QUIC) — token semantics, Retry vs NEW_TOKEN, stateless tokens, address validation guidance. [2]
  • Netty incubator QUIC release notes (QuicTokenHandler fixes/changes). [3]

If you want, I can: (a) sketch a sample QuicTokenHandler implementation (AEAD + timestamp + nonce) compatible with Netty, or (b) review your existing handler code. Which would you prefer?


🏁 Script executed:

# Search for InsecureQuicTokenHandler usage in the codebase
rg "InsecureQuicTokenHandler" --type java -B 3 -A 3

# Also search for any token handler related settings or configurations
rg "token.*handler|TokenHandler" --type java -i | head -50

# Look for TODO or FIXME comments related to QUIC or token handling
rg "TODO|FIXME" --type java | grep -i "quic\|token\|security" | head -20

# Check if there are any settings related to insecure handlers or QUIC security
rg "insecure|h3|QUIC" --type java | grep -i "setting\|config" | head -30

Repository: opensearch-project/OpenSearch

Length of output: 202


🏁 Script executed:

# Find all QUIC-related files in the transport-netty4 module
fd -e java . modules/transport-netty4 | xargs grep -l "Quic\|QUIC\|H3\|h3" 2>/dev/null

# Check the settings definitions for QUIC/H3 related configurations
fd -e java . modules/transport-netty4 | xargs grep -l "SETTING.*H3\|SETTING.*QUIC" 2>/dev/null

Repository: opensearch-project/OpenSearch

Length of output: 202


QUIC server codec configuration uses insecure token handler; replace with cryptographically-backed implementation for production.

The QUIC setup uses InsecureQuicTokenHandler.INSTANCE, which is explicitly documented by Netty as unsuitable for production. This handler performs token generation and validation without cryptographic integrity or secrecy, enabling address-spoofing, replay/amplification attacks, and token forgery. RFC 9000 explicitly requires address-validation tokens to be integrity-protected—a requirement that InsecureQuicTokenHandler violates.

For production deployment, replace with a cryptographically-backed QuicTokenHandler implementation that:

  • Uses AEAD or HMAC for token integrity and confidentiality
  • Encodes client transport address, timestamp, and nonce to prevent replay
  • Implements stateless token design (signed/encrypted payload) with key rotation and short TTL
  • Binds tokens to transport address and connection context
  • Enforces short acceptance windows for address validation to mitigate DDoS amplification

At minimum, add a feature flag (e.g., h3.require_secure_token_handler) that defaults to enforcing secure tokens and prevents accidental production use of InsecureQuicTokenHandler, with clear documentation linking to RFC 9000 token validation requirements.

🤖 Prompt for AI Agents
In
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java
around lines 247 to 291, the QUIC server codec currently uses
InsecureQuicTokenHandler.INSTANCE which is unsuitable for production; replace it
with a cryptographically-backed QuicTokenHandler implementation (or factory)
that signs/encrypts token payloads (client address, timestamp, nonce), verifies
address binding, enforces short TTL and replay protection, and supports key
rotation; add a boolean setting (e.g., h3.require_secure_token_handler)
defaulting to true that prevents use of the insecure handler unless explicitly
disabled for tests, wire the setting into codec construction to select the
secure handler and document the requirement per RFC 9000.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 5, 2025

❌ Gradle check result for 0593761: 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

@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

♻️ Duplicate comments (9)
CHANGELOG.md (1)

35-35: Remove duplicate entry and fix malformed link.

Line 39 duplicates the pull-based ingestion entry from line 35 with a malformed markdown link (ends with )] instead of )). Line 40 (HTTP/3) is the intended new entry.

Apply this diff to remove the duplicate and correct the link syntax:

  - Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765))
  - Add search API tracker ([#18601](https://github.com/opensearch-project/OpenSearch/pull/18601))
  - Support dynamic consumer configuration update in pull-based ingestion ([#19963](https://github.com/opensearch-project/OpenSearch/pull/19963))
  - Cache the `StoredFieldsReader` for scroll query optimization ([#20112](https://github.com/opensearch-project/OpenSearch/pull/20112))
- - Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)]
  - Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017))

Also applies to: 39-40

modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)

27-27: Security issue: Mutable array exposed as public API (previously flagged).

This concern was already raised in a previous review and remains unresolved. Exposing DEFAULT_SSL_PROTOCOLS as a public mutable array allows any caller to modify the TLS protocol list at runtime (e.g., DEFAULT_SSL_PROTOCOLS[0] = "TLSv1"), creating a security vulnerability and breaking encapsulation.

The previous review provided a correct solution: keep the array private and expose protocols via a defensive-copy accessor method. Please implement that recommendation before merging this PR.

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

42-46: [DUPLICATE] Fix unresolved critical artifact coordinate mismatch — dependency resolution will fail.

This issue was flagged in the previous review but remains unresolved. The correct artifact coordinates are io.netty.incubator:netty-incubator-codec-native-quic, not io.netty:netty-codec-native-quic. Using the wrong groupId and artifactId will cause dependency resolution to fail. Additionally, the version should reference a QUIC release (e.g., 0.0.72.Final), not ${versions.netty}.

Apply this diff to use the correct coordinates and align with the lib references at lines 38–39:

-  // Bundle all supported OSes and Archs
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:linux-x86_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:linux-aarch_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:osx-x86_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:osx-aarch_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:windows-x86_64"
+  // Bundle all supported OSes and Archs
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:linux-x86_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:linux-aarch_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:osx-x86_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:osx-aarch_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:windows-x86_64"

Then define versions.nettyQuic in gradle/libs.versions.toml (or the appropriate version catalog) with a valid QUIC release (e.g., 0.0.72.Final).

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (2)

274-274: Security: InsecureQuicTokenHandler is not suitable for production.

This handler bypasses QUIC address validation tokens, which protect against address spoofing attacks per RFC 9000. While acceptable for initial development, a production-ready token handler should be implemented before release.

Consider adding a configuration option or TODO to track this:

-                            .tokenHandler(InsecureQuicTokenHandler.INSTANCE)
+                            // TODO: Implement secure token handler before production release
+                            // See RFC 9000 Section 8 for token validation requirements
+                            .tokenHandler(InsecureQuicTokenHandler.INSTANCE)

357-376: ServerChannelExceptionHandler is defined but never used.

This class is never instantiated or added to any pipeline. Either integrate it for proper server-level exception handling or remove the dead code.

If this should handle server channel exceptions:

// In configureServerChannelHandler(), after adding the QUIC server codec:
ch.pipeline().addLast("server_exception_handler", new ServerChannelExceptionHandler(Netty4QuicServerTransport.this));
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

380-388: Potential UnsupportedOperationException if buffer is not heap-backed.

At line 387, calling response.content().array() assumes the ByteBuf is heap-backed. If the allocator returns a direct buffer, this will throw UnsupportedOperationException. Also, prefer StandardCharsets.UTF_8 over Charset.forName("UTF-8").

-                final String url = "/" + new String(new byte[maxInitialLineLength], Charset.forName("UTF-8"));
+                final String url = "/" + new String(new byte[maxInitialLineLength], StandardCharsets.UTF_8);
                 final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url);

                 final FullHttpResponse response = client.send(remoteAddress.address(), request);
                 try {
                     assertThat(response.status(), equalTo(HttpResponseStatus.BAD_REQUEST));
                     assertThat(
-                        new String(response.content().array(), Charset.forName("UTF-8")),
+                        new String(ByteBufUtil.getBytes(response.content()), StandardCharsets.UTF_8),
                         containsString("you sent a bad request and you should feel bad")
                     );

426-438: Test uses Settings.EMPTY which may cause port binding issues.

Unlike other tests that use createSettings() to configure a random port range, this test passes Settings.EMPTY which relies on default port binding. This could cause flaky failures in CI environments due to port conflicts.

         try (
             Netty4QuicServerTransport transport = new Netty4QuicServerTransport(
-                Settings.EMPTY,
+                createSettings(),
                 networkService,
                 bigArrays,
                 threadPool,
                 xContentRegistry(),
                 dispatcher,
                 clusterSettings,
-                new SharedGroupFactory(Settings.EMPTY),
+                new SharedGroupFactory(createSettings()),
                 secureHttpTransportSettingsProvider,
                 NoopTracer.INSTANCE
             )
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (2)

299-300: Critical: HTTP/3 server not cleaned up if HTTP/1.1/2 bind fails.

If http11or2.bindNow() at line 300 throws an exception after http3Server has successfully bound at line 299, the HTTP/3 server remains bound and is not cleaned up, leading to a resource leak.

Apply this diff to ensure proper cleanup:

 final DisposableServer http3Server = http3Opt.get();
-final DisposableServer http11or2Server = http11or2.bindNow();
+final DisposableServer http11or2Server;
+try {
+    http11or2Server = http11or2.bindNow();
+} catch (Exception e) {
+    http3Server.disposeNow();
+    throw e;
+}

Based on past review comments, this issue was marked as addressed but the fix is not present in the current code.


302-313: Latent defect: Anonymous DisposableServer returns null from channel().

The anonymous DisposableServer implementation returns null for channel(). While the current code only calls disposeNow() (line 541), this is fragile—if any future code (logging, monitoring, debugging, or refactoring) invokes channel() expecting a valid reference, it will cause a NullPointerException.

Consider returning a representative channel or throwing UnsupportedOperationException:

 @Override
 public Channel channel() {
-    return null; /* not implemented */
+    // Return the primary HTTP/1.1/2 channel for compatibility
+    return http11or2Server.channel();
 }

Based on past review comments, this issue was marked as addressed but the fix is not present in the current code.

🧹 Nitpick comments (3)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

498-501: Consider accepting test-specific settings instead of using Settings.EMPTY.

The QUIC client codec is configured with Settings.EMPTY for max content length and stream parameters. If tests need custom settings (e.g., larger content limits), this will use the defaults instead of test-provided values.

Consider:

  1. Adding a Settings parameter to CountDownLatchHandlerHttp3 constructor, or
  2. Passing settings through the handlerFactory if tests require custom configuration.

For now, Settings.EMPTY may be acceptable if all tests use default limits.

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

243-243: Optional: Remove extraneous blank line.

This extra blank line appears to be an unintended formatting change with no behavioral impact.

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

337-351: Protocol selection logic is sound.

The randomProtocol() method correctly selects protocols based on security, HTTP/3 availability, and settings, ensuring test coverage across different protocol paths.

Simplify the boolean check at line 341:

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

The explicit == true comparison is redundant with primitive booleans.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0593761 and 3c97207.

📒 Files selected for processing (44)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (13 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (5 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 hunks)
  • server/src/main/java/org/opensearch/bootstrap/Security.java (1 hunks)
  • server/src/main/java/org/opensearch/common/settings/ClusterSettings.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 (3)
  • 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
  • modules/transport-netty4/licenses/netty-codec-http3-4.2.7.Final.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (25)
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • plugins/transport-reactor-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
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java
  • server/src/main/java/org/opensearch/common/settings/ClusterSettings.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-x86_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • gradle/libs.versions.toml
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java
  • server/src/main/java/org/opensearch/http/HttpTransportSettings.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1
  • test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4CompositeHttpServerChannel.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java
🧰 Additional context used
🧬 Code graph analysis (3)
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/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 (77-353)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (3)
server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java (1)
  • AbstractHttpServerTransport (93-507)
modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1)
  • NettyAllocator (51-350)
modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (3)
  • ChannelHandler (543-562)
  • Netty4HttpServerTransport (130-635)
  • HttpChannelHandler (364-541)
⏰ 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 (21, macos-15)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: Analyze (java)
  • GitHub Check: Mend Security Check
🔇 Additional comments (42)
plugins/transport-reactor-netty4/build.gradle (2)

162-162: Addition of SegmentedDatagramPacket to audit exclusions is appropriate.

The inclusion of io.netty.channel.epoll.SegmentedDatagramPacket in ignoreMissingClasses is correct for QUIC support, as this class is only available on Linux systems with kernel support for UDP segmentation offload (GSO), which is leveraged by QUIC's native implementation.


233-268: LGTM: Removing QUIC classes from audit violations reflects appropriate architectural elevation.

By removing QUIC-related classes from ignoreViolations (per the AI summary), this PR properly elevates QUIC from an experimental/hidden dependency to first-class public API. This signals that Netty's QUIC codec is stable enough for production use within OpenSearch's HTTP/3 transport layer.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (4)

197-197: Scheme header logic is now correct.

The ternary expression correctly sets "https" when secure is true and "http" when secure is false. The previously reported inversion issue has been addressed.

Also applies to: 210-210, 234-234


335-343: LGTM! Clean abstraction for protocol-specific channel preparation.

The generic type parameter and prepare() hook provide a flexible way for different protocol handlers to customize channel setup. HTTP/1 and HTTP/2 use the default (return channel as-is), while HTTP/3 can override to create a QuicStreamChannel.


520-540: LGTM! HTTP/3 request stream pipeline is correctly ordered.

The pipeline correctly places:

  1. Http3FrameToHttpObjectCodec(false) first to convert HTTP/3 frames to HTTP objects
  2. HttpContentDecompressor for decompression
  3. HttpObjectAggregator to aggregate chunked content
  4. Application handler to process FullHttpResponse

This addresses the previous review comment about codec ordering and removes the incorrect HTTP/1.x codecs (HttpResponseDecoder, HttpRequestEncoder).


181-189: The review comment requires verification against the actual implementation of the prepare() method and sendRequests loop. The concern about creating multiple QuicChannel instances per request cannot be confirmed or refuted without examining the complete code at the referenced lines (508-543). The visible snippet (lines 181-189) shows only the factory method, which appears correct for basic HTTP/3 client setup.

To properly verify this review comment, access to the full CountDownLatchHandlerHttp3 class and the sendRequests method implementation is necessary.

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

79-84: Platform-specific native libraries bundled for all supported platforms.

The approach of bundling native QUIC codecs for all platforms ensures the module works out-of-the-box on any supported OS and architecture. This follows the existing Netty pattern in the project but does increase the artifact size.


219-221: Appropriate addition to ignore platform-specific class.

SegmentedDatagramPacket is a Linux-specific (epoll) class used for optimized UDP packet handling in QUIC. It's correct to ignore this in third-party audit since it's platform-specific and not available on all operating systems.


66-68: Confirm these are incubator artifacts and document production-readiness strategy.

These HTTP/3 and QUIC codecs (netty-codec-http3, netty-codec-classes-quic, netty-codec-native-quic) are Netty incubator artifacts, not yet graduated to Netty core. As of early 2025, they remain at 0.0.xx.Final versions. While actively maintained and used in production by downstream projects like Reactor Netty (which declared HTTP/3 production-ready in Nov 2024), the incubator status means API changes and frequent releases are possible. Verify the specific ${versions.netty} resolves to a supported incubator release and document the production-readiness rationale for this project.

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

1-1: Verify the SHA1 hash matches the official Maven Central artifact.

Version 4.2.7.Final is production-ready—the QUIC codec graduated from the incubator into Netty Core starting with 4.2.1.Final. Confirm the SHA1 hash d6a7141d5fab45c8d2f6c646965f2dd53a43b41e matches the published artifact in Maven Central.

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

100-100: LGTM!

The change correctly passes the settings object to ReactorHttpClient.create(), aligning with the updated API that now requires settings for protocol selection and configuration.

plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12)

92-92: LGTM!

Import for CertificateBuilder.Algorithm enum supports the updated key store creation with explicit algorithm selection.


121-121: LGTM!

Explicit algorithm specification (Algorithm.ecp384) for key store creation improves clarity and aligns with the updated KeyStoreUtils API.


166-170: LGTM!

The SSL engine construction is clean and correctly uses the key manager factory with the insecure trust manager for test purposes.


295-298: LGTM!

Correctly propagates the HTTP/3 enabled setting from initialSettings to ensure consistent transport configuration when testing address binding conflicts.


450-456: LGTM!

Randomized HTTP/3 enablement provides good test coverage for both HTTP/1.x and HTTP/3 paths in the large compressed response test.


256-256: LGTM!

Passing settings to ReactorHttpClient.https() ensures the client is configured consistently with the server's protocol settings.


363-363: LGTM!

Client creation with settings aligns with the updated API contract.


410-410: LGTM!

Consistent settings propagation to the HTTP client.


471-471: LGTM!

Settings-aware client creation for the large compressed response test.


543-543: LGTM!

Settings propagation for CORS pre-flight request test.


560-560: LGTM!

Settings propagation for CORS short-circuited request test.


646-648: LGTM!

Adding randomized HTTP/3 enablement to the base settings builder ensures comprehensive test coverage across both protocol modes for all tests in this class.

modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (5)

98-120: LGTM!

The HTTP/3 stream settings are well-documented with sensible defaults. The 100 concurrent bidirectional streams default aligns with RFC 9114 recommendations for maintaining performance parallelism.


148-189: LGTM!

Constructor properly initializes all HTTP/3 transport settings and follows established patterns from the existing Netty4HttpServerTransport implementation.


196-228: LGTM!

The lifecycle implementation correctly uses NioDatagramChannel for UDP-based QUIC transport and properly manages the shared group and bootstrap configuration.


337-354: LGTM!

The HTTP/3 pipeline is correctly configured with Http3FrameToHttpObjectCodec placed first to convert HTTP/3 frames to HTTP objects before downstream handlers process them. This addresses the previous review feedback about codec ordering.


378-447: LGTM!

Extension points for header verification and decompression provide appropriate plugin extensibility. The compression options correctly exclude ZSTD with clear documentation explaining the direct buffer constraints.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (4)

109-169: LGTM!

Test setup properly initializes the secure HTTP transport settings provider with appropriate key/trust manager factories for QUIC/TLS testing.


186-284: LGTM!

The "Expect: 100-continue" tests are well-structured, correctly use the HTTP/3 client, and properly handle response lifecycle with ByteBufUtil.getBytes() for safe buffer access.


577-588: LGTM!

The channel type mismatch from the previous review has been addressed. The bootstrap now correctly uses NioDatagramChannel with a matching ChannelInitializer<NioDatagramChannel> for proper UDP/QUIC testing.


599-605: LGTM!

Helper methods for creating test settings with randomized port ranges are clean and consistent.

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

63-64: LGTM!

Adding HTTP_3_0 to the HttpVersion enum correctly extends the public API to support HTTP/3 protocol identification. The placement maintains logical version ordering and is backward compatible.

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

122-122: LGTM!

The test correctly adapts to the updated ReactorHttpClient.create() signature by passing Settings.EMPTY.


162-162: LGTM!

The test correctly adapts to the updated ReactorHttpClient.create() signature by passing Settings.EMPTY in the try-with-resources block.

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

110-135: LGTM!

The HTTP/3 stream settings use appropriate defaults:

  • 1 MB (1,000,000 bytes) per stream for local and remote bidirectional streams aligns with typical QUIC implementation ranges (1-10 MB)
  • 100 concurrent bidirectional streams matches the HTTP/3 standard's minimum recommendation for maintaining parallelism

These values address the concerns raised in previous reviews about excessive memory allocation.


319-368: LGTM!

The configureHttp3() method correctly:

  • Checks for HTTP/3 availability and enablement (line 327)
  • Configures QUIC SSL context with appropriate trust managers and client auth (lines 328-336)
  • Uses SETTING_HTTP_MAX_CONTENT_LENGTH for connection-level maxData (line 356), which addresses previous feedback about not using the too-small SETTING_HTTP_MAX_CHUNK_SIZE
  • Applies the newly defined HTTP/3 stream settings for bidirectional data limits and stream counts (lines 357-359)

The connection-level maxData value derived from MAX_CONTENT_LENGTH is semantically reasonable and within typical QUIC implementation ranges.


370-370: LGTM!

Renaming the method to configureHttp11orHttp2() improves clarity by explicitly distinguishing HTTP/1.1/2 configuration from the new configureHttp3() method.

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

99-116: LGTM!

The updated constructor and factory method signatures correctly accept Settings to enable protocol selection (including HTTP/3) based on configuration. This is a necessary API evolution for HTTP/3 support, and the changes are consistent across all factory methods.


286-326: LGTM!

The createClient() method correctly configures protocol-specific SSL contexts and settings:

  • HTTP/1.1 and H2 paths use appropriate Http11SslContextSpec and Http2SslContextSpec
  • HTTP/3 path uses Http3SslContextSpec without the erroneous .build() call in the lambda (addressing previous feedback)
  • HTTP/3 settings use SETTING_HTTP_MAX_CONTENT_LENGTH for connection-level maxData instead of the inappropriate SETTING_HTTP_MAX_CHUNK_SIZE (addressing previous feedback)
  • All settings align with the server-side HTTP/3 configuration

The changes address the concerns raised in previous reviews.


333-335: LGTM!

Refactoring useHttp11only() to check the protocol field instead of a separate boolean flag is cleaner and more maintainable.

server/src/main/java/org/opensearch/bootstrap/Security.java (1)

132-134: Regex pattern correctly captures platform-specific JAR classifiers for Netty HTTP/3 libraries.

The updated pattern properly handles JAR names with platform prefixes (linux-, windows-, osx-) required for HTTP/3 QUIC support. The regex correctly extracts both the base library name and optional platform-specific classifier from test cases including netty-tcnative-boringssl-static, kafka-server-common, lucene-core, and zstd-jni variants.

Comment on lines +508 to +543
Channel prepare(Bootstrap clientBootstrap, Channel channel) throws InterruptedException {
final QuicChannel quicChannel = QuicChannel.newBootstrap(channel)
.handler(new Http3ClientConnectionHandler())
.remoteAddress(channel.remoteAddress())
.connect()
.sync()
.getNow();

return Http3.newRequestStream(quicChannel, new Http3RequestStreamInitializer() {
@Override
protected void initRequestStream(QuicStreamChannel ch) {
final int maxContentLength = new ByteSizeValue(100, ByteSizeUnit.MB).bytesAsInt();
ch.pipeline().addLast(new Http3FrameToHttpObjectCodec(false));
ch.pipeline().addLast(new HttpContentDecompressor());
ch.pipeline().addLast(new HttpObjectAggregator(maxContentLength));
ch.pipeline().addLast(new SimpleChannelInboundHandler<HttpObject>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
if (msg instanceof FullHttpResponse ht) {
// We copy the buffer manually to avoid a huge allocation on a pooled allocator. We have
// a test that tracks huge allocations, so we want to avoid them in this test code.
ByteBuf newContent = Unpooled.copiedBuffer(ht.content());
content.add(ht.replace(newContent));
}
latch.countDown();
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
latch.countDown();
}
});
}
}).sync().getNow();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Creating a new QUIC connection for each request is inefficient and non-idiomatic.

The prepare() method is called once per request in the sendRequests loop (line 256). Each invocation creates a new QuicChannel via QuicChannel.newBootstrap(channel).connect() (line 509), which establishes a new QUIC connection. For multiple requests, this results in multiple QUIC connections instead of reusing a single connection with multiple streams.

Correct HTTP/3 behavior:

  1. Create the QuicChannel once (e.g., cache it in a field after the first call)
  2. For subsequent requests, reuse the cached QuicChannel and create only new QuicStreamChannel instances via Http3.newRequestStream(cachedQuicChannel, ...)

Consider refactoring to cache the QuicChannel:

 private static class CountDownLatchHandlerHttp3 extends AwaitableChannelInitializer<DatagramChannel> {
     private final CountDownLatch latch;
     private final Collection<FullHttpResponse> content;
+    private volatile QuicChannel quicChannel;

     CountDownLatchHandlerHttp3(final CountDownLatch latch, final Collection<FullHttpResponse> content, final boolean secure) {
         this.latch = latch;
         this.content = content;
     }

     // ... initChannel remains the same ...

     @Override
     Channel prepare(Bootstrap clientBootstrap, Channel channel) throws InterruptedException {
-        final QuicChannel quicChannel = QuicChannel.newBootstrap(channel)
-            .handler(new Http3ClientConnectionHandler())
-            .remoteAddress(channel.remoteAddress())
-            .connect()
-            .sync()
-            .getNow();
+        if (quicChannel == null) {
+            synchronized (this) {
+                if (quicChannel == null) {
+                    quicChannel = QuicChannel.newBootstrap(channel)
+                        .handler(new Http3ClientConnectionHandler())
+                        .remoteAddress(channel.remoteAddress())
+                        .connect()
+                        .sync()
+                        .getNow();
+                }
+            }
+        }

         return Http3.newRequestStream(quicChannel, new Http3RequestStreamInitializer() {
             // ... rest remains the same ...
         }).sync().getNow();
     }
 }

Committable suggestion skipped: line range outside the PR's diff.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 5, 2025

❌ Gradle check result for 3c97207: 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

@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

♻️ Duplicate comments (10)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

507-543: Reuse the QuicChannel across multiple requests instead of creating a new connection per request.

The prepare() method creates a new QuicChannel (QUIC connection) on each invocation. Since sendRequests calls prepare() in a loop (line 256), each request establishes a separate QUIC connection. This is inefficient and non-idiomatic for HTTP/3, where multiple request streams should share a single QUIC connection.

Expected behavior:

  • First request: Create QuicChannel → create stream 1 → send request
  • Second request: Reuse QuicChannel → create stream 2 → send request

Current behavior:

  • First request: Create QuicChannel 1 → create stream → send request
  • Second request: Create QuicChannel 2 → create stream → send request

Cache the QuicChannel in a field and reuse it for subsequent streams:

 private static class CountDownLatchHandlerHttp3 extends AwaitableChannelInitializer<DatagramChannel> {
     private final CountDownLatch latch;
     private final Collection<FullHttpResponse> content;
+    private volatile QuicChannel quicChannel;

     CountDownLatchHandlerHttp3(final CountDownLatch latch, final Collection<FullHttpResponse> content, final boolean secure) {
         this.latch = latch;
         this.content = content;
     }

     // ... initChannel remains the same ...

     @Override
     Channel prepare(Bootstrap clientBootstrap, Channel channel) throws InterruptedException {
-        final QuicChannel quicChannel = QuicChannel.newBootstrap(channel)
-            .handler(new Http3ClientConnectionHandler())
-            .remoteAddress(channel.remoteAddress())
-            .connect()
-            .sync()
-            .getNow();
+        if (quicChannel == null) {
+            synchronized (this) {
+                if (quicChannel == null) {
+                    quicChannel = QuicChannel.newBootstrap(channel)
+                        .handler(new Http3ClientConnectionHandler())
+                        .remoteAddress(channel.remoteAddress())
+                        .connect()
+                        .sync()
+                        .getNow();
+                }
+            }
+        }

         return Http3.newRequestStream(quicChannel, new Http3RequestStreamInitializer() {
             @Override
             protected void initRequestStream(QuicStreamChannel ch) {
                 // ... pipeline setup remains the same ...
             }
         }).sync().getNow();
     }
 }
modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1)

27-27: Avoid exposing mutable DEFAULT_SSL_PROTOCOLS array as public API.

This concern was raised in a prior review. Changing this to public static final exposes a mutable array; any caller can modify its elements, silently changing TLS behavior globally at runtime. Prefer keeping the array private and exposing a defensive copy via an accessor method.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

380-388: Use StandardCharsets.UTF_8 instead of Charset.forName("UTF-8").

Line 380 uses Charset.forName("UTF-8") while the rest of the file uses StandardCharsets.UTF_8. Additionally, the past review concern about response.content().array() potentially throwing UnsupportedOperationException for direct buffers remains relevant.

-                final String url = "/" + new String(new byte[maxInitialLineLength], Charset.forName("UTF-8"));
+                final String url = "/" + new String(new byte[maxInitialLineLength], StandardCharsets.UTF_8);

For the response.content().array() issue on lines 386-388, consider using ByteBufUtil.getBytes() as suggested in the past review to handle both heap and direct buffers.


426-438: Test uses Settings.EMPTY which may cause port binding issues.

This was flagged in a prior review. Unlike other tests that use createSettings() to configure a random port range, testLargeCompressedResponse passes Settings.EMPTY which relies on default port binding. This could cause flaky failures in CI environments due to port conflicts.

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

357-376: Remove unused ServerChannelExceptionHandler or integrate it into the pipeline.

This class is defined but never instantiated or added to any channel pipeline. Either wire it into configureServerChannelHandler() to handle server-level exceptions, or remove the dead code to reduce maintenance burden.

If server-level exception handling is needed, consider adding it to the server channel pipeline. Otherwise, apply this diff:

-    @ChannelHandler.Sharable
-    private static class ServerChannelExceptionHandler extends ChannelInboundHandlerAdapter {
-
-        private final Netty4QuicServerTransport transport;
-
-        private ServerChannelExceptionHandler(Netty4QuicServerTransport transport) {
-            this.transport = transport;
-        }
-
-        @Override
-        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-            ExceptionsHelper.maybeDieOnAnotherThread(cause);
-            Netty4HttpServerChannel httpServerChannel = ctx.channel().attr(HTTP_SERVER_CHANNEL_KEY).get();
-            if (cause instanceof Error) {
-                transport.onServerException(httpServerChannel, new Exception(cause));
-            } else {
-                transport.onServerException(httpServerChannel, (Exception) cause);
-            }
-        }
-    }
CHANGELOG.md (1)

39-39: Remove duplicate changelog entry with malformed link.

Line 39 duplicates the entry already present on line 35 and has a malformed markdown link (trailing ] instead of )).

Apply this diff:

 - Support dynamic consumer configuration update in pull-based ingestion ([#19963](https://github.com/opensearch-project/OpenSearch/pull/19963))
 - Cache the `StoredFieldsReader` for scroll query optimization ([#20112](https://github.com/opensearch-project/OpenSearch/pull/20112))
-- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)]
 - Support for HTTP/3 (server side) ([#20017](https://github.com/opensearch-project/OpenSearch/pull/20017))
gradle/libs.versions.toml (1)

152-153: Dependency resolution will fail: netty-codec-classes-quic 4.2.7.Final unavailable.

As previously verified, netty-codec-classes-quic is not published at version 4.2.7.Final on Maven Central. The build will fail during dependency resolution.

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

26-37: Missing input validation in constructor may cause NPE.

The constructor accepts a varargs channels parameter without validating that it's non-null and non-empty. Line 37's getLocalAddress() dereferences channels[0] directly, which will throw NPE or ArrayIndexOutOfBoundsException if the array is null or empty.

Add validation at the start of the constructor:

 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 (1)

295-317: HTTP/3 server resource leak if HTTP/1.1/2 bind fails.

If http11or2.bindNow() (line 301) throws after http3Server is successfully created (line 300), the HTTP/3 server remains bound and will not be disposed, causing a resource leak and leaving a port occupied.

Wrap the HTTP/1.1/2 bind in try-catch to ensure cleanup:

         } else {
             final DisposableServer http3Server = http3Opt.get();
-            final DisposableServer http11or2Server = http11or2.bindNow();
+            final DisposableServer http11or2Server;
+            try {
+                http11or2Server = http11or2.bindNow();
+            } catch (Exception e) {
+                disposeQuietly(http3Server);
+                throw e;
+            }

             disposableServer = new DisposableServer() {
plugins/transport-reactor-netty4/build.gradle (1)

42-46: [DUPLICATE] Incorrect Netty QUIC native artifact coordinates—dependency resolution will fail.

This critical issue was flagged in a prior review and remains unresolved. The artifact coordinates io.netty:netty-codec-native-quic do not exist on Maven Central. The correct coordinates are io.netty.incubator:netty-incubator-codec-native-quic with separate versioning (historically 0.0.x.Final, now aligned with Netty releases).

Apply this diff to correct the artifact coordinates:

-  // Bundle all supported OSes and Archs
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:linux-x86_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:linux-aarch_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:osx-x86_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:osx-aarch_64"
-  runtimeOnly "io.netty:netty-codec-native-quic:${versions.netty}:windows-x86_64"
+  // Bundle all supported OSes and Archs
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:linux-x86_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:linux-aarch_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:osx-x86_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:osx-aarch_64"
+  runtimeOnly "io.netty.incubator:netty-incubator-codec-native-quic:${versions.nettyQuic}:windows-x86_64"

Then verify the corrected coordinates resolve by running a dependency check:

#!/bin/bash
# Verify corrected QUIC artifact coordinates resolve on Maven Central
cd plugins/transport-reactor-netty4
./gradlew dependencies --configuration runtimeClasspath 2>&1 | grep -A2 -B2 'netty-incubator-codec-native-quic'
🧹 Nitpick comments (4)
modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (1)

488-505: Consider parameterizing QUIC client settings for test flexibility.

The QUIC client codec uses Settings.EMPTY for all configuration (max content length, stream lengths, max streams). While default values work for most tests, consider accepting a Settings parameter in the factory method to allow tests to customize these limits when needed (e.g., testing large payloads or many concurrent streams).

Example approach:

-public static Netty4HttpClient http3() {
+public static Netty4HttpClient http3(Settings settings) {
     return new Netty4HttpClient(
         new Bootstrap().channel(NioDatagramChannel.class)
             .option(ChannelOption.ALLOCATOR, NettyAllocator.getAllocator(true))
             .group(new NioEventLoopGroup(1)),
-        CountDownLatchHandlerHttp3::new,
+        (latch, content, secure) -> new CountDownLatchHandlerHttp3(latch, content, secure, settings),
         false
     );
 }

Then pass settings instead of Settings.EMPTY in lines 498-501.

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

160-166: Consider simplifying the boolean comparison.

The logic correctly provides direct buffer support for HTTP/3/QUIC which requires direct buffers. Minor style suggestion: directBuffers == true can be simplified to directBuffers.

     public static ByteBufAllocator getAllocator(boolean directBuffers) {
-        if (directBuffers == true && ALLOCATOR instanceof NoDirectBuffers ndb) {
+        if (directBuffers && ALLOCATOR instanceof NoDirectBuffers ndb) {
             return ndb.delegate; /* Http3/Quic only supports direct buffers */
         } else {
             return ALLOCATOR;
         }
     }
plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransport.java (1)

320-369: Consider validating QUIC availability earlier to fail fast.

The HTTP/3 configuration checks Http3.isHttp3Available() inside configureHttp3(), which is called during bind. Consider validating HTTP/3 availability during doStart() and logging a clear warning if HTTP/3 is enabled but unavailable (e.g., missing native libraries for the current OS/architecture), so operators can detect configuration issues before attempting to bind.

server/src/main/java/org/opensearch/bootstrap/Security.java (1)

132-134: Regex update for CODEBASE_JAR_WITH_CLASSIFIER looks correct; confirm classifier semantics vs existing policies

The new pattern:

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

behaves as expected for the examples called out in the comments:

  • netty-tcnative-boringssl-static-2.0.61.Final-linux-x86_64.jargroup(2) == "linux-x86_64".
  • kafka-server-common-3.6.1-test.jargroup(2) == "test".
  • zstd-jni-1.5.6-1.jargroup(2) == "1".
  • Plain versioned jars like lucene-core-9.11.0.jar keep group(2) == null and follow the existing non-classifier path.

One nuance to be aware of: for names with multiple hyphen-separated tokens after the version (e.g., lucene-core-9.11.0-snapshot-8a555eb.jar), group(2) will only expose the final token ("8a555eb"), not "snapshot-8a555eb". That’s fine if the intent is just to derive a unique suffix for aliasing, but it can change the exact alias key used in policy files (codebase.<name>@<suffix>).

I’d suggest:

  • Double-checking whether any existing .policy files rely on the old group(2) shape (e.g., expecting snapshot-<hash> instead of just <hash>), since that could silently change alias names.
  • Adding or updating a small unit test for CODEBASE_JAR_WITH_CLASSIFIER covering the four examples in the comment (including the lucene snapshot case) so future classifier variants don’t regress.

If you want, I can sketch a small JUnit test that exercises this pattern against representative jar names and asserts the expected group(1) / group(2) pairs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c97207 and ffa76d3.

📒 Files selected for processing (44)
  • 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)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java (2 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4QuicServerTransport.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/NettyAllocator.java (1 hunks)
  • modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/SslUtils.java (1 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (13 hunks)
  • modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.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 (7 hunks)
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/transport/reactor/ReactorNetty4Plugin.java (1 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 (3 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (7 hunks)
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java (12 hunks)
  • server/src/main/java/org/opensearch/bootstrap/Security.java (1 hunks)
  • server/src/main/java/org/opensearch/common/settings/ClusterSettings.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 (1)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final.jar.sha1
🚧 Files skipped from review as they are similar to previous changes (22)
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequestHandler.java
  • modules/transport-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4PipeliningIT.java
  • plugins/transport-reactor-netty4/src/internalClusterTest/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequestSizeLimitIT.java
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_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-native-quic-4.2.7.Final-windows-x86_64.jar.sha1
  • plugins/transport-reactor-netty4/licenses/netty-codec-classes-quic-4.2.7.Final.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpRequest.java
  • modules/transport-netty4/licenses/netty-codec-native-quic-4.2.7.Final-osx-aarch_64.jar.sha1
  • plugins/transport-reactor-netty4/src/main/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpRequest.java
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ssl/SecureReactorNetty4HttpServerTransportTests.java
  • plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportStreamingTests.java
  • 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-osx-x86_64.jar.sha1
  • modules/transport-netty4/licenses/netty-codec-native-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
  • plugins/transport-reactor-netty4/licenses/netty-codec-native-quic-4.2.7.Final-linux-aarch_64.jar.sha1
  • modules/transport-netty4/src/main/java/org/opensearch/http/netty4/Netty4HttpServerTransport.java
  • test/framework/src/main/java/org/opensearch/test/KeyStoreUtils.java
🧰 Additional context used
🧬 Code graph analysis (2)
server/src/main/java/org/opensearch/common/settings/ClusterSettings.java (1)
server/src/main/java/org/opensearch/http/HttpTransportSettings.java (1)
  • HttpTransportSettings (58-270)
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)
⏰ 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: assemble (21, ubuntu-24.04-arm)
  • GitHub Check: assemble (25, ubuntu-latest)
  • GitHub Check: assemble (21, windows-latest)
  • GitHub Check: assemble (21, ubuntu-latest)
  • GitHub Check: assemble (25, ubuntu-24.04-arm)
  • GitHub Check: assemble (25, windows-latest)
  • GitHub Check: precommit (25, macos-15-intel)
  • GitHub Check: precommit (25, macos-15)
  • GitHub Check: precommit (21, windows-2025, true)
  • GitHub Check: precommit (25, ubuntu-24.04-arm)
  • GitHub Check: precommit (25, ubuntu-latest)
  • GitHub Check: precommit (25, windows-latest)
  • GitHub Check: precommit (21, macos-15-intel)
  • GitHub Check: precommit (21, macos-15)
  • GitHub Check: precommit (21, ubuntu-24.04-arm)
  • GitHub Check: precommit (21, ubuntu-latest)
  • GitHub Check: precommit (21, windows-latest)
  • GitHub Check: Analyze (java)
  • GitHub Check: Mend Security Check
🔇 Additional comments (20)
plugins/transport-reactor-netty4/src/test/java/org/opensearch/http/reactor/netty4/ReactorNetty4HttpServerTransportTests.java (1)

205-205: LGTM! Consistent Settings propagation to ReactorHttpClient.

The updates consistently pass Settings to ReactorHttpClient.create() across all test methods, aligning client configuration with the transport. When the transport uses specific settings, the client receives them; when the transport uses Settings.EMPTY, so does the client. This enables HTTP/3 protocol configuration to flow through the test infrastructure.

Also applies to: 310-310, 356-356, 412-412, 478-478, 541-541, 558-558

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java (2)

181-189: LGTM! HTTP/3 factory correctly configured for QUIC transport.

The factory method properly sets up a UDP-based (DatagramChannel) bootstrap for QUIC/HTTP/3, with the appropriate allocator and handler.


516-542: LGTM! HTTP/3 request stream pipeline correctly configured.

The pipeline setup follows the correct order for HTTP/3:

  1. Http3FrameToHttpObjectCodec(false) converts HTTP/3 frames to HTTP objects
  2. Standard HTTP processing (HttpContentDecompressor, HttpObjectAggregator)
  3. Application handler

The response handler properly copies buffers to avoid pooled allocator issues and counts down the latch in both success and exception paths.

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

59-66: LGTM!

The expansion of getSettings() to include the new HTTP/3 related settings (SETTING_H3_MAX_STREAM_LOCAL_LENGTH, SETTING_H3_MAX_STREAM_REMOTE_LENGTH, SETTING_H3_MAX_STREAMS) aligns with the HTTP/3 feature additions and properly exposes these settings for cluster configuration.

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

1-1: LGTM!

SHA1 checksum file for the new netty-codec-http3 dependency required for HTTP/3 support.

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

60-65: LGTM!

The HTTP_3_0 constant extends the public HttpVersion enum to support HTTP/3 protocol identification, maintaining consistent naming with existing versions.

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4QuicServerTransportTests.java (2)

109-169: LGTM on test setup!

The test infrastructure is well-configured with proper SSL/TLS setup using PKIX key manager factory and ECP384 algorithm, appropriate for HTTP/3 testing requirements.


577-596: LGTM on read timeout test structure!

The test correctly uses NioDatagramChannel with matching ChannelInitializer<NioDatagramChannel> generic type, addressing the previous channel type mismatch concern. The UDP-based bootstrap is appropriate for QUIC testing.

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

99-104: LGTM on constructor refactoring!

The constructor now properly accepts Settings and delegates to randomProtocol() for protocol selection, enabling settings-driven HTTP/3 enablement.


106-116: LGTM on factory method updates!

The static factory methods now require Settings parameter, ensuring consistent settings propagation for protocol selection.


287-318: LGTM on HTTP/3 client configuration!

The secure client configuration correctly handles all three protocol paths:

  • HTTP/1.1 with Http11SslContextSpec
  • HTTP/2 with Http2SslContextSpec (including HTTP/1.1 fallback)
  • HTTP/3 with Http3SslContextSpec and proper QUIC settings

The http3Settings configuration correctly uses connection-level SETTING_HTTP_MAX_CONTENT_LENGTH for maxData (addressing the prior review concern) and stream-level settings for bidirectional stream limits.


337-351: LGTM on protocol selection logic!

The randomProtocol() method correctly:

  • Checks Http3.isHttp3Available() before including HTTP/3 as an option
  • Respects SETTING_HTTP_HTTP3_ENABLED setting
  • Falls back to HTTP/1.1 and H2 when HTTP/3 is unavailable or disabled
server/src/main/java/org/opensearch/common/settings/ClusterSettings.java (1)

427-427: LGTM! HTTP/3 setting properly registered.

The addition of SETTING_HTTP_HTTP3_ENABLED to the built-in cluster settings is correct and necessary for cluster-wide recognition of the HTTP/3 enablement flag.

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

262-267: LGTM! HTTP/3 enablement setting properly defined.

The setting declaration is correct with appropriate default (false), scope (NodeScope), and documentation noting OS/architecture dependencies.

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

66-84: LGTM! HTTP/3 and QUIC dependencies properly added.

The additions correctly wire HTTP/3 and QUIC codecs as API dependencies and include platform-specific native QUIC libraries for comprehensive runtime support across Linux, macOS, and Windows on both x86_64 and aarch64 architectures.


219-221: LGTM! thirdPartyAudit exclusions appropriate for QUIC integration.

The additions to ignoreMissingClasses for io.netty.pkitesting.X509Bundle and io.netty.channel.epoll.SegmentedDatagramPacket are appropriate for the Netty QUIC codec integration.

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

114-136: LGTM! HTTP/3 stream settings use reasonable defaults.

The defaults of 1MB per stream (local/remote) and 100 concurrent bidirectional streams align with typical QUIC implementations and provide a good balance between memory usage and throughput for server-side HTTP/3.

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

162-162: Addition of SegmentedDatagramPacket to ignoreMissingClasses is appropriate for UDP-based QUIC support.

The addition of io.netty.channel.epoll.SegmentedDatagramPacket to the ignoreMissingClasses list aligns with Netty's UDP-based QUIC implementation and is consistent with the native QUIC codec additions in this file.


37-39: Verify that libs.netty.codec.classes.quic and libs.netty.codec.native.quic are defined in the version catalog.

Lines 38–39 reference version catalog properties for QUIC codecs. Ensure these aliases are properly defined in the central version catalog (typically gradle/libs.versions.toml) and resolve to valid Netty QUIC artifacts.

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

1-1: Confirm the SHA-1 hash matches Maven Central upstream.

The io.netty:netty-codec-native-quic:4.2.7.Final version is current (released October 14, 2025) and the checksum file format is correct. Verify the digest 6a3e4398852f926c4b22f381d89dae2388446ae8 matches the upstream artifact by running:

curl -s "https://repo1.maven.org/maven2/io/netty/netty-codec-native-quic/4.2.7.Final/netty-codec-native-quic-4.2.7.Final-linux-x86_64.jar.sha1"

If the value differs from what's in the file, update the checksum to match the upstream artifact.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 5, 2025

❌ Gradle check result for ffa76d3: 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?

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.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for HTTP/3 (server side)

2 participants