View Javadoc
1   /*
2    * Copyright 2015 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
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   * Abstract base class which defines commonly used features required to build {@link Http2ConnectionHandler} instances.
29   *
30   * <h3>Three ways to build a {@link Http2ConnectionHandler}</h3>
31   * <h4>Let the builder create a {@link Http2ConnectionHandler}</h4>
32   * Simply call all the necessary setter methods, and then use {@link #build()} to build a new
33   * {@link Http2ConnectionHandler}. Setting the following properties are prohibited because they are used for
34   * other ways of building a {@link Http2ConnectionHandler}.
35   * conflicts with this option:
36   * <ul>
37   *   <li>{@link #connection(Http2Connection)}</li>
38   *   <li>{@link #codec(Http2ConnectionDecoder, Http2ConnectionEncoder)}</li>
39   * </ul>
40   *
41   *
42   * <h4>Let the builder use the {@link Http2ConnectionHandler} you specified</h4>
43   * Call {@link #connection(Http2Connection)} to tell the builder that you want to build the handler from the
44   * {@link Http2Connection} you specified. Setting the following properties are prohibited and thus will trigger
45   * an {@link IllegalStateException} because they conflict with this option.
46   * <ul>
47   *   <li>{@link #server(boolean)}</li>
48   *   <li>{@link #codec(Http2ConnectionDecoder, Http2ConnectionEncoder)}</li>
49   * </ul>
50   *
51   * <h4>Let the builder use the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} you specified</h4>
52   * Call {@link #codec(Http2ConnectionDecoder, Http2ConnectionEncoder)} to tell the builder that you want to built the
53   * handler from the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} you specified. Setting the
54   * following properties are prohibited and thus will trigger an {@link IllegalStateException} because they conflict
55   * with this option:
56   * <ul>
57   *   <li>{@link #server(boolean)}</li>
58   *   <li>{@link #connection(Http2Connection)}</li>
59   *   <li>{@link #frameLogger(Http2FrameLogger)}</li>
60   *   <li>{@link #headerSensitivityDetector(SensitivityDetector)}</li>
61   *   <li>{@link #encoderEnforceMaxConcurrentStreams(boolean)}</li>
62   *   <li>{@link #encoderIgnoreMaxHeaderListSize(boolean)}</li>
63   * </ul>
64   *
65   * <h3>Exposing necessary methods in a subclass</h3>
66   * {@link #build()} method and all property access methods are {@code protected}. Choose the methods to expose to the
67   * users of your builder implementation and make them {@code public}.
68   *
69   * @param <T> The type of handler created by this builder.
70   * @param <B> The concrete type of this builder.
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      // The properties that can always be set.
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      // The property that will prohibit connection() and codec() if set by server(),
87      // because this property is used only when this builder creates an Http2Connection.
88      private Boolean isServer;
89      private Integer maxReservedStreams;
90  
91      // The property that will prohibit server() and codec() if set by connection().
92      private Http2Connection connection;
93  
94      // The properties that will prohibit server() and connection() if set by codec().
95      private Http2ConnectionDecoder decoder;
96      private Http2ConnectionEncoder encoder;
97  
98      // The properties that are:
99      // * mutually exclusive against codec() and
100     // * OK to use with server() and connection()
101     private Boolean validateHeaders;
102     private Http2FrameLogger frameLogger;
103     private SensitivityDetector headerSensitivityDetector;
104     private Boolean encoderEnforceMaxConcurrentStreams;
105     private Boolean encoderIgnoreMaxHeaderListSize;
106     private Http2PromisedRequestVerifier promisedRequestVerifier = ALWAYS_VERIFY;
107     private boolean autoAckSettingsFrame = true;
108     private boolean autoAckPingFrame = true;
109     private int maxQueuedControlFrames = Http2CodecUtil.DEFAULT_MAX_QUEUED_CONTROL_FRAMES;
110     private int maxConsecutiveEmptyFrames = 2;
111     private Integer maxDecodedRstFramesPerWindow;
112     private int maxDecodedRstFramesSecondsPerWindow = 30;
113     private Integer maxEncodedRstFramesPerWindow;
114     private int maxEncodedRstFramesSecondsPerWindow = 30;
115     private int maxSmallContinuationFrames = Http2CodecUtil.DEFAULT_MAX_SMALL_CONTINUATION_FRAME;
116 
117     /**
118      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
119      */
120     protected Http2Settings initialSettings() {
121         return initialSettings;
122     }
123 
124     /**
125      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
126      */
127     protected B initialSettings(Http2Settings settings) {
128         initialSettings = checkNotNull(settings, "settings");
129         return self();
130     }
131 
132     /**
133      * Returns the listener of inbound frames.
134      *
135      * @return {@link Http2FrameListener} if set, or {@code null} if not set.
136      */
137     protected Http2FrameListener frameListener() {
138         return frameListener;
139     }
140 
141     /**
142      * Sets the listener of inbound frames.
143      * This listener will only be set if the decoder's listener is {@code null}.
144      */
145     protected B frameListener(Http2FrameListener frameListener) {
146         this.frameListener = checkNotNull(frameListener, "frameListener");
147         return self();
148     }
149 
150     /**
151      * Returns the graceful shutdown timeout of the {@link Http2Connection} in milliseconds. Returns -1 if the
152      * timeout is indefinite.
153      */
154     protected long gracefulShutdownTimeoutMillis() {
155         return gracefulShutdownTimeoutMillis;
156     }
157 
158     /**
159      * Sets the graceful shutdown timeout of the {@link Http2Connection} in milliseconds.
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      * Returns if {@link #build()} will to create a {@link Http2Connection} in server mode ({@code true})
172      * or client mode ({@code false}).
173      */
174     protected boolean isServer() {
175         return isServer != null ? isServer : true;
176     }
177 
178     /**
179      * Sets if {@link #build()} will to create a {@link Http2Connection} in server mode ({@code true})
180      * or client mode ({@code false}).
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      * Get the maximum number of streams which can be in the reserved state at any given time.
193      * <p>
194      * By default this value will be ignored on the server for local endpoint. This is because the RFC provides
195      * no way to explicitly communicate a limit to how many states can be in the reserved state, and instead relies
196      * on the peer to send RST_STREAM frames when they will be rejected.
197      */
198     protected int maxReservedStreams() {
199         return maxReservedStreams != null ? maxReservedStreams : DEFAULT_MAX_RESERVED_STREAMS;
200     }
201 
202     /**
203      * Set the maximum number of streams which can be in the reserved state at any given time.
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      * Returns the {@link Http2Connection} to use.
216      *
217      * @return {@link Http2Connection} if set, or {@code null} if not set.
218      */
219     protected Http2Connection connection() {
220         return connection;
221     }
222 
223     /**
224      * Sets the {@link Http2Connection} to use.
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      * Returns the {@link Http2ConnectionDecoder} to use.
239      *
240      * @return {@link Http2ConnectionDecoder} if set, or {@code null} if not set.
241      */
242     protected Http2ConnectionDecoder decoder() {
243         return decoder;
244     }
245 
246     /**
247      * Returns the {@link Http2ConnectionEncoder} to use.
248      *
249      * @return {@link Http2ConnectionEncoder} if set, or {@code null} if not set.
250      */
251     protected Http2ConnectionEncoder encoder() {
252         return encoder;
253     }
254 
255     /**
256      * Sets the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} to use.
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      * Returns if HTTP headers should be validated according to
282      * <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
283      */
284     protected boolean isValidateHeaders() {
285         return validateHeaders != null ? validateHeaders : true;
286     }
287 
288     /**
289      * Sets if HTTP headers should be validated according to
290      * <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
291      */
292     protected B validateHeaders(boolean validateHeaders) {
293         enforceNonCodecConstraints("validateHeaders");
294         this.validateHeaders = validateHeaders;
295         return self();
296     }
297 
298     /**
299      * Returns the logger that is used for the encoder and decoder.
300      *
301      * @return {@link Http2FrameLogger} if set, or {@code null} if not set.
302      */
303     protected Http2FrameLogger frameLogger() {
304         return frameLogger;
305     }
306 
307     /**
308      * Sets the logger that is used for the encoder and decoder.
309      */
310     protected B frameLogger(Http2FrameLogger frameLogger) {
311         enforceNonCodecConstraints("frameLogger");
312         this.frameLogger = checkNotNull(frameLogger, "frameLogger");
313         return self();
314     }
315 
316     /**
317      * Returns if the encoder should queue frames if the maximum number of concurrent streams
318      * would otherwise be exceeded.
319      */
320     protected boolean encoderEnforceMaxConcurrentStreams() {
321         return encoderEnforceMaxConcurrentStreams != null ? encoderEnforceMaxConcurrentStreams : false;
322     }
323 
324     /**
325      * Sets if the encoder should queue frames if the maximum number of concurrent streams
326      * would otherwise be exceeded.
327      */
328     protected B encoderEnforceMaxConcurrentStreams(boolean encoderEnforceMaxConcurrentStreams) {
329         enforceNonCodecConstraints("encoderEnforceMaxConcurrentStreams");
330         this.encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams;
331         return self();
332     }
333 
334     /**
335      * Returns the maximum number of queued control frames that are allowed before the connection is closed.
336      * This allows to protected against various attacks that can lead to high CPU / memory usage if the remote-peer
337      * floods us with frames that would have us produce control frames, but stops to read from the underlying socket.
338      *
339      * {@code 0} means no protection is in place.
340      */
341     protected int encoderEnforceMaxQueuedControlFrames() {
342         return maxQueuedControlFrames;
343     }
344 
345     /**
346      * Sets the maximum number of queued control frames that are allowed before the connection is closed.
347      * This allows to protected against various attacks that can lead to high CPU / memory usage if the remote-peer
348      * floods us with frames that would have us produce control frames, but stops to read from the underlying socket.
349      *
350      * {@code 0} means no protection should be applied.
351      */
352     protected B encoderEnforceMaxQueuedControlFrames(int maxQueuedControlFrames) {
353         enforceNonCodecConstraints("encoderEnforceMaxQueuedControlFrames");
354         this.maxQueuedControlFrames = checkPositiveOrZero(maxQueuedControlFrames, "maxQueuedControlFrames");
355         return self();
356     }
357 
358     /**
359      * Returns the {@link SensitivityDetector} to use.
360      */
361     protected SensitivityDetector headerSensitivityDetector() {
362         return headerSensitivityDetector != null ? headerSensitivityDetector : DEFAULT_HEADER_SENSITIVITY_DETECTOR;
363     }
364 
365     /**
366      * Sets the {@link SensitivityDetector} to use.
367      */
368     protected B headerSensitivityDetector(SensitivityDetector headerSensitivityDetector) {
369         enforceNonCodecConstraints("headerSensitivityDetector");
370         this.headerSensitivityDetector = checkNotNull(headerSensitivityDetector, "headerSensitivityDetector");
371         return self();
372     }
373 
374     /**
375      * Sets if the <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_HEADER_LIST_SIZE</a>
376      * should be ignored when encoding headers.
377      * @param ignoreMaxHeaderListSize {@code true} to ignore
378      * <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_HEADER_LIST_SIZE</a>.
379      * @return this.
380      */
381     protected B encoderIgnoreMaxHeaderListSize(boolean ignoreMaxHeaderListSize) {
382         enforceNonCodecConstraints("encoderIgnoreMaxHeaderListSize");
383         encoderIgnoreMaxHeaderListSize = ignoreMaxHeaderListSize;
384         return self();
385     }
386 
387     /**
388      * Does nothing, do not call.
389      *
390      * @deprecated Huffman decoding no longer depends on having a decode capacity.
391      */
392     @Deprecated
393     protected B initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
394         return self();
395     }
396 
397     /**
398      * Set the {@link Http2PromisedRequestVerifier} to use.
399      * @return this.
400      */
401     protected B promisedRequestVerifier(Http2PromisedRequestVerifier promisedRequestVerifier) {
402         enforceNonCodecConstraints("promisedRequestVerifier");
403         this.promisedRequestVerifier = checkNotNull(promisedRequestVerifier, "promisedRequestVerifier");
404         return self();
405     }
406 
407     /**
408      * Get the {@link Http2PromisedRequestVerifier} to use.
409      * @return the {@link Http2PromisedRequestVerifier} to use.
410      */
411     protected Http2PromisedRequestVerifier promisedRequestVerifier() {
412         return promisedRequestVerifier;
413     }
414 
415     /**
416      * Returns the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
417      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
418      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
419      *
420      * {@code 0} means no protection is in place.
421      */
422     protected int decoderEnforceMaxConsecutiveEmptyDataFrames() {
423         return maxConsecutiveEmptyFrames;
424     }
425 
426     /**
427      * Sets the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
428      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
429      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
430      *
431      * {@code 0} means no protection should be applied.
432      */
433     protected B decoderEnforceMaxConsecutiveEmptyDataFrames(int maxConsecutiveEmptyFrames) {
434         enforceNonCodecConstraints("maxConsecutiveEmptyFrames");
435         this.maxConsecutiveEmptyFrames = checkPositiveOrZero(
436                 maxConsecutiveEmptyFrames, "maxConsecutiveEmptyFrames");
437         return self();
438     }
439 
440     /**
441      * Sets the maximum number RST frames that are allowed per window before
442      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
443      * so use up a lot of CPU.
444      *
445      * {@code 0} for any of the parameters means no protection should be applied.
446      */
447     protected B decoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
448         enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
449         this.maxDecodedRstFramesPerWindow = checkPositiveOrZero(
450                 maxRstFramesPerWindow, "maxRstFramesPerWindow");
451         this.maxDecodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
452         return self();
453     }
454 
455     /**
456      * Sets the maximum number RST frames that are allowed per window before
457      * the connection is closed. This allows to protect against the remote peer that will trigger us to generate a flood
458      * of RST frames and so use up a lot of CPU.
459      *
460      * {@code 0} for any of the parameters means no protection should be applied.
461      */
462     protected B encoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
463         enforceNonCodecConstraints("encoderEnforceMaxRstFramesPerWindow");
464         this.maxEncodedRstFramesPerWindow = checkPositiveOrZero(
465                 maxRstFramesPerWindow, "maxRstFramesPerWindow");
466         this.maxEncodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
467         return self();
468     }
469 
470     /**
471      * Returns the maximum number of small CONTINUATION frames per HEADERS block that are allowed
472      * before the connection is closed. Small is defined as 8 KiB, half the minimum allowed HTTP2 frame size.
473      * This setting is to protect against the remote peer flooding us with such frames.
474      *
475      * {@code 0} means no protection is in place.
476      */
477     protected int decoderEnforceMaxSmallContinuationFrames() {
478         return maxSmallContinuationFrames;
479     }
480 
481     /**
482      * Returns the maximum number of small CONTINUATION frames per HEADERS block that are allowed
483      * before the connection is closed. Small is defined as 8 KiB, half the minimum allowed HTTP2 frame size.
484      * This setting is to protect against the remote peer flooding us with such frames.
485      * {@code 0} means no protection should be applied.
486      */
487     protected B decoderEnforceMaxSmallContinuationFrames(int maxSmallContinuationFrames) {
488         enforceNonCodecConstraints("maxSmallContinuationFrames");
489         this.maxSmallContinuationFrames = checkPositiveOrZero(
490                 maxSmallContinuationFrames, "maxSmallContinuationFrames");
491         return self();
492     }
493 
494     /**
495      * Determine if settings frame should automatically be acknowledged and applied.
496      * @return this.
497      */
498     protected B autoAckSettingsFrame(boolean autoAckSettings) {
499         enforceNonCodecConstraints("autoAckSettingsFrame");
500         autoAckSettingsFrame = autoAckSettings;
501         return self();
502     }
503 
504     /**
505      * Determine if the SETTINGS frames should be automatically acknowledged and applied.
506      * @return {@code true} if the SETTINGS frames should be automatically acknowledged and applied.
507      */
508     protected boolean isAutoAckSettingsFrame() {
509         return autoAckSettingsFrame;
510     }
511 
512     /**
513      * Determine if PING frame should automatically be acknowledged or not.
514      * @return this.
515      */
516     protected B autoAckPingFrame(boolean autoAckPingFrame) {
517         enforceNonCodecConstraints("autoAckPingFrame");
518         this.autoAckPingFrame = autoAckPingFrame;
519         return self();
520     }
521 
522     /**
523      * Determine if the PING frames should be automatically acknowledged or not.
524      * @return {@code true} if the PING frames should be automatically acknowledged.
525      */
526     protected boolean isAutoAckPingFrame() {
527         return autoAckPingFrame;
528     }
529 
530     /**
531      * Determine if the {@link Channel#close()} should be coupled with goaway and graceful close.
532      * @param decoupleCloseAndGoAway {@code true} to make {@link Channel#close()} directly close the underlying
533      *   transport, and not attempt graceful closure via GOAWAY.
534      * @return {@code this}.
535      */
536     protected B decoupleCloseAndGoAway(boolean decoupleCloseAndGoAway) {
537         this.decoupleCloseAndGoAway = decoupleCloseAndGoAway;
538         return self();
539     }
540 
541     /**
542      * Determine if the {@link Channel#close()} should be coupled with goaway and graceful close.
543      */
544     protected boolean decoupleCloseAndGoAway() {
545         return decoupleCloseAndGoAway;
546     }
547 
548     /**
549      * Determine if the <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">Preface</a>
550      * should be automatically flushed when the {@link Channel} becomes active or not.
551      * <p>
552      * Client may choose to opt-out from this automatic behavior and manage flush manually if it's ready to send
553      * request frames immediately after the preface. It may help to avoid unnecessary latency.
554      *
555      * @param flushPreface {@code true} to automatically flush, {@code false otherwise}.
556      * @return {@code this}.
557      * @see <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">HTTP/2 Connection Preface</a>
558      */
559     protected B flushPreface(boolean flushPreface) {
560         this.flushPreface = flushPreface;
561         return self();
562     }
563 
564     /**
565      * Determine if the <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">Preface</a>
566      * should be automatically flushed when the {@link Channel} becomes active or not.
567      * <p>
568      * Client may choose to opt-out from this automatic behavior and manage flush manually if it's ready to send
569      * request frames immediately after the preface. It may help to avoid unnecessary latency.
570      *
571      * @return {@code true} if automatically flushed.
572      * @see <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">HTTP/2 Connection Preface</a>
573      */
574     protected boolean flushPreface() {
575         return flushPreface;
576     }
577 
578     /**
579      * Create a new {@link Http2ConnectionHandler}.
580      */
581     protected T build() {
582         if (encoder != null) {
583             assert decoder != null;
584             return buildFromCodec(decoder, encoder);
585         }
586 
587         Http2Connection connection = this.connection;
588         if (connection == null) {
589             connection = new DefaultHttp2Connection(isServer(), maxReservedStreams());
590         }
591 
592         return buildFromConnection(connection);
593     }
594 
595     private T buildFromConnection(Http2Connection connection) {
596         Long maxHeaderListSize = initialSettings.maxHeaderListSize();
597         Http2FrameReader reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(isValidateHeaders(),
598                 maxHeaderListSize == null ? DEFAULT_HEADER_LIST_SIZE : maxHeaderListSize,
599                 /* initialHuffmanDecodeCapacity= */ -1), maxSmallContinuationFrames);
600         Http2FrameWriter writer = encoderIgnoreMaxHeaderListSize == null ?
601                 new DefaultHttp2FrameWriter(headerSensitivityDetector()) :
602                 new DefaultHttp2FrameWriter(headerSensitivityDetector(), encoderIgnoreMaxHeaderListSize);
603 
604         if (frameLogger != null) {
605             reader = new Http2InboundFrameLogger(reader, frameLogger);
606             writer = new Http2OutboundFrameLogger(writer, frameLogger);
607         }
608 
609         Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, writer);
610         boolean encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams();
611 
612         if (maxQueuedControlFrames != 0) {
613             encoder = new Http2ControlFrameLimitEncoder(encoder, maxQueuedControlFrames);
614         }
615         final int maxEncodedRstFrames;
616         if (maxEncodedRstFramesPerWindow == null) {
617             // Only enable by default on the server.
618             if (isServer()) {
619                 maxEncodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
620             } else {
621                 maxEncodedRstFrames = 0;
622             }
623         } else {
624             maxEncodedRstFrames = maxEncodedRstFramesPerWindow;
625         }
626         if (maxEncodedRstFrames > 0 && maxEncodedRstFramesSecondsPerWindow > 0) {
627             encoder = new Http2MaxRstFrameLimitEncoder(
628                     encoder, maxEncodedRstFrames, maxEncodedRstFramesSecondsPerWindow);
629         }
630         if (encoderEnforceMaxConcurrentStreams) {
631             if (connection.isServer()) {
632                 encoder.close();
633                 reader.close();
634                 throw new IllegalArgumentException(
635                         "encoderEnforceMaxConcurrentStreams: " + encoderEnforceMaxConcurrentStreams +
636                         " not supported for server");
637             }
638             encoder = new StreamBufferingEncoder(encoder);
639         }
640 
641         DefaultHttp2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, reader,
642             promisedRequestVerifier(), isAutoAckSettingsFrame(), isAutoAckPingFrame(), isValidateHeaders());
643         return buildFromCodec(decoder, encoder);
644     }
645 
646     private T buildFromCodec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
647         int maxConsecutiveEmptyDataFrames = decoderEnforceMaxConsecutiveEmptyDataFrames();
648         if (maxConsecutiveEmptyDataFrames > 0) {
649             decoder = new Http2EmptyDataFrameConnectionDecoder(decoder, maxConsecutiveEmptyDataFrames);
650         }
651         final int maxDecodedRstFrames;
652         if (maxDecodedRstFramesPerWindow == null) {
653             // Only enable by default on the server.
654             if (isServer()) {
655                 maxDecodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
656             } else {
657                 maxDecodedRstFrames = 0;
658             }
659         } else {
660             maxDecodedRstFrames = maxDecodedRstFramesPerWindow;
661         }
662         if (maxDecodedRstFrames > 0 && maxDecodedRstFramesSecondsPerWindow > 0) {
663             decoder = new Http2MaxRstFrameDecoder(decoder, maxDecodedRstFrames, maxDecodedRstFramesSecondsPerWindow);
664         }
665         final T handler;
666         try {
667             // Call the abstract build method
668             handler = build(decoder, encoder, initialSettings);
669         } catch (Throwable t) {
670             encoder.close();
671             decoder.close();
672             throw new IllegalStateException("failed to build an Http2ConnectionHandler", t);
673         }
674 
675         // Setup post build options
676         handler.gracefulShutdownTimeoutMillis(gracefulShutdownTimeoutMillis);
677         if (handler.decoder().frameListener() == null) {
678             handler.decoder().frameListener(frameListener);
679         }
680         return handler;
681     }
682 
683     /**
684      * Implement this method to create a new {@link Http2ConnectionHandler} or its subtype instance.
685      * <p>
686      * The return of this method will be subject to the following:
687      * <ul>
688      *   <li>{@link #frameListener(Http2FrameListener)} will be set if not already set in the decoder</li>
689      *   <li>{@link #gracefulShutdownTimeoutMillis(long)} will always be set</li>
690      * </ul>
691      */
692     protected abstract T build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
693                                Http2Settings initialSettings) throws Exception;
694 
695     /**
696      * Returns {@code this}.
697      */
698     @SuppressWarnings("unchecked")
699     protected final B self() {
700         return (B) this;
701     }
702 
703     private void enforceNonCodecConstraints(String rejected) {
704         enforceConstraint(rejected, "server/connection", decoder);
705         enforceConstraint(rejected, "server/connection", encoder);
706     }
707 
708     private static void enforceConstraint(String methodName, String rejectorName, Object value) {
709         if (value != null) {
710             throw new IllegalStateException(
711                     methodName + "() cannot be called because " + rejectorName + "() has been called already.");
712         }
713     }
714 }