View Javadoc
1   /*
2    * Copyright 2014 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  
17  package io.netty.handler.codec;
18  
19  
20  import java.util.Map.Entry;
21  
22  import io.netty.buffer.ByteBuf;
23  import io.netty.buffer.ByteBufUtil;
24  import io.netty.util.AsciiString;
25  import io.netty.util.CharsetUtil;
26  
27  public final class AsciiHeadersEncoder {
28  
29      /**
30       * The separator characters to insert between a header name and a header value.
31       */
32      public enum SeparatorType {
33          /**
34           * {@code ':'}
35           */
36          COLON,
37          /**
38           * {@code ': '}
39           */
40          COLON_SPACE,
41      }
42  
43      /**
44       * The newline characters to insert between header entries.
45       */
46      public enum NewlineType {
47          /**
48           * {@code '\n'}
49           */
50          LF,
51          /**
52           * {@code '\r\n'}
53           */
54          CRLF
55      }
56  
57      private final ByteBuf buf;
58      private final SeparatorType separatorType;
59      private final NewlineType newlineType;
60  
61      public AsciiHeadersEncoder(ByteBuf buf) {
62          this(buf, SeparatorType.COLON_SPACE, NewlineType.CRLF);
63      }
64  
65      public AsciiHeadersEncoder(ByteBuf buf, SeparatorType separatorType, NewlineType newlineType) {
66          if (buf == null) {
67              throw new NullPointerException("buf");
68          }
69          if (separatorType == null) {
70              throw new NullPointerException("separatorType");
71          }
72          if (newlineType == null) {
73              throw new NullPointerException("newlineType");
74          }
75  
76          this.buf = buf;
77          this.separatorType = separatorType;
78          this.newlineType = newlineType;
79      }
80  
81      public void encode(Entry<CharSequence, CharSequence> entry) {
82          final CharSequence name = entry.getKey();
83          final CharSequence value = entry.getValue();
84          final ByteBuf buf = this.buf;
85          final int nameLen = name.length();
86          final int valueLen = value.length();
87          final int entryLen = nameLen + valueLen + 4;
88          int offset = buf.writerIndex();
89          buf.ensureWritable(entryLen);
90          writeAscii(buf, offset, name);
91          offset += nameLen;
92  
93          switch (separatorType) {
94              case COLON:
95                  buf.setByte(offset ++, ':');
96                  break;
97              case COLON_SPACE:
98                  buf.setByte(offset ++, ':');
99                  buf.setByte(offset ++, ' ');
100                 break;
101             default:
102                 throw new Error();
103         }
104 
105         writeAscii(buf, offset, value);
106         offset += valueLen;
107 
108         switch (newlineType) {
109             case LF:
110                 buf.setByte(offset ++, '\n');
111                 break;
112             case CRLF:
113                 buf.setByte(offset ++, '\r');
114                 buf.setByte(offset ++, '\n');
115                 break;
116             default:
117                 throw new Error();
118         }
119 
120         buf.writerIndex(offset);
121     }
122 
123     private static void writeAscii(ByteBuf buf, int offset, CharSequence value) {
124         if (value instanceof AsciiString) {
125             ByteBufUtil.copy((AsciiString) value, 0, buf, offset, value.length());
126         } else {
127             buf.setCharSequence(offset, value, CharsetUtil.US_ASCII);
128         }
129     }
130 }