| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| package org.apache.ahc.util; |
| |
| /** |
| * <p> |
| * This formatter produces a textual representation of attribute/value pairs. It |
| * comforms to the generic grammar and formatting rules outlined in the |
| * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.1">Section 2.1</a> |
| * and |
| * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a> |
| * of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a> |
| * </p> |
| * <h2>2.1 Augmented BNF</h2> |
| * <p> |
| * 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). |
| * </p> |
| * <pre>{@code |
| * token = 1*<any CHAR except CTLs or separators> |
| * separators = "(" | ")" | "<" | ">" | "@" |
| * | "," | ";" | ":" | "\" | <"> |
| * | "/" | "[" | "]" | "?" | "=" |
| * | "{" | "}" | SP | HT |
| * }</pre> |
| * <p> |
| * A string of text is parsed as a single word if it is quoted using double-quote marks. |
| * </p> |
| * <pre>{@code |
| * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) |
| * qdtext = <any TEXT except <">> |
| * }</pre> |
| * <p> |
| * The backslash character ("\") MAY be used as a single-character quoting mechanism only |
| * within quoted-string and comment constructs. |
| * </p> |
| * <pre> |
| * quoted-pair = "\" CHAR |
| * </pre> |
| * <h2>3.6 Transfer Codings</h2> |
| * <p> |
| * Parameters are in the form of attribute/value pairs. |
| * </p> |
| * <pre> |
| * parameter = attribute "=" value |
| * attribute = token |
| * value = token | quoted-string |
| * </pre> |
| * |
| * @author oleg at ural.ru Oleg Kalnichevski |
| * |
| */ |
| 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 <tt>true</tt> if all parameter values must be enclosed in |
| * quotation marks, <tt>false</tt> 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 <tt>true</tt> if the parameter value must |
| * be enclosed in quotation marks, even if it does not contain any special |
| * characters<tt>, false</tt> 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 representation of the attribute/value pair using |
| * formatting rules defined in RFC 2616 |
| * |
| * @param param the parameter to be formatted |
| * |
| * @return RFC 2616 conformant textual representation of the |
| * attribute/value pair |
| */ |
| public String format(final NameValuePair param) { |
| StringBuffer buffer = new StringBuffer(); |
| format(buffer, param); |
| return buffer.toString(); |
| } |
| } |