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 org.jboss.netty.handler.codec.http;
17  
18  import java.util.Iterator;
19  import java.util.List;
20  
21  final class HttpCodecUtil {
22  
23      static void validateHeaderName(String name) {
24          if (name == null) {
25              throw new NullPointerException("name");
26          }
27          for (int i = 0; i < name.length(); i ++) {
28              char c = name.charAt(i);
29              if (c > 127) {
30                  throw new IllegalArgumentException(
31                          "name contains non-ascii character: " + name);
32              }
33  
34              // Check prohibited characters.
35              switch (c) {
36              case '\t': case '\n': case 0x0b: case '\f': case '\r':
37              case ' ':  case ',':  case ':':  case ';':  case '=':
38                  throw new IllegalArgumentException(
39                          "name contains one of the following prohibited characters: " +
40                          "=,;: \\t\\r\\n\\v\\f: " + name);
41              }
42          }
43      }
44  
45      static void validateHeaderValue(String value) {
46          if (value == null) {
47              throw new NullPointerException("value");
48          }
49  
50          // 0 - the previous character was neither CR nor LF
51          // 1 - the previous character was CR
52          // 2 - the previous character was LF
53          int state = 0;
54  
55          for (int i = 0; i < value.length(); i ++) {
56              char c = value.charAt(i);
57  
58              // Check the absolutely prohibited characters.
59              switch (c) {
60              case 0x0b: // Vertical tab
61                  throw new IllegalArgumentException(
62                          "value contains a prohibited character '\\v': " + value);
63              case '\f':
64                  throw new IllegalArgumentException(
65                          "value contains a prohibited character '\\f': " + value);
66              }
67  
68              // Check the CRLF (HT | SP) pattern
69              switch (state) {
70              case 0:
71                  switch (c) {
72                  case '\r':
73                      state = 1;
74                      break;
75                  case '\n':
76                      state = 2;
77                      break;
78                  }
79                  break;
80              case 1:
81                  switch (c) {
82                  case '\n':
83                      state = 2;
84                      break;
85                  default:
86                      throw new IllegalArgumentException(
87                              "Only '\\n' is allowed after '\\r': " + value);
88                  }
89                  break;
90              case 2:
91                  switch (c) {
92                  case '\t': case ' ':
93                      state = 0;
94                      break;
95                  default:
96                      throw new IllegalArgumentException(
97                              "Only ' ' and '\\t' are allowed after '\\n': " + value);
98                  }
99              }
100         }
101 
102         if (state != 0) {
103             throw new IllegalArgumentException(
104                     "value must not end with '\\r' or '\\n':" + value);
105         }
106     }
107 
108     static boolean isTransferEncodingChunked(HttpMessage m) {
109         List<String> chunked = m.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING);
110         if (chunked.isEmpty()) {
111             return false;
112         }
113 
114         for (String v: chunked) {
115             if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
116                 return true;
117             }
118         }
119         return false;
120     }
121 
122     static void removeTransferEncodingChunked(HttpMessage m) {
123         List<String> values = m.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING);
124         if (values.isEmpty()) {
125             return;
126         }
127         Iterator<String> valuesIt = values.iterator();
128         while (valuesIt.hasNext()) {
129             String value = valuesIt.next();
130             if (value.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
131                 valuesIt.remove();
132             }
133         }
134         if (values.isEmpty()) {
135             m.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
136         } else {
137             m.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, values);
138         }
139     }
140 
141     static boolean isContentLengthSet(HttpMessage m) {
142         List<String> contentLength = m.headers().getAll(HttpHeaders.Names.CONTENT_LENGTH);
143         return !contentLength.isEmpty();
144     }
145 
146     private HttpCodecUtil() {
147     }
148 }