Skip to content

Conversation

@starlightromero
Copy link

@starlightromero starlightromero commented Dec 11, 2025

Description

This PR adds HTTP/2 cleartext (h2c) protocol support to the interceptor proxy server, enabling AWS Application Load Balancers and other clients to communicate using HTTP/2 over plain HTTP.

Changes

  • Wrapped non-TLS handlers with to support HTTP/2 cleartext connections
  • Added dependency golang.org/x/net/http2 for h2c support
  • Comprehensive test coverage in pkg/http/h2c_test.go for both HTTP/1.1 and HTTP/2 h2c
  • HTTP/1.1 clients continue to work without any changes

Motivation

When using the AWS Load Balancer Controller Gateway API implementation, setting appProtocol: kubernetes.io/h2c on a Kubernetes Service instructs the controller to create ALB target groups with ProtocolVersion: HTTP2. However, the KEDA HTTP Add-on interceptor did not support h2c, causing health checks and traffic to fail.

This change enables:

  • ALB → Interceptor communication using HTTP/2 for improved performance
  • Support for appProtocol: kubernetes.io/h2c on Kubernetes Services
  • Better efficiency with HTTP/2 multiplexing and header compression

How It Works

The implementation wraps non-TLS handlers with h2c.NewHandler, which automatically:

  • Handles HTTP/2 connections with prior knowledge (what ALBs use)
  • Falls back to HTTP/1.1 for standard requests
  • Requires no configuration changes in Kubernetes manifests

TLS connections remain unchanged and continue to use native HTTP/2 over TLS.

Testing

  • ✅ All existing unit tests pass
  • ✅ New test TestHTTP2H2CSupport validates both HTTP/1.1 and HTTP/2 h2c functionality
  • ✅ Tested in live cluster with AWS ALB successfully using HTTP/2 target groups

Checklist

  • Commits are signed (DCO)
  • Tests pass locally (make test)
  • Code follows project style (pre-commit checks)
  • Backwards compatible with HTTP/1.1
  • Documentation included in commit message

Fixes: Enables HTTP/2 h2c support from ALB to interceptor pods

Enable HTTP/2 cleartext (h2c) protocol support for non-TLS connections in the interceptor proxy server. This allows AWS Application Load Balancers and other clients to communicate with the interceptor using HTTP/2 over plain HTTP. When tlsConfig is nil, the handler is wrapped with h2c.NewHandler to support both HTTP/2 prior knowledge and HTTP/1.1 connections. TLS connections remain unchanged and continue to support native HTTP/2 over TLS. This change enables the use of appProtocol: kubernetes.io/h2c on Kubernetes Services, which instructs the AWS Load Balancer Controller to create target groups with ProtocolVersion: HTTP2 for improved performance and efficiency. Changes: - Wrap non-TLS handlers with h2c.NewHandler in pkg/http/server.go - Add golang.org/x/net/http2 dependency for h2c support - Add comprehensive test coverage for both HTTP/1.1 and HTTP/2 h2c - Maintain backwards compatibility with HTTP/1.1 clients Fixes: Enables HTTP/2 h2c support from ALB to interceptor pods Signed-off-by: Starlight Romero <28881133+starlightromero@users.noreply.github.com>
@snyk-io
Copy link

snyk-io bot commented Dec 11, 2025

⚠️ Snyk checks are incomplete.

Status Scanner Critical High Medium Low Total (0)
⚠️ Open Source Security 0 0 0 0 See details

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Copy link
Contributor

@linkvt linkvt left a comment

Choose a reason for hiding this comment

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

Hi @starlightromero ,

thanks for the PR! I left a few comments but also think that we would benefit from a written design in an issue here in the repo - at least in my opinion.

I'm not a maintainer of this project though.

Comment on lines +16 to +19
if tlsConfig == nil {
h2s := &http2.Server{}
hdl = h2c.NewHandler(hdl, h2s)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

golang has HTTP2 support for server and clients in its standard library, they added it quite recently: https://go.dev/doc/go1.24#nethttppkgnethttp

I would prefer using that over the extended standard library as they already plan to deprecate the golang.org/x/net/http2/client subpackage: golang/go#72039

Handler: hdl,
Addr: addr,
TLSConfig: tlsConfig,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

How do we handle:

  1. HTTP1 connections to services responding with h2c
  2. h2c connections to services responding with HTTP1?
Comment on lines +69 to +72
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
// Use standard dialer for h2c (cleartext HTTP/2)
return net.Dial(network, addr)
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this actually needed/used during an non HTTPS request?

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

serverAddr := "127.0.0.1:18888"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should not expect a specific port on a system to be free for us to use during a test. I know that the httptest package can pick a selected port, not sure if we can use it here, but maybe there is another way to get a port thats always free to use.

@@ -0,0 +1,90 @@
package http
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO we should have e2e tests covering the different scenarios here (client uses http1/h2c, user application supports http1/h2c/both) as unit tests would not cover all cases.

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

Labels

None yet

2 participants