1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http2;
17
18 import io.netty.channel.Channel;
19 import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
20
21 import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE;
22 import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_RESERVED_STREAMS;
23 import static io.netty.handler.codec.http2.Http2PromisedRequestVerifier.ALWAYS_VERIFY;
24 import static io.netty.util.internal.ObjectUtil.checkNotNull;
25 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
26
27
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 public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2ConnectionHandler,
73 B extends AbstractHttp2ConnectionHandlerBuilder<T, B>> {
74
75 private static final SensitivityDetector DEFAULT_HEADER_SENSITIVITY_DETECTOR = Http2HeadersEncoder.NEVER_SENSITIVE;
76
77 private static final int DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER = 200;
78
79
80 private Http2Settings initialSettings = Http2Settings.defaultSettings();
81 private Http2FrameListener frameListener;
82 private long gracefulShutdownTimeoutMillis = Http2CodecUtil.DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT_MILLIS;
83 private boolean decoupleCloseAndGoAway;
84 private boolean flushPreface = true;
85
86
87
88 private Boolean isServer;
89 private Integer maxReservedStreams;
90
91
92 private Http2Connection connection;
93
94
95 private Http2ConnectionDecoder decoder;
96 private Http2ConnectionEncoder encoder;
97
98
99
100
101 private Boolean validateHeaders;
102 private Boolean validateRequiredPseudoHeaders;
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 private Integer maxDecodedRstFramesPerWindow;
113 private int maxDecodedRstFramesSecondsPerWindow = 30;
114 private Integer maxEncodedRstFramesPerWindow;
115 private int maxEncodedRstFramesSecondsPerWindow = 30;
116 private int maxSmallContinuationFrames = Http2CodecUtil.DEFAULT_MAX_SMALL_CONTINUATION_FRAME;
117
118
119
120
121 protected Http2Settings initialSettings() {
122 return initialSettings;
123 }
124
125
126
127
128 protected B initialSettings(Http2Settings settings) {
129 initialSettings = checkNotNull(settings, "settings");
130 return self();
131 }
132
133
134
135
136
137
138 protected Http2FrameListener frameListener() {
139 return frameListener;
140 }
141
142
143
144
145
146 protected B frameListener(Http2FrameListener frameListener) {
147 this.frameListener = checkNotNull(frameListener, "frameListener");
148 return self();
149 }
150
151
152
153
154
155 protected long gracefulShutdownTimeoutMillis() {
156 return gracefulShutdownTimeoutMillis;
157 }
158
159
160
161
162 protected B gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis) {
163 if (gracefulShutdownTimeoutMillis < -1) {
164 throw new IllegalArgumentException("gracefulShutdownTimeoutMillis: " + gracefulShutdownTimeoutMillis +
165 " (expected: -1 for indefinite or >= 0)");
166 }
167 this.gracefulShutdownTimeoutMillis = gracefulShutdownTimeoutMillis;
168 return self();
169 }
170
171
172
173
174
175 protected boolean isServer() {
176 return isServer != null ? isServer : true;
177 }
178
179
180
181
182
183 protected B server(boolean isServer) {
184 enforceConstraint("server", "connection", connection);
185 enforceConstraint("server", "codec", decoder);
186 enforceConstraint("server", "codec", encoder);
187
188 this.isServer = isServer;
189 return self();
190 }
191
192
193
194
195
196
197
198
199 protected int maxReservedStreams() {
200 return maxReservedStreams != null ? maxReservedStreams : DEFAULT_MAX_RESERVED_STREAMS;
201 }
202
203
204
205
206 protected B maxReservedStreams(int maxReservedStreams) {
207 enforceConstraint("server", "connection", connection);
208 enforceConstraint("server", "codec", decoder);
209 enforceConstraint("server", "codec", encoder);
210
211 this.maxReservedStreams = checkPositiveOrZero(maxReservedStreams, "maxReservedStreams");
212 return self();
213 }
214
215
216
217
218
219
220 protected Http2Connection connection() {
221 return connection;
222 }
223
224
225
226
227 protected B connection(Http2Connection connection) {
228 enforceConstraint("connection", "maxReservedStreams", maxReservedStreams);
229 enforceConstraint("connection", "server", isServer);
230 enforceConstraint("connection", "codec", decoder);
231 enforceConstraint("connection", "codec", encoder);
232
233 this.connection = checkNotNull(connection, "connection");
234
235 return self();
236 }
237
238
239
240
241
242
243 protected Http2ConnectionDecoder decoder() {
244 return decoder;
245 }
246
247
248
249
250
251
252 protected Http2ConnectionEncoder encoder() {
253 return encoder;
254 }
255
256
257
258
259 protected B codec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
260 enforceConstraint("codec", "server", isServer);
261 enforceConstraint("codec", "maxReservedStreams", maxReservedStreams);
262 enforceConstraint("codec", "connection", connection);
263 enforceConstraint("codec", "frameLogger", frameLogger);
264 enforceConstraint("codec", "validateHeaders", validateHeaders);
265 enforceConstraint("codec", "validateRequiredPseudoHeaders", validateRequiredPseudoHeaders);
266 enforceConstraint("codec", "headerSensitivityDetector", headerSensitivityDetector);
267 enforceConstraint("codec", "encoderEnforceMaxConcurrentStreams", encoderEnforceMaxConcurrentStreams);
268
269 checkNotNull(decoder, "decoder");
270 checkNotNull(encoder, "encoder");
271
272 if (decoder.connection() != encoder.connection()) {
273 throw new IllegalArgumentException("The specified encoder and decoder have different connections.");
274 }
275
276 this.decoder = decoder;
277 this.encoder = encoder;
278
279 return self();
280 }
281
282
283
284
285
286 protected boolean isValidateHeaders() {
287 return validateHeaders != null ? validateHeaders : true;
288 }
289
290
291
292
293
294 protected B validateHeaders(boolean validateHeaders) {
295 enforceNonCodecConstraints("validateHeaders");
296 this.validateHeaders = validateHeaders;
297 return self();
298 }
299
300
301
302
303
304 protected boolean isValidateRequiredPseudoHeaders() {
305 return validateRequiredPseudoHeaders != null ? validateRequiredPseudoHeaders : false;
306 }
307
308
309
310
311
312
313 protected B validateRequiredPseudoHeaders(boolean validateRequiredPseudoHeaders) {
314 enforceNonCodecConstraints("validateRequiredPseudoHeaders");
315 this.validateRequiredPseudoHeaders = validateRequiredPseudoHeaders;
316 return self();
317 }
318
319
320
321
322
323
324 protected Http2FrameLogger frameLogger() {
325 return frameLogger;
326 }
327
328
329
330
331 protected B frameLogger(Http2FrameLogger frameLogger) {
332 enforceNonCodecConstraints("frameLogger");
333 this.frameLogger = checkNotNull(frameLogger, "frameLogger");
334 return self();
335 }
336
337
338
339
340
341 protected boolean encoderEnforceMaxConcurrentStreams() {
342 return encoderEnforceMaxConcurrentStreams != null ? encoderEnforceMaxConcurrentStreams : false;
343 }
344
345
346
347
348
349 protected B encoderEnforceMaxConcurrentStreams(boolean encoderEnforceMaxConcurrentStreams) {
350 enforceNonCodecConstraints("encoderEnforceMaxConcurrentStreams");
351 this.encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams;
352 return self();
353 }
354
355
356
357
358
359
360
361
362 protected int encoderEnforceMaxQueuedControlFrames() {
363 return maxQueuedControlFrames;
364 }
365
366
367
368
369
370
371
372
373 protected B encoderEnforceMaxQueuedControlFrames(int maxQueuedControlFrames) {
374 enforceNonCodecConstraints("encoderEnforceMaxQueuedControlFrames");
375 this.maxQueuedControlFrames = checkPositiveOrZero(maxQueuedControlFrames, "maxQueuedControlFrames");
376 return self();
377 }
378
379
380
381
382 protected SensitivityDetector headerSensitivityDetector() {
383 return headerSensitivityDetector != null ? headerSensitivityDetector : DEFAULT_HEADER_SENSITIVITY_DETECTOR;
384 }
385
386
387
388
389 protected B headerSensitivityDetector(SensitivityDetector headerSensitivityDetector) {
390 enforceNonCodecConstraints("headerSensitivityDetector");
391 this.headerSensitivityDetector = checkNotNull(headerSensitivityDetector, "headerSensitivityDetector");
392 return self();
393 }
394
395
396
397
398
399
400
401
402 protected B encoderIgnoreMaxHeaderListSize(boolean ignoreMaxHeaderListSize) {
403 enforceNonCodecConstraints("encoderIgnoreMaxHeaderListSize");
404 encoderIgnoreMaxHeaderListSize = ignoreMaxHeaderListSize;
405 return self();
406 }
407
408
409
410
411
412
413 @Deprecated
414 protected B initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
415 return self();
416 }
417
418
419
420
421
422 protected B promisedRequestVerifier(Http2PromisedRequestVerifier promisedRequestVerifier) {
423 enforceNonCodecConstraints("promisedRequestVerifier");
424 this.promisedRequestVerifier = checkNotNull(promisedRequestVerifier, "promisedRequestVerifier");
425 return self();
426 }
427
428
429
430
431
432 protected Http2PromisedRequestVerifier promisedRequestVerifier() {
433 return promisedRequestVerifier;
434 }
435
436
437
438
439
440
441
442
443 protected int decoderEnforceMaxConsecutiveEmptyDataFrames() {
444 return maxConsecutiveEmptyFrames;
445 }
446
447
448
449
450
451
452
453
454 protected B decoderEnforceMaxConsecutiveEmptyDataFrames(int maxConsecutiveEmptyFrames) {
455 enforceNonCodecConstraints("maxConsecutiveEmptyFrames");
456 this.maxConsecutiveEmptyFrames = checkPositiveOrZero(
457 maxConsecutiveEmptyFrames, "maxConsecutiveEmptyFrames");
458 return self();
459 }
460
461
462
463
464
465
466
467
468 protected B decoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
469 enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
470 this.maxDecodedRstFramesPerWindow = checkPositiveOrZero(
471 maxRstFramesPerWindow, "maxRstFramesPerWindow");
472 this.maxDecodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
473 return self();
474 }
475
476
477
478
479
480
481
482
483 protected B encoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
484 enforceNonCodecConstraints("encoderEnforceMaxRstFramesPerWindow");
485 this.maxEncodedRstFramesPerWindow = checkPositiveOrZero(
486 maxRstFramesPerWindow, "maxRstFramesPerWindow");
487 this.maxEncodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
488 return self();
489 }
490
491
492
493
494
495
496
497
498 protected int decoderEnforceMaxSmallContinuationFrames() {
499 return maxSmallContinuationFrames;
500 }
501
502
503
504
505
506
507
508 protected B decoderEnforceMaxSmallContinuationFrames(int maxSmallContinuationFrames) {
509 enforceNonCodecConstraints("maxSmallContinuationFrames");
510 this.maxSmallContinuationFrames = checkPositiveOrZero(
511 maxSmallContinuationFrames, "maxSmallContinuationFrames");
512 return self();
513 }
514
515
516
517
518
519 protected B autoAckSettingsFrame(boolean autoAckSettings) {
520 enforceNonCodecConstraints("autoAckSettingsFrame");
521 autoAckSettingsFrame = autoAckSettings;
522 return self();
523 }
524
525
526
527
528
529 protected boolean isAutoAckSettingsFrame() {
530 return autoAckSettingsFrame;
531 }
532
533
534
535
536
537 protected B autoAckPingFrame(boolean autoAckPingFrame) {
538 enforceNonCodecConstraints("autoAckPingFrame");
539 this.autoAckPingFrame = autoAckPingFrame;
540 return self();
541 }
542
543
544
545
546
547 protected boolean isAutoAckPingFrame() {
548 return autoAckPingFrame;
549 }
550
551
552
553
554
555
556
557 protected B decoupleCloseAndGoAway(boolean decoupleCloseAndGoAway) {
558 this.decoupleCloseAndGoAway = decoupleCloseAndGoAway;
559 return self();
560 }
561
562
563
564
565 protected boolean decoupleCloseAndGoAway() {
566 return decoupleCloseAndGoAway;
567 }
568
569
570
571
572
573
574
575
576
577
578
579
580 protected B flushPreface(boolean flushPreface) {
581 this.flushPreface = flushPreface;
582 return self();
583 }
584
585
586
587
588
589
590
591
592
593
594
595 protected boolean flushPreface() {
596 return flushPreface;
597 }
598
599
600
601
602 protected T build() {
603 if (encoder != null) {
604 assert decoder != null;
605 return buildFromCodec(decoder, encoder);
606 }
607
608 Http2Connection connection = this.connection;
609 if (connection == null) {
610 connection = new DefaultHttp2Connection(isServer(), maxReservedStreams());
611 }
612
613 return buildFromConnection(connection);
614 }
615
616 private T buildFromConnection(Http2Connection connection) {
617
618
619 enforceMaxActiveStreams(connection, initialSettings);
620
621 Long maxHeaderListSize = initialSettings.maxHeaderListSize();
622 Http2FrameReader reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(isValidateHeaders(),
623 maxHeaderListSize == null ? DEFAULT_HEADER_LIST_SIZE : maxHeaderListSize,
624 -1), maxSmallContinuationFrames);
625 Http2FrameWriter writer = encoderIgnoreMaxHeaderListSize == null ?
626 new DefaultHttp2FrameWriter(headerSensitivityDetector()) :
627 new DefaultHttp2FrameWriter(headerSensitivityDetector(), encoderIgnoreMaxHeaderListSize);
628
629 if (frameLogger != null) {
630 reader = new Http2InboundFrameLogger(reader, frameLogger);
631 writer = new Http2OutboundFrameLogger(writer, frameLogger);
632 }
633
634 Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, writer);
635 boolean encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams();
636
637 if (maxQueuedControlFrames != 0) {
638 encoder = new Http2ControlFrameLimitEncoder(encoder, maxQueuedControlFrames);
639 }
640 final int maxEncodedRstFrames;
641 if (maxEncodedRstFramesPerWindow == null) {
642
643 if (isServer()) {
644 maxEncodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
645 } else {
646 maxEncodedRstFrames = 0;
647 }
648 } else {
649 maxEncodedRstFrames = maxEncodedRstFramesPerWindow;
650 }
651 if (maxEncodedRstFrames > 0 && maxEncodedRstFramesSecondsPerWindow > 0) {
652 encoder = new Http2MaxRstFrameLimitEncoder(
653 encoder, maxEncodedRstFrames, maxEncodedRstFramesSecondsPerWindow);
654 }
655 if (encoderEnforceMaxConcurrentStreams) {
656 if (connection.isServer()) {
657 encoder.close();
658 reader.close();
659 throw new IllegalArgumentException(
660 "encoderEnforceMaxConcurrentStreams: " + encoderEnforceMaxConcurrentStreams +
661 " not supported for server");
662 }
663 encoder = new StreamBufferingEncoder(encoder);
664 }
665
666 DefaultHttp2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, reader,
667 promisedRequestVerifier(), isAutoAckSettingsFrame(), isAutoAckPingFrame(), isValidateHeaders(),
668 isValidateRequiredPseudoHeaders());
669 return buildFromCodec(decoder, encoder);
670 }
671
672 private T buildFromCodec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
673
674
675 enforceMaxActiveStreams(encoder.connection(), initialSettings);
676
677 int maxConsecutiveEmptyDataFrames = decoderEnforceMaxConsecutiveEmptyDataFrames();
678 if (maxConsecutiveEmptyDataFrames > 0) {
679 decoder = new Http2EmptyDataFrameConnectionDecoder(decoder, maxConsecutiveEmptyDataFrames);
680 }
681 final int maxDecodedRstFrames;
682 if (maxDecodedRstFramesPerWindow == null) {
683
684 if (isServer()) {
685 maxDecodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
686 } else {
687 maxDecodedRstFrames = 0;
688 }
689 } else {
690 maxDecodedRstFrames = maxDecodedRstFramesPerWindow;
691 }
692 if (maxDecodedRstFrames > 0 && maxDecodedRstFramesSecondsPerWindow > 0) {
693 decoder = new Http2MaxRstFrameDecoder(decoder, maxDecodedRstFrames, maxDecodedRstFramesSecondsPerWindow);
694 }
695 final T handler;
696 try {
697
698 handler = build(decoder, encoder, initialSettings);
699 } catch (Throwable t) {
700 encoder.close();
701 decoder.close();
702 throw new IllegalStateException("failed to build an Http2ConnectionHandler", t);
703 }
704
705
706 handler.gracefulShutdownTimeoutMillis(gracefulShutdownTimeoutMillis);
707 if (handler.decoder().frameListener() == null) {
708 handler.decoder().frameListener(frameListener);
709 }
710 return handler;
711 }
712
713 private static void enforceMaxActiveStreams(Http2Connection connection, Http2Settings initialSettings) {
714 Long maxConcurrentStreams = initialSettings.maxConcurrentStreams();
715 if (maxConcurrentStreams != null) {
716 connection.remote().maxActiveStreams((int) Math.min(maxConcurrentStreams, Integer.MAX_VALUE));
717 }
718 }
719
720
721
722
723
724
725
726
727
728
729 protected abstract T build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
730 Http2Settings initialSettings) throws Exception;
731
732
733
734
735 @SuppressWarnings("unchecked")
736 protected final B self() {
737 return (B) this;
738 }
739
740 private void enforceNonCodecConstraints(String rejected) {
741 enforceConstraint(rejected, "server/connection", decoder);
742 enforceConstraint(rejected, "server/connection", encoder);
743 }
744
745 private static void enforceConstraint(String methodName, String rejectorName, Object value) {
746 if (value != null) {
747 throw new IllegalStateException(
748 methodName + "() cannot be called because " + rejectorName + "() has been called already.");
749 }
750 }
751 }