CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-grpc--grpc-netty

Netty-based HTTP/2 transport implementation for gRPC Java providing high-performance network communication

Pending
Overview
Eval results
Files

protocol-negotiation.mddocs/

Protocol Negotiation

HTTP/2 protocol negotiation strategies for different deployment scenarios, from TLS ALPN to plaintext upgrades and direct HTTP/2 connections.

Core Imports

import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
import io.grpc.netty.NettyServerBuilder;

NegotiationType

Enum defining the negotiation method for establishing HTTP/2 connections.

public enum NegotiationType {
    TLS,
    PLAINTEXT_UPGRADE,
    PLAINTEXT
}

TLS

Uses TLS ALPN (Application Layer Protocol Negotiation) or NPN (Next Protocol Negotiation) to negotiate HTTP/2 over an encrypted connection.

  • Use Case: Production deployments, internet-facing services
  • Security: Encrypted communication
  • Port: Typically 443 or custom secure ports
  • Requirements: Valid TLS certificates and SSL configuration

PLAINTEXT_UPGRADE

Uses HTTP/1.1 Upgrade header to negotiate from HTTP/1.1 to HTTP/2 over a plaintext connection.

  • Use Case: Development, testing, or controlled network environments
  • Security: Unencrypted communication
  • Port: Typically 80 or custom ports
  • Requirements: Initial HTTP/1.1 request with upgrade headers

PLAINTEXT

Assumes the connection directly supports HTTP/2 without negotiation.

  • Use Case: Internal services, microservice communication, load balancer backends
  • Security: Unencrypted communication
  • Port: Custom ports
  • Requirements: Both endpoints must support direct HTTP/2

InsecureFromHttp1ChannelCredentials

Experimental credentials for HTTP/1.1 to HTTP/2 upgrade scenarios.

public static ChannelCredentials create();

Returns: ChannelCredentials that performs insecure HTTP/1 to HTTP/2 upgrade

ProtocolNegotiator (Experimental)

Abstract base class for custom protocol negotiators.

public abstract AsciiString scheme();
public abstract ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler);

Methods:

  • scheme() - Returns protocol scheme ("https", "http", etc.)
  • newHandler() - Creates Netty channel handler for negotiation

ProtocolNegotiators (Experimental)

Factory for creating various protocol negotiators.

Server Negotiators

public static ProtocolNegotiator serverTls(SslContext sslContext);
public static ProtocolNegotiator serverTls(SslContext sslContext, HostnameVerifier hostnameVerifier);
public static ProtocolNegotiator serverPlaintext();

Client Negotiators

public static ProtocolNegotiator tls(SslContext sslContext);
public static ProtocolNegotiator tls(SslContext sslContext, String authority);
public static ProtocolNegotiator plaintext();
public static ProtocolNegotiator plaintextUpgrade();

Parameters:

  • sslContext - Netty SSL context for TLS connections
  • hostnameVerifier - Custom hostname verification
  • authority - Expected server authority for verification

Usage Examples

TLS Negotiation (Production)

import io.grpc.netty.NettyChannelBuilder;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.GrpcSslContexts;

// Client
SslContext sslContext = GrpcSslContexts.forClient().build();

ManagedChannel channel = NettyChannelBuilder.forAddress("api.example.com", 443)
    .negotiationType(NegotiationType.TLS)
    .sslContext(sslContext)
    .build();

// Server  
SslContext serverSslContext = GrpcSslContexts.forServer(
    new File("server-cert.pem"),
    new File("server-key.pem")
).build();

Server server = NettyServerBuilder.forPort(443)
    .sslContext(serverSslContext)
    .addService(new GreeterImpl())
    .build();

Plaintext Upgrade (Development)

import io.grpc.netty.InsecureFromHttp1ChannelCredentials;

// Client with HTTP/1.1 to HTTP/2 upgrade
ChannelCredentials creds = InsecureFromHttp1ChannelCredentials.create();

ManagedChannel channel = Grpc.newChannelBuilder("localhost:8080", creds)
    .build();

// Alternative using NegotiationType
ManagedChannel channel2 = NettyChannelBuilder.forAddress("localhost", 8080)
    .negotiationType(NegotiationType.PLAINTEXT_UPGRADE)
    .usePlaintext()
    .build();

// Server supporting upgrade
Server server = NettyServerBuilder.forPort(8080)
    .addService(new GreeterImpl())
    .build();

Direct Plaintext (Internal Services)

// Client assuming direct HTTP/2
ManagedChannel channel = NettyChannelBuilder.forAddress("internal-service", 9090)
    .negotiationType(NegotiationType.PLAINTEXT)
    .usePlaintext()
    .build();

// Server with direct HTTP/2
Server server = NettyServerBuilder.forPort(9090)
    .addService(new GreeterImpl())
    .build();

Custom Protocol Negotiator (Advanced)

import io.grpc.netty.ProtocolNegotiators;
import io.grpc.netty.ProtocolNegotiator;

// Client with custom TLS negotiator
SslContext sslContext = GrpcSslContexts.forClient()
    .trustManager(InsecureTrustManagerFactory.INSTANCE)
    .build();

ProtocolNegotiator negotiator = ProtocolNegotiators.tls(sslContext, "my-service");

// Use with Netty internals (experimental)

Load Balancer Scenarios

Behind HTTPS Load Balancer

// Load balancer terminates TLS, forwards HTTP/2 plaintext to backend
ManagedChannel channel = NettyChannelBuilder.forAddress("backend-service", 9090)
    .negotiationType(NegotiationType.PLAINTEXT)
    .usePlaintext()
    .build();

HTTP/1.1 Load Balancer

// Load balancer only supports HTTP/1.1, needs upgrade
ManagedChannel channel = NettyChannelBuilder.forAddress("service", 80)
    .negotiationType(NegotiationType.PLAINTEXT_UPGRADE)
    .usePlaintext()
    .build();

Testing Scenarios

Development Setup

// Simple plaintext for local development
ManagedChannel channel = NettyChannelBuilder.forAddress("localhost", 9090)
    .usePlaintext() // Automatically uses appropriate negotiation
    .build();

Server server = NettyServerBuilder.forPort(9090)
    .addService(new GreeterImpl())
    .build();

Integration Testing with TLS

// Self-signed certificates for testing
SslContext testSslContext = GrpcSslContexts.forServer(
    new File("test-cert.pem"),
    new File("test-key.pem")
).build();

Server testServer = NettyServerBuilder.forPort(0) // Random available port
    .sslContext(testSslContext)
    .addService(new GreeterImpl())
    .build()
    .start();

int port = testServer.getPort();

SslContext clientSslContext = GrpcSslContexts.forClient()
    .trustManager(InsecureTrustManagerFactory.INSTANCE)
    .build();

ManagedChannel channel = NettyChannelBuilder.forAddress("localhost", port)
    .sslContext(clientSslContext)
    .build();

Docker and Container Deployments

Container-to-Container Communication

// Direct HTTP/2 within container network
ManagedChannel channel = NettyChannelBuilder.forAddress("service-name", 9090)
    .negotiationType(NegotiationType.PLAINTEXT)
    .usePlaintext()
    .build();

Ingress with TLS Termination

// Ingress handles TLS, forwards plaintext to pods
Server server = NettyServerBuilder.forPort(9090)
    .addService(new GreeterImpl())
    .build(); // Plaintext server for ingress backend

Debugging Negotiation Issues

Enable Netty Logging

// Add to JVM args or logging configuration
-Dio.netty.leakDetection.level=paranoid
-Djavax.net.debug=ssl:handshake:verbose

Check ALPN Support

import io.netty.handler.ssl.OpenSsl;

System.out.println("OpenSSL available: " + OpenSsl.isAvailable());
System.out.println("ALPN support: " + OpenSsl.isAlpnSupported());

Common Negotiation Errors

HTTP/2 not negotiated:

UNAVAILABLE: HTTP/2 connection preface not received

Solution: Verify ALPN configuration and protocol support

TLS handshake failure:

SSLHandshakeException during negotiation

Solution: Check certificate configuration and cipher suite compatibility

Upgrade failure:

UNAVAILABLE: HTTP/1.1 to HTTP/2 upgrade failed

Solution: Ensure server supports HTTP/2 upgrade headers

Best Practices

  1. Production: Always use NegotiationType.TLS with proper certificates
  2. Development: Use usePlaintext() for simplicity, let gRPC choose negotiation
  3. Internal Services: Use NegotiationType.PLAINTEXT for direct HTTP/2
  4. Load Balancers: Match negotiation type to load balancer capabilities
  5. Testing: Use insecure trust managers only in test environments
  6. Monitoring: Log negotiation outcomes for debugging

Install with Tessl CLI

npx tessl i tessl/maven-io-grpc--grpc-netty

docs

client-transport.md

index.md

protocol-negotiation.md

server-transport.md

socket-support.md

ssl-tls.md

tile.json