View Javadoc
1   /*
2    * Copyright 2013 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.buffer.ByteBufUtil;
20  import io.netty.buffer.Unpooled;
21  import io.netty.util.IllegalReferenceCountException;
22  
23  import static io.netty.handler.codec.http.DefaultHttpHeadersFactory.headersFactory;
24  import static io.netty.handler.codec.http.DefaultHttpHeadersFactory.trailersFactory;
25  import static io.netty.util.internal.ObjectUtil.checkNotNull;
26  
27  /**
28   * Default implementation of {@link FullHttpRequest}.
29   */
30  public class DefaultFullHttpRequest extends DefaultHttpRequest implements FullHttpRequest {
31      private final ByteBuf content;
32      private final HttpHeaders trailingHeader;
33  
34      /**
35       * Used to cache the value of the hash code and avoid {@link IllegalReferenceCountException}.
36       */
37      private int hash;
38  
39      /**
40       * Create a full HTTP response with the given HTTP version, method, and URI.
41       */
42      public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri) {
43          this(httpVersion, method, uri, Unpooled.buffer(0), headersFactory(), trailersFactory());
44      }
45  
46      /**
47       * Create a full HTTP response with the given HTTP version, method, URI, and contents.
48       */
49      public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, ByteBuf content) {
50          this(httpVersion, method, uri, content, headersFactory(), trailersFactory());
51      }
52  
53      /**
54       * Create a full HTTP response with the given HTTP version, method, URI, and optional validation.
55       * @deprecated Use the {@link #DefaultFullHttpRequest(HttpVersion, HttpMethod, String, ByteBuf,
56       * HttpHeadersFactory, HttpHeadersFactory)} constructor instead.
57       */
58      @Deprecated
59      public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, boolean validateHeaders) {
60          this(httpVersion, method, uri, Unpooled.buffer(0),
61                  headersFactory().withValidation(validateHeaders),
62                  trailersFactory().withValidation(validateHeaders));
63      }
64  
65      /**
66       * Create a full HTTP response with the given HTTP version, method, URI, contents, and optional validation.
67       * @deprecated Use the {@link #DefaultFullHttpRequest(HttpVersion, HttpMethod, String, ByteBuf,
68       * HttpHeadersFactory, HttpHeadersFactory)} constructor instead.
69       */
70      @Deprecated
71      public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri,
72                                    ByteBuf content, boolean validateHeaders) {
73          this(httpVersion, method, uri, content,
74                  headersFactory().withValidation(validateHeaders),
75                  trailersFactory().withValidation(validateHeaders));
76      }
77  
78      /**
79       * Create a full HTTP response with the given HTTP version, method, URI, contents,
80       * and factories for creating headers and trailers.
81       * <p>
82       * The recommended default header factory is {@link DefaultHttpHeadersFactory#headersFactory()},
83       * and the recommended default trailer factory is {@link DefaultHttpHeadersFactory#trailersFactory()}.
84       */
85      public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri,
86              ByteBuf content, HttpHeadersFactory headersFactory, HttpHeadersFactory trailersFactory) {
87          this(httpVersion, method, uri, content, headersFactory.newHeaders(), trailersFactory.newHeaders());
88      }
89  
90      /**
91       * Create a full HTTP response with the given HTTP version, method, URI, contents, and header and trailer objects.
92       */
93      public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri,
94              ByteBuf content, HttpHeaders headers, HttpHeaders trailingHeader) {
95          this(httpVersion, method, uri, content, headers, trailingHeader, true);
96      }
97  
98      /**
99       * Create a full HTTP response with the given HTTP version, method, URI, contents, and header and trailer objects.
100      */
101     public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri,
102             ByteBuf content, HttpHeaders headers, HttpHeaders trailingHeader, boolean validateRequestLine) {
103         super(httpVersion, method, uri, headers, validateRequestLine);
104         this.content = checkNotNull(content, "content");
105         this.trailingHeader = checkNotNull(trailingHeader, "trailingHeader");
106     }
107 
108     @Override
109     public HttpHeaders trailingHeaders() {
110         return trailingHeader;
111     }
112 
113     @Override
114     public ByteBuf content() {
115         return content;
116     }
117 
118     @Override
119     public int refCnt() {
120         return content.refCnt();
121     }
122 
123     @Override
124     public FullHttpRequest retain() {
125         content.retain();
126         return this;
127     }
128 
129     @Override
130     public FullHttpRequest retain(int increment) {
131         content.retain(increment);
132         return this;
133     }
134 
135     @Override
136     public FullHttpRequest touch() {
137         content.touch();
138         return this;
139     }
140 
141     @Override
142     public FullHttpRequest touch(Object hint) {
143         content.touch(hint);
144         return this;
145     }
146 
147     @Override
148     public boolean release() {
149         return content.release();
150     }
151 
152     @Override
153     public boolean release(int decrement) {
154         return content.release(decrement);
155     }
156 
157     @Override
158     public FullHttpRequest setProtocolVersion(HttpVersion version) {
159         super.setProtocolVersion(version);
160         return this;
161     }
162 
163     @Override
164     public FullHttpRequest setMethod(HttpMethod method) {
165         super.setMethod(method);
166         return this;
167     }
168 
169     @Override
170     public FullHttpRequest setUri(String uri) {
171         super.setUri(uri);
172         return this;
173     }
174 
175     @Override
176     public FullHttpRequest copy() {
177         return replace(content().copy());
178     }
179 
180     @Override
181     public FullHttpRequest duplicate() {
182         return replace(content().duplicate());
183     }
184 
185     @Override
186     public FullHttpRequest retainedDuplicate() {
187         return replace(content().retainedDuplicate());
188     }
189 
190     @Override
191     public FullHttpRequest replace(ByteBuf content) {
192         FullHttpRequest request = new DefaultFullHttpRequest(protocolVersion(), method(), uri(), content,
193                 headers().copy(), trailingHeaders().copy());
194         request.setDecoderResult(decoderResult());
195         return request;
196     }
197 
198     @Override
199     public int hashCode() {
200         int hash = this.hash;
201         if (hash == 0) {
202             if (ByteBufUtil.isAccessible(content())) {
203                 try {
204                     hash = 31 + content().hashCode();
205                 } catch (IllegalReferenceCountException ignored) {
206                     // Handle race condition between checking refCnt() == 0 and using the object.
207                     hash = 31;
208                 }
209             } else {
210                 hash = 31;
211             }
212             hash = 31 * hash + trailingHeaders().hashCode();
213             hash = 31 * hash + super.hashCode();
214             this.hash = hash;
215         }
216         return hash;
217     }
218 
219     @Override
220     public boolean equals(Object o) {
221         if (!(o instanceof DefaultFullHttpRequest)) {
222             return false;
223         }
224 
225         DefaultFullHttpRequest other = (DefaultFullHttpRequest) o;
226 
227         return super.equals(other) &&
228                content().equals(other.content()) &&
229                trailingHeaders().equals(other.trailingHeaders());
230     }
231 
232     @Override
233     public String toString() {
234         return HttpMessageUtil.appendFullRequest(new StringBuilder(256), this).toString();
235     }
236 }