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