View Javadoc

1   /*******************************************************************************
2    * Copyright (c) 2011 Michael Mimo Moratti.
3    *
4    * Michael Mimo Moratti 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 License.
6    * You may obtain a copy of the License at:
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
11   * License for the specific language governing permissions and limitations
12   * under the License.
13   *******************************************************************************/
14  package ch.mimo.netty.handler.codec.icap;
15  
16  import java.nio.charset.Charset;
17  
18  
19  /**
20   * This Codec class provides all required special characters such as space and linefeed.
21   * It also provides validation methods for icap header name and value validation.
22   * 
23   * @author Michael Mimo Moratti (mimo@mimo.ch)
24   *
25   */
26  public final class IcapCodecUtil {
27  
28  	/**
29  	 * Preview early termination sequence
30  	 * 
31  	 * 0; ieof
32  	 */
33  	public static final Byte[] IEOF_SEQUENCE = new Byte[]{48,59,32,105,101,111,102};
34  	
35  	public static final byte[] NATIVE_IEOF_SEQUENCE = new byte[]{48,59,32,105,101,111,102};
36  	
37  	public static final String IEOF_SEQUENCE_STRING = "0; ieof";
38  	
39  	/**
40  	 * Space
41  	 */
42  	public static final byte SPACE = 32;
43  
44      /**
45       * Carriage return
46       */
47  	public static final byte CR = 13;
48  
49      /**
50       * Line feed character
51       */
52  	public static final byte LF = 10;
53  
54      /**
55       * carriage return line feed
56       */
57  	public static final byte[] CRLF = new byte[] { CR, LF };
58  
59      /**
60      * Colon ':'
61      */
62  	public static final byte COLON = 58;
63  
64      
65  	public static final Charset ASCII_CHARSET = Charset.forName("ASCII");
66      
67  	public static final String ENCAPSULATION_ELEMENT_REQHDR = "req-hdr";
68  	public static final String ENCAPSULATION_ELEMENT_RESHDR = "res-hdr";
69  	public static final String ENCAPSULATION_ELEMENT_REQBODY = "req-body";
70  	public static final String ENCAPSULATION_ELEMENT_RESBODY = "res-body";
71  	public static final String ENCAPSULATION_ELEMENT_OPTBODY = "opt-body";
72  	public static final String ENCAPSULATION_ELEMENT_NULLBODY = "null-body";
73      
74      private IcapCodecUtil() {
75      }
76  
77      /**
78       * Valiation method for Icap header names.
79       * 
80       * @param name to be validated
81       */
82      public static void validateHeaderName(String name) {
83          if (name == null) {
84              throw new NullPointerException("name");
85          }
86          for (int i = 0; i < name.length(); i ++) {
87              char caracter = name.charAt(i);
88              if (caracter > 127) {
89                  throw new IllegalArgumentException("name contains non-ascii character: " + name);
90              }
91  
92              // Check prohibited characters.
93              switch (caracter) {
94              case '\t': case '\n': case 0x0b: case '\f': case '\r':
95              case ' ':  case ',':  case ':':  case ';':  case '=':
96                  throw new IllegalArgumentException("name contains one of the following prohibited characters: =,;: \\t\\r\\n\\v\\f: " + name);
97              }
98          }
99      }
100 
101     /**
102      * Validation method for Icap header values
103      * 
104      * @param value to be validated
105      */
106     public static void validateHeaderValue(String value) {
107         if (value == null) {
108             throw new NullPointerException("value");
109         }
110 
111         // 0 - the previous character was neither CR nor LF
112         // 1 - the previous character was CR
113         // 2 - the previous character was LF
114         int state = 0;
115 
116         for (int i = 0; i < value.length(); i ++) {
117             final char caracter = value.charAt(i);
118 
119             // Check the absolutely prohibited characters.
120             if(caracter == 0x0b | caracter == '\f') {
121             	throw new IllegalArgumentException("value contains a prohibited character " + caracter + ": " + value);
122             }
123 
124             // Check the CRLF (HT | SP) pattern
125             if(state == 0) {
126             	if(caracter == '\r') {
127             		state = 1;
128             	}
129             	if(caracter == '\n') {
130             		state = 2;
131             	}
132             } else if(state == 1) {
133             	if(caracter == '\n') {
134             		state = 2;
135             	} else {
136             		throw new IllegalArgumentException("Only '\\n' is allowed after '\\r': " + value);
137             	}
138             } else if(state == 2) {
139             	if(caracter == '\t') {
140             		state = 0;
141             	} else {
142             		throw new IllegalArgumentException("Only ' ' and '\\t' are allowed after '\\n': " + value);
143             	}
144             }
145         }
146 
147         if (state != 0) {
148             throw new IllegalArgumentException("value must not end with '\\r' or '\\n':" + value);
149         }
150     }
151 }