1 /*
2 * Copyright 2012 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty.handler.codec.http;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelPipeline;
20
21 /**
22 * Decodes {@link ByteBuf}s into {@link HttpRequest}s and {@link HttpContent}s.
23 *
24 * <h3>Parameters that prevents excessive memory consumption</h3>
25 * <table border="1">
26 * <tr>
27 * <th>Name</th><th>Meaning</th>
28 * </tr>
29 * <tr>
30 * <td>{@code maxInitialLineLength}</td>
31 * <td>The maximum length of the initial line (e.g. {@code "GET / HTTP/1.0"})
32 * If the length of the initial line exceeds this value, a
33 * {@link TooLongHttpLineException} will be raised.</td>
34 * </tr>
35 * <tr>
36 * <td>{@code maxHeaderSize}</td>
37 * <td>The maximum length of all headers. If the sum of the length of each
38 * header exceeds this value, a {@link TooLongHttpHeaderException} will be raised.</td>
39 * </tr>
40 * <tr>
41 * <td>{@code maxChunkSize}</td>
42 * <td>The maximum length of the content or each chunk. If the content length
43 * exceeds this value, the transfer encoding of the decoded request will be
44 * converted to 'chunked' and the content will be split into multiple
45 * {@link HttpContent}s. If the transfer encoding of the HTTP request is
46 * 'chunked' already, each chunk will be split into smaller chunks if the
47 * length of the chunk exceeds this value. If you prefer not to handle
48 * {@link HttpContent}s in your handler, insert {@link HttpObjectAggregator}
49 * after this decoder in the {@link ChannelPipeline}.</td>
50 * </tr>
51 * </table>
52 *
53 * <h3>Parameters that control parsing behavior</h3>
54 * <table border="1">
55 * <tr>
56 * <th>Name</th><th>Default value</th><th>Meaning</th>
57 * </tr>
58 * <tr>
59 * <td>{@code allowDuplicateContentLengths}</td>
60 * <td>{@value #DEFAULT_ALLOW_DUPLICATE_CONTENT_LENGTHS}</td>
61 * <td>When set to {@code false}, will reject any messages that contain multiple Content-Length header fields.
62 * When set to {@code true}, will allow multiple Content-Length headers only if they are all the same decimal value.
63 * The duplicated field-values will be replaced with a single valid Content-Length field.
64 * See <a href="https://tools.ietf.org/html/rfc7230#section-3.3.2">RFC 7230, Section 3.3.2</a>.</td>
65 * </tr>
66 * <tr>
67 * <td>{@code allowPartialChunks}</td>
68 * <td>{@value #DEFAULT_ALLOW_PARTIAL_CHUNKS}</td>
69 * <td>If the length of a chunk exceeds the {@link ByteBuf}s readable bytes and {@code allowPartialChunks}
70 * is set to {@code true}, the chunk will be split into multiple {@link HttpContent}s.
71 * Otherwise, if the chunk size does not exceed {@code maxChunkSize} and {@code allowPartialChunks}
72 * is set to {@code false}, the {@link ByteBuf} is not decoded into an {@link HttpContent} until
73 * the readable bytes are greater or equal to the chunk size.</td>
74 * </tr>
75 * </table>
76 */
77 public class HttpRequestDecoder extends HttpObjectDecoder {
78
79 /**
80 * Creates a new instance with the default
81 * {@code maxInitialLineLength (4096)}, {@code maxHeaderSize (8192)}, and
82 * {@code maxChunkSize (8192)}.
83 */
84 public HttpRequestDecoder() {
85 }
86
87 /**
88 * Creates a new instance with the specified parameters.
89 */
90 public HttpRequestDecoder(
91 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) {
92 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED);
93 }
94
95 public HttpRequestDecoder(
96 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders) {
97 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders);
98 }
99
100 public HttpRequestDecoder(
101 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
102 int initialBufferSize) {
103 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
104 initialBufferSize);
105 }
106
107 public HttpRequestDecoder(
108 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
109 int initialBufferSize, boolean allowDuplicateContentLengths) {
110 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
111 initialBufferSize, allowDuplicateContentLengths);
112 }
113
114 public HttpRequestDecoder(
115 int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
116 int initialBufferSize, boolean allowDuplicateContentLengths, boolean allowPartialChunks) {
117 super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
118 initialBufferSize, allowDuplicateContentLengths, allowPartialChunks);
119 }
120
121 @Override
122 protected HttpMessage createMessage(String[] initialLine) throws Exception {
123 return new DefaultHttpRequest(
124 HttpVersion.valueOf(initialLine[2]),
125 HttpMethod.valueOf(initialLine[0]), initialLine[1], validateHeaders);
126 }
127
128 @Override
129 protected HttpMessage createInvalidMessage() {
130 return new DefaultFullHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request", validateHeaders);
131 }
132
133 @Override
134 protected boolean isDecodingRequest() {
135 return true;
136 }
137 }