You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ol...@apache.org on 2005/05/26 20:21:15 UTC

svn commit: r178662 - in /jakarta/commons/proper/httpclient/trunk/src: java/org/apache/commons/httpclient/auth/ java/org/apache/commons/httpclient/cookie/ java/org/apache/commons/httpclient/util/ test/org/apache/commons/httpclient/

Author: olegk
Date: Thu May 26 11:21:14 2005
New Revision: 178662

URL: http://svn.apache.org/viewcvs?rev=178662&view=rev
Log:
PR #34961 (HttpClient does not correctly handle escaped characters in HTTP header elements)

Contributed by Oleg Kalnichevski
Reviewed by Ortwin Glück

Added:
    jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java   (with props)
    jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java   (with props)
Modified:
    jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/auth/DigestScheme.java
    jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/cookie/RFC2109Spec.java
    jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterParser.java
    jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestNoHost.java
    jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterParser.java

Modified: jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/auth/DigestScheme.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/auth/DigestScheme.java?rev=178662&r1=178661&r2=178662&view=diff
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/auth/DigestScheme.java (original)
+++ jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/auth/DigestScheme.java Thu May 26 11:21:14 2005
@@ -31,13 +31,17 @@
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.StringTokenizer;
 
 import org.apache.commons.httpclient.Credentials;
 import org.apache.commons.httpclient.HttpClientError;
 import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.NameValuePair;
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 import org.apache.commons.httpclient.util.EncodingUtil;
+import org.apache.commons.httpclient.util.ParameterFormatter;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -97,6 +101,7 @@
     private int qopVariant = QOP_MISSING;
     private String cnonce;
 
+    private final ParameterFormatter formatter;
     /**
      * Default constructor for the digest authetication scheme.
      * 
@@ -105,6 +110,8 @@
     public DigestScheme() {
         super();
         this.complete = false;
+        this.formatter = new ParameterFormatter();
+        this.formatter.setAlwaysUseQuotes(true);
     }
 
     /**
@@ -138,8 +145,8 @@
      */
     public DigestScheme(final String challenge) 
       throws MalformedChallengeException {
-        super(challenge);
-        this.complete = true;
+        this();
+        processChallenge(challenge);
     }
 
     /**
@@ -431,7 +438,7 @@
 
         return serverDigest;
     }
-    
+
     /**
      * Creates digest-response header as defined in RFC2617.
      * 
@@ -440,12 +447,12 @@
      * 
      * @return The digest-response as String.
      */
-    private String createDigestHeader(String uname, String digest) throws AuthenticationException {
+    private String createDigestHeader(final String uname, final String digest) 
+        throws AuthenticationException {
 
         LOG.trace("enter DigestScheme.createDigestHeader(String, Map, "
             + "String)");
 
-        StringBuffer sb = new StringBuffer();
         String uri = getParameter("uri");
         String realm = getParameter("realm");
         String nonce = getParameter("nonce");
@@ -455,22 +462,34 @@
         String qop = getParameter("qop");
         String algorithm = getParameter("algorithm");
 
-        sb.append("username=\"" + uname + "\"")
-          .append(", realm=\"" + realm + "\"")
-          .append(", nonce=\"" + nonce + "\"").append(", uri=\"" + uri + "\"")
-          .append(", response=\"" + response + "\"");
+        List params = new ArrayList(20);
+        params.add(new NameValuePair("username", uname));
+        params.add(new NameValuePair("realm", realm));
+        params.add(new NameValuePair("nonce", nonce));
+        params.add(new NameValuePair("uri", uri));
+        params.add(new NameValuePair("response", response));
+        
         if (qopVariant != QOP_MISSING) {
-            sb.append(", qop=\"" + getQopVariantString() + "\"")
-              .append(", nc="+ NC)
-              .append(", cnonce=\"" + cnonce + "\"");
+            params.add(new NameValuePair("qop", getQopVariantString()));
+            params.add(new NameValuePair("nc", NC));
+            params.add(new NameValuePair("cnonce", this.cnonce));
         }
         if (algorithm != null) {
-            sb.append(", algorithm=\"" + algorithm + "\"");
+            params.add(new NameValuePair("algorithm", algorithm));
         }    
         if (opaque != null) {
-            sb.append(", opaque=\"" + opaque + "\"");
+            params.add(new NameValuePair("opaque", opaque));
+        }
+
+        StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < params.size(); i++) {
+            NameValuePair param = (NameValuePair) params.get(i);
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            this.formatter.format(buffer, param);
         }
-        return sb.toString();
+        return buffer.toString();
     }
 
     private String getQopVariantString() {

Modified: jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/cookie/RFC2109Spec.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/cookie/RFC2109Spec.java?rev=178662&r1=178661&r2=178662&view=diff
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/cookie/RFC2109Spec.java (original)
+++ jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/cookie/RFC2109Spec.java Thu May 26 11:21:14 2005
@@ -31,6 +31,7 @@
 
 import org.apache.commons.httpclient.NameValuePair;
 import org.apache.commons.httpclient.Cookie;
+import org.apache.commons.httpclient.util.ParameterFormatter;
 
 /**
  * <p>RFC 2109 specific cookie management functions
@@ -51,12 +52,15 @@
 
 public class RFC2109Spec extends CookieSpecBase {
 
+    private final ParameterFormatter formatter;
+    
     /** Default constructor */    
     public RFC2109Spec() {
         super();
+        this.formatter = new ParameterFormatter();
+        this.formatter.setAlwaysUseQuotes(true);
     }
 
-
     /**
       * Parse RFC 2109 specific cookie attribute and update the corresponsing
       * {@link Cookie} properties.
@@ -189,60 +193,46 @@
      * Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
      * header as defined in RFC 2109 for backward compatibility with cookie
      * version 0
-     * @param name The name.
-     * @param value The value
+     * @param buffer The string buffer to use for output
+     * @param param The parameter.
      * @param version The cookie version 
-     * @return a string suitable for sending in a <tt>"Cookie"</tt> header.
      */
-
-    private String formatNameValuePair(
-        final String name, final String value, int version) {
-            
-        final StringBuffer buffer = new StringBuffer();
+    private void formatParam(final StringBuffer buffer, final NameValuePair param, int version) {
         if (version < 1) {
-            buffer.append(name);
+            buffer.append(param.getName());
             buffer.append("=");
-            if (value != null) {
-                buffer.append(value);   
+            if (param.getValue() != null) {
+                buffer.append(param.getValue());   
             }
         } else {
-            buffer.append(name);
-            buffer.append("=\"");
-            if (value != null) {
-                buffer.append(value);
-            }
-            buffer.append("\"");
+            this.formatter.format(buffer, param);
         }
-        return buffer.toString(); 
     }
 
     /**
      * Return a string suitable for sending in a <tt>"Cookie"</tt> header 
      * as defined in RFC 2109 for backward compatibility with cookie version 0
-     * @param cookie a {@link Cookie} to be formatted as string
+     * @param buffer The string buffer to use for output
+     * @param cookie The {@link Cookie} to be formatted as string
      * @param version The version to use.
-     * @return a string suitable for sending in a <tt>"Cookie"</tt> header.
      */
-    private String formatCookieAsVer(Cookie cookie, int version) {
-        LOG.trace("enter RFC2109Spec.formatCookieAsVer(Cookie)");
-        StringBuffer buf = new StringBuffer();
-        buf.append(formatNameValuePair(cookie.getName(), 
-            cookie.getValue(), version));
+    private void formatCookieAsVer(final StringBuffer buffer, final Cookie cookie, int version) {
+        String value = cookie.getValue();
+        if (value == null) {
+            value = "";
+        }
+        formatParam(buffer, new NameValuePair(cookie.getName(), value), version);
         if (cookie.getDomain() != null 
             && cookie.isDomainAttributeSpecified()) {
-                
-            buf.append("; ");
-            buf.append(formatNameValuePair("$Domain", 
-                cookie.getDomain(), version));
+            buffer.append("; ");
+            formatParam(buffer, new NameValuePair("$Domain", cookie.getDomain()), version);
         }
         if (cookie.getPath() != null && cookie.isPathAttributeSpecified()) {
-            buf.append("; ");
-            buf.append(formatNameValuePair("$Path", cookie.getPath(), version));
+            buffer.append("; ");
+            formatParam(buffer, new NameValuePair("$Path", cookie.getPath()), version);
         }
-        return buf.toString();
     }
 
-
     /**
      * Return a string suitable for sending in a <tt>"Cookie"</tt> header as
      * defined in RFC 2109
@@ -254,12 +244,13 @@
         if (cookie == null) {
             throw new IllegalArgumentException("Cookie may not be null");
         }
-        int ver = cookie.getVersion();
+        int version = cookie.getVersion();
         StringBuffer buffer = new StringBuffer();
-        buffer.append(formatNameValuePair("$Version", 
-          Integer.toString(ver), ver));
+        formatParam(buffer, 
+                new NameValuePair("$Version", Integer.toString(version)), 
+                version);
         buffer.append("; ");
-        buffer.append(formatCookieAsVer(cookie, ver));
+        formatCookieAsVer(buffer, cookie, version);
         return buffer.toString();
     }
 
@@ -281,11 +272,12 @@
             }
         }
         final StringBuffer buffer = new StringBuffer();
-        buffer.append(formatNameValuePair("$Version", 
-            Integer.toString(version), version));
+        formatParam(buffer, 
+                new NameValuePair("$Version", Integer.toString(version)), 
+                version);
         for (int i = 0; i < cookies.length; i++) {
             buffer.append("; ");
-            buffer.append(formatCookieAsVer(cookies[i], version));
+            formatCookieAsVer(buffer, cookies[i], version);
         }
         return buffer.toString();
     }

Added: jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java?rev=178662&view=auto
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java (added)
+++ jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java Thu May 26 11:21:14 2005
@@ -0,0 +1,241 @@
+/*
+ * $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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.httpclient.util;
+
+import org.apache.commons.httpclient.NameValuePair;
+
+/**
+ * <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>
+ * <h>2.1 Augmented BNF</h>
+ * <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>
+ * 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>
+ * 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>
+ * <h>3.6 Transfer Codings</h>
+ * <p>
+ *  Parameters are in the form of attribute/value pairs.
+ * </p>
+ * <pre>
+ * parameter               = attribute "=" value
+ * attribute               = token
+ * value                   = token | quoted-string
+ * </pre>
+ * 
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * 
+ * @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 <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 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();
+    }
+
+}

Propchange: jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterFormatter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterParser.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterParser.java?rev=178662&r1=178661&r2=178662&view=diff
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterParser.java (original)
+++ jakarta/commons/proper/httpclient/trunk/src/java/org/apache/commons/httpclient/util/ParameterParser.java Thu May 26 11:21:14 2005
@@ -142,16 +142,19 @@
         i1 = pos;
         i2 = pos;
         boolean quoted = false;
+        boolean charEscaped = false;
         while (hasChar()) {
             ch = chars[pos];
             if (!quoted && isOneOf(ch, terminators)) {
                 break;
             }
-            if (ch == '"') {
+            if (!charEscaped && ch == '"') {
                 quoted = !quoted;
             }
+            charEscaped = (!charEscaped && ch == '\\');
             i2++;
             pos++;
+
         }
         return getToken(true);
     }

Modified: jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestNoHost.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestNoHost.java?rev=178662&r1=178661&r2=178662&view=diff
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestNoHost.java (original)
+++ jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestNoHost.java Thu May 26 11:21:14 2005
@@ -64,6 +64,7 @@
         suite.addTest(TestRequestHeaders.suite());
         suite.addTest(TestStreams.suite());
         suite.addTest(TestParameterParser.suite());
+        suite.addTest(TestParameterFormatter.suite());
         suite.addTest(TestNVP.suite());
         suite.addTest(TestMethodCharEncoding.suite());
         suite.addTest(TestHttpVersion.suite());

Added: jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java?rev=178662&view=auto
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java (added)
+++ jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java Thu May 26 11:21:14 2005
@@ -0,0 +1,88 @@
+/*
+ * $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
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.httpclient;
+
+import org.apache.commons.httpclient.util.ParameterFormatter;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit tests for {@link ParameterFormatter}.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ */
+public class TestParameterFormatter extends TestCase {
+
+    // ------------------------------------------------------------ Constructor
+    public TestParameterFormatter(String testName) {
+        super(testName);
+    }
+
+    // ------------------------------------------------------------------- Main
+    public static void main(String args[]) {
+        String[] testCaseName = { TestParameterFormatter.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    // ------------------------------------------------------- TestCase Methods
+
+    public static Test suite() {
+        return new TestSuite(TestParameterFormatter.class);
+    }
+
+    public void testBasicValueFormatting() throws Exception {
+        ParameterFormatter formatter = new ParameterFormatter();
+        
+        NameValuePair param1 = new NameValuePair("param", "regular_stuff"); 
+        NameValuePair param2 = new NameValuePair("param", "this\\that"); 
+        NameValuePair param3 = new NameValuePair("param", "this,that"); 
+        NameValuePair param4 = new NameValuePair("param", "quote marks (\") must be escaped"); 
+        NameValuePair param5 = new NameValuePair("param", "back slash (\\) must be escaped too"); 
+        NameValuePair param6 = new NameValuePair("param", "values with\tblanks must always be quoted"); 
+        
+        formatter.setAlwaysUseQuotes(false);
+        assertEquals("param=regular_stuff", formatter.format(param1));
+        assertEquals("param=\"this\\\\that\"", formatter.format(param2));
+        assertEquals("param=\"this,that\"", formatter.format(param3));
+        assertEquals("param=\"quote marks (\\\") must be escaped\"", formatter.format(param4));
+        assertEquals("param=\"back slash (\\\\) must be escaped too\"", formatter.format(param5));
+        assertEquals("param=\"values with\tblanks must always be quoted\"", formatter.format(param6));
+
+        formatter.setAlwaysUseQuotes(true);
+        assertEquals("param=\"regular_stuff\"", formatter.format(param1));
+        assertEquals("param=\"this\\\\that\"", formatter.format(param2));
+        assertEquals("param=\"this,that\"", formatter.format(param3));
+        assertEquals("param=\"quote marks (\\\") must be escaped\"", formatter.format(param4));
+        assertEquals("param=\"back slash (\\\\) must be escaped too\"", formatter.format(param5));
+        assertEquals("param=\"values with\tblanks must always be quoted\"", formatter.format(param6));
+    }
+    
+}

Propchange: jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterFormatter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterParser.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterParser.java?rev=178662&r1=178661&r2=178662&view=diff
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterParser.java (original)
+++ jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestParameterParser.java Thu May 26 11:21:14 2005
@@ -1,4 +1,7 @@
 /*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
  * ====================================================================
  *
  *  Copyright 1999-2004 The Apache Software Foundation
@@ -21,8 +24,6 @@
  * information on the Apache Software Foundation, please see
  * <http://www.apache.org/>.
  *
- * [Additional notices, if required by prior licensing conditions]
- *
  */
 
 package org.apache.commons.httpclient;
@@ -38,7 +39,7 @@
 /**
  * Unit tests for {@link ParameterParser}.
  *
- * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
  */
 public class TestParameterParser extends TestCase {
 
@@ -98,4 +99,27 @@
         params = parser.parse(s, ';');
         assertEquals(0, params.size());
     }
+    
+    public void testParsingEscapedChars() {
+        String s = "param = \"stuff\\\"; more stuff\"";
+        ParameterParser parser = new ParameterParser();
+        List params = parser.parse(s, ';');
+        assertEquals(1, params.size());
+        assertEquals("param", 
+                ((NameValuePair)params.get(0)).getName());
+        assertEquals("stuff\\\"; more stuff", 
+                ((NameValuePair)params.get(0)).getValue());
+
+        s = "param = \"stuff\\\\\"; anotherparam";
+        params = parser.parse(s, ';');
+        assertEquals(2, params.size());
+        assertEquals("param", 
+                ((NameValuePair)params.get(0)).getName());
+        assertEquals("stuff\\\\", 
+                ((NameValuePair)params.get(0)).getValue());
+        assertEquals("anotherparam", 
+                ((NameValuePair)params.get(1)).getName());
+        assertNull(
+                ((NameValuePair)params.get(1)).getValue());
+    }    
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org