View Javadoc
1   /*******************************************************************************
2    * Copyright 2012 Internet2
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * 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,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   ******************************************************************************/
16  /*
17   * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/oac.hc3x/tags/HTTPCLIENT_3_1/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java $
18   * $Revision: 1.1 $
19   * $Date: 2008-11-30 10:57:27 $
20   *
21   * ====================================================================
22   *
23   *  Licensed to the Apache Software Foundation (ASF) under one or more
24   *  contributor license agreements.  See the NOTICE file distributed with
25   *  this work for additional information regarding copyright ownership.
26   *  The ASF licenses this file to You under the Apache License, Version 2.0
27   *  (the "License"); you may not use this file except in compliance with
28   *  the License.  You may obtain a copy of the License at
29   *
30   *      http://www.apache.org/licenses/LICENSE-2.0
31   *
32   *  Unless required by applicable law or agreed to in writing, software
33   *  distributed under the License is distributed on an "AS IS" BASIS,
34   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35   *  See the License for the specific language governing permissions and
36   *  limitations under the License.
37   * ====================================================================
38   *
39   * This software consists of voluntary contributions made by many
40   * individuals on behalf of the Apache Software Foundation.  For more
41   * information on the Apache Software Foundation, please see
42   * <http://www.apache.org/>.
43   *
44   */
45  
46  package edu.internet2.middleware.grouperInstallerExt.org.apache.commons.httpclient.util;
47  
48  import edu.internet2.middleware.grouperInstallerExt.org.apache.commons.httpclient.NameValuePair;
49  
50  /**
51   * <p>
52   *  This formatter produces a textual representation of attribute/value pairs. It 
53   *  comforms to the generic grammar and formatting rules outlined in the 
54   *  <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.1">Section 2.1</a>
55   *  and  
56   *  <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>
57   *  of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>
58   * </p>
59   * <h>2.1 Augmented BNF</h>
60   * <p>
61   *  Many HTTP/1.1 header field values consist of words separated by LWS or special 
62   *  characters. These special characters MUST be in a quoted string to be used within 
63   *  a parameter value (as defined in section 3.6).
64   * <p>
65   * <pre>
66   * token          = 1*<any CHAR except CTLs or separators>
67   * separators     = "(" | ")" | "<" | ">" | "@"
68   *                | "," | ";" | ":" | "\" | <">
69   *                | "/" | "[" | "]" | "?" | "="
70   *                | "{" | "}" | SP | HT
71   * </pre>
72   * <p>
73   *  A string of text is parsed as a single word if it is quoted using double-quote marks.
74   * </p>
75   * <pre>
76   * quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
77   * qdtext         = <any TEXT except <">>
78   * </pre>
79   * <p>
80   *  The backslash character ("\") MAY be used as a single-character quoting mechanism only 
81   *  within quoted-string and comment constructs.
82   * </p>
83   * <pre>
84   * quoted-pair    = "\" CHAR
85   * </pre>
86   * <h>3.6 Transfer Codings</h>
87   * <p>
88   *  Parameters are in the form of attribute/value pairs.
89   * </p>
90   * <pre>
91   * parameter               = attribute "=" value
92   * attribute               = token
93   * value                   = token | quoted-string
94   * </pre>
95   * 
96   * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
97   * 
98   * @since 3.0
99   */
100 public class ParameterFormatter {
101     
102     /**
103      * Special characters that can be used as separators in HTTP parameters.
104      * These special characters MUST be in a quoted string to be used within
105      * a parameter value 
106      */
107     private static final char[] SEPARATORS   = {
108             '(', ')', '<', '>', '@', 
109             ',', ';', ':', '\\', '"', 
110             '/', '[', ']', '?', '=',
111             '{', '}', ' ', '\t'
112             };
113     
114     /**
115      * Unsafe special characters that must be escaped using the backslash
116      * character
117      */
118     private static final char[] UNSAFE_CHARS = {
119             '"', '\\'
120             };
121     
122     /**
123      * This flag determines whether all parameter values must be enclosed in 
124      * quotation marks, even if they do not contain any special characters
125      */
126     private boolean alwaysUseQuotes = true;
127     
128     /** Default ParameterFormatter constructor */
129     public ParameterFormatter() {
130         super();
131     }
132     
133     private static boolean isOneOf(char[] chars, char ch) {
134         for (int i = 0; i < chars.length; i++) {
135             if (ch == chars[i]) {
136                 return true;
137             }
138         }
139         return false;
140     }
141     
142     private static boolean isUnsafeChar(char ch) {
143         return isOneOf(UNSAFE_CHARS, ch);
144     }
145     
146     private static boolean isSeparator(char ch) {
147         return isOneOf(SEPARATORS, ch);
148     }
149 
150     /**
151      * Determines whether all parameter values must be enclosed in quotation 
152      * marks, even if they do not contain any special characters
153      * 
154      * @return <tt>true</tt> if all parameter values must be enclosed in 
155      * quotation marks, <tt>false</tt> otherwise
156      */
157     public boolean isAlwaysUseQuotes() {
158         return alwaysUseQuotes;
159     }
160     
161     /**
162      * Defines whether all parameter values must be enclosed in quotation 
163      * marks, even if they do not contain any special characters
164      * 
165      * @param alwaysUseQuotes
166      */
167     public void setAlwaysUseQuotes(boolean alwaysUseQuotes) {
168         this.alwaysUseQuotes = alwaysUseQuotes;
169     }
170     
171     /**
172      * Formats the given parameter value using formatting rules defined
173      * in RFC 2616 
174      * 
175      * @param buffer output buffer 
176      * @param value the parameter value to be formatted
177      * @param alwaysUseQuotes <tt>true</tt> if the parameter value must 
178      * be enclosed in quotation marks, even if it does not contain any special 
179      * characters<tt>, false</tt> only if the parameter value contains 
180      * potentially unsafe special characters
181      */
182     public static void formatValue(
183             final StringBuffer buffer, final String value, boolean alwaysUseQuotes) {
184         if (buffer == null) {
185             throw new IllegalArgumentException("String buffer may not be null");
186         }
187         if (value == null) {
188             throw new IllegalArgumentException("Value buffer may not be null");
189         }
190         if (alwaysUseQuotes) {
191             buffer.append('"');
192             for (int i = 0; i < value.length(); i++) {
193                 char ch = value.charAt(i);
194                 if (isUnsafeChar(ch)) {
195                     buffer.append('\\');
196                 }
197                 buffer.append(ch);
198             }
199             buffer.append('"');
200         } else {
201             int offset = buffer.length();
202             boolean unsafe = false;
203             for (int i = 0; i < value.length(); i++) {
204                 char ch = value.charAt(i);
205                 if (isSeparator(ch)) {
206                     unsafe = true;
207                 }
208                 if (isUnsafeChar(ch)) {
209                     buffer.append('\\');
210                 }
211                 buffer.append(ch);
212             }
213             if (unsafe) {
214                 buffer.insert(offset, '"');
215                 buffer.append('"');
216             }
217         }
218     }
219     
220     /**
221      * Produces textual representaion of the attribute/value pair using 
222      * formatting rules defined in RFC 2616
223      *  
224      * @param buffer output buffer 
225      * @param param the parameter to be formatted
226      */
227     public void format(final StringBuffer buffer, final NameValuePair param) {
228         if (buffer == null) {
229             throw new IllegalArgumentException("String buffer may not be null");
230         }
231         if (param == null) {
232             throw new IllegalArgumentException("Parameter may not be null");
233         }
234         buffer.append(param.getName());
235         String value = param.getValue();
236         if (value != null) {
237             buffer.append("=");
238             formatValue(buffer, value, this.alwaysUseQuotes);
239         }
240     }
241     
242     /**
243      * Produces textual representaion of the attribute/value pair using 
244      * formatting rules defined in RFC 2616
245      *  
246      * @param param the parameter to be formatted
247      * 
248      * @return RFC 2616 conformant textual representaion of the 
249      * attribute/value pair
250      */
251     public String format(final NameValuePair param) {
252         StringBuffer buffer = new StringBuffer();
253         format(buffer, param);
254         return buffer.toString();
255     }
256 
257 }