/* * $HeadURL$ * $Revision$ * $Date$ * * ==================================================================== * * Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.commons.httpclient.util; import org.apache.commons.httpclient.NameValuePair; /** *

* This formatter produces a textual representation of attribute/value pairs. It * comforms to the generic grammar and formatting rules outlined in the * Section 2.1 * and * Section 3.6 * of RFC 2616 *

* 2.1 Augmented BNF *

* Many HTTP/1.1 header field values consist of words separated by LWS or special * characters. These special characters MUST be in a quoted string to be used within * a parameter value (as defined in section 3.6). *

*

 * token          = 1*
 * separators     = "(" | ")" | "<" | ">" | "@"
 *                | "," | ";" | ":" | "\" | <">
 *                | "/" | "[" | "]" | "?" | "="
 *                | "{" | "}" | SP | HT
 * 
*

* A string of text is parsed as a single word if it is quoted using double-quote marks. *

*
 * quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
 * qdtext         = >
 * 
*

* The backslash character ("\") MAY be used as a single-character quoting mechanism only * within quoted-string and comment constructs. *

*
 * quoted-pair    = "\" CHAR
 * 
* 3.6 Transfer Codings *

* Parameters are in the form of attribute/value pairs. *

*
 * parameter               = attribute "=" value
 * attribute               = token
 * value                   = token | quoted-string
 * 
* * @author Oleg Kalnichevski * * @since 3.0 */ public class ParameterFormatter { /** * Special characters that can be used as separators in HTTP parameters. * These special characters MUST be in a quoted string to be used within * a parameter value */ private static final char[] SEPARATORS = { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t' }; /** * Unsafe special characters that must be escaped using the backslash * character */ private static final char[] UNSAFE_CHARS = { '"', '\\' }; /** * This flag determines whether all parameter values must be enclosed in * quotation marks, even if they do not contain any special characters */ private boolean alwaysUseQuotes = true; /** Default ParameterFormatter constructor */ public ParameterFormatter() { super(); } private static boolean isOneOf(char[] chars, char ch) { for (int i = 0; i < chars.length; i++) { if (ch == chars[i]) { return true; } } return false; } private static boolean isUnsafeChar(char ch) { return isOneOf(UNSAFE_CHARS, ch); } private static boolean isSeparator(char ch) { return isOneOf(SEPARATORS, ch); } /** * Determines whether all parameter values must be enclosed in quotation * marks, even if they do not contain any special characters * * @return true if all parameter values must be enclosed in * quotation marks, false otherwise */ public boolean isAlwaysUseQuotes() { return alwaysUseQuotes; } /** * Defines whether all parameter values must be enclosed in quotation * marks, even if they do not contain any special characters * * @param alwaysUseQuotes */ public void setAlwaysUseQuotes(boolean alwaysUseQuotes) { this.alwaysUseQuotes = alwaysUseQuotes; } /** * Formats the given parameter value using formatting rules defined * in RFC 2616 * * @param buffer output buffer * @param value the parameter value to be formatted * @param alwaysUseQuotes true if the parameter value must * be enclosed in quotation marks, even if it does not contain any special * characters, false only if the parameter value contains * potentially unsafe special characters */ public static void formatValue( final StringBuffer buffer, final String value, boolean alwaysUseQuotes) { if (buffer == null) { throw new IllegalArgumentException("String buffer may not be null"); } if (value == null) { throw new IllegalArgumentException("Value buffer may not be null"); } if (alwaysUseQuotes) { buffer.append('"'); for (int i = 0; i < value.length(); i++) { char ch = value.charAt(i); if (isUnsafeChar(ch)) { buffer.append('\\'); } buffer.append(ch); } buffer.append('"'); } else { int offset = buffer.length(); boolean unsafe = false; for (int i = 0; i < value.length(); i++) { char ch = value.charAt(i); if (isSeparator(ch)) { unsafe = true; } if (isUnsafeChar(ch)) { buffer.append('\\'); } buffer.append(ch); } if (unsafe) { buffer.insert(offset, '"'); buffer.append('"'); } } } /** * Produces textual representaion of the attribute/value pair using * formatting rules defined in RFC 2616 * * @param buffer output buffer * @param param the parameter to be formatted */ public void format(final StringBuffer buffer, final NameValuePair param) { if (buffer == null) { throw new IllegalArgumentException("String buffer may not be null"); } if (param == null) { throw new IllegalArgumentException("Parameter may not be null"); } buffer.append(param.getName()); String value = param.getValue(); if (value != null) { buffer.append("="); formatValue(buffer, value, this.alwaysUseQuotes); } } /** * Produces textual representaion of the attribute/value pair using * formatting rules defined in RFC 2616 * * @param param the parameter to be formatted * * @return RFC 2616 conformant textual representaion of the * attribute/value pair */ public String format(final NameValuePair param) { StringBuffer buffer = new StringBuffer(); format(buffer, param); return buffer.toString(); } }