001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/oac.hc3x/tags/HTTPCLIENT_3_1/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java $
003: * $Revision: 480424 $
004: * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030:
031: package org.apache.commons.httpclient.util;
032:
033: import org.apache.commons.httpclient.NameValuePair;
034:
035: /**
036: * <p>
037: * This formatter produces a textual representation of attribute/value pairs. It
038: * comforms to the generic grammar and formatting rules outlined in the
039: * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.1">Section 2.1</a>
040: * and
041: * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>
042: * of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>
043: * </p>
044: * <h>2.1 Augmented BNF</h>
045: * <p>
046: * Many HTTP/1.1 header field values consist of words separated by LWS or special
047: * characters. These special characters MUST be in a quoted string to be used within
048: * a parameter value (as defined in section 3.6).
049: * <p>
050: * <pre>
051: * token = 1*<any CHAR except CTLs or separators>
052: * separators = "(" | ")" | "<" | ">" | "@"
053: * | "," | ";" | ":" | "\" | <">
054: * | "/" | "[" | "]" | "?" | "="
055: * | "{" | "}" | SP | HT
056: * </pre>
057: * <p>
058: * A string of text is parsed as a single word if it is quoted using double-quote marks.
059: * </p>
060: * <pre>
061: * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
062: * qdtext = <any TEXT except <">>
063: * </pre>
064: * <p>
065: * The backslash character ("\") MAY be used as a single-character quoting mechanism only
066: * within quoted-string and comment constructs.
067: * </p>
068: * <pre>
069: * quoted-pair = "\" CHAR
070: * </pre>
071: * <h>3.6 Transfer Codings</h>
072: * <p>
073: * Parameters are in the form of attribute/value pairs.
074: * </p>
075: * <pre>
076: * parameter = attribute "=" value
077: * attribute = token
078: * value = token | quoted-string
079: * </pre>
080: *
081: * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
082: *
083: * @since 3.0
084: */
085: public class ParameterFormatter {
086:
087: /**
088: * Special characters that can be used as separators in HTTP parameters.
089: * These special characters MUST be in a quoted string to be used within
090: * a parameter value
091: */
092: private static final char[] SEPARATORS = { '(', ')', '<', '>', '@',
093: ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{',
094: '}', ' ', '\t' };
095:
096: /**
097: * Unsafe special characters that must be escaped using the backslash
098: * character
099: */
100: private static final char[] UNSAFE_CHARS = { '"', '\\' };
101:
102: /**
103: * This flag determines whether all parameter values must be enclosed in
104: * quotation marks, even if they do not contain any special characters
105: */
106: private boolean alwaysUseQuotes = true;
107:
108: /** Default ParameterFormatter constructor */
109: public ParameterFormatter() {
110: super ();
111: }
112:
113: private static boolean isOneOf(char[] chars, char ch) {
114: for (int i = 0; i < chars.length; i++) {
115: if (ch == chars[i]) {
116: return true;
117: }
118: }
119: return false;
120: }
121:
122: private static boolean isUnsafeChar(char ch) {
123: return isOneOf(UNSAFE_CHARS, ch);
124: }
125:
126: private static boolean isSeparator(char ch) {
127: return isOneOf(SEPARATORS, ch);
128: }
129:
130: /**
131: * Determines whether all parameter values must be enclosed in quotation
132: * marks, even if they do not contain any special characters
133: *
134: * @return <tt>true</tt> if all parameter values must be enclosed in
135: * quotation marks, <tt>false</tt> otherwise
136: */
137: public boolean isAlwaysUseQuotes() {
138: return alwaysUseQuotes;
139: }
140:
141: /**
142: * Defines whether all parameter values must be enclosed in quotation
143: * marks, even if they do not contain any special characters
144: *
145: * @param alwaysUseQuotes
146: */
147: public void setAlwaysUseQuotes(boolean alwaysUseQuotes) {
148: this .alwaysUseQuotes = alwaysUseQuotes;
149: }
150:
151: /**
152: * Formats the given parameter value using formatting rules defined
153: * in RFC 2616
154: *
155: * @param buffer output buffer
156: * @param value the parameter value to be formatted
157: * @param alwaysUseQuotes <tt>true</tt> if the parameter value must
158: * be enclosed in quotation marks, even if it does not contain any special
159: * characters<tt>, false</tt> only if the parameter value contains
160: * potentially unsafe special characters
161: */
162: public static void formatValue(final StringBuffer buffer,
163: final String value, boolean alwaysUseQuotes) {
164: if (buffer == null) {
165: throw new IllegalArgumentException(
166: "String buffer may not be null");
167: }
168: if (value == null) {
169: throw new IllegalArgumentException(
170: "Value buffer may not be null");
171: }
172: if (alwaysUseQuotes) {
173: buffer.append('"');
174: for (int i = 0; i < value.length(); i++) {
175: char ch = value.charAt(i);
176: if (isUnsafeChar(ch)) {
177: buffer.append('\\');
178: }
179: buffer.append(ch);
180: }
181: buffer.append('"');
182: } else {
183: int offset = buffer.length();
184: boolean unsafe = false;
185: for (int i = 0; i < value.length(); i++) {
186: char ch = value.charAt(i);
187: if (isSeparator(ch)) {
188: unsafe = true;
189: }
190: if (isUnsafeChar(ch)) {
191: buffer.append('\\');
192: }
193: buffer.append(ch);
194: }
195: if (unsafe) {
196: buffer.insert(offset, '"');
197: buffer.append('"');
198: }
199: }
200: }
201:
202: /**
203: * Produces textual representaion of the attribute/value pair using
204: * formatting rules defined in RFC 2616
205: *
206: * @param buffer output buffer
207: * @param param the parameter to be formatted
208: */
209: public void format(final StringBuffer buffer,
210: final NameValuePair param) {
211: if (buffer == null) {
212: throw new IllegalArgumentException(
213: "String buffer may not be null");
214: }
215: if (param == null) {
216: throw new IllegalArgumentException(
217: "Parameter may not be null");
218: }
219: buffer.append(param.getName());
220: String value = param.getValue();
221: if (value != null) {
222: buffer.append("=");
223: formatValue(buffer, value, this .alwaysUseQuotes);
224: }
225: }
226:
227: /**
228: * Produces textual representaion of the attribute/value pair using
229: * formatting rules defined in RFC 2616
230: *
231: * @param param the parameter to be formatted
232: *
233: * @return RFC 2616 conformant textual representaion of the
234: * attribute/value pair
235: */
236: public String format(final NameValuePair param) {
237: StringBuffer buffer = new StringBuffer();
238: format(buffer, param);
239: return buffer.toString();
240: }
241:
242: }
|