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 public HttpRequestDecoder() {
131 }
132
133
134
135
136 public HttpRequestDecoder(
137 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) {
138 this(new HttpDecoderConfig()
139 .setMaxInitialLineLength(maxInitialLineLength)
140 .setMaxHeaderSize(maxHeaderSize)
141 .setMaxChunkSize(maxChunkSize));
142 }
143
144
145
146
147
148 @Deprecated
149 public HttpRequestDecoder(
150 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders) {
151 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders);
152 }
153
154
155
156
157
158 @Deprecated
159 public HttpRequestDecoder(
160 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
161 int initialBufferSize) {
162 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
163 initialBufferSize);
164 }
165
166
167
168
169
170 @Deprecated
171 public HttpRequestDecoder(
172 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
173 int initialBufferSize, boolean allowDuplicateContentLengths) {
174 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
175 initialBufferSize, allowDuplicateContentLengths);
176 }
177
178
179
180
181
182 @Deprecated
183 public HttpRequestDecoder(
184 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
185 int initialBufferSize, boolean allowDuplicateContentLengths, boolean allowPartialChunks) {
186 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
187 initialBufferSize, allowDuplicateContentLengths, allowPartialChunks);
188 }
189
190
191
192
193 public HttpRequestDecoder(HttpDecoderConfig config) {
194 super(config);
195 }
196
197 @Override
198 protected HttpMessage createMessage(String[] initialLine) throws Exception {
199 return new DefaultHttpRequest(
200 HttpVersion.valueOf(initialLine[2]),
201 HttpMethod.valueOf(initialLine[0]), initialLine[1], headersFactory);
202 }
203
204 @Override
205 protected AsciiString splitHeaderName(final byte[] sb, final int start, final int length) {
206 final byte firstChar = sb[start];
207 if (firstChar == 'H') {
208 if (length == 4 && isHost(sb, start)) {
209 return Host;
210 }
211 } else if (firstChar == 'A') {
212 if (length == 6 && isAccept(sb, start)) {
213 return Accept;
214 }
215 } else if (firstChar == 'C') {
216 if (length == 10) {
217 if (isConnection(sb, start)) {
218 return Connection;
219 }
220 } else if (length == 12) {
221 if (isContentType(sb, start)) {
222 return ContentType;
223 }
224 } else if (length == 14) {
225 if (isContentLength(sb, start)) {
226 return ContentLength;
227 }
228 }
229 }
230 return super.splitHeaderName(sb, start, length);
231 }
232
233 private static boolean isAccept(byte[] sb, int start) {
234 final long maybeAccept = sb[start] |
235 sb[start + 1] << 8 |
236 sb[start + 2] << 16 |
237 sb[start + 3] << 24 |
238 (long) sb[start + 4] << 32 |
239 (long) sb[start + 5] << 40;
240 return maybeAccept == ACCEPT_AS_LONG;
241 }
242
243 private static boolean isHost(byte[] sb, int start) {
244 final int maybeHost = sb[start] |
245 sb[start + 1] << 8 |
246 sb[start + 2] << 16 |
247 sb[start + 3] << 24;
248 return maybeHost == HOST_AS_INT;
249 }
250
251 private static boolean isConnection(byte[] sb, int start) {
252 final long maybeConnecti = sb[start] |
253 sb[start + 1] << 8 |
254 sb[start + 2] << 16 |
255 sb[start + 3] << 24 |
256 (long) sb[start + 4] << 32 |
257 (long) sb[start + 5] << 40 |
258 (long) sb[start + 6] << 48 |
259 (long) sb[start + 7] << 56;
260 if (maybeConnecti != CONNECTION_AS_LONG_0) {
261 return false;
262 }
263 final short maybeOn = (short) (sb[start + 8] | sb[start + 9] << 8);
264 return maybeOn == CONNECTION_AS_SHORT_1;
265 }
266
267 private static boolean isContentType(byte[] sb, int start) {
268 final long maybeContent = sb[start] |
269 sb[start + 1] << 8 |
270 sb[start + 2] << 16 |
271 sb[start + 3] << 24 |
272 (long) sb[start + 4] << 32 |
273 (long) sb[start + 5] << 40 |
274 (long) sb[start + 6] << 48 |
275 (long) sb[start + 7] << 56;
276 if (maybeContent != CONTENT_AS_LONG) {
277 return false;
278 }
279 final int maybeType = sb[start + 8] |
280 sb[start + 9] << 8 |
281 sb[start + 10] << 16 |
282 sb[start + 11] << 24;
283 return maybeType == TYPE_AS_INT;
284 }
285
286 private static boolean isContentLength(byte[] sb, int start) {
287 final long maybeContent = sb[start] |
288 sb[start + 1] << 8 |
289 sb[start + 2] << 16 |
290 sb[start + 3] << 24 |
291 (long) sb[start + 4] << 32 |
292 (long) sb[start + 5] << 40 |
293 (long) sb[start + 6] << 48 |
294 (long) sb[start + 7] << 56;
295 if (maybeContent != CONTENT_AS_LONG) {
296 return false;
297 }
298 final long maybeLength = sb[start + 8] |
299 sb[start + 9] << 8 |
300 sb[start + 10] << 16 |
301 sb[start + 11] << 24 |
302 (long) sb[start + 12] << 32 |
303 (long) sb[start + 13] << 40;
304 return maybeLength == LENGTH_AS_LONG;
305 }
306
307 private static boolean isGetMethod(final byte[] sb, int start) {
308 final int maybeGet = sb[start] |
309 sb[start + 1] << 8 |
310 sb[start + 2] << 16;
311 return maybeGet == GET_AS_INT;
312 }
313
314 private static boolean isPostMethod(final byte[] sb, int start) {
315 final int maybePost = sb[start] |
316 sb[start + 1] << 8 |
317 sb[start + 2] << 16 |
318 sb[start + 3] << 24;
319 return maybePost == POST_AS_INT;
320 }
321
322 @Override
323 protected String splitFirstWordInitialLine(final byte[] sb, final int start, final int length) {
324 if (length == 3) {
325 if (isGetMethod(sb, start)) {
326 return HttpMethod.GET.name();
327 }
328 } else if (length == 4) {
329 if (isPostMethod(sb, start)) {
330 return HttpMethod.POST.name();
331 }
332 }
333 return super.splitFirstWordInitialLine(sb, start, length);
334 }
335
336 @Override
337 protected String splitThirdWordInitialLine(final byte[] sb, final int start, final int length) {
338 if (length == 8) {
339 final long maybeHttp1_x = sb[start] |
340 sb[start + 1] << 8 |
341 sb[start + 2] << 16 |
342 sb[start + 3] << 24 |
343 (long) sb[start + 4] << 32 |
344 (long) sb[start + 5] << 40 |
345 (long) sb[start + 6] << 48 |
346 (long) sb[start + 7] << 56;
347 if (maybeHttp1_x == HTTP_1_1_AS_LONG) {
348 return HttpVersion.HTTP_1_1_STRING;
349 } else if (maybeHttp1_x == HTTP_1_0_AS_LONG) {
350 return HttpVersion.HTTP_1_0_STRING;
351 }
352 }
353 return super.splitThirdWordInitialLine(sb, start, length);
354 }
355
356 @Override
357 protected HttpMessage createInvalidMessage() {
358 return new DefaultFullHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request",
359 Unpooled.buffer(0), headersFactory, trailersFactory);
360 }
361
362 @Override
363 protected boolean isDecodingRequest() {
364 return true;
365 }
366
367 @Override
368 protected boolean isContentAlwaysEmpty(final HttpMessage msg) {
369
370
371
372 if (msg.getClass() == DefaultHttpRequest.class) {
373 return false;
374 }
375 return super.isContentAlwaysEmpty(msg);
376 }
377 }