View Javadoc
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.buffer.Unpooled;
20  import io.netty.util.internal.StringUtil;
21  
22  import java.util.Map.Entry;
23  
24  import static io.netty.handler.codec.http.DefaultHttpHeadersFactory.trailersFactory;
25  import static io.netty.util.internal.ObjectUtil.checkNotNull;
26  
27  /**
28   * The default {@link LastHttpContent} implementation.
29   */
30  public class DefaultLastHttpContent extends DefaultHttpContent implements LastHttpContent {
31      private final HttpHeaders trailingHeaders;
32  
33      /**
34       * Create a new empty, last HTTP content message.
35       */
36      public DefaultLastHttpContent() {
37          this(Unpooled.buffer(0));
38      }
39  
40      /**
41       * Create a new last HTTP content message with the given contents.
42       */
43      public DefaultLastHttpContent(ByteBuf content) {
44          this(content, trailersFactory());
45      }
46  
47      /**
48       * Create a new last HTTP content message with the given contents, and optional trailing header validation.
49       * <p>
50       * <b>Warning!</b> Setting {@code validateHeaders} to {@code false} will mean that Netty won't
51       * validate & protect against user-supplied header values that are malicious.
52       * This can leave your server implementation vulnerable to
53       * <a href="https://cwe.mitre.org/data/definitions/113.html">
54       *     CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Response Splitting')
55       * </a>.
56       * When disabling this validation, it is the responsibility of the caller to ensure that the values supplied
57       * do not contain a non-url-escaped carriage return (CR) and/or line feed (LF) characters.
58       *
59       * @deprecated Prefer the {@link #DefaultLastHttpContent(ByteBuf)} constructor instead, to always have header
60       * validation enabled.
61       */
62      @Deprecated
63      public DefaultLastHttpContent(ByteBuf content, boolean validateHeaders) {
64          this(content, trailersFactory().withValidation(validateHeaders));
65      }
66  
67      /**
68       * Create a new last HTTP content message with the given contents, and trailing headers from the given factory.
69       */
70      public DefaultLastHttpContent(ByteBuf content, HttpHeadersFactory trailersFactory) {
71          super(content);
72          trailingHeaders = trailersFactory.newHeaders();
73      }
74  
75      /**
76       * Create a new last HTTP content message with the given contents, and trailing headers.
77       */
78      public DefaultLastHttpContent(ByteBuf content, HttpHeaders trailingHeaders) {
79          super(content);
80          this.trailingHeaders = checkNotNull(trailingHeaders, "trailingHeaders");
81      }
82  
83      @Override
84      public LastHttpContent copy() {
85          return replace(content().copy());
86      }
87  
88      @Override
89      public LastHttpContent duplicate() {
90          return replace(content().duplicate());
91      }
92  
93      @Override
94      public LastHttpContent retainedDuplicate() {
95          return replace(content().retainedDuplicate());
96      }
97  
98      @Override
99      public LastHttpContent replace(ByteBuf content) {
100         return new DefaultLastHttpContent(content, trailingHeaders().copy());
101     }
102 
103     @Override
104     public LastHttpContent retain(int increment) {
105         super.retain(increment);
106         return this;
107     }
108 
109     @Override
110     public LastHttpContent retain() {
111         super.retain();
112         return this;
113     }
114 
115     @Override
116     public LastHttpContent touch() {
117         super.touch();
118         return this;
119     }
120 
121     @Override
122     public LastHttpContent touch(Object hint) {
123         super.touch(hint);
124         return this;
125     }
126 
127     @Override
128     public HttpHeaders trailingHeaders() {
129         return trailingHeaders;
130     }
131 
132     @Override
133     public String toString() {
134         StringBuilder buf = new StringBuilder(super.toString());
135         buf.append(StringUtil.NEWLINE);
136         appendHeaders(buf);
137 
138         // Remove the last newline.
139         buf.setLength(buf.length() - StringUtil.NEWLINE.length());
140         return buf.toString();
141     }
142 
143     private void appendHeaders(StringBuilder buf) {
144         for (Entry<String, String> e : trailingHeaders()) {
145             buf.append(e.getKey());
146             buf.append(": ");
147             buf.append(e.getValue());
148             buf.append(StringUtil.NEWLINE);
149         }
150     }
151 }