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
201 HttpVersion.valueOf(initialLine[2], true),
202 HttpMethod.valueOf(initialLine[0]), initialLine[1], headersFactory);
203 }
204
205 @Override
206 protected AsciiString splitHeaderName(final byte[] sb, final int start, final int length) {
207 final byte firstChar = sb[start];
208 if (firstChar == 'H') {
209 if (length == 4 && isHost(sb, start)) {
210 return Host;
211 }
212 } else if (firstChar == 'A') {
213 if (length == 6 && isAccept(sb, start)) {
214 return Accept;
215 }
216 } else if (firstChar == 'C') {
217 if (length == 10) {
218 if (isConnection(sb, start)) {
219 return Connection;
220 }
221 } else if (length == 12) {
222 if (isContentType(sb, start)) {
223 return ContentType;
224 }
225 } else if (length == 14) {
226 if (isContentLength(sb, start)) {
227 return ContentLength;
228 }
229 }
230 }
231 return super.splitHeaderName(sb, start, length);
232 }
233
234 private static boolean isAccept(byte[] sb, int start) {
235 final long maybeAccept = sb[start] |
236 sb[start + 1] << 8 |
237 sb[start + 2] << 16 |
238 sb[start + 3] << 24 |
239 (long) sb[start + 4] << 32 |
240 (long) sb[start + 5] << 40;
241 return maybeAccept == ACCEPT_AS_LONG;
242 }
243
244 private static boolean isHost(byte[] sb, int start) {
245 final int maybeHost = sb[start] |
246 sb[start + 1] << 8 |
247 sb[start + 2] << 16 |
248 sb[start + 3] << 24;
249 return maybeHost == HOST_AS_INT;
250 }
251
252 private static boolean isConnection(byte[] sb, int start) {
253 final long maybeConnecti = sb[start] |
254 sb[start + 1] << 8 |
255 sb[start + 2] << 16 |
256 sb[start + 3] << 24 |
257 (long) sb[start + 4] << 32 |
258 (long) sb[start + 5] << 40 |
259 (long) sb[start + 6] << 48 |
260 (long) sb[start + 7] << 56;
261 if (maybeConnecti != CONNECTION_AS_LONG_0) {
262 return false;
263 }
264 final short maybeOn = (short) (sb[start + 8] | sb[start + 9] << 8);
265 return maybeOn == CONNECTION_AS_SHORT_1;
266 }
267
268 private static boolean isContentType(byte[] sb, int start) {
269 final long maybeContent = sb[start] |
270 sb[start + 1] << 8 |
271 sb[start + 2] << 16 |
272 sb[start + 3] << 24 |
273 (long) sb[start + 4] << 32 |
274 (long) sb[start + 5] << 40 |
275 (long) sb[start + 6] << 48 |
276 (long) sb[start + 7] << 56;
277 if (maybeContent != CONTENT_AS_LONG) {
278 return false;
279 }
280 final int maybeType = sb[start + 8] |
281 sb[start + 9] << 8 |
282 sb[start + 10] << 16 |
283 sb[start + 11] << 24;
284 return maybeType == TYPE_AS_INT;
285 }
286
287 private static boolean isContentLength(byte[] sb, int start) {
288 final long maybeContent = sb[start] |
289 sb[start + 1] << 8 |
290 sb[start + 2] << 16 |
291 sb[start + 3] << 24 |
292 (long) sb[start + 4] << 32 |
293 (long) sb[start + 5] << 40 |
294 (long) sb[start + 6] << 48 |
295 (long) sb[start + 7] << 56;
296 if (maybeContent != CONTENT_AS_LONG) {
297 return false;
298 }
299 final long maybeLength = sb[start + 8] |
300 sb[start + 9] << 8 |
301 sb[start + 10] << 16 |
302 sb[start + 11] << 24 |
303 (long) sb[start + 12] << 32 |
304 (long) sb[start + 13] << 40;
305 return maybeLength == LENGTH_AS_LONG;
306 }
307
308 private static boolean isGetMethod(final byte[] sb, int start) {
309 final int maybeGet = sb[start] |
310 sb[start + 1] << 8 |
311 sb[start + 2] << 16;
312 return maybeGet == GET_AS_INT;
313 }
314
315 private static boolean isPostMethod(final byte[] sb, int start) {
316 final int maybePost = sb[start] |
317 sb[start + 1] << 8 |
318 sb[start + 2] << 16 |
319 sb[start + 3] << 24;
320 return maybePost == POST_AS_INT;
321 }
322
323 @Override
324 protected String splitFirstWordInitialLine(final byte[] sb, final int start, final int length) {
325 if (length == 3) {
326 if (isGetMethod(sb, start)) {
327 return HttpMethod.GET.name();
328 }
329 } else if (length == 4) {
330 if (isPostMethod(sb, start)) {
331 return HttpMethod.POST.name();
332 }
333 }
334 return super.splitFirstWordInitialLine(sb, start, length);
335 }
336
337 @Override
338 protected String splitThirdWordInitialLine(final byte[] sb, final int start, final int length) {
339 if (length == 8) {
340 final long maybeHttp1_x = sb[start] |
341 sb[start + 1] << 8 |
342 sb[start + 2] << 16 |
343 sb[start + 3] << 24 |
344 (long) sb[start + 4] << 32 |
345 (long) sb[start + 5] << 40 |
346 (long) sb[start + 6] << 48 |
347 (long) sb[start + 7] << 56;
348 if (maybeHttp1_x == HTTP_1_1_AS_LONG) {
349 return HttpVersion.HTTP_1_1_STRING;
350 } else if (maybeHttp1_x == HTTP_1_0_AS_LONG) {
351 return HttpVersion.HTTP_1_0_STRING;
352 }
353 }
354 return super.splitThirdWordInitialLine(sb, start, length);
355 }
356
357 @Override
358 protected HttpMessage createInvalidMessage() {
359 return new DefaultFullHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request",
360 Unpooled.buffer(0), headersFactory, trailersFactory);
361 }
362
363 @Override
364 protected boolean isDecodingRequest() {
365 return true;
366 }
367
368 @Override
369 protected boolean isContentAlwaysEmpty(final HttpMessage msg) {
370
371
372
373 if (msg.getClass() == DefaultHttpRequest.class) {
374 return false;
375 }
376 return super.isContentAlwaysEmpty(msg);
377 }
378 }