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.netty5.handler.codec.http2;
33
34 import io.netty5.handler.codec.UnsupportedValueConverter;
35 import io.netty5.util.AsciiString;
36
37 import java.util.Arrays;
38 import java.util.List;
39
40 import static io.netty5.handler.codec.http2.HpackUtil.equalsVariableTime;
41
42 final class HpackStaticTable {
43
44 static final int NOT_FOUND = -1;
45
46
47
48 private static final List<HpackHeaderField> STATIC_TABLE = Arrays.asList(
49 newEmptyHeaderField(":authority"),
50 newHeaderField(":method", "GET"),
51 newHeaderField(":method", "POST"),
52 newHeaderField(":path", "/"),
53 newHeaderField(":path", "/index.html"),
54 newHeaderField(":scheme", "http"),
55 newHeaderField(":scheme", "https"),
56 newHeaderField(":status", "200"),
57 newHeaderField(":status", "204"),
58 newHeaderField(":status", "206"),
59 newHeaderField(":status", "304"),
60 newHeaderField(":status", "400"),
61 newHeaderField(":status", "404"),
62 newHeaderField(":status", "500"),
63 newEmptyHeaderField("accept-charset"),
64 newHeaderField("accept-encoding", "gzip, deflate"),
65 newEmptyHeaderField("accept-language"),
66 newEmptyHeaderField("accept-ranges"),
67 newEmptyHeaderField("accept"),
68 newEmptyHeaderField("access-control-allow-origin"),
69 newEmptyHeaderField("age"),
70 newEmptyHeaderField("allow"),
71 newEmptyHeaderField("authorization"),
72 newEmptyHeaderField("cache-control"),
73 newEmptyHeaderField("content-disposition"),
74 newEmptyHeaderField("content-encoding"),
75 newEmptyHeaderField("content-language"),
76 newEmptyHeaderField("content-length"),
77 newEmptyHeaderField("content-location"),
78 newEmptyHeaderField("content-range"),
79 newEmptyHeaderField("content-type"),
80 newEmptyHeaderField("cookie"),
81 newEmptyHeaderField("date"),
82 newEmptyHeaderField("etag"),
83 newEmptyHeaderField("expect"),
84 newEmptyHeaderField("expires"),
85 newEmptyHeaderField("from"),
86 newEmptyHeaderField("host"),
87 newEmptyHeaderField("if-match"),
88 newEmptyHeaderField("if-modified-since"),
89 newEmptyHeaderField("if-none-match"),
90 newEmptyHeaderField("if-range"),
91 newEmptyHeaderField("if-unmodified-since"),
92 newEmptyHeaderField("last-modified"),
93 newEmptyHeaderField("link"),
94 newEmptyHeaderField("location"),
95 newEmptyHeaderField("max-forwards"),
96 newEmptyHeaderField("proxy-authenticate"),
97 newEmptyHeaderField("proxy-authorization"),
98 newEmptyHeaderField("range"),
99 newEmptyHeaderField("referer"),
100 newEmptyHeaderField("refresh"),
101 newEmptyHeaderField("retry-after"),
102 newEmptyHeaderField("server"),
103 newEmptyHeaderField("set-cookie"),
104 newEmptyHeaderField("strict-transport-security"),
105 newEmptyHeaderField("transfer-encoding"),
106 newEmptyHeaderField("user-agent"),
107 newEmptyHeaderField("vary"),
108 newEmptyHeaderField("via"),
109 newEmptyHeaderField("www-authenticate")
110 );
111
112 private static HpackHeaderField newEmptyHeaderField(String name) {
113 return new HpackHeaderField(AsciiString.cached(name), AsciiString.EMPTY_STRING);
114 }
115
116 private static HpackHeaderField newHeaderField(String name, String value) {
117 return new HpackHeaderField(AsciiString.cached(name), AsciiString.cached(value));
118 }
119
120 private static final CharSequenceMap<Integer> STATIC_INDEX_BY_NAME = createMap();
121
122 private static final int MAX_SAME_NAME_FIELD_INDEX = maxSameNameFieldIndex();
123
124
125
126
127 static final int length = STATIC_TABLE.size();
128
129
130
131
132 static HpackHeaderField getEntry(int index) {
133 return STATIC_TABLE.get(index - 1);
134 }
135
136
137
138
139
140 static int getIndex(CharSequence name) {
141 Integer index = STATIC_INDEX_BY_NAME.get(name);
142 if (index == null) {
143 return NOT_FOUND;
144 }
145 return index;
146 }
147
148
149
150
151
152 static int getIndexInsensitive(CharSequence name, CharSequence value) {
153 int index = getIndex(name);
154 if (index == NOT_FOUND) {
155 return NOT_FOUND;
156 }
157
158
159 HpackHeaderField entry = getEntry(index);
160 if (equalsVariableTime(value, entry.value)) {
161 return index;
162 }
163
164
165 index++;
166 while (index <= MAX_SAME_NAME_FIELD_INDEX) {
167 entry = getEntry(index);
168 if (!equalsVariableTime(name, entry.name)) {
169
170
171
172 return NOT_FOUND;
173 }
174 if (equalsVariableTime(value, entry.value)) {
175 return index;
176 }
177 index++;
178 }
179
180 return NOT_FOUND;
181 }
182
183
184 private static CharSequenceMap<Integer> createMap() {
185 int length = STATIC_TABLE.size();
186 CharSequenceMap<Integer> ret = new CharSequenceMap<>(true,
187 UnsupportedValueConverter.instance(), length);
188
189
190 for (int index = length; index > 0; index--) {
191 HpackHeaderField entry = getEntry(index);
192 CharSequence name = entry.name;
193 ret.set(name, index);
194 }
195 return ret;
196 }
197
198
199
200
201
202
203
204 private static int maxSameNameFieldIndex() {
205 final int length = STATIC_TABLE.size();
206 HpackHeaderField cursor = getEntry(length);
207 for (int index = length - 1; index > 0; index--) {
208 HpackHeaderField entry = getEntry(index);
209 if (equalsVariableTime(entry.name, cursor.name)) {
210 return index + 1;
211 } else {
212 cursor = entry;
213 }
214 }
215 return length;
216 }
217
218
219 private HpackStaticTable() {
220 }
221 }