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  
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   * Abstract base class which defines commonly used features required to build {@link Http2ConnectionHandler} instances.
30   *
31   * <h3>Three ways to build a {@link Http2ConnectionHandler}</h3>
32   * <h4>Let the builder create a {@link Http2ConnectionHandler}</h4>
33   * Simply call all the necessary setter methods, and then use {@link #build()} to build a new
34   * {@link Http2ConnectionHandler}. Setting the following properties are prohibited because they are used for
35   * other ways of building a {@link Http2ConnectionHandler}.
36   * conflicts with this option:
37   * <ul>
38   *   <li>{@link #connection(Http2Connection)}</li>
39   *   <li>{@link #codec(Http2ConnectionDecoder, Http2ConnectionEncoder)}</li>
40   * </ul>
41   *
42   *
43   * <h4>Let the builder use the {@link Http2ConnectionHandler} you specified</h4>
44   * Call {@link #connection(Http2Connection)} to tell the builder that you want to build the handler from the
45   * {@link Http2Connection} you specified. Setting the following properties are prohibited and thus will trigger
46   * an {@link IllegalStateException} because they conflict with this option.
47   * <ul>
48   *   <li>{@link #server(boolean)}</li>
49   *   <li>{@link #codec(Http2ConnectionDecoder, Http2ConnectionEncoder)}</li>
50   * </ul>
51   *
52   * <h4>Let the builder use the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} you specified</h4>
53   * Call {@link #codec(Http2ConnectionDecoder, Http2ConnectionEncoder)} to tell the builder that you want to built the
54   * handler from the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} you specified. Setting the
55   * following properties are prohibited and thus will trigger an {@link IllegalStateException} because they conflict
56   * with this option:
57   * <ul>
58   *   <li>{@link #server(boolean)}</li>
59   *   <li>{@link #connection(Http2Connection)}</li>
60   *   <li>{@link #frameLogger(Http2FrameLogger)}</li>
61   *   <li>{@link #headerSensitivityDetector(SensitivityDetector)}</li>
62   *   <li>{@link #encoderEnforceMaxConcurrentStreams(boolean)}</li>
63   *   <li>{@link #encoderIgnoreMaxHeaderListSize(boolean)}</li>
64   * </ul>
65   *
66   * <h3>Exposing necessary methods in a subclass</h3>
67   * {@link #build()} method and all property access methods are {@code protected}. Choose the methods to expose to the
68   * users of your builder implementation and make them {@code public}.
69   *
70   * @param <T> The type of handler created by this builder.
71   * @param <B> The concrete type of this builder.
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      // The properties that can always be set.
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      // The property that will prohibit connection() and codec() if set by server(),
88      // because this property is used only when this builder creates an Http2Connection.
89      private Boolean isServer;
90      private Integer maxReservedStreams;
91  
92      // The property that will prohibit server() and codec() if set by connection().
93      private Http2Connection connection;
94  
95      // The properties that will prohibit server() and connection() if set by codec().
96      private Http2ConnectionDecoder decoder;
97      private Http2ConnectionEncoder encoder;
98  
99      // The properties that are:
100     // * mutually exclusive against codec() and
101     // * OK to use with server() and connection()
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      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
117      */
118     protected Http2Settings initialSettings() {
119         return initialSettings;
120     }
121 
122     /**
123      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
124      */
125     protected B initialSettings(Http2Settings settings) {
126         initialSettings = checkNotNull(settings, "settings");
127         return self();
128     }
129 
130     /**
131      * Returns the listener of inbound frames.
132      *
133      * @return {@link Http2FrameListener} if set, or {@code null} if not set.
134      */
135     protected Http2FrameListener frameListener() {
136         return frameListener;
137     }
138 
139     /**
140      * Sets the listener of inbound frames.
141      * This listener will only be set if the decoder's listener is {@code null}.
142      */
143     protected B frameListener(Http2FrameListener frameListener) {
144         this.frameListener = checkNotNull(frameListener, "frameListener");
145         return self();
146     }
147 
148     /**
149      * Returns the graceful shutdown timeout of the {@link Http2Connection} in milliseconds. Returns -1 if the
150      * timeout is indefinite.
151      */
152     protected long gracefulShutdownTimeoutMillis() {
153         return gracefulShutdownTimeoutMillis;
154     }
155 
156     /**
157      * Sets the graceful shutdown timeout of the {@link Http2Connection} in milliseconds.
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      * Returns if {@link #build()} will to create a {@link Http2Connection} in server mode ({@code true})
170      * or client mode ({@code false}).
171      */
172     protected boolean isServer() {
173         return isServer != null ? isServer : true;
174     }
175 
176     /**
177      * Sets if {@link #build()} will to create a {@link Http2Connection} in server mode ({@code true})
178      * or client mode ({@code false}).
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      * Get the maximum number of streams which can be in the reserved state at any given time.
191      * <p>
192      * By default this value will be ignored on the server for local endpoint. This is because the RFC provides
193      * no way to explicitly communicate a limit to how many states can be in the reserved state, and instead relies
194      * on the peer to send RST_STREAM frames when they will be rejected.
195      */
196     protected int maxReservedStreams() {
197         return maxReservedStreams != null ? maxReservedStreams : DEFAULT_MAX_RESERVED_STREAMS;
198     }
199 
200     /**
201      * Set the maximum number of streams which can be in the reserved state at any given time.
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      * Returns the {@link Http2Connection} to use.
214      *
215      * @return {@link Http2Connection} if set, or {@code null} if not set.
216      */
217     protected Http2Connection connection() {
218         return connection;
219     }
220 
221     /**
222      * Sets the {@link Http2Connection} to use.
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      * Returns the {@link Http2ConnectionDecoder} to use.
237      *
238      * @return {@link Http2ConnectionDecoder} if set, or {@code null} if not set.
239      */
240     protected Http2ConnectionDecoder decoder() {
241         return decoder;
242     }
243 
244     /**
245      * Returns the {@link Http2ConnectionEncoder} to use.
246      *
247      * @return {@link Http2ConnectionEncoder} if set, or {@code null} if not set.
248      */
249     protected Http2ConnectionEncoder encoder() {
250         return encoder;
251     }
252 
253     /**
254      * Sets the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} to use.
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      * Returns if HTTP headers should be validated according to
280      * <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
281      */
282     protected boolean isValidateHeaders() {
283         return validateHeaders != null ? validateHeaders : true;
284     }
285 
286     /**
287      * Sets if HTTP headers should be validated according to
288      * <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
289      */
290     protected B validateHeaders(boolean validateHeaders) {
291         enforceNonCodecConstraints("validateHeaders");
292         this.validateHeaders = validateHeaders;
293         return self();
294     }
295 
296     /**
297      * Returns the logger that is used for the encoder and decoder.
298      *
299      * @return {@link Http2FrameLogger} if set, or {@code null} if not set.
300      */
301     protected Http2FrameLogger frameLogger() {
302         return frameLogger;
303     }
304 
305     /**
306      * Sets the logger that is used for the encoder and decoder.
307      */
308     protected B frameLogger(Http2FrameLogger frameLogger) {
309         enforceNonCodecConstraints("frameLogger");
310         this.frameLogger = checkNotNull(frameLogger, "frameLogger");
311         return self();
312     }
313 
314     /**
315      * Returns if the encoder should queue frames if the maximum number of concurrent streams
316      * would otherwise be exceeded.
317      */
318     protected boolean encoderEnforceMaxConcurrentStreams() {
319         return encoderEnforceMaxConcurrentStreams != null ? encoderEnforceMaxConcurrentStreams : false;
320     }
321 
322     /**
323      * Sets if the encoder should queue frames if the maximum number of concurrent streams
324      * would otherwise be exceeded.
325      */
326     protected B encoderEnforceMaxConcurrentStreams(boolean encoderEnforceMaxConcurrentStreams) {
327         enforceNonCodecConstraints("encoderEnforceMaxConcurrentStreams");
328         this.encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams;
329         return self();
330     }
331 
332     /**
333      * Returns the maximum number of queued control frames that are allowed before the connection is closed.
334      * This allows to protected against various attacks that can lead to high CPU / memory usage if the remote-peer
335      * floods us with frames that would have us produce control frames, but stops to read from the underlying socket.
336      *
337      * {@code 0} means no protection is in place.
338      */
339     protected int encoderEnforceMaxQueuedControlFrames() {
340         return maxQueuedControlFrames;
341     }
342 
343     /**
344      * Sets the maximum number of queued control frames that are allowed before the connection is closed.
345      * This allows to protected against various attacks that can lead to high CPU / memory usage if the remote-peer
346      * floods us with frames that would have us produce control frames, but stops to read from the underlying socket.
347      *
348      * {@code 0} means no protection should be applied.
349      */
350     protected B encoderEnforceMaxQueuedControlFrames(int maxQueuedControlFrames) {
351         enforceNonCodecConstraints("encoderEnforceMaxQueuedControlFrames");
352         this.maxQueuedControlFrames = checkPositiveOrZero(maxQueuedControlFrames, "maxQueuedControlFrames");
353         return self();
354     }
355 
356     /**
357      * Returns the {@link SensitivityDetector} to use.
358      */
359     protected SensitivityDetector headerSensitivityDetector() {
360         return headerSensitivityDetector != null ? headerSensitivityDetector : DEFAULT_HEADER_SENSITIVITY_DETECTOR;
361     }
362 
363     /**
364      * Sets the {@link SensitivityDetector} to use.
365      */
366     protected B headerSensitivityDetector(SensitivityDetector headerSensitivityDetector) {
367         enforceNonCodecConstraints("headerSensitivityDetector");
368         this.headerSensitivityDetector = checkNotNull(headerSensitivityDetector, "headerSensitivityDetector");
369         return self();
370     }
371 
372     /**
373      * Sets if the <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_HEADER_LIST_SIZE</a>
374      * should be ignored when encoding headers.
375      * @param ignoreMaxHeaderListSize {@code true} to ignore
376      * <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_HEADER_LIST_SIZE</a>.
377      * @return this.
378      */
379     protected B encoderIgnoreMaxHeaderListSize(boolean ignoreMaxHeaderListSize) {
380         enforceNonCodecConstraints("encoderIgnoreMaxHeaderListSize");
381         encoderIgnoreMaxHeaderListSize = ignoreMaxHeaderListSize;
382         return self();
383     }
384 
385     /**
386      * Does nothing, do not call.
387      *
388      * @deprecated Huffman decoding no longer depends on having a decode capacity.
389      */
390     @Deprecated
391     protected B initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
392         return self();
393     }
394 
395     /**
396      * Set the {@link Http2PromisedRequestVerifier} to use.
397      * @return this.
398      */
399     protected B promisedRequestVerifier(Http2PromisedRequestVerifier promisedRequestVerifier) {
400         enforceNonCodecConstraints("promisedRequestVerifier");
401         this.promisedRequestVerifier = checkNotNull(promisedRequestVerifier, "promisedRequestVerifier");
402         return self();
403     }
404 
405     /**
406      * Get the {@link Http2PromisedRequestVerifier} to use.
407      * @return the {@link Http2PromisedRequestVerifier} to use.
408      */
409     protected Http2PromisedRequestVerifier promisedRequestVerifier() {
410         return promisedRequestVerifier;
411     }
412 
413     /**
414      * Returns the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
415      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
416      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
417      *
418      * {@code 0} means no protection is in place.
419      */
420     protected int decoderEnforceMaxConsecutiveEmptyDataFrames() {
421         return maxConsecutiveEmptyFrames;
422     }
423 
424     /**
425      * Sets the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
426      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
427      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
428      *
429      * {@code 0} means no protection should be applied.
430      */
431     protected B decoderEnforceMaxConsecutiveEmptyDataFrames(int maxConsecutiveEmptyFrames) {
432         enforceNonCodecConstraints("maxConsecutiveEmptyFrames");
433         this.maxConsecutiveEmptyFrames = checkPositiveOrZero(
434                 maxConsecutiveEmptyFrames, "maxConsecutiveEmptyFrames");
435         return self();
436     }
437 
438     /**
439      * Sets the maximum number RST frames that are allowed per window before
440      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
441      * so use up a lot of CPU.
442      *
443      * {@code 0} for any of the parameters means no protection should be applied.
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      * Determine if settings frame should automatically be acknowledged and applied.
455      * @return this.
456      */
457     protected B autoAckSettingsFrame(boolean autoAckSettings) {
458         enforceNonCodecConstraints("autoAckSettingsFrame");
459         autoAckSettingsFrame = autoAckSettings;
460         return self();
461     }
462 
463     /**
464      * Determine if the SETTINGS frames should be automatically acknowledged and applied.
465      * @return {@code true} if the SETTINGS frames should be automatically acknowledged and applied.
466      */
467     protected boolean isAutoAckSettingsFrame() {
468         return autoAckSettingsFrame;
469     }
470 
471     /**
472      * Determine if PING frame should automatically be acknowledged or not.
473      * @return this.
474      */
475     protected B autoAckPingFrame(boolean autoAckPingFrame) {
476         enforceNonCodecConstraints("autoAckPingFrame");
477         this.autoAckPingFrame = autoAckPingFrame;
478         return self();
479     }
480 
481     /**
482      * Determine if the PING frames should be automatically acknowledged or not.
483      * @return {@code true} if the PING frames should be automatically acknowledged.
484      */
485     protected boolean isAutoAckPingFrame() {
486         return autoAckPingFrame;
487     }
488 
489     /**
490      * Determine if the {@link Channel#close()} should be coupled with goaway and graceful close.
491      * @param decoupleCloseAndGoAway {@code true} to make {@link Channel#close()} directly close the underlying
492      *   transport, and not attempt graceful closure via GOAWAY.
493      * @return {@code this}.
494      */
495     protected B decoupleCloseAndGoAway(boolean decoupleCloseAndGoAway) {
496         this.decoupleCloseAndGoAway = decoupleCloseAndGoAway;
497         return self();
498     }
499 
500     /**
501      * Determine if the {@link Channel#close()} should be coupled with goaway and graceful close.
502      */
503     protected boolean decoupleCloseAndGoAway() {
504         return decoupleCloseAndGoAway;
505     }
506 
507     /**
508      * Determine if the <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">Preface</a>
509      * should be automatically flushed when the {@link Channel} becomes active or not.
510      * <p>
511      * Client may choose to opt-out from this automatic behavior and manage flush manually if it's ready to send
512      * request frames immediately after the preface. It may help to avoid unnecessary latency.
513      *
514      * @param flushPreface {@code true} to automatically flush, {@code false otherwise}.
515      * @return {@code this}.
516      * @see <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">HTTP/2 Connection Preface</a>
517      */
518     protected B flushPreface(boolean flushPreface) {
519         this.flushPreface = flushPreface;
520         return self();
521     }
522 
523     /**
524      * Determine if the <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">Preface</a>
525      * should be automatically flushed when the {@link Channel} becomes active or not.
526      * <p>
527      * Client may choose to opt-out from this automatic behavior and manage flush manually if it's ready to send
528      * request frames immediately after the preface. It may help to avoid unnecessary latency.
529      *
530      * @return {@code true} if automatically flushed.
531      * @see <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">HTTP/2 Connection Preface</a>
532      */
533     protected boolean flushPreface() {
534         return flushPreface;
535     }
536 
537     /**
538      * Create a new {@link Http2ConnectionHandler}.
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                 /* initialHuffmanDecodeCapacity= */ -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             // Only enable by default on the server.
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             // Call the abstract build method
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         // Setup post build options
620         handler.gracefulShutdownTimeoutMillis(gracefulShutdownTimeoutMillis);
621         if (handler.decoder().frameListener() == null) {
622             handler.decoder().frameListener(frameListener);
623         }
624         return handler;
625     }
626 
627     /**
628      * Implement this method to create a new {@link Http2ConnectionHandler} or its subtype instance.
629      * <p>
630      * The return of this method will be subject to the following:
631      * <ul>
632      *   <li>{@link #frameListener(Http2FrameListener)} will be set if not already set in the decoder</li>
633      *   <li>{@link #gracefulShutdownTimeoutMillis(long)} will always be set</li>
634      * </ul>
635      */
636     protected abstract T build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
637                                Http2Settings initialSettings) throws Exception;
638 
639     /**
640      * Returns {@code this}.
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 }