1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.handler.codec.http2;
18
19 import io.netty.channel.Channel;
20 import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
21 import io.netty.util.internal.UnstableApi;
22
23 import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE;
24 import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_RESERVED_STREAMS;
25 import static io.netty.handler.codec.http2.Http2PromisedRequestVerifier.ALWAYS_VERIFY;
26 import static io.netty.util.internal.ObjectUtil.checkNotNull;
27 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 @UnstableApi
75 public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2ConnectionHandler,
76 B extends AbstractHttp2ConnectionHandlerBuilder<T, B>> {
77
78 private static final SensitivityDetector DEFAULT_HEADER_SENSITIVITY_DETECTOR = Http2HeadersEncoder.NEVER_SENSITIVE;
79
80
81 private Http2Settings initialSettings = Http2Settings.defaultSettings();
82 private Http2FrameListener frameListener;
83 private long gracefulShutdownTimeoutMillis = Http2CodecUtil.DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
84 private boolean decoupleCloseAndGoAway;
85 private boolean flushPreface = true;
86
87
88
89 private Boolean isServer;
90 private Integer maxReservedStreams;
91
92
93 private Http2Connection connection;
94
95
96 private Http2ConnectionDecoder decoder;
97 private Http2ConnectionEncoder encoder;
98
99
100
101
102 private Boolean validateHeaders;
103 private Http2FrameLogger frameLogger;
104 private SensitivityDetector headerSensitivityDetector;
105 private Boolean encoderEnforceMaxConcurrentStreams;
106 private Boolean encoderIgnoreMaxHeaderListSize;
107 private Http2PromisedRequestVerifier promisedRequestVerifier = ALWAYS_VERIFY;
108 private boolean autoAckSettingsFrame = true;
109 private boolean autoAckPingFrame = true;
110 private int maxQueuedControlFrames = Http2CodecUtil.DEFAULT_MAX_QUEUED_CONTROL_FRAMES;
111 private int maxConsecutiveEmptyFrames = 2;
112
113
114
115
116 protected Http2Settings initialSettings() {
117 return initialSettings;
118 }
119
120
121
122
123 protected B initialSettings(Http2Settings settings) {
124 initialSettings = checkNotNull(settings, "settings");
125 return self();
126 }
127
128
129
130
131
132
133 protected Http2FrameListener frameListener() {
134 return frameListener;
135 }
136
137
138
139
140
141 protected B frameListener(Http2FrameListener frameListener) {
142 this.frameListener = checkNotNull(frameListener, "frameListener");
143 return self();
144 }
145
146
147
148
149
150 protected long gracefulShutdownTimeoutMillis() {
151 return gracefulShutdownTimeoutMillis;
152 }
153
154
155
156
157 protected B gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis) {
158 if (gracefulShutdownTimeoutMillis < -1) {
159 throw new IllegalArgumentException("gracefulShutdownTimeoutMillis: " + gracefulShutdownTimeoutMillis +
160 " (expected: -1 for indefinite or >= 0)");
161 }
162 this.gracefulShutdownTimeoutMillis = gracefulShutdownTimeoutMillis;
163 return self();
164 }
165
166
167
168
169
170 protected boolean isServer() {
171 return isServer != null ? isServer : true;
172 }
173
174
175
176
177
178 protected B server(boolean isServer) {
179 enforceConstraint("server", "connection", connection);
180 enforceConstraint("server", "codec", decoder);
181 enforceConstraint("server", "codec", encoder);
182
183 this.isServer = isServer;
184 return self();
185 }
186
187
188
189
190
191
192
193
194 protected int maxReservedStreams() {
195 return maxReservedStreams != null ? maxReservedStreams : DEFAULT_MAX_RESERVED_STREAMS;
196 }
197
198
199
200
201 protected B maxReservedStreams(int maxReservedStreams) {
202 enforceConstraint("server", "connection", connection);
203 enforceConstraint("server", "codec", decoder);
204 enforceConstraint("server", "codec", encoder);
205
206 this.maxReservedStreams = checkPositiveOrZero(maxReservedStreams, "maxReservedStreams");
207 return self();
208 }
209
210
211
212
213
214
215 protected Http2Connection connection() {
216 return connection;
217 }
218
219
220
221
222 protected B connection(Http2Connection connection) {
223 enforceConstraint("connection", "maxReservedStreams", maxReservedStreams);
224 enforceConstraint("connection", "server", isServer);
225 enforceConstraint("connection", "codec", decoder);
226 enforceConstraint("connection", "codec", encoder);
227
228 this.connection = checkNotNull(connection, "connection");
229
230 return self();
231 }
232
233
234
235
236
237
238 protected Http2ConnectionDecoder decoder() {
239 return decoder;
240 }
241
242
243
244
245
246
247 protected Http2ConnectionEncoder encoder() {
248 return encoder;
249 }
250
251
252
253
254 protected B codec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
255 enforceConstraint("codec", "server", isServer);
256 enforceConstraint("codec", "maxReservedStreams", maxReservedStreams);
257 enforceConstraint("codec", "connection", connection);
258 enforceConstraint("codec", "frameLogger", frameLogger);
259 enforceConstraint("codec", "validateHeaders", validateHeaders);
260 enforceConstraint("codec", "headerSensitivityDetector", headerSensitivityDetector);
261 enforceConstraint("codec", "encoderEnforceMaxConcurrentStreams", encoderEnforceMaxConcurrentStreams);
262
263 checkNotNull(decoder, "decoder");
264 checkNotNull(encoder, "encoder");
265
266 if (decoder.connection() != encoder.connection()) {
267 throw new IllegalArgumentException("The specified encoder and decoder have different connections.");
268 }
269
270 this.decoder = decoder;
271 this.encoder = encoder;
272
273 return self();
274 }
275
276
277
278
279
280 protected boolean isValidateHeaders() {
281 return validateHeaders != null ? validateHeaders : true;
282 }
283
284
285
286
287
288 protected B validateHeaders(boolean validateHeaders) {
289 enforceNonCodecConstraints("validateHeaders");
290 this.validateHeaders = validateHeaders;
291 return self();
292 }
293
294
295
296
297
298
299 protected Http2FrameLogger frameLogger() {
300 return frameLogger;
301 }
302
303
304
305
306 protected B frameLogger(Http2FrameLogger frameLogger) {
307 enforceNonCodecConstraints("frameLogger");
308 this.frameLogger = checkNotNull(frameLogger, "frameLogger");
309 return self();
310 }
311
312
313
314
315
316 protected boolean encoderEnforceMaxConcurrentStreams() {
317 return encoderEnforceMaxConcurrentStreams != null ? encoderEnforceMaxConcurrentStreams : false;
318 }
319
320
321
322
323
324 protected B encoderEnforceMaxConcurrentStreams(boolean encoderEnforceMaxConcurrentStreams) {
325 enforceNonCodecConstraints("encoderEnforceMaxConcurrentStreams");
326 this.encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams;
327 return self();
328 }
329
330
331
332
333
334
335
336
337 protected int encoderEnforceMaxQueuedControlFrames() {
338 return maxQueuedControlFrames;
339 }
340
341
342
343
344
345
346
347
348 protected B encoderEnforceMaxQueuedControlFrames(int maxQueuedControlFrames) {
349 enforceNonCodecConstraints("encoderEnforceMaxQueuedControlFrames");
350 this.maxQueuedControlFrames = checkPositiveOrZero(maxQueuedControlFrames, "maxQueuedControlFrames");
351 return self();
352 }
353
354
355
356
357 protected SensitivityDetector headerSensitivityDetector() {
358 return headerSensitivityDetector != null ? headerSensitivityDetector : DEFAULT_HEADER_SENSITIVITY_DETECTOR;
359 }
360
361
362
363
364 protected B headerSensitivityDetector(SensitivityDetector headerSensitivityDetector) {
365 enforceNonCodecConstraints("headerSensitivityDetector");
366 this.headerSensitivityDetector = checkNotNull(headerSensitivityDetector, "headerSensitivityDetector");
367 return self();
368 }
369
370
371
372
373
374
375
376
377 protected B encoderIgnoreMaxHeaderListSize(boolean ignoreMaxHeaderListSize) {
378 enforceNonCodecConstraints("encoderIgnoreMaxHeaderListSize");
379 encoderIgnoreMaxHeaderListSize = ignoreMaxHeaderListSize;
380 return self();
381 }
382
383
384
385
386
387
388 @Deprecated
389 protected B initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
390 return self();
391 }
392
393
394
395
396
397 protected B promisedRequestVerifier(Http2PromisedRequestVerifier promisedRequestVerifier) {
398 enforceNonCodecConstraints("promisedRequestVerifier");
399 this.promisedRequestVerifier = checkNotNull(promisedRequestVerifier, "promisedRequestVerifier");
400 return self();
401 }
402
403
404
405
406
407 protected Http2PromisedRequestVerifier promisedRequestVerifier() {
408 return promisedRequestVerifier;
409 }
410
411
412
413
414
415
416
417
418 protected int decoderEnforceMaxConsecutiveEmptyDataFrames() {
419 return maxConsecutiveEmptyFrames;
420 }
421
422
423
424
425
426
427
428
429 protected B decoderEnforceMaxConsecutiveEmptyDataFrames(int maxConsecutiveEmptyFrames) {
430 enforceNonCodecConstraints("maxConsecutiveEmptyFrames");
431 this.maxConsecutiveEmptyFrames = checkPositiveOrZero(
432 maxConsecutiveEmptyFrames, "maxConsecutiveEmptyFrames");
433 return self();
434 }
435
436
437
438
439
440 protected B autoAckSettingsFrame(boolean autoAckSettings) {
441 enforceNonCodecConstraints("autoAckSettingsFrame");
442 autoAckSettingsFrame = autoAckSettings;
443 return self();
444 }
445
446
447
448
449
450 protected boolean isAutoAckSettingsFrame() {
451 return autoAckSettingsFrame;
452 }
453
454
455
456
457
458 protected B autoAckPingFrame(boolean autoAckPingFrame) {
459 enforceNonCodecConstraints("autoAckPingFrame");
460 this.autoAckPingFrame = autoAckPingFrame;
461 return self();
462 }
463
464
465
466
467
468 protected boolean isAutoAckPingFrame() {
469 return autoAckPingFrame;
470 }
471
472
473
474
475
476
477
478 protected B decoupleCloseAndGoAway(boolean decoupleCloseAndGoAway) {
479 this.decoupleCloseAndGoAway = decoupleCloseAndGoAway;
480 return self();
481 }
482
483
484
485
486 protected boolean decoupleCloseAndGoAway() {
487 return decoupleCloseAndGoAway;
488 }
489
490
491
492
493
494
495
496
497
498
499
500
501 protected B flushPreface(boolean flushPreface) {
502 this.flushPreface = flushPreface;
503 return self();
504 }
505
506
507
508
509
510
511
512
513
514
515
516 protected boolean flushPreface() {
517 return flushPreface;
518 }
519
520
521
522
523 protected T build() {
524 if (encoder != null) {
525 assert decoder != null;
526 return buildFromCodec(decoder, encoder);
527 }
528
529 Http2Connection connection = this.connection;
530 if (connection == null) {
531 connection = new DefaultHttp2Connection(isServer(), maxReservedStreams());
532 }
533
534 return buildFromConnection(connection);
535 }
536
537 private T buildFromConnection(Http2Connection connection) {
538 Long maxHeaderListSize = initialSettings.maxHeaderListSize();
539 Http2FrameReader reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(isValidateHeaders(),
540 maxHeaderListSize == null ? DEFAULT_HEADER_LIST_SIZE : maxHeaderListSize,
541 -1));
542 Http2FrameWriter writer = encoderIgnoreMaxHeaderListSize == null ?
543 new DefaultHttp2FrameWriter(headerSensitivityDetector()) :
544 new DefaultHttp2FrameWriter(headerSensitivityDetector(), encoderIgnoreMaxHeaderListSize);
545
546 if (frameLogger != null) {
547 reader = new Http2InboundFrameLogger(reader, frameLogger);
548 writer = new Http2OutboundFrameLogger(writer, frameLogger);
549 }
550
551 Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, writer);
552 boolean encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams();
553
554 if (maxQueuedControlFrames != 0) {
555 encoder = new Http2ControlFrameLimitEncoder(encoder, maxQueuedControlFrames);
556 }
557 if (encoderEnforceMaxConcurrentStreams) {
558 if (connection.isServer()) {
559 encoder.close();
560 reader.close();
561 throw new IllegalArgumentException(
562 "encoderEnforceMaxConcurrentStreams: " + encoderEnforceMaxConcurrentStreams +
563 " not supported for server");
564 }
565 encoder = new StreamBufferingEncoder(encoder);
566 }
567
568 DefaultHttp2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, reader,
569 promisedRequestVerifier(), isAutoAckSettingsFrame(), isAutoAckPingFrame());
570 return buildFromCodec(decoder, encoder);
571 }
572
573 private T buildFromCodec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
574 int maxConsecutiveEmptyDataFrames = decoderEnforceMaxConsecutiveEmptyDataFrames();
575 if (maxConsecutiveEmptyDataFrames > 0) {
576 decoder = new Http2EmptyDataFrameConnectionDecoder(decoder, maxConsecutiveEmptyDataFrames);
577 }
578 final T handler;
579 try {
580
581 handler = build(decoder, encoder, initialSettings);
582 } catch (Throwable t) {
583 encoder.close();
584 decoder.close();
585 throw new IllegalStateException("failed to build an Http2ConnectionHandler", t);
586 }
587
588
589 handler.gracefulShutdownTimeoutMillis(gracefulShutdownTimeoutMillis);
590 if (handler.decoder().frameListener() == null) {
591 handler.decoder().frameListener(frameListener);
592 }
593 return handler;
594 }
595
596
597
598
599
600
601
602
603
604
605 protected abstract T build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
606 Http2Settings initialSettings) throws Exception;
607
608
609
610
611 @SuppressWarnings("unchecked")
612 protected final B self() {
613 return (B) this;
614 }
615
616 private void enforceNonCodecConstraints(String rejected) {
617 enforceConstraint(rejected, "server/connection", decoder);
618 enforceConstraint(rejected, "server/connection", encoder);
619 }
620
621 private static void enforceConstraint(String methodName, String rejectorName, Object value) {
622 if (value != null) {
623 throw new IllegalStateException(
624 methodName + "() cannot be called because " + rejectorName + "() has been called already.");
625 }
626 }
627 }