or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-transport.mdindex.mdprotocol-negotiation.mdserver-transport.mdsocket-support.mdssl-tls.md

protocol-negotiation.mddocs/

0

# Protocol Negotiation

1

2

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

3

4

## Core Imports

5

6

```java

7

import io.grpc.netty.NegotiationType;

8

import io.grpc.netty.NettyChannelBuilder;

9

import io.grpc.netty.NettyServerBuilder;

10

```

11

12

## NegotiationType

13

14

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

15

16

```java { .api }

17

public enum NegotiationType {

18

TLS,

19

PLAINTEXT_UPGRADE,

20

PLAINTEXT

21

}

22

```

23

24

### TLS

25

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

26

27

- **Use Case**: Production deployments, internet-facing services

28

- **Security**: Encrypted communication

29

- **Port**: Typically 443 or custom secure ports

30

- **Requirements**: Valid TLS certificates and SSL configuration

31

32

### PLAINTEXT_UPGRADE

33

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

34

35

- **Use Case**: Development, testing, or controlled network environments

36

- **Security**: Unencrypted communication

37

- **Port**: Typically 80 or custom ports

38

- **Requirements**: Initial HTTP/1.1 request with upgrade headers

39

40

### PLAINTEXT

41

Assumes the connection directly supports HTTP/2 without negotiation.

42

43

- **Use Case**: Internal services, microservice communication, load balancer backends

44

- **Security**: Unencrypted communication

45

- **Port**: Custom ports

46

- **Requirements**: Both endpoints must support direct HTTP/2

47

48

## InsecureFromHttp1ChannelCredentials

49

50

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

51

52

```java { .api }

53

public static ChannelCredentials create();

54

```

55

56

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

57

58

## ProtocolNegotiator (Experimental)

59

60

Abstract base class for custom protocol negotiators.

61

62

```java { .api }

63

public abstract AsciiString scheme();

64

public abstract ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler);

65

```

66

67

**Methods:**

68

- `scheme()` - Returns protocol scheme ("https", "http", etc.)

69

- `newHandler()` - Creates Netty channel handler for negotiation

70

71

## ProtocolNegotiators (Experimental)

72

73

Factory for creating various protocol negotiators.

74

75

### Server Negotiators

76

77

```java { .api }

78

public static ProtocolNegotiator serverTls(SslContext sslContext);

79

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

80

public static ProtocolNegotiator serverPlaintext();

81

```

82

83

### Client Negotiators

84

85

```java { .api }

86

public static ProtocolNegotiator tls(SslContext sslContext);

87

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

88

public static ProtocolNegotiator plaintext();

89

public static ProtocolNegotiator plaintextUpgrade();

90

```

91

92

**Parameters:**

93

- `sslContext` - Netty SSL context for TLS connections

94

- `hostnameVerifier` - Custom hostname verification

95

- `authority` - Expected server authority for verification

96

97

## Usage Examples

98

99

### TLS Negotiation (Production)

100

101

```java

102

import io.grpc.netty.NettyChannelBuilder;

103

import io.grpc.netty.NegotiationType;

104

import io.grpc.netty.GrpcSslContexts;

105

106

// Client

107

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

108

109

ManagedChannel channel = NettyChannelBuilder.forAddress("api.example.com", 443)

110

.negotiationType(NegotiationType.TLS)

111

.sslContext(sslContext)

112

.build();

113

114

// Server

115

SslContext serverSslContext = GrpcSslContexts.forServer(

116

new File("server-cert.pem"),

117

new File("server-key.pem")

118

).build();

119

120

Server server = NettyServerBuilder.forPort(443)

121

.sslContext(serverSslContext)

122

.addService(new GreeterImpl())

123

.build();

124

```

125

126

### Plaintext Upgrade (Development)

127

128

```java

129

import io.grpc.netty.InsecureFromHttp1ChannelCredentials;

130

131

// Client with HTTP/1.1 to HTTP/2 upgrade

132

ChannelCredentials creds = InsecureFromHttp1ChannelCredentials.create();

133

134

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

135

.build();

136

137

// Alternative using NegotiationType

138

ManagedChannel channel2 = NettyChannelBuilder.forAddress("localhost", 8080)

139

.negotiationType(NegotiationType.PLAINTEXT_UPGRADE)

140

.usePlaintext()

141

.build();

142

143

// Server supporting upgrade

144

Server server = NettyServerBuilder.forPort(8080)

145

.addService(new GreeterImpl())

146

.build();

147

```

148

149

### Direct Plaintext (Internal Services)

150

151

```java

152

// Client assuming direct HTTP/2

153

ManagedChannel channel = NettyChannelBuilder.forAddress("internal-service", 9090)

154

.negotiationType(NegotiationType.PLAINTEXT)

155

.usePlaintext()

156

.build();

157

158

// Server with direct HTTP/2

159

Server server = NettyServerBuilder.forPort(9090)

160

.addService(new GreeterImpl())

161

.build();

162

```

163

164

### Custom Protocol Negotiator (Advanced)

165

166

```java

167

import io.grpc.netty.ProtocolNegotiators;

168

import io.grpc.netty.ProtocolNegotiator;

169

170

// Client with custom TLS negotiator

171

SslContext sslContext = GrpcSslContexts.forClient()

172

.trustManager(InsecureTrustManagerFactory.INSTANCE)

173

.build();

174

175

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

176

177

// Use with Netty internals (experimental)

178

```

179

180

## Load Balancer Scenarios

181

182

### Behind HTTPS Load Balancer

183

184

```java

185

// Load balancer terminates TLS, forwards HTTP/2 plaintext to backend

186

ManagedChannel channel = NettyChannelBuilder.forAddress("backend-service", 9090)

187

.negotiationType(NegotiationType.PLAINTEXT)

188

.usePlaintext()

189

.build();

190

```

191

192

### HTTP/1.1 Load Balancer

193

194

```java

195

// Load balancer only supports HTTP/1.1, needs upgrade

196

ManagedChannel channel = NettyChannelBuilder.forAddress("service", 80)

197

.negotiationType(NegotiationType.PLAINTEXT_UPGRADE)

198

.usePlaintext()

199

.build();

200

```

201

202

## Testing Scenarios

203

204

### Development Setup

205

206

```java

207

// Simple plaintext for local development

208

ManagedChannel channel = NettyChannelBuilder.forAddress("localhost", 9090)

209

.usePlaintext() // Automatically uses appropriate negotiation

210

.build();

211

212

Server server = NettyServerBuilder.forPort(9090)

213

.addService(new GreeterImpl())

214

.build();

215

```

216

217

### Integration Testing with TLS

218

219

```java

220

// Self-signed certificates for testing

221

SslContext testSslContext = GrpcSslContexts.forServer(

222

new File("test-cert.pem"),

223

new File("test-key.pem")

224

).build();

225

226

Server testServer = NettyServerBuilder.forPort(0) // Random available port

227

.sslContext(testSslContext)

228

.addService(new GreeterImpl())

229

.build()

230

.start();

231

232

int port = testServer.getPort();

233

234

SslContext clientSslContext = GrpcSslContexts.forClient()

235

.trustManager(InsecureTrustManagerFactory.INSTANCE)

236

.build();

237

238

ManagedChannel channel = NettyChannelBuilder.forAddress("localhost", port)

239

.sslContext(clientSslContext)

240

.build();

241

```

242

243

## Docker and Container Deployments

244

245

### Container-to-Container Communication

246

247

```java

248

// Direct HTTP/2 within container network

249

ManagedChannel channel = NettyChannelBuilder.forAddress("service-name", 9090)

250

.negotiationType(NegotiationType.PLAINTEXT)

251

.usePlaintext()

252

.build();

253

```

254

255

### Ingress with TLS Termination

256

257

```java

258

// Ingress handles TLS, forwards plaintext to pods

259

Server server = NettyServerBuilder.forPort(9090)

260

.addService(new GreeterImpl())

261

.build(); // Plaintext server for ingress backend

262

```

263

264

## Debugging Negotiation Issues

265

266

### Enable Netty Logging

267

268

```java

269

// Add to JVM args or logging configuration

270

-Dio.netty.leakDetection.level=paranoid

271

-Djavax.net.debug=ssl:handshake:verbose

272

```

273

274

### Check ALPN Support

275

276

```java

277

import io.netty.handler.ssl.OpenSsl;

278

279

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

280

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

281

```

282

283

### Common Negotiation Errors

284

285

**HTTP/2 not negotiated:**

286

```

287

UNAVAILABLE: HTTP/2 connection preface not received

288

```

289

**Solution:** Verify ALPN configuration and protocol support

290

291

**TLS handshake failure:**

292

```

293

SSLHandshakeException during negotiation

294

```

295

**Solution:** Check certificate configuration and cipher suite compatibility

296

297

**Upgrade failure:**

298

```

299

UNAVAILABLE: HTTP/1.1 to HTTP/2 upgrade failed

300

```

301

**Solution:** Ensure server supports HTTP/2 upgrade headers

302

303

## Best Practices

304

305

1. **Production**: Always use `NegotiationType.TLS` with proper certificates

306

2. **Development**: Use `usePlaintext()` for simplicity, let gRPC choose negotiation

307

3. **Internal Services**: Use `NegotiationType.PLAINTEXT` for direct HTTP/2

308

4. **Load Balancers**: Match negotiation type to load balancer capabilities

309

5. **Testing**: Use insecure trust managers only in test environments

310

6. **Monitoring**: Log negotiation outcomes for debugging