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.util.internal.ObjectUtil.checkNotNull;
24  
25  /**
26   * Default implementation of a {@link FullHttpResponse}.
27   */
28  public class DefaultFullHttpResponse extends DefaultHttpResponse implements FullHttpResponse {
29  
30      private final ByteBuf content;
31      private final HttpHeaders trailingHeaders;
32  
33      /**
34       * Used to cache the value of the hash code and avoid {@link IllegalReferenceCountException}.
35       */
36      private int hash;
37  
38      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status) {
39          this(version, status, Unpooled.buffer(0));
40      }
41  
42      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status, ByteBuf content) {
43          this(version, status, content, true);
44      }
45  
46      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status, boolean validateHeaders) {
47          this(version, status, Unpooled.buffer(0), validateHeaders, false);
48      }
49  
50      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status, boolean validateHeaders,
51                                     boolean singleFieldHeaders) {
52          this(version, status, Unpooled.buffer(0), validateHeaders, singleFieldHeaders);
53      }
54  
55      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status,
56                                     ByteBuf content, boolean validateHeaders) {
57          this(version, status, content, validateHeaders, false);
58      }
59  
60      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status,
61                                     ByteBuf content, boolean validateHeaders, boolean singleFieldHeaders) {
62          super(version, status, validateHeaders, singleFieldHeaders);
63          this.content = checkNotNull(content, "content");
64          this.trailingHeaders = singleFieldHeaders ? new CombinedHttpHeaders(validateHeaders)
65                                                    : new DefaultHttpHeaders(validateHeaders);
66      }
67  
68      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status,
69              ByteBuf content, HttpHeaders headers, HttpHeaders trailingHeaders) {
70          super(version, status, headers);
71          this.content = checkNotNull(content, "content");
72          this.trailingHeaders = checkNotNull(trailingHeaders, "trailingHeaders");
73      }
74  
75      @Override
76      public HttpHeaders trailingHeaders() {
77          return trailingHeaders;
78      }
79  
80      @Override
81      public ByteBuf content() {
82          return content;
83      }
84  
85      @Override
86      public int refCnt() {
87          return content.refCnt();
88      }
89  
90      @Override
91      public FullHttpResponse retain() {
92          content.retain();
93          return this;
94      }
95  
96      @Override
97      public FullHttpResponse retain(int increment) {
98          content.retain(increment);
99          return this;
100     }
101 
102     @Override
103     public FullHttpResponse touch() {
104         content.touch();
105         return this;
106     }
107 
108     @Override
109     public FullHttpResponse touch(Object hint) {
110         content.touch(hint);
111         return this;
112     }
113 
114     @Override
115     public boolean release() {
116         return content.release();
117     }
118 
119     @Override
120     public boolean release(int decrement) {
121         return content.release(decrement);
122     }
123 
124     @Override
125     public FullHttpResponse setProtocolVersion(HttpVersion version) {
126         super.setProtocolVersion(version);
127         return this;
128     }
129 
130     @Override
131     public FullHttpResponse setStatus(HttpResponseStatus status) {
132         super.setStatus(status);
133         return this;
134     }
135 
136     @Override
137     public FullHttpResponse copy() {
138         return replace(content().copy());
139     }
140 
141     @Override
142     public FullHttpResponse duplicate() {
143         return replace(content().duplicate());
144     }
145 
146     @Override
147     public FullHttpResponse retainedDuplicate() {
148         return replace(content().retainedDuplicate());
149     }
150 
151     @Override
152     public FullHttpResponse replace(ByteBuf content) {
153         FullHttpResponse response = new DefaultFullHttpResponse(protocolVersion(), status(), content,
154                 headers().copy(), trailingHeaders().copy());
155         response.setDecoderResult(decoderResult());
156         return response;
157     }
158 
159     @Override
160     public int hashCode() {
161         int hash = this.hash;
162         if (hash == 0) {
163             if (ByteBufUtil.isAccessible(content())) {
164                 try {
165                     hash = 31 + content().hashCode();
166                 } catch (IllegalReferenceCountException ignored) {
167                     // Handle race condition between checking refCnt() == 0 and using the object.
168                     hash = 31;
169                 }
170             } else {
171                 hash = 31;
172             }
173             hash = 31 * hash + trailingHeaders().hashCode();
174             hash = 31 * hash + super.hashCode();
175             this.hash = hash;
176         }
177         return hash;
178     }
179 
180     @Override
181     public boolean equals(Object o) {
182         if (!(o instanceof DefaultFullHttpResponse)) {
183             return false;
184         }
185 
186         DefaultFullHttpResponse other = (DefaultFullHttpResponse) o;
187 
188         return super.equals(other) &&
189                content().equals(other.content()) &&
190                trailingHeaders().equals(other.trailingHeaders());
191     }
192 
193     @Override
194     public String toString() {
195         return HttpMessageUtil.appendFullResponse(new StringBuilder(256), this).toString();
196     }
197 }