1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.Unpooled;
20 import io.netty.channel.ChannelPipeline;
21 import io.netty.util.AsciiString;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public class HttpRequestDecoder extends HttpObjectDecoder {
92
93 private static final AsciiString Accept = AsciiString.cached("Accept");
94 private static final AsciiString Host = AsciiString.cached("Host");
95 private static final AsciiString Connection = AsciiString.cached("Connection");
96 private static final AsciiString ContentType = AsciiString.cached("Content-Type");
97 private static final AsciiString ContentLength = AsciiString.cached("Content-Length");
98
99 private static final int GET_AS_INT = 'G' | 'E' << 8 | 'T' << 16;
100 private static final int POST_AS_INT = 'P' | 'O' << 8 | 'S' << 16 | 'T' << 24;
101 private static final long HTTP_1_1_AS_LONG = 'H' | 'T' << 8 | 'T' << 16 | 'P' << 24 | (long) '/' << 32 |
102 (long) '1' << 40 | (long) '.' << 48 | (long) '1' << 56;
103
104 private static final long HTTP_1_0_AS_LONG = 'H' | 'T' << 8 | 'T' << 16 | 'P' << 24 | (long) '/' << 32 |
105 (long) '1' << 40 | (long) '.' << 48 | (long) '0' << 56;
106
107 private static final int HOST_AS_INT = 'H' | 'o' << 8 | 's' << 16 | 't' << 24;
108
109 private static final long CONNECTION_AS_LONG_0 = 'C' | 'o' << 8 | 'n' << 16 | 'n' << 24 |
110 (long) 'e' << 32 | (long) 'c' << 40 | (long) 't' << 48 | (long) 'i' << 56;
111
112 private static final short CONNECTION_AS_SHORT_1 = 'o' | 'n' << 8;
113
114 private static final long CONTENT_AS_LONG = 'C' | 'o' << 8 | 'n' << 16 | 't' << 24 |
115 (long) 'e' << 32 | (long) 'n' << 40 | (long) 't' << 48 | (long) '-' << 56;
116
117 private static final int TYPE_AS_INT = 'T' | 'y' << 8 | 'p' << 16 | 'e' << 24;
118
119 private static final long LENGTH_AS_LONG = 'L' | 'e' << 8 | 'n' << 16 | 'g' << 24 |
120 (long) 't' << 32 | (long) 'h' << 40;
121
122 private static final long ACCEPT_AS_LONG = 'A' | 'c' << 8 | 'c' << 16 | 'e' << 24 |
123 (long) 'p' << 32 | (long) 't' << 40;
124
125
126
127
128
129
130
131
132 public HttpRequestDecoder() {
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146 public HttpRequestDecoder(
147 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) {
148 this(new HttpDecoderConfig()
149 .setMaxInitialLineLength(maxInitialLineLength)
150 .setMaxHeaderSize(maxHeaderSize)
151 .setMaxChunkSize(maxChunkSize));
152 }
153
154
155
156
157
158
159
160 @Deprecated
161 public HttpRequestDecoder(
162 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders) {
163 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders);
164 }
165
166
167
168
169
170
171
172 @Deprecated
173 public HttpRequestDecoder(
174 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
175 int initialBufferSize) {
176 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
177 initialBufferSize);
178 }
179
180
181
182
183
184
185
186 @Deprecated
187 public HttpRequestDecoder(
188 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
189 int initialBufferSize, boolean allowDuplicateContentLengths) {
190 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
191 initialBufferSize, allowDuplicateContentLengths);
192 }
193
194
195
196
197
198
199
200 @Deprecated
201 public HttpRequestDecoder(
202 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
203 int initialBufferSize, boolean allowDuplicateContentLengths, boolean allowPartialChunks) {
204 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
205 initialBufferSize, allowDuplicateContentLengths, allowPartialChunks);
206 }
207
208
209
210
211
212
213 public HttpRequestDecoder(HttpDecoderConfig config) {
214 super(config);
215 }
216
217 @Override
218 protected HttpMessage createMessage(String[] initialLine) throws Exception {
219 return new DefaultHttpRequest(
220
221 HttpVersion.valueOf(initialLine[2], true),
222 HttpMethod.valueOf(initialLine[0]), initialLine[1], headersFactory);
223 }
224
225 @Override
226 protected AsciiString splitHeaderName(final byte[] sb, final int start, final int length) {
227 final byte firstChar = sb[start];
228 if (firstChar == 'H') {
229 if (length == 4 && isHost(sb, start)) {
230 return Host;
231 }
232 } else if (firstChar == 'A') {
233 if (length == 6 && isAccept(sb, start)) {
234 return Accept;
235 }
236 } else if (firstChar == 'C') {
237 if (length == 10) {
238 if (isConnection(sb, start)) {
239 return Connection;
240 }
241 } else if (length == 12) {
242 if (isContentType(sb, start)) {
243 return ContentType;
244 }
245 } else if (length == 14) {
246 if (isContentLength(sb, start)) {
247 return ContentLength;
248 }
249 }
250 }
251 return super.splitHeaderName(sb, start, length);
252 }
253
254 private static boolean isAccept(byte[] sb, int start) {
255 final long maybeAccept = sb[start] |
256 sb[start + 1] << 8 |
257 sb[start + 2] << 16 |
258 sb[start + 3] << 24 |
259 (long) sb[start + 4] << 32 |
260 (long) sb[start + 5] << 40;
261 return maybeAccept == ACCEPT_AS_LONG;
262 }
263
264 private static boolean isHost(byte[] sb, int start) {
265 final int maybeHost = sb[start] |
266 sb[start + 1] << 8 |
267 sb[start + 2] << 16 |
268 sb[start + 3] << 24;
269 return maybeHost == HOST_AS_INT;
270 }
271
272 private static boolean isConnection(byte[] sb, int start) {
273 final long maybeConnecti = sb[start] |
274 sb[start + 1] << 8 |
275 sb[start + 2] << 16 |
276 sb[start + 3] << 24 |
277 (long) sb[start + 4] << 32 |
278 (long) sb[start + 5] << 40 |
279 (long) sb[start + 6] << 48 |
280 (long) sb[start + 7] << 56;
281 if (maybeConnecti != CONNECTION_AS_LONG_0) {
282 return false;
283 }
284 final short maybeOn = (short) (sb[start + 8] | sb[start + 9] << 8);
285 return maybeOn == CONNECTION_AS_SHORT_1;
286 }
287
288 private static boolean isContentType(byte[] sb, int start) {
289 final long maybeContent = sb[start] |
290 sb[start + 1] << 8 |
291 sb[start + 2] << 16 |
292 sb[start + 3] << 24 |
293 (long) sb[start + 4] << 32 |
294 (long) sb[start + 5] << 40 |
295 (long) sb[start + 6] << 48 |
296 (long) sb[start + 7] << 56;
297 if (maybeContent != CONTENT_AS_LONG) {
298 return false;
299 }
300 final int maybeType = sb[start + 8] |
301 sb[start + 9] << 8 |
302 sb[start + 10] << 16 |
303 sb[start + 11] << 24;
304 return maybeType == TYPE_AS_INT;
305 }
306
307 private static boolean isContentLength(byte[] sb, int start) {
308 final long maybeContent = sb[start] |
309 sb[start + 1] << 8 |
310 sb[start + 2] << 16 |
311 sb[start + 3] << 24 |
312 (long) sb[start + 4] << 32 |
313 (long) sb[start + 5] << 40 |
314 (long) sb[start + 6] << 48 |
315 (long) sb[start + 7] << 56;
316 if (maybeContent != CONTENT_AS_LONG) {
317 return false;
318 }
319 final long maybeLength = sb[start + 8] |
320 sb[start + 9] << 8 |
321 sb[start + 10] << 16 |
322 sb[start + 11] << 24 |
323 (long) sb[start + 12] << 32 |
324 (long) sb[start + 13] << 40;
325 return maybeLength == LENGTH_AS_LONG;
326 }
327
328 private static boolean isGetMethod(final byte[] sb, int start) {
329 final int maybeGet = sb[start] |
330 sb[start + 1] << 8 |
331 sb[start + 2] << 16;
332 return maybeGet == GET_AS_INT;
333 }
334
335 private static boolean isPostMethod(final byte[] sb, int start) {
336 final int maybePost = sb[start] |
337 sb[start + 1] << 8 |
338 sb[start + 2] << 16 |
339 sb[start + 3] << 24;
340 return maybePost == POST_AS_INT;
341 }
342
343 @Override
344 protected String splitFirstWordInitialLine(final byte[] sb, final int start, final int length) {
345 if (length == 3) {
346 if (isGetMethod(sb, start)) {
347 return HttpMethod.GET.name();
348 }
349 } else if (length == 4) {
350 if (isPostMethod(sb, start)) {
351 return HttpMethod.POST.name();
352 }
353 }
354 return super.splitFirstWordInitialLine(sb, start, length);
355 }
356
357 @Override
358 protected String splitThirdWordInitialLine(final byte[] sb, final int start, final int length) {
359 if (length == 8) {
360 final long maybeHttp1_x = sb[start] |
361 sb[start + 1] << 8 |
362 sb[start + 2] << 16 |
363 sb[start + 3] << 24 |
364 (long) sb[start + 4] << 32 |
365 (long) sb[start + 5] << 40 |
366 (long) sb[start + 6] << 48 |
367 (long) sb[start + 7] << 56;
368 if (maybeHttp1_x == HTTP_1_1_AS_LONG) {
369 return HttpVersion.HTTP_1_1_STRING;
370 } else if (maybeHttp1_x == HTTP_1_0_AS_LONG) {
371 return HttpVersion.HTTP_1_0_STRING;
372 }
373 }
374 return super.splitThirdWordInitialLine(sb, start, length);
375 }
376
377 @Override
378 protected HttpMessage createInvalidMessage() {
379 return new DefaultFullHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request",
380 Unpooled.buffer(0), headersFactory, trailersFactory);
381 }
382
383 @Override
384 protected boolean isDecodingRequest() {
385 return true;
386 }
387
388 @Override
389 protected boolean isContentAlwaysEmpty(final HttpMessage msg) {
390
391
392
393 if (msg.getClass() == DefaultHttpRequest.class) {
394 return false;
395 }
396 return super.isContentAlwaysEmpty(msg);
397 }
398 }