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