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  *   http://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 import io.netty.handler.codec.TooLongFrameException;
21
22
23 /**
24  * Decodes {@link ByteBuf}s into {@link HttpResponse}s and
25  * {@link HttpContent}s.
26  *
27  * <h3>Parameters that prevents excessive memory consumption</h3>
28  * <table border="1">
29  * <tr>
30  * <th>Name</th><th>Meaning</th>
31  * </tr>
32  * <tr>
33  * <td>{@code maxInitialLineLength}</td>
34  * <td>The maximum length of the initial line (e.g. {@code "HTTP/1.0 200 OK"})
35  *     If the length of the initial line exceeds this value, a
36  *     {@link TooLongFrameException} will be raised.</td>
37  * </tr>
38  * <tr>
39  * <td>{@code maxHeaderSize}</td>
40  * <td>The maximum length of all headers.  If the sum of the length of each
41  *     header exceeds this value, a {@link TooLongFrameException} will be raised.</td>
42  * </tr>
43  * <tr>
44  * <td>{@code maxChunkSize}</td>
45  * <td>The maximum length of the content or each chunk.  If the content length
46  *     exceeds this value, the transfer encoding of the decoded response will be
47  *     converted to 'chunked' and the content will be split into multiple
48  *     {@link HttpContent}s.  If the transfer encoding of the HTTP response is
49  *     'chunked' already, each chunk will be split into smaller chunks if the
50  *     length of the chunk exceeds this value.  If you prefer not to handle
51  *     {@link HttpContent}s in your handler, insert {@link HttpObjectAggregator}
52  *     after this decoder in the {@link ChannelPipeline}.</td>
53  * </tr>
54  * </table>
55  *
56  * <h3>Decoding a response for a <tt>HEAD</tt> request</h3>
57  * <p>
58  * Unlike other HTTP requests, the successful response of a <tt>HEAD</tt>
59  * request does not have any content even if there is <tt>Content-Length</tt>
60  * header.  Because {@link HttpResponseDecoder} is not able to determine if the
61  * response currently being decoded is associated with a <tt>HEAD</tt> request,
62  * you must override {@link #isContentAlwaysEmpty(HttpMessage)} to return
63  * <tt>true</tt> for the response of the <tt>HEAD</tt> request.
64  * </p><p>
65  * If you are writing an HTTP client that issues a <tt>HEAD</tt> request,
66  * please use {@link HttpClientCodec} instead of this decoder.  It will perform
67  * additional state management to handle the responses for <tt>HEAD</tt>
68  * requests correctly.
69  * </p>
70  *
71  * <h3>Decoding a response for a <tt>CONNECT</tt> request</h3>
72  * <p>
73  * You also need to do additional state management to handle the response of a
74  * <tt>CONNECT</tt> request properly, like you did for <tt>HEAD</tt>.  One
75  * difference is that the decoder should stop decoding completely after decoding
76  * the successful 200 response since the connection is not an HTTP connection
77  * anymore.
78  * </p><p>
79  * {@link HttpClientCodec} also handles this edge case correctly, so you have to
80  * use {@link HttpClientCodec} if you are writing an HTTP client that issues a
81  * <tt>CONNECT</tt> request.
82  * </p>
83  */

84 public class HttpResponseDecoder extends HttpObjectDecoder {
85
86     private static final HttpResponseStatus UNKNOWN_STATUS = new HttpResponseStatus(999, "Unknown");
87
88     /**
89      * Creates a new instance with the default
90      * {@code maxInitialLineLength (4096)}, {@code maxHeaderSize (8192)}, and
91      * {@code maxChunkSize (8192)}.
92      */

93     public HttpResponseDecoder() {
94     }
95
96     /**
97      * Creates a new instance with the specified parameters.
98      */

99     public HttpResponseDecoder(
100             int maxInitialLineLength, int maxHeaderSize, int maxChunkSize) {
101         super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED);
102     }
103
104     public HttpResponseDecoder(
105             int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders) {
106         super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders);
107     }
108
109     public HttpResponseDecoder(
110             int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
111             int initialBufferSize) {
112         super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
113               initialBufferSize);
114     }
115
116     public HttpResponseDecoder(
117             int maxInitialLineLength, int maxHeaderSize, int maxChunkSize, boolean validateHeaders,
118             int initialBufferSize, boolean allowDuplicateContentLengths) {
119         super(maxInitialLineLength, maxHeaderSize, maxChunkSize, DEFAULT_CHUNKED_SUPPORTED, validateHeaders,
120               initialBufferSize, allowDuplicateContentLengths);
121     }
122
123     @Override
124     protected HttpMessage createMessage(String[] initialLine) {
125         return new DefaultHttpResponse(
126                 HttpVersion.valueOf(initialLine[0]),
127                 HttpResponseStatus.valueOf(Integer.parseInt(initialLine[1]), initialLine[2]), validateHeaders);
128     }
129
130     @Override
131     protected HttpMessage createInvalidMessage() {
132         return new DefaultFullHttpResponse(HttpVersion.HTTP_1_0, UNKNOWN_STATUS, validateHeaders);
133     }
134
135     @Override
136     protected boolean isDecodingRequest() {
137         return false;
138     }
139 }
140