View Javadoc

1   /*
2    * Copyright 2009 Red Hat, Inc.
3    *
4    * Red Hat licenses this file to you under the Apache License, version 2.0
5    * (the "License"); you may not use this file except in compliance with the
6    * 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 org.jboss.netty.handler.codec.http2;
17  
18  import java.nio.charset.Charset;
19  import java.util.List;
20  
21  import org.jboss.netty.util.CharsetUtil;
22  
23  /**
24   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
25   * @author Andy Taylor (andy.taylor@jboss.org)
26   * @version $Rev: 619 $, $Date: 2010-11-11 20:30:06 +0100 (jeu., 11 nov. 2010) $
27   */
28  class HttpCodecUtil {
29      //space ' '
30      static final byte SP = 32;
31  
32      //tab ' '
33      static final byte HT = 9;
34  
35      /**
36       * Carriage return
37       */
38      static final byte CR = 13;
39  
40      /**
41       * Equals '='
42       */
43      static final byte EQUALS = 61;
44  
45      /**
46       * Line feed character
47       */
48      static final byte LF = 10;
49  
50      /**
51       * carriage return line feed
52       */
53      static final byte[] CRLF = new byte[] { CR, LF };
54  
55      /**
56      * Colon ':'
57      */
58      static final byte COLON = 58;
59  
60      /**
61      * Semicolon ';'
62      */
63      static final byte SEMICOLON = 59;
64  
65       /**
66      * comma ','
67      */
68      static final byte COMMA = 44;
69  
70      static final byte DOUBLE_QUOTE = '"';
71  
72      static final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
73  
74      private HttpCodecUtil() {
75          super();
76      }
77  
78      static void validateHeaderName(String name) {
79          if (name == null) {
80              throw new NullPointerException("name");
81          }
82          for (int i = 0; i < name.length(); i ++) {
83              char c = name.charAt(i);
84              if (c > 127) {
85                  throw new IllegalArgumentException(
86                          "name contains non-ascii character: " + name);
87              }
88  
89              // Check prohibited characters.
90              switch (c) {
91              case '\t': case '\n': case 0x0b: case '\f': case '\r':
92              case ' ':  case ',':  case ':':  case ';':  case '=':
93                  throw new IllegalArgumentException(
94                          "name contains one of the following prohibited characters: " +
95                          "=,;: \\t\\r\\n\\v\\f: " + name);
96              }
97          }
98      }
99  
100     static void validateHeaderValue(String value) {
101         if (value == null) {
102             throw new NullPointerException("value");
103         }
104 
105         // 0 - the previous character was neither CR nor LF
106         // 1 - the previous character was CR
107         // 2 - the previous character was LF
108         int state = 0;
109 
110         for (int i = 0; i < value.length(); i ++) {
111             char c = value.charAt(i);
112 
113             // Check the absolutely prohibited characters.
114             switch (c) {
115             case 0x0b: // Vertical tab
116                 throw new IllegalArgumentException(
117                         "value contains a prohibited character '\\v': " + value);
118             case '\f':
119                 throw new IllegalArgumentException(
120                         "value contains a prohibited character '\\f': " + value);
121             }
122 
123             // Check the CRLF (HT | SP) pattern
124             switch (state) {
125             case 0:
126                 switch (c) {
127                 case '\r':
128                     state = 1;
129                     break;
130                 case '\n':
131                     state = 2;
132                     break;
133                 }
134                 break;
135             case 1:
136                 switch (c) {
137                 case '\n':
138                     state = 2;
139                     break;
140                 default:
141                     throw new IllegalArgumentException(
142                             "Only '\\n' is allowed after '\\r': " + value);
143                 }
144                 break;
145             case 2:
146                 switch (c) {
147                 case '\t': case ' ':
148                     state = 0;
149                     break;
150                 default:
151                     throw new IllegalArgumentException(
152                             "Only ' ' and '\\t' are allowed after '\\n': " + value);
153                 }
154             }
155         }
156 
157         if (state != 0) {
158             throw new IllegalArgumentException(
159                     "value must not end with '\\r' or '\\n':" + value);
160         }
161     }
162 
163     static boolean isTransferEncodingChunked(HttpMessage m) {
164         List<String> chunked = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
165         if (chunked.isEmpty()) {
166             return false;
167         }
168 
169         for (String v: chunked) {
170             if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
171                 return true;
172             }
173         }
174         return false;
175     }
176 }