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