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.netty5.handler.codec.http;
17  
18  import io.netty5.buffer.api.Buffer;
19  import io.netty5.buffer.api.BufferClosedException;
20  import io.netty5.util.Send;
21  
22  import static java.util.Objects.requireNonNull;
23  
24  /**
25   * Default implementation of a {@link FullHttpResponse}.
26   */
27  public class DefaultFullHttpResponse extends DefaultHttpResponse implements FullHttpResponse {
28  
29      private final Buffer payload;
30      private final HttpHeaders trailingHeaders;
31  
32      /**
33       * Used to cache the value of the hash code and avoid {@link BufferClosedException}.
34       */
35      private int hash;
36  
37      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status, Buffer payload) {
38          this(version, status, payload, true);
39      }
40  
41      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status,
42                                     Buffer payload, boolean validateHeaders) {
43          this(version, status, payload, validateHeaders, false);
44      }
45  
46      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status,
47                                     Buffer payload, boolean validateHeaders, boolean singleFieldHeaders) {
48          super(version, status, validateHeaders, singleFieldHeaders);
49          this.payload = requireNonNull(payload, "payload");
50          this.trailingHeaders = singleFieldHeaders ? new CombinedHttpHeaders(validateHeaders)
51                                                    : new DefaultHttpHeaders(validateHeaders);
52      }
53  
54      public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status,
55                                     Buffer payload, HttpHeaders headers, HttpHeaders trailingHeaders) {
56          super(version, status, headers);
57          this.payload = requireNonNull(payload, "payload");
58          this.trailingHeaders = requireNonNull(trailingHeaders, "trailingHeaders");
59      }
60  
61      @Override
62      public void close() {
63          payload.close();
64      }
65  
66      @Override
67      public boolean isAccessible() {
68          return payload.isAccessible();
69      }
70  
71      @Override
72      public FullHttpResponse touch(Object hint) {
73          payload.touch(hint);
74          return this;
75      }
76  
77      @Override
78      public Buffer payload() {
79          return payload;
80      }
81  
82      @Override
83      public Send<FullHttpResponse> send() {
84          return payload.send().map(FullHttpResponse.class,
85                  payload -> new DefaultFullHttpResponse(protocolVersion(), status(), payload, headers(),
86                          trailingHeaders));
87      }
88  
89      @Override
90      public DefaultFullHttpResponse copy() {
91          return new DefaultFullHttpResponse(
92                  protocolVersion(), status(), payload.copy(), headers().copy(), trailingHeaders.copy());
93      }
94  
95      @Override
96      public HttpHeaders trailingHeaders() {
97          return trailingHeaders;
98      }
99  
100     @Override
101     public FullHttpResponse setProtocolVersion(HttpVersion version) {
102         super.setProtocolVersion(version);
103         return this;
104     }
105 
106     @Override
107     public FullHttpResponse setStatus(HttpResponseStatus status) {
108         super.setStatus(status);
109         return this;
110     }
111 
112     @Override
113     public int hashCode() {
114         int hash = this.hash;
115         if (hash == 0) {
116             final Buffer payload = payload();
117             if (payload.isAccessible()) {
118                 try {
119                     hash = 31 + payload.hashCode();
120                 } catch (BufferClosedException ignored) {
121                     // Handle race condition between liveness checking and using the object.
122                     hash = 31;
123                 }
124             } else {
125                 hash = 31;
126             }
127             hash = 31 * hash + trailingHeaders().hashCode();
128             hash = 31 * hash + super.hashCode();
129             this.hash = hash;
130         }
131         return hash;
132     }
133 
134     @Override
135     public boolean equals(Object o) {
136         if (!(o instanceof DefaultFullHttpResponse)) {
137             return false;
138         }
139 
140         DefaultFullHttpResponse other = (DefaultFullHttpResponse) o;
141 
142         return super.equals(other) &&
143                payload().equals(other.payload()) &&
144                trailingHeaders().equals(other.trailingHeaders());
145     }
146 
147     @Override
148     public String toString() {
149         return HttpMessageUtil.appendFullResponse(new StringBuilder(256), this).toString();
150     }
151 }