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    *   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.buffer.Unpooled;
20  import io.netty.handler.codec.DefaultHeaders.NameValidator;
21  import io.netty.util.internal.StringUtil;
22  
23  import java.util.Map.Entry;
24  
25  /**
26   * The default {@link LastHttpContent} implementation.
27   */
28  public class DefaultLastHttpContent extends DefaultHttpContent implements LastHttpContent {
29      private final HttpHeaders trailingHeaders;
30      private final boolean validateHeaders;
31  
32      public DefaultLastHttpContent() {
33          this(Unpooled.buffer(0));
34      }
35  
36      public DefaultLastHttpContent(ByteBuf content) {
37          this(content, true);
38      }
39  
40      public DefaultLastHttpContent(ByteBuf content, boolean validateHeaders) {
41          super(content);
42          trailingHeaders = new TrailingHttpHeaders(validateHeaders);
43          this.validateHeaders = validateHeaders;
44      }
45  
46      @Override
47      public LastHttpContent copy() {
48          return replace(content().copy());
49      }
50  
51      @Override
52      public LastHttpContent duplicate() {
53          return replace(content().duplicate());
54      }
55  
56      @Override
57      public LastHttpContent retainedDuplicate() {
58          return replace(content().retainedDuplicate());
59      }
60  
61      @Override
62      public LastHttpContent replace(ByteBuf content) {
63          final DefaultLastHttpContent dup = new DefaultLastHttpContent(content, validateHeaders);
64          dup.trailingHeaders().set(trailingHeaders());
65          return dup;
66      }
67  
68      @Override
69      public LastHttpContent retain(int increment) {
70          super.retain(increment);
71          return this;
72      }
73  
74      @Override
75      public LastHttpContent retain() {
76          super.retain();
77          return this;
78      }
79  
80      @Override
81      public LastHttpContent touch() {
82          super.touch();
83          return this;
84      }
85  
86      @Override
87      public LastHttpContent touch(Object hint) {
88          super.touch(hint);
89          return this;
90      }
91  
92      @Override
93      public HttpHeaders trailingHeaders() {
94          return trailingHeaders;
95      }
96  
97      @Override
98      public String toString() {
99          StringBuilder buf = new StringBuilder(super.toString());
100         buf.append(StringUtil.NEWLINE);
101         appendHeaders(buf);
102 
103         // Remove the last newline.
104         buf.setLength(buf.length() - StringUtil.NEWLINE.length());
105         return buf.toString();
106     }
107 
108     private void appendHeaders(StringBuilder buf) {
109         for (Entry<String, String> e : trailingHeaders()) {
110             buf.append(e.getKey());
111             buf.append(": ");
112             buf.append(e.getValue());
113             buf.append(StringUtil.NEWLINE);
114         }
115     }
116 
117     private static final class TrailingHttpHeaders extends DefaultHttpHeaders {
118         private static final NameValidator<CharSequence> TrailerNameValidator = new NameValidator<CharSequence>() {
119             @Override
120             public void validateName(CharSequence name) {
121                 DefaultHttpHeaders.HttpNameValidator.validateName(name);
122                 if (HttpHeaderNames.CONTENT_LENGTH.contentEqualsIgnoreCase(name)
123                         || HttpHeaderNames.TRANSFER_ENCODING.contentEqualsIgnoreCase(name)
124                         || HttpHeaderNames.TRAILER.contentEqualsIgnoreCase(name)) {
125                     throw new IllegalArgumentException("prohibited trailing header: " + name);
126                 }
127             }
128         };
129 
130         @SuppressWarnings({ "unchecked" })
131         TrailingHttpHeaders(boolean validate) {
132             super(validate, validate ? TrailerNameValidator : NameValidator.NOT_NULL);
133         }
134     }
135 }