1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  package io.netty.handler.codec.http2;
33  
34  import io.netty.handler.codec.http.HttpHeaderNames;
35  import io.netty.handler.codec.http.HttpMethod;
36  import io.netty.handler.codec.http.HttpResponseStatus;
37  import io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName;
38  import io.netty.util.AsciiString;
39  import io.netty.util.internal.PlatformDependent;
40  
41  import java.util.Arrays;
42  import java.util.List;
43  
44  import static io.netty.handler.codec.http2.HpackUtil.equalsVariableTime;
45  
46  final class HpackStaticTable {
47  
48      static final int NOT_FOUND = -1;
49  
50      
51      
52      private static final List<HpackHeaderField> STATIC_TABLE = Arrays.asList(
53       newEmptyPseudoHeaderField(PseudoHeaderName.AUTHORITY),
54       newPseudoHeaderMethodField(HttpMethod.GET),
55       newPseudoHeaderMethodField(HttpMethod.POST),
56       newPseudoHeaderField(PseudoHeaderName.PATH, "/"),
57       newPseudoHeaderField(PseudoHeaderName.PATH, "/index.html"),
58       newPseudoHeaderField(PseudoHeaderName.SCHEME, "http"),
59       newPseudoHeaderField(PseudoHeaderName.SCHEME, "https"),
60       newPseudoHeaderField(PseudoHeaderName.STATUS, HttpResponseStatus.OK.codeAsText()),
61       newPseudoHeaderField(PseudoHeaderName.STATUS, HttpResponseStatus.NO_CONTENT.codeAsText()),
62       newPseudoHeaderField(PseudoHeaderName.STATUS, HttpResponseStatus.PARTIAL_CONTENT.codeAsText()),
63       newPseudoHeaderField(PseudoHeaderName.STATUS, HttpResponseStatus.NOT_MODIFIED.codeAsText()),
64       newPseudoHeaderField(PseudoHeaderName.STATUS, HttpResponseStatus.BAD_REQUEST.codeAsText()),
65       newPseudoHeaderField(PseudoHeaderName.STATUS, HttpResponseStatus.NOT_FOUND.codeAsText()),
66       newPseudoHeaderField(PseudoHeaderName.STATUS, HttpResponseStatus.INTERNAL_SERVER_ERROR.codeAsText()),
67       newEmptyHeaderField(HttpHeaderNames.ACCEPT_CHARSET),
68       newHeaderField(HttpHeaderNames.ACCEPT_ENCODING, "gzip, deflate"),
69       newEmptyHeaderField(HttpHeaderNames.ACCEPT_LANGUAGE),
70       newEmptyHeaderField(HttpHeaderNames.ACCEPT_RANGES),
71       newEmptyHeaderField(HttpHeaderNames.ACCEPT),
72       newEmptyHeaderField(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN),
73       newEmptyHeaderField(HttpHeaderNames.AGE),
74       newEmptyHeaderField(HttpHeaderNames.ALLOW),
75       newEmptyHeaderField(HttpHeaderNames.AUTHORIZATION),
76       newEmptyHeaderField(HttpHeaderNames.CACHE_CONTROL),
77       newEmptyHeaderField(HttpHeaderNames.CONTENT_DISPOSITION),
78       newEmptyHeaderField(HttpHeaderNames.CONTENT_ENCODING),
79       newEmptyHeaderField(HttpHeaderNames.CONTENT_LANGUAGE),
80       newEmptyHeaderField(HttpHeaderNames.CONTENT_LENGTH),
81       newEmptyHeaderField(HttpHeaderNames.CONTENT_LOCATION),
82       newEmptyHeaderField(HttpHeaderNames.CONTENT_RANGE),
83       newEmptyHeaderField(HttpHeaderNames.CONTENT_TYPE),
84       newEmptyHeaderField(HttpHeaderNames.COOKIE),
85       newEmptyHeaderField(HttpHeaderNames.DATE),
86       newEmptyHeaderField(HttpHeaderNames.ETAG),
87       newEmptyHeaderField(HttpHeaderNames.EXPECT),
88       newEmptyHeaderField(HttpHeaderNames.EXPIRES),
89       newEmptyHeaderField(HttpHeaderNames.FROM),
90       newEmptyHeaderField(HttpHeaderNames.HOST),
91       newEmptyHeaderField(HttpHeaderNames.IF_MATCH),
92       newEmptyHeaderField(HttpHeaderNames.IF_MODIFIED_SINCE),
93       newEmptyHeaderField(HttpHeaderNames.IF_NONE_MATCH),
94       newEmptyHeaderField(HttpHeaderNames.IF_RANGE),
95       newEmptyHeaderField(HttpHeaderNames.IF_UNMODIFIED_SINCE),
96       newEmptyHeaderField(HttpHeaderNames.LAST_MODIFIED),
97       newEmptyHeaderField("link"),
98       newEmptyHeaderField(HttpHeaderNames.LOCATION),
99       newEmptyHeaderField(HttpHeaderNames.MAX_FORWARDS),
100      newEmptyHeaderField(HttpHeaderNames.PROXY_AUTHENTICATE),
101      newEmptyHeaderField(HttpHeaderNames.PROXY_AUTHORIZATION),
102      newEmptyHeaderField(HttpHeaderNames.RANGE),
103      newEmptyHeaderField(HttpHeaderNames.REFERER),
104      newEmptyHeaderField("refresh"),
105      newEmptyHeaderField(HttpHeaderNames.RETRY_AFTER),
106      newEmptyHeaderField(HttpHeaderNames.SERVER),
107      newEmptyHeaderField(HttpHeaderNames.SET_COOKIE),
108      newEmptyHeaderField("strict-transport-security"),
109      newEmptyHeaderField(HttpHeaderNames.TRANSFER_ENCODING),
110      newEmptyHeaderField(HttpHeaderNames.USER_AGENT),
111      newEmptyHeaderField(HttpHeaderNames.VARY),
112      newEmptyHeaderField(HttpHeaderNames.VIA),
113      newEmptyHeaderField(HttpHeaderNames.WWW_AUTHENTICATE)
114     );
115 
116     private static HpackHeaderField newEmptyHeaderField(AsciiString name) {
117         return new HpackHeaderField(name, AsciiString.EMPTY_STRING);
118     }
119 
120     private static HpackHeaderField newEmptyHeaderField(String name) {
121         return new HpackHeaderField(AsciiString.cached(name), AsciiString.EMPTY_STRING);
122     }
123 
124     private static HpackHeaderField newHeaderField(AsciiString name, String value) {
125         return new HpackHeaderField(name, AsciiString.cached(value));
126     }
127 
128     private static HpackHeaderField newPseudoHeaderMethodField(HttpMethod method) {
129         return new HpackHeaderField(PseudoHeaderName.METHOD.value(), method.asciiName());
130     }
131 
132     private static HpackHeaderField newPseudoHeaderField(PseudoHeaderName name, AsciiString value) {
133         return new HpackHeaderField(name.value(), value);
134     }
135 
136     private static HpackHeaderField newPseudoHeaderField(PseudoHeaderName name, String value) {
137         return new HpackHeaderField(name.value(), AsciiString.cached(value));
138     }
139 
140     private static HpackHeaderField newEmptyPseudoHeaderField(PseudoHeaderName name) {
141         return new HpackHeaderField(name.value(), AsciiString.EMPTY_STRING);
142     }
143 
144     
145     private static final int HEADER_NAMES_TABLE_SIZE = 1 << 9;
146 
147     private static final int HEADER_NAMES_TABLE_SHIFT = PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? 22 : 18;
148 
149     
150     private static final HeaderNameIndex[] HEADER_NAMES = new HeaderNameIndex[HEADER_NAMES_TABLE_SIZE];
151     static {
152         
153         
154         for (int index = STATIC_TABLE.size(); index > 0; index--) {
155             HpackHeaderField entry = getEntry(index);
156             int bucket = headerNameBucket(entry.name);
157             HeaderNameIndex tableEntry = HEADER_NAMES[bucket];
158             if (tableEntry != null && !equalsVariableTime(tableEntry.name, entry.name)) {
159                 
160                 throw new IllegalStateException("Hash bucket collision between " +
161                   tableEntry.name + " and " + entry.name);
162             }
163             HEADER_NAMES[bucket] = new HeaderNameIndex(entry.name, index, entry.value.length() == 0);
164         }
165     }
166 
167     
168     private static final int HEADERS_WITH_NON_EMPTY_VALUES_TABLE_SIZE = 1 << 6;
169 
170     private static final int HEADERS_WITH_NON_EMPTY_VALUES_TABLE_SHIFT =
171       PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? 0 : 6;
172 
173     
174     private static final HeaderIndex[] HEADERS_WITH_NON_EMPTY_VALUES =
175       new HeaderIndex[HEADERS_WITH_NON_EMPTY_VALUES_TABLE_SIZE];
176     static {
177         for (int index = STATIC_TABLE.size(); index > 0; index--) {
178             HpackHeaderField entry = getEntry(index);
179             if (entry.value.length() > 0) {
180                 int bucket = headerBucket(entry.value);
181                 HeaderIndex tableEntry = HEADERS_WITH_NON_EMPTY_VALUES[bucket];
182                 if (tableEntry != null) {
183                     
184                     throw new IllegalStateException("Hash bucket collision between " +
185                       tableEntry.value + " and " + entry.value);
186                 }
187                 HEADERS_WITH_NON_EMPTY_VALUES[bucket] = new HeaderIndex(entry.name, entry.value, index);
188             }
189         }
190     }
191 
192     
193 
194 
195     static final int length = STATIC_TABLE.size();
196 
197     
198 
199 
200     static HpackHeaderField getEntry(int index) {
201         return STATIC_TABLE.get(index - 1);
202     }
203 
204     
205 
206 
207 
208     static int getIndex(CharSequence name) {
209         HeaderNameIndex entry = getEntry(name);
210         return entry == null ? NOT_FOUND : entry.index;
211     }
212 
213     
214 
215 
216 
217     static int getIndexInsensitive(CharSequence name, CharSequence value) {
218         if (value.length() == 0) {
219             HeaderNameIndex entry = getEntry(name);
220             return entry == null || !entry.emptyValue ? NOT_FOUND : entry.index;
221         }
222         int bucket = headerBucket(value);
223         HeaderIndex header = HEADERS_WITH_NON_EMPTY_VALUES[bucket];
224         if (header == null) {
225             return NOT_FOUND;
226         }
227         if (equalsVariableTime(header.name, name) && equalsVariableTime(header.value, value)) {
228             return header.index;
229         }
230         return NOT_FOUND;
231     }
232 
233     private static HeaderNameIndex getEntry(CharSequence name) {
234         int bucket = headerNameBucket(name);
235         HeaderNameIndex entry = HEADER_NAMES[bucket];
236         if (entry == null) {
237             return null;
238         }
239         return equalsVariableTime(entry.name, name) ? entry : null;
240     }
241 
242     private static int headerNameBucket(CharSequence name) {
243         return bucket(name, HEADER_NAMES_TABLE_SHIFT, HEADER_NAMES_TABLE_SIZE - 1);
244     }
245 
246     private static int headerBucket(CharSequence value) {
247         return bucket(value, HEADERS_WITH_NON_EMPTY_VALUES_TABLE_SHIFT, HEADERS_WITH_NON_EMPTY_VALUES_TABLE_SIZE - 1);
248     }
249 
250     private static int bucket(CharSequence s, int shift, int mask) {
251         return (AsciiString.hashCode(s) >> shift) & mask;
252     }
253 
254     private static final class HeaderNameIndex {
255         final CharSequence name;
256         final int index;
257         final boolean emptyValue;
258 
259         HeaderNameIndex(CharSequence name, int index, boolean emptyValue) {
260             this.name = name;
261             this.index = index;
262             this.emptyValue = emptyValue;
263         }
264     }
265 
266     private static final class HeaderIndex {
267         final CharSequence name;
268         final CharSequence value;
269         final int index;
270 
271         HeaderIndex(CharSequence name, CharSequence value, int index) {
272             this.name = name;
273             this.value = value;
274             this.index = index;
275         }
276     }
277 
278     
279     private HpackStaticTable() {
280     }
281 }