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