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 maxDecodedRstFramesPerWindow;
113     private int maxDecodedRstFramesSecondsPerWindow = 30;
114     private Integer maxEncodedRstFramesPerWindow;
115     private int maxEncodedRstFramesSecondsPerWindow = 30;
116     /**
117      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
118      */
119     protected Http2Settings initialSettings() {
120         return initialSettings;
121     }
122 
123     /**
124      * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
125      */
126     protected B initialSettings(Http2Settings settings) {
127         initialSettings = checkNotNull(settings, "settings");
128         return self();
129     }
130 
131     /**
132      * Returns the listener of inbound frames.
133      *
134      * @return {@link Http2FrameListener} if set, or {@code null} if not set.
135      */
136     protected Http2FrameListener frameListener() {
137         return frameListener;
138     }
139 
140     /**
141      * Sets the listener of inbound frames.
142      * This listener will only be set if the decoder's listener is {@code null}.
143      */
144     protected B frameListener(Http2FrameListener frameListener) {
145         this.frameListener = checkNotNull(frameListener, "frameListener");
146         return self();
147     }
148 
149     /**
150      * Returns the graceful shutdown timeout of the {@link Http2Connection} in milliseconds. Returns -1 if the
151      * timeout is indefinite.
152      */
153     protected long gracefulShutdownTimeoutMillis() {
154         return gracefulShutdownTimeoutMillis;
155     }
156 
157     /**
158      * Sets the graceful shutdown timeout of the {@link Http2Connection} in milliseconds.
159      */
160     protected B gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis) {
161         if (gracefulShutdownTimeoutMillis < -1) {
162             throw new IllegalArgumentException("gracefulShutdownTimeoutMillis: " + gracefulShutdownTimeoutMillis +
163                                                " (expected: -1 for indefinite or >= 0)");
164         }
165         this.gracefulShutdownTimeoutMillis = gracefulShutdownTimeoutMillis;
166         return self();
167     }
168 
169     /**
170      * Returns if {@link #build()} will to create a {@link Http2Connection} in server mode ({@code true})
171      * or client mode ({@code false}).
172      */
173     protected boolean isServer() {
174         return isServer != null ? isServer : true;
175     }
176 
177     /**
178      * Sets if {@link #build()} will to create a {@link Http2Connection} in server mode ({@code true})
179      * or client mode ({@code false}).
180      */
181     protected B server(boolean isServer) {
182         enforceConstraint("server", "connection", connection);
183         enforceConstraint("server", "codec", decoder);
184         enforceConstraint("server", "codec", encoder);
185 
186         this.isServer = isServer;
187         return self();
188     }
189 
190     /**
191      * Get the maximum number of streams which can be in the reserved state at any given time.
192      * <p>
193      * By default this value will be ignored on the server for local endpoint. This is because the RFC provides
194      * no way to explicitly communicate a limit to how many states can be in the reserved state, and instead relies
195      * on the peer to send RST_STREAM frames when they will be rejected.
196      */
197     protected int maxReservedStreams() {
198         return maxReservedStreams != null ? maxReservedStreams : DEFAULT_MAX_RESERVED_STREAMS;
199     }
200 
201     /**
202      * Set the maximum number of streams which can be in the reserved state at any given time.
203      */
204     protected B maxReservedStreams(int maxReservedStreams) {
205         enforceConstraint("server", "connection", connection);
206         enforceConstraint("server", "codec", decoder);
207         enforceConstraint("server", "codec", encoder);
208 
209         this.maxReservedStreams = checkPositiveOrZero(maxReservedStreams, "maxReservedStreams");
210         return self();
211     }
212 
213     /**
214      * Returns the {@link Http2Connection} to use.
215      *
216      * @return {@link Http2Connection} if set, or {@code null} if not set.
217      */
218     protected Http2Connection connection() {
219         return connection;
220     }
221 
222     /**
223      * Sets the {@link Http2Connection} to use.
224      */
225     protected B connection(Http2Connection connection) {
226         enforceConstraint("connection", "maxReservedStreams", maxReservedStreams);
227         enforceConstraint("connection", "server", isServer);
228         enforceConstraint("connection", "codec", decoder);
229         enforceConstraint("connection", "codec", encoder);
230 
231         this.connection = checkNotNull(connection, "connection");
232 
233         return self();
234     }
235 
236     /**
237      * Returns the {@link Http2ConnectionDecoder} to use.
238      *
239      * @return {@link Http2ConnectionDecoder} if set, or {@code null} if not set.
240      */
241     protected Http2ConnectionDecoder decoder() {
242         return decoder;
243     }
244 
245     /**
246      * Returns the {@link Http2ConnectionEncoder} to use.
247      *
248      * @return {@link Http2ConnectionEncoder} if set, or {@code null} if not set.
249      */
250     protected Http2ConnectionEncoder encoder() {
251         return encoder;
252     }
253 
254     /**
255      * Sets the {@link Http2ConnectionDecoder} and {@link Http2ConnectionEncoder} to use.
256      */
257     protected B codec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
258         enforceConstraint("codec", "server", isServer);
259         enforceConstraint("codec", "maxReservedStreams", maxReservedStreams);
260         enforceConstraint("codec", "connection", connection);
261         enforceConstraint("codec", "frameLogger", frameLogger);
262         enforceConstraint("codec", "validateHeaders", validateHeaders);
263         enforceConstraint("codec", "headerSensitivityDetector", headerSensitivityDetector);
264         enforceConstraint("codec", "encoderEnforceMaxConcurrentStreams", encoderEnforceMaxConcurrentStreams);
265 
266         checkNotNull(decoder, "decoder");
267         checkNotNull(encoder, "encoder");
268 
269         if (decoder.connection() != encoder.connection()) {
270             throw new IllegalArgumentException("The specified encoder and decoder have different connections.");
271         }
272 
273         this.decoder = decoder;
274         this.encoder = encoder;
275 
276         return self();
277     }
278 
279     /**
280      * Returns if HTTP headers should be validated according to
281      * <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
282      */
283     protected boolean isValidateHeaders() {
284         return validateHeaders != null ? validateHeaders : true;
285     }
286 
287     /**
288      * Sets if HTTP headers should be validated according to
289      * <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.6">RFC 7540, 8.1.2.6</a>.
290      */
291     protected B validateHeaders(boolean validateHeaders) {
292         enforceNonCodecConstraints("validateHeaders");
293         this.validateHeaders = validateHeaders;
294         return self();
295     }
296 
297     /**
298      * Returns the logger that is used for the encoder and decoder.
299      *
300      * @return {@link Http2FrameLogger} if set, or {@code null} if not set.
301      */
302     protected Http2FrameLogger frameLogger() {
303         return frameLogger;
304     }
305 
306     /**
307      * Sets the logger that is used for the encoder and decoder.
308      */
309     protected B frameLogger(Http2FrameLogger frameLogger) {
310         enforceNonCodecConstraints("frameLogger");
311         this.frameLogger = checkNotNull(frameLogger, "frameLogger");
312         return self();
313     }
314 
315     /**
316      * Returns if the encoder should queue frames if the maximum number of concurrent streams
317      * would otherwise be exceeded.
318      */
319     protected boolean encoderEnforceMaxConcurrentStreams() {
320         return encoderEnforceMaxConcurrentStreams != null ? encoderEnforceMaxConcurrentStreams : false;
321     }
322 
323     /**
324      * Sets if the encoder should queue frames if the maximum number of concurrent streams
325      * would otherwise be exceeded.
326      */
327     protected B encoderEnforceMaxConcurrentStreams(boolean encoderEnforceMaxConcurrentStreams) {
328         enforceNonCodecConstraints("encoderEnforceMaxConcurrentStreams");
329         this.encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams;
330         return self();
331     }
332 
333     /**
334      * Returns the maximum number of queued control frames that are allowed before the connection is closed.
335      * This allows to protected against various attacks that can lead to high CPU / memory usage if the remote-peer
336      * floods us with frames that would have us produce control frames, but stops to read from the underlying socket.
337      *
338      * {@code 0} means no protection is in place.
339      */
340     protected int encoderEnforceMaxQueuedControlFrames() {
341         return maxQueuedControlFrames;
342     }
343 
344     /**
345      * Sets the maximum number of queued control frames that are allowed before the connection is closed.
346      * This allows to protected against various attacks that can lead to high CPU / memory usage if the remote-peer
347      * floods us with frames that would have us produce control frames, but stops to read from the underlying socket.
348      *
349      * {@code 0} means no protection should be applied.
350      */
351     protected B encoderEnforceMaxQueuedControlFrames(int maxQueuedControlFrames) {
352         enforceNonCodecConstraints("encoderEnforceMaxQueuedControlFrames");
353         this.maxQueuedControlFrames = checkPositiveOrZero(maxQueuedControlFrames, "maxQueuedControlFrames");
354         return self();
355     }
356 
357     /**
358      * Returns the {@link SensitivityDetector} to use.
359      */
360     protected SensitivityDetector headerSensitivityDetector() {
361         return headerSensitivityDetector != null ? headerSensitivityDetector : DEFAULT_HEADER_SENSITIVITY_DETECTOR;
362     }
363 
364     /**
365      * Sets the {@link SensitivityDetector} to use.
366      */
367     protected B headerSensitivityDetector(SensitivityDetector headerSensitivityDetector) {
368         enforceNonCodecConstraints("headerSensitivityDetector");
369         this.headerSensitivityDetector = checkNotNull(headerSensitivityDetector, "headerSensitivityDetector");
370         return self();
371     }
372 
373     /**
374      * Sets if the <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_HEADER_LIST_SIZE</a>
375      * should be ignored when encoding headers.
376      * @param ignoreMaxHeaderListSize {@code true} to ignore
377      * <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_HEADER_LIST_SIZE</a>.
378      * @return this.
379      */
380     protected B encoderIgnoreMaxHeaderListSize(boolean ignoreMaxHeaderListSize) {
381         enforceNonCodecConstraints("encoderIgnoreMaxHeaderListSize");
382         encoderIgnoreMaxHeaderListSize = ignoreMaxHeaderListSize;
383         return self();
384     }
385 
386     /**
387      * Does nothing, do not call.
388      *
389      * @deprecated Huffman decoding no longer depends on having a decode capacity.
390      */
391     @Deprecated
392     protected B initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
393         return self();
394     }
395 
396     /**
397      * Set the {@link Http2PromisedRequestVerifier} to use.
398      * @return this.
399      */
400     protected B promisedRequestVerifier(Http2PromisedRequestVerifier promisedRequestVerifier) {
401         enforceNonCodecConstraints("promisedRequestVerifier");
402         this.promisedRequestVerifier = checkNotNull(promisedRequestVerifier, "promisedRequestVerifier");
403         return self();
404     }
405 
406     /**
407      * Get the {@link Http2PromisedRequestVerifier} to use.
408      * @return the {@link Http2PromisedRequestVerifier} to use.
409      */
410     protected Http2PromisedRequestVerifier promisedRequestVerifier() {
411         return promisedRequestVerifier;
412     }
413 
414     /**
415      * Returns the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
416      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
417      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
418      *
419      * {@code 0} means no protection is in place.
420      */
421     protected int decoderEnforceMaxConsecutiveEmptyDataFrames() {
422         return maxConsecutiveEmptyFrames;
423     }
424 
425     /**
426      * Sets the maximum number of consecutive empty DATA frames (without end_of_stream flag) that are allowed before
427      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
428      * so use up a lot of CPU. There is no valid use-case for empty DATA frames without end_of_stream flag.
429      *
430      * {@code 0} means no protection should be applied.
431      */
432     protected B decoderEnforceMaxConsecutiveEmptyDataFrames(int maxConsecutiveEmptyFrames) {
433         enforceNonCodecConstraints("maxConsecutiveEmptyFrames");
434         this.maxConsecutiveEmptyFrames = checkPositiveOrZero(
435                 maxConsecutiveEmptyFrames, "maxConsecutiveEmptyFrames");
436         return self();
437     }
438 
439     /**
440      * Sets the maximum number RST frames that are allowed per window before
441      * the connection is closed. This allows to protect against the remote peer flooding us with such frames and
442      * so use up a lot of CPU.
443      *
444      * {@code 0} for any of the parameters means no protection should be applied.
445      */
446     protected B decoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
447         enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
448         this.maxDecodedRstFramesPerWindow = checkPositiveOrZero(
449                 maxRstFramesPerWindow, "maxRstFramesPerWindow");
450         this.maxDecodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
451         return self();
452     }
453 
454     /**
455      * Sets the maximum number RST frames that are allowed per window before
456      * the connection is closed. This allows to protect against the remote peer that will trigger us to generate a flood
457      * of RST frames and so use up a lot of CPU.
458      *
459      * {@code 0} for any of the parameters means no protection should be applied.
460      */
461     protected B encoderEnforceMaxRstFramesPerWindow(int maxRstFramesPerWindow, int secondsPerWindow) {
462         enforceNonCodecConstraints("decoderEnforceMaxRstFramesPerWindow");
463         this.maxEncodedRstFramesPerWindow = checkPositiveOrZero(
464                 maxRstFramesPerWindow, "maxRstFramesPerWindow");
465         this.maxEncodedRstFramesSecondsPerWindow = checkPositiveOrZero(secondsPerWindow, "secondsPerWindow");
466         return self();
467     }
468 
469     /**
470      * Determine if settings frame should automatically be acknowledged and applied.
471      * @return this.
472      */
473     protected B autoAckSettingsFrame(boolean autoAckSettings) {
474         enforceNonCodecConstraints("autoAckSettingsFrame");
475         autoAckSettingsFrame = autoAckSettings;
476         return self();
477     }
478 
479     /**
480      * Determine if the SETTINGS frames should be automatically acknowledged and applied.
481      * @return {@code true} if the SETTINGS frames should be automatically acknowledged and applied.
482      */
483     protected boolean isAutoAckSettingsFrame() {
484         return autoAckSettingsFrame;
485     }
486 
487     /**
488      * Determine if PING frame should automatically be acknowledged or not.
489      * @return this.
490      */
491     protected B autoAckPingFrame(boolean autoAckPingFrame) {
492         enforceNonCodecConstraints("autoAckPingFrame");
493         this.autoAckPingFrame = autoAckPingFrame;
494         return self();
495     }
496 
497     /**
498      * Determine if the PING frames should be automatically acknowledged or not.
499      * @return {@code true} if the PING frames should be automatically acknowledged.
500      */
501     protected boolean isAutoAckPingFrame() {
502         return autoAckPingFrame;
503     }
504 
505     /**
506      * Determine if the {@link Channel#close()} should be coupled with goaway and graceful close.
507      * @param decoupleCloseAndGoAway {@code true} to make {@link Channel#close()} directly close the underlying
508      *   transport, and not attempt graceful closure via GOAWAY.
509      * @return {@code this}.
510      */
511     protected B decoupleCloseAndGoAway(boolean decoupleCloseAndGoAway) {
512         this.decoupleCloseAndGoAway = decoupleCloseAndGoAway;
513         return self();
514     }
515 
516     /**
517      * Determine if the {@link Channel#close()} should be coupled with goaway and graceful close.
518      */
519     protected boolean decoupleCloseAndGoAway() {
520         return decoupleCloseAndGoAway;
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      * @param flushPreface {@code true} to automatically flush, {@code false otherwise}.
531      * @return {@code this}.
532      * @see <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">HTTP/2 Connection Preface</a>
533      */
534     protected B flushPreface(boolean flushPreface) {
535         this.flushPreface = flushPreface;
536         return self();
537     }
538 
539     /**
540      * Determine if the <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">Preface</a>
541      * should be automatically flushed when the {@link Channel} becomes active or not.
542      * <p>
543      * Client may choose to opt-out from this automatic behavior and manage flush manually if it's ready to send
544      * request frames immediately after the preface. It may help to avoid unnecessary latency.
545      *
546      * @return {@code true} if automatically flushed.
547      * @see <a href="https://datatracker.ietf.org/doc/html/rfc7540#section-3.5">HTTP/2 Connection Preface</a>
548      */
549     protected boolean flushPreface() {
550         return flushPreface;
551     }
552 
553     /**
554      * Create a new {@link Http2ConnectionHandler}.
555      */
556     protected T build() {
557         if (encoder != null) {
558             assert decoder != null;
559             return buildFromCodec(decoder, encoder);
560         }
561 
562         Http2Connection connection = this.connection;
563         if (connection == null) {
564             connection = new DefaultHttp2Connection(isServer(), maxReservedStreams());
565         }
566 
567         return buildFromConnection(connection);
568     }
569 
570     private T buildFromConnection(Http2Connection connection) {
571         Long maxHeaderListSize = initialSettings.maxHeaderListSize();
572         Http2FrameReader reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(isValidateHeaders(),
573                 maxHeaderListSize == null ? DEFAULT_HEADER_LIST_SIZE : maxHeaderListSize,
574                 /* initialHuffmanDecodeCapacity= */ -1));
575         Http2FrameWriter writer = encoderIgnoreMaxHeaderListSize == null ?
576                 new DefaultHttp2FrameWriter(headerSensitivityDetector()) :
577                 new DefaultHttp2FrameWriter(headerSensitivityDetector(), encoderIgnoreMaxHeaderListSize);
578 
579         if (frameLogger != null) {
580             reader = new Http2InboundFrameLogger(reader, frameLogger);
581             writer = new Http2OutboundFrameLogger(writer, frameLogger);
582         }
583 
584         Http2ConnectionEncoder encoder = new DefaultHttp2ConnectionEncoder(connection, writer);
585         boolean encoderEnforceMaxConcurrentStreams = encoderEnforceMaxConcurrentStreams();
586 
587         if (maxQueuedControlFrames != 0) {
588             encoder = new Http2ControlFrameLimitEncoder(encoder, maxQueuedControlFrames);
589         }
590         final int maxEncodedRstFrames;
591         if (maxEncodedRstFramesPerWindow == null) {
592             // Only enable by default on the server.
593             if (isServer()) {
594                 maxEncodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
595             } else {
596                 maxEncodedRstFrames = 0;
597             }
598         } else {
599             maxEncodedRstFrames = maxEncodedRstFramesPerWindow;
600         }
601         if (maxEncodedRstFrames > 0 && maxEncodedRstFramesSecondsPerWindow > 0) {
602             encoder = new Http2MaxRstFrameLimitEncoder(
603                     encoder, maxEncodedRstFrames, maxEncodedRstFramesSecondsPerWindow);
604         }
605         if (encoderEnforceMaxConcurrentStreams) {
606             if (connection.isServer()) {
607                 encoder.close();
608                 reader.close();
609                 throw new IllegalArgumentException(
610                         "encoderEnforceMaxConcurrentStreams: " + encoderEnforceMaxConcurrentStreams +
611                         " not supported for server");
612             }
613             encoder = new StreamBufferingEncoder(encoder);
614         }
615 
616         DefaultHttp2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder, reader,
617             promisedRequestVerifier(), isAutoAckSettingsFrame(), isAutoAckPingFrame(), isValidateHeaders());
618         return buildFromCodec(decoder, encoder);
619     }
620 
621     private T buildFromCodec(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder) {
622         int maxConsecutiveEmptyDataFrames = decoderEnforceMaxConsecutiveEmptyDataFrames();
623         if (maxConsecutiveEmptyDataFrames > 0) {
624             decoder = new Http2EmptyDataFrameConnectionDecoder(decoder, maxConsecutiveEmptyDataFrames);
625         }
626         final int maxDecodedRstFrames;
627         if (maxDecodedRstFramesPerWindow == null) {
628             // Only enable by default on the server.
629             if (isServer()) {
630                 maxDecodedRstFrames = DEFAULT_MAX_RST_FRAMES_PER_CONNECTION_FOR_SERVER;
631             } else {
632                 maxDecodedRstFrames = 0;
633             }
634         } else {
635             maxDecodedRstFrames = maxDecodedRstFramesPerWindow;
636         }
637         if (maxDecodedRstFrames > 0 && maxDecodedRstFramesSecondsPerWindow > 0) {
638             decoder = new Http2MaxRstFrameDecoder(decoder, maxDecodedRstFrames, maxDecodedRstFramesSecondsPerWindow);
639         }
640         final T handler;
641         try {
642             // Call the abstract build method
643             handler = build(decoder, encoder, initialSettings);
644         } catch (Throwable t) {
645             encoder.close();
646             decoder.close();
647             throw new IllegalStateException("failed to build an Http2ConnectionHandler", t);
648         }
649 
650         // Setup post build options
651         handler.gracefulShutdownTimeoutMillis(gracefulShutdownTimeoutMillis);
652         if (handler.decoder().frameListener() == null) {
653             handler.decoder().frameListener(frameListener);
654         }
655         return handler;
656     }
657 
658     /**
659      * Implement this method to create a new {@link Http2ConnectionHandler} or its subtype instance.
660      * <p>
661      * The return of this method will be subject to the following:
662      * <ul>
663      *   <li>{@link #frameListener(Http2FrameListener)} will be set if not already set in the decoder</li>
664      *   <li>{@link #gracefulShutdownTimeoutMillis(long)} will always be set</li>
665      * </ul>
666      */
667     protected abstract T build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
668                                Http2Settings initialSettings) throws Exception;
669 
670     /**
671      * Returns {@code this}.
672      */
673     @SuppressWarnings("unchecked")
674     protected final B self() {
675         return (B) this;
676     }
677 
678     private void enforceNonCodecConstraints(String rejected) {
679         enforceConstraint(rejected, "server/connection", decoder);
680         enforceConstraint(rejected, "server/connection", encoder);
681     }
682 
683     private static void enforceConstraint(String methodName, String rejectorName, Object value) {
684         if (value != null) {
685             throw new IllegalStateException(
686                     methodName + "() cannot be called because " + rejectorName + "() has been called already.");
687         }
688     }
689 }