View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at:
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software distributed under the License
11   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing permissions and limitations under
13   * the License.
14   */
15  
16  package io.netty.handler.codec.http2;
17  
18  import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_CONCURRENT_STREAMS;
19  import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_TABLE_SIZE;
20  import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_INITIAL_WINDOW_SIZE;
21  import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_LIST_SIZE;
22  import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_HEADER_TABLE_SIZE;
23  import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_CONCURRENT_STREAMS;
24  import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_INITIAL_WINDOW_SIZE;
25  import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_HEADER_LIST_SIZE;
26  import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_ENABLE_PUSH;
27  import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_HEADER_TABLE_SIZE;
28  import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_INITIAL_WINDOW_SIZE;
29  import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_MAX_CONCURRENT_STREAMS;
30  import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_MAX_FRAME_SIZE;
31  import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_MAX_HEADER_LIST_SIZE;
32  import static io.netty.handler.codec.http2.Http2CodecUtil.isMaxFrameSizeValid;
33  import static io.netty.util.internal.ObjectUtil.checkNotNull;
34  import io.netty.util.collection.IntObjectHashMap;
35  
36  /**
37   * Settings for one endpoint in an HTTP/2 connection. Each of the values are optional as defined in
38   * the spec for the SETTINGS frame. Permits storage of arbitrary key/value pairs but provides helper
39   * methods for standard settings.
40   */
41  public final class Http2Settings extends IntObjectHashMap<Long> {
42  
43      public Http2Settings() {
44          this(6 /* number of standard settings */);
45      }
46  
47      public Http2Settings(int initialCapacity, float loadFactor) {
48          super(initialCapacity, loadFactor);
49      }
50  
51      public Http2Settings(int initialCapacity) {
52          super(initialCapacity);
53      }
54  
55      /**
56       * Overrides the superclass method to perform verification of standard HTTP/2 settings.
57       *
58       * @throws IllegalArgumentException if verification of the setting fails.
59       */
60      @Override
61      public Long put(int key, Long value) {
62          verifyStandardSetting(key, value);
63          return super.put(key, value);
64      }
65  
66      /**
67       * Gets the {@code SETTINGS_HEADER_TABLE_SIZE} value. If unavailable, returns {@code null}.
68       */
69      public Long headerTableSize() {
70          return get(SETTINGS_HEADER_TABLE_SIZE);
71      }
72  
73      /**
74       * Sets the {@code SETTINGS_HEADER_TABLE_SIZE} value.
75       *
76       * @throws IllegalArgumentException if verification of the setting fails.
77       */
78      public Http2Settings headerTableSize(int value) {
79          put(SETTINGS_HEADER_TABLE_SIZE, (long) value);
80          return this;
81      }
82  
83      /**
84       * Gets the {@code SETTINGS_ENABLE_PUSH} value. If unavailable, returns {@code null}.
85       */
86      public Boolean pushEnabled() {
87          Long value = get(SETTINGS_ENABLE_PUSH);
88          if (value == null) {
89              return null;
90          }
91          return value != 0L;
92      }
93  
94      /**
95       * Sets the {@code SETTINGS_ENABLE_PUSH} value.
96       */
97      public Http2Settings pushEnabled(boolean enabled) {
98          put(SETTINGS_ENABLE_PUSH, enabled ? 1L : 0L);
99          return this;
100     }
101 
102     /**
103      * Gets the {@code SETTINGS_MAX_CONCURRENT_STREAMS} value. If unavailable, returns {@code null}.
104      */
105     public Long maxConcurrentStreams() {
106         return get(SETTINGS_MAX_CONCURRENT_STREAMS);
107     }
108 
109     /**
110      * Sets the {@code SETTINGS_MAX_CONCURRENT_STREAMS} value.
111      *
112      * @throws IllegalArgumentException if verification of the setting fails.
113      */
114     public Http2Settings maxConcurrentStreams(long value) {
115         put(SETTINGS_MAX_CONCURRENT_STREAMS, value);
116         return this;
117     }
118 
119     /**
120      * Gets the {@code SETTINGS_INITIAL_WINDOW_SIZE} value. If unavailable, returns {@code null}.
121      */
122     public Integer initialWindowSize() {
123         return getIntValue(SETTINGS_INITIAL_WINDOW_SIZE);
124     }
125 
126     /**
127      * Sets the {@code SETTINGS_INITIAL_WINDOW_SIZE} value.
128      *
129      * @throws IllegalArgumentException if verification of the setting fails.
130      */
131     public Http2Settings initialWindowSize(int value) {
132         put(SETTINGS_INITIAL_WINDOW_SIZE, (long) value);
133         return this;
134     }
135 
136     /**
137      * Gets the {@code SETTINGS_MAX_FRAME_SIZE} value. If unavailable, returns {@code null}.
138      */
139     public Integer maxFrameSize() {
140         return getIntValue(SETTINGS_MAX_FRAME_SIZE);
141     }
142 
143     /**
144      * Sets the {@code SETTINGS_MAX_FRAME_SIZE} value.
145      *
146      * @throws IllegalArgumentException if verification of the setting fails.
147      */
148     public Http2Settings maxFrameSize(int value) {
149         put(SETTINGS_MAX_FRAME_SIZE, (long) value);
150         return this;
151     }
152 
153     /**
154      * Gets the {@code SETTINGS_MAX_HEADER_LIST_SIZE} value. If unavailable, returns {@code null}.
155      */
156     public Integer maxHeaderListSize() {
157         return getIntValue(SETTINGS_MAX_HEADER_LIST_SIZE);
158     }
159 
160     /**
161      * Sets the {@code SETTINGS_MAX_HEADER_LIST_SIZE} value.
162      *
163      * @throws IllegalArgumentException if verification of the setting fails.
164      */
165     public Http2Settings maxHeaderListSize(int value) {
166         put(SETTINGS_MAX_HEADER_LIST_SIZE, (long) value);
167         return this;
168     }
169 
170     /**
171      * Clears and then copies the given settings into this object.
172      */
173     public Http2Settings copyFrom(Http2Settings settings) {
174         clear();
175         putAll(settings);
176         return this;
177     }
178 
179     Integer getIntValue(int key) {
180         Long value = get(key);
181         if (value == null) {
182             return null;
183         }
184         return value.intValue();
185     }
186 
187     private static void verifyStandardSetting(int key, Long value) {
188         checkNotNull(value, "value");
189         switch (key) {
190             case SETTINGS_HEADER_TABLE_SIZE:
191                 if (value < MIN_HEADER_TABLE_SIZE || value > MAX_HEADER_TABLE_SIZE) {
192                     throw new IllegalArgumentException("Setting HEADER_TABLE_SIZE is invalid: " + value);
193                 }
194                 break;
195             case SETTINGS_ENABLE_PUSH:
196                 if (value != 0L && value != 1L) {
197                     throw new IllegalArgumentException("Setting ENABLE_PUSH is invalid: " + value);
198                 }
199                 break;
200             case SETTINGS_MAX_CONCURRENT_STREAMS:
201                 if (value < MIN_CONCURRENT_STREAMS || value > MAX_CONCURRENT_STREAMS) {
202                     throw new IllegalArgumentException(
203                             "Setting MAX_CONCURRENT_STREAMS is invalid: " + value);
204                 }
205                 break;
206             case SETTINGS_INITIAL_WINDOW_SIZE:
207                 if (value < MIN_INITIAL_WINDOW_SIZE || value > MAX_INITIAL_WINDOW_SIZE) {
208                     throw new IllegalArgumentException("Setting INITIAL_WINDOW_SIZE is invalid: "
209                             + value);
210                 }
211                 break;
212             case SETTINGS_MAX_FRAME_SIZE:
213                 if (!isMaxFrameSizeValid(value.intValue())) {
214                     throw new IllegalArgumentException("Setting MAX_FRAME_SIZE is invalid: " + value);
215                 }
216                 break;
217             case SETTINGS_MAX_HEADER_LIST_SIZE:
218                 if (value < MIN_HEADER_LIST_SIZE || value > MAX_HEADER_LIST_SIZE) {
219                     throw new IllegalArgumentException("Setting MAX_HEADER_LIST_SIZE is invalid: " + value);
220                 }
221                 break;
222             default:
223                 throw new IllegalArgumentException("key");
224         }
225     }
226 
227     @Override
228     protected String keyToString(int key) {
229         switch (key) {
230             case SETTINGS_HEADER_TABLE_SIZE:
231                 return "HEADER_TABLE_SIZE";
232             case SETTINGS_ENABLE_PUSH:
233                 return "ENABLE_PUSH";
234             case SETTINGS_MAX_CONCURRENT_STREAMS:
235                 return "MAX_CONCURRENT_STREAMS";
236             case SETTINGS_INITIAL_WINDOW_SIZE:
237                 return "INITIAL_WINDOW_SIZE";
238             case SETTINGS_MAX_FRAME_SIZE:
239                 return "MAX_FRAME_SIZE";
240             case SETTINGS_MAX_HEADER_LIST_SIZE:
241                 return "MAX_HEADER_LIST_SIZE";
242             default:
243                 // Unknown keys.
244                 return super.keyToString(key);
245         }
246     }
247 }