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 2003/07/13 15:54:51 UTC

cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient TestParameterParser.java TestHeaderElement.java TestNoHost.java

olegk       2003/07/13 06:54:51

  Modified:    httpclient/src/java/org/apache/commons/httpclient
                        ChunkedInputStream.java Header.java
                        HeaderElement.java HttpMethodBase.java
                        HttpState.java package.html
               httpclient/src/java/org/apache/commons/httpclient/auth
                        AuthChallengeParser.java HttpAuthenticator.java
               httpclient/src/java/org/apache/commons/httpclient/cookie
                        CookieSpecBase.java
               httpclient/src/java/org/apache/commons/httpclient/util
                        DateParser.java
               httpclient/src/test/org/apache/commons/httpclient
                        TestHeaderElement.java TestNoHost.java
  Added:       httpclient/src/java/org/apache/commons/httpclient/util
                        ParameterParser.java
               httpclient/src/test/org/apache/commons/httpclient
                        TestParameterParser.java
  Log:
  Bug fix #21210 (HeaderElement#parse(String) implementation is not optimal)
  
  Changelog:
  - Header parsing routines completely reworked
  - Handling of Netscape cookies improved
  - Javadoc tags cleaned up
  
  Contributed by Oleg Kalnichevski
  Reviewed by Michael Becke
  
  Revision  Changes    Path
  1.17      +3 -5      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java
  
  Index: ChunkedInputStream.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- ChunkedInputStream.java	8 May 2003 17:33:51 -0000	1.16
  +++ ChunkedInputStream.java	13 Jul 2003 13:54:50 -0000	1.17
  @@ -78,8 +78,6 @@
    * not requiring the client to remember to read the entire contents of the
    * response.</p>
    *
  - * @see ResponseInputStream
  - *
    * @author Ortwin Gl�ck
    * @author Sean C. Sullivan
    * @author Martin Elwin
  
  
  
  1.11      +18 -4     jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Header.java
  
  Index: Header.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Header.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- Header.java	28 Jan 2003 04:40:20 -0000	1.10
  +++ Header.java	13 Jul 2003 13:54:50 -0000	1.11
  @@ -123,9 +123,23 @@
        * @see HeaderElement#parse
        * @throws HttpException When ? occurs
        * @return an array of header elements
  +     * 
  +     * @deprecated Use #getElements
        */
       public HeaderElement[] getValues() throws HttpException {
           return HeaderElement.parse(getValue());
  +    }
  +
  +    /**
  +     * Returns an array of {@link HeaderElement}s
  +     * constructed from my value.
  +     *
  +     * @see HeaderElement#parseElements(String)
  +     * 
  +     * @return an array of header elements
  +     */
  +    public HeaderElement[] getElements() {
  +        return HeaderElement.parseElements(getValue());
       }
   
   }
  
  
  
  1.19      +99 -234   jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HeaderElement.java
  
  Index: HeaderElement.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HeaderElement.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- HeaderElement.java	14 Apr 2003 04:06:55 -0000	1.18
  +++ HeaderElement.java	13 Jul 2003 13:54:50 -0000	1.19
  @@ -63,15 +63,13 @@
   
   package org.apache.commons.httpclient;
   
  +import java.util.ArrayList;
  +import java.util.List;
  +
  +import org.apache.commons.httpclient.util.ParameterParser;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   
  -import java.util.BitSet;
  -import java.util.NoSuchElementException;
  -import java.util.StringTokenizer;
  -import java.util.Vector;
  -
  -
   /**
    * <p>One element of an HTTP header's value.</p>
    * <p>
  @@ -114,6 +112,7 @@
    * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
    * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
  + * @author <a href="mailto:oleg@ural.com">Oleg Kalnichevski</a>
    * 
    * @since 1.0
    * @version $Revision$ $Date$
  @@ -148,87 +147,47 @@
       public HeaderElement(String name, String value,
               NameValuePair[] parameters) {
           super(name, value);
  -        setParameters(parameters);
  +        this.parameters = parameters;
       }
   
  -    // -------------------------------------------------------- Constants
  -
  -    /** Log object for this class. */
  -    private static final Log LOG = LogFactory.getLog(HeaderElement.class);
  -
       /**
  -     * Map of numeric values to whether or not the
  -     * corresponding character is a "separator
  -     * character" (tspecial).
  -     */
  -    private static final BitSet SEPARATORS = new BitSet(128);
  -
  -    /**
  -     * Map of numeric values to whether or not the
  -     * corresponding character is a "token
  -     * character".
  -     */
  -    private static final BitSet TOKEN_CHAR = new BitSet(128);
  +     * Constructor with array of characters.
  +     *
  +     * @param chars the array of characters
  +     * @param offset - the initial offset.
  +     * @param length - the length.
  +     */
  +    public HeaderElement(char[] chars, int offset, int length) {
  +        this();
  +        if (chars == null) {
  +            return;
  +        }
  +        ParameterParser parser = new ParameterParser();
  +        List params = parser.parse(chars, offset, length, ';');
  +        if (params.size() > 0) {
  +            NameValuePair element = (NameValuePair)params.remove(0);
  +            setName(element.getName());  
  +            setValue(element.getValue());
  +            if (params.size() > 0) {
  +                this.parameters = (NameValuePair[])
  +                    params.toArray(new NameValuePair[params.size()]);    
  +            }
  +        }
  +    }
   
       /**
  -     * Map of numeric values to whether or not the
  -     * corresponding character is an "unsafe
  -     * character".
  +     * Constructor with array of characters.
  +     *
  +     * @param chars the array of characters
        */
  -    private static final BitSet UNSAFE_CHAR = new BitSet(128);
  +    public HeaderElement(char[] chars) {
  +        this(chars, 0, chars.length);
  +    }
   
  -    /**
  -     * Static initializer for {@link #SEPARATORS},
  -     * {@link #TOKEN_CHAR}, and {@link #UNSAFE_CHAR}.
  -     */
  -    static {
  -        // rfc-2068 tspecial
  -        SEPARATORS.set('(');
  -        SEPARATORS.set(')');
  -        SEPARATORS.set('<');
  -        SEPARATORS.set('>');
  -        SEPARATORS.set('@');
  -        SEPARATORS.set(',');
  -        SEPARATORS.set(';');
  -        SEPARATORS.set(':');
  -        SEPARATORS.set('\\');
  -        SEPARATORS.set('"');
  -        SEPARATORS.set('/');
  -        SEPARATORS.set('[');
  -        SEPARATORS.set(']');
  -        SEPARATORS.set('?');
  -        SEPARATORS.set('=');
  -        SEPARATORS.set('{');
  -        SEPARATORS.set('}');
  -        SEPARATORS.set(' ');
  -        SEPARATORS.set('\t');
  -
  -        // rfc-2068 token
  -        for (int ch = 32; ch < 127; ch++) {
  -            TOKEN_CHAR.set(ch);
  -        }
  -        TOKEN_CHAR.xor(SEPARATORS);
  +    // -------------------------------------------------------- Constants
   
  -        // rfc-1738 unsafe characters, including CTL and SP, and excluding
  -        // "#" and "%"
  -        for (int ch = 0; ch < 32; ch++) {
  -            UNSAFE_CHAR.set(ch);
  -        }
  -        UNSAFE_CHAR.set(' ');
  -        UNSAFE_CHAR.set('<');
  -        UNSAFE_CHAR.set('>');
  -        UNSAFE_CHAR.set('"');
  -        UNSAFE_CHAR.set('{');
  -        UNSAFE_CHAR.set('}');
  -        UNSAFE_CHAR.set('|');
  -        UNSAFE_CHAR.set('\\');
  -        UNSAFE_CHAR.set('^');
  -        UNSAFE_CHAR.set('~');
  -        UNSAFE_CHAR.set('[');
  -        UNSAFE_CHAR.set(']');
  -        UNSAFE_CHAR.set('`');
  -        UNSAFE_CHAR.set(127);
  -    }
  +    /** Log object for this class. */
  +    private static final Log LOG = LogFactory.getLog(HeaderElement.class);
   
       // ----------------------------------------------------- Instance Variables
   
  @@ -247,187 +206,91 @@
           return this.parameters;
       }
   
  -    /**
  -     * 
  -     * @param pairs The new parameters.  May be null.
  -     */
  -    protected void setParameters(final NameValuePair[] pairs) {
  -        parameters = pairs;
  -    }
       // --------------------------------------------------------- Public Methods
   
       /**
        * This parses the value part of a header. The result is an array of
        * HeaderElement objects.
        *
  -     * @param headerValue  the string representation of the header value
  +     * @param headerValue  the array of char representation of the header value
        *                     (as received from the web server).
  -     * @return the header elements containing <code>Header</code> elements.
  -     * @throws HttpException if the above syntax rules are violated.
  +     * @return array of {@link HeaderElement}s.
        */
  -    public static final HeaderElement[] parse(String headerValue)
  -        throws HttpException {
  +    public static final HeaderElement[] parseElements(char[] headerValue) {
               
  -        LOG.trace("enter HeaderElement.parse(String)");
  +        LOG.trace("enter HeaderElement.parseElements(char[])");
   
           if (headerValue == null) {
  -            return null;
  +            return new HeaderElement[] {};
           }
  +        List elements = new ArrayList(); 
           
  -        Vector elements = new Vector();
  -        StringTokenizer tokenizer =
  -            new StringTokenizer(headerValue.trim(), ",");
  -
  -        while (tokenizer.countTokens() > 0) {
  -            String nextToken = tokenizer.nextToken();
  -
  -            // FIXME: refactor into private method named ?
  -            // careful... there may have been a comma in a quoted string
  -            try {
  -                while (HeaderElement.hasOddNumberOfQuotationMarks(nextToken)) {
  -                    nextToken += "," + tokenizer.nextToken();
  -                }
  -            } catch (NoSuchElementException exception) {
  -                throw new HttpException(
  -                    "Bad header format: wrong number of quotation marks");
  +        int i = 0;
  +        int from = 0;
  +        int len = headerValue.length;
  +        boolean qouted = false;
  +        while(i < len) {
  +            char ch = headerValue[i];
  +            if (ch == '"') {
  +                qouted = !qouted;
               }
  -
  -            // FIXME: Refactor out into a private method named ?
  -            try {
  -                /*
  -                 * Following to RFC 2109 and 2965, in order not to conflict
  -                 * with the next header element, make it sure to parse tokens.
  -                 * the expires date format is "Wdy, DD-Mon-YY HH:MM:SS GMT".
  -                 * Notice that there is always comma(',') sign.
  -                 * For the general cases, rfc1123-date, rfc850-date.
  -                 */
  -                if (tokenizer.hasMoreTokens()) {
  -                    String s = nextToken.toLowerCase();
  -                    if (s.endsWith("mon") 
  -                        || s.endsWith("tue")
  -                        || s.endsWith("wed") 
  -                        || s.endsWith("thu")
  -                        || s.endsWith("fri")
  -                        || s.endsWith("sat")
  -                        || s.endsWith("sun")
  -                        || s.endsWith("monday") 
  -                        || s.endsWith("tuesday") 
  -                        || s.endsWith("wednesday") 
  -                        || s.endsWith("thursday") 
  -                        || s.endsWith("friday") 
  -                        || s.endsWith("saturday") 
  -                        || s.endsWith("sunday")) {
  -
  -                        nextToken += "," + tokenizer.nextToken();
  -                    }
  -                }
  -            } catch (NoSuchElementException exception) {
  -                throw new HttpException
  -                    ("Bad header format: parsing with wrong header elements");
  -            }
  -
  -            String tmp = nextToken.trim();
  -            if (!tmp.endsWith(";")) {
  -                tmp += ";";
  +            HeaderElement element = null;
  +            if ((!qouted) && (ch == ',')) {
  +                element = new HeaderElement(headerValue, from, i);
  +                from = i + 1;
  +            } else if (i == len - 1) {
  +                element = new HeaderElement(headerValue, from, len);
               }
  -            char[] header = tmp.toCharArray();
  -
  -            // FIXME: refactor into a private method named? parseElement?
  -            boolean inAString = false;
  -            int startPos = 0;
  -            HeaderElement element = new HeaderElement();
  -            Vector paramlist = new Vector();
  -            for (int i = 0 ; i < header.length ; i++) {
  -                if (header[i] == ';' && !inAString) {
  -                    NameValuePair pair = parsePair(header, startPos, i);
  -                    if (pair == null) {
  -                        throw new HttpException(
  -                            "Bad header format: empty name/value pair in" 
  -                            + nextToken);
  -
  -                    // the first name/value pair are handled differently
  -                    } else if (startPos == 0) {
  -                        element.setName(pair.getName());
  -                        element.setValue(pair.getValue());
  -                    } else {
  -                        paramlist.addElement(pair);
  -                    }
  -                    startPos = i + 1;
  -                } else if (header[i] == '"' 
  -                    && !(inAString && i > 0 && header[i - 1] == '\\')) {
  -                    inAString = !inAString;
  -                }
  +            if ((element != null) && (element.getName() != null)) {
  +                elements.add(element);
               }
  -
  -            // now let's add all the parameters into the header element
  -            if (paramlist.size() > 0) {
  -                NameValuePair[] tmp2 = new NameValuePair[paramlist.size()];
  -                paramlist.copyInto((NameValuePair[]) tmp2);
  -                element.setParameters (tmp2);
  -                paramlist.removeAllElements();
  -            }
  -
  -            // and save the header element into the list of header elements
  -            elements.addElement(element);
  +            i++;
           }
  -
  -        HeaderElement[] headerElements = new HeaderElement[elements.size()];
  -        elements.copyInto((HeaderElement[]) headerElements);
  -        return headerElements;
  +        return (HeaderElement[])
  +            elements.toArray(new HeaderElement[elements.size()]);
       }
   
       /**
  -     * Return <tt>true</tt> if <i>string</i> has
  -     * an odd number of <tt>"</tt> characters.
  +     * This parses the value part of a header. The result is an array of
  +     * HeaderElement objects.
        *
  -     * @param string the string to test
  -     * @return true if there are an odd number of quotation marks, false 
  -     *      otherwise
  +     * @param headerValue  the string representation of the header value
  +     *                     (as received from the web server).
  +     * @return array of {@link HeaderElement}s.
  +     * @throws HttpException if the above syntax rules are violated.
        */
  -    private static final boolean hasOddNumberOfQuotationMarks(String string) {
  -        boolean odd = false;
  -        int start = -1;
  -        while ((start = string.indexOf('"', start + 1)) != -1) {
  -            odd = !odd;
  +    public static final HeaderElement[] parseElements(String headerValue) {
  +            
  +        LOG.trace("enter HeaderElement.parseElements(String)");
  +
  +        if (headerValue == null) {
  +            return new HeaderElement[] {};
           }
  -        return odd;
  +        return parseElements(headerValue.toCharArray());
       }
   
       /**
  -     * Parse a header character array into a {@link NameValuePair}
  +     * This parses the value part of a header. The result is an array of
  +     * HeaderElement objects.
        *
  -     * @param header the character array to parse
  -     * @param start the starting position of the text within the array
  -     * @param end the end position of the text within the array
  -     * @return a {@link NameValuePair} representing the header
  +     * @param headerValue  the string representation of the header value
  +     *                     (as received from the web server).
  +     * @return array of {@link HeaderElement}s.
  +     * @throws HttpException if the above syntax rules are violated.
  +     * 
  +     * @deprecated Use #parseElements(String).
        */
  -    private static final NameValuePair parsePair(char[] header, 
  -        int start, int end) {
  +    public static final HeaderElement[] parse(String headerValue)
  +        throws HttpException {
               
  -        LOG.trace("enter HeaderElement.parsePair(char[], int, int)");
  +        LOG.trace("enter HeaderElement.parse(String)");
   
  -        NameValuePair pair = null;
  -        String name = new String(header, start, end - start).trim();
  -        String value = null;
  -
  -        //TODO: This would certainly benefit from a StringBuffer
  -        int index = name.indexOf("=");
  -        if (index >= 0) {
  -            if ((index + 1) < name.length()) {
  -                value = name.substring(index + 1).trim();
  -                // strip quotation marks
  -                if (value.startsWith("\"") && value.endsWith("\"")) {
  -                    value = value.substring(1, value.length() - 1);
  -                }
  -            }
  -            name = name.substring(0, index).trim();
  +        if (headerValue == null) {
  +            return new HeaderElement[] {};
           }
  -
  -        pair = new NameValuePair(name, value);
  -
  -        return pair;
  +        return parseElements(headerValue.toCharArray());
       }
  -
  +         
   
       /**
        * Returns parameter with the given name, if found. Otherwise null 
  @@ -438,8 +301,11 @@
        */
   
       public NameValuePair getParameterByName(String name) {
  +
  +        LOG.trace("enter HeaderElement.getParameterByName(String)");
  +
           if (name == null) {
  -            throw new NullPointerException("Name is null");
  +            throw new IllegalArgumentException("Name may not be null");
           } 
           NameValuePair found = null;
           NameValuePair parameters[] = getParameters();
  @@ -454,7 +320,6 @@
           }
           return found;
       }
  -
   
   }
   
  
  
  
  1.165     +14 -18    jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java
  
  Index: HttpMethodBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v
  retrieving revision 1.164
  retrieving revision 1.165
  diff -u -r1.164 -r1.165
  --- HttpMethodBase.java	11 Jul 2003 01:07:29 -0000	1.164
  +++ HttpMethodBase.java	13 Jul 2003 13:54:50 -0000	1.165
  @@ -2054,7 +2054,7 @@
                       LOG.warn("Unsupported transfer encoding: " + transferEncoding);
                   }
               }
  -            HeaderElement[] encodings = transferEncodingHeader.getValues();
  +            HeaderElement[] encodings = transferEncodingHeader.getElements();
               // The chunked encoding must be the last one applied
               // RFC2616, 14.41
               int len = encodings.length;            
  @@ -2655,20 +2655,16 @@
           LOG.trace("enter getContentCharSet( Header contentheader )");
           String charset = null;
           if (contentheader != null) {
  -            try {
  -                HeaderElement values[] = contentheader.getValues();
  -                // I expect only one header element to be there
  -                // No more. no less
  -                if (values.length == 1) {
  -                    NameValuePair param = values[0].getParameterByName("charset");
  -                    if (param != null) {
  -                        // If I get anything "funny" 
  -                        // UnsupportedEncondingException will result
  -                        charset = param.getValue();
  -                    }
  +            HeaderElement values[] = contentheader.getElements();
  +            // I expect only one header element to be there
  +            // No more. no less
  +            if (values.length == 1) {
  +                NameValuePair param = values[0].getParameterByName("charset");
  +                if (param != null) {
  +                    // If I get anything "funny" 
  +                    // UnsupportedEncondingException will result
  +                    charset = param.getValue();
                   }
  -            } catch (HttpException e) {
  -                LOG.error(e);
               }
           }
           if (charset == null) {
  
  
  
  1.25      +9 -8      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java
  
  Index: HttpState.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpState.java,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- HttpState.java	5 Jul 2003 22:31:20 -0000	1.24
  +++ HttpState.java	13 Jul 2003 13:54:50 -0000	1.25
  @@ -233,7 +233,7 @@
        * 
        * @return an array of my {@link Cookie}s.
        * 
  -     * @see #getCookies(String, int, String, boolean, java.util.Date)
  +     * @see #getCookies(String, int, String, boolean)
        * 
        */
       public synchronized Cookie[] getCookies() {
  @@ -251,9 +251,10 @@
        * @param secure <code>true</code> when using HTTPS
        * @return an array of my {@link Cookie}s.
        * 
  -     * @see Cookie#matches
        * @see #getCookies()
        * 
  +     * @deprecated Use {@link CookieSpec#match(String,int,String,boolean,Cookie)}
  +     * 
        */
       public synchronized Cookie[] getCookies(
           String domain, 
  @@ -455,8 +456,8 @@
        * @param proxyHost the proxy host
        * @param credentials the authentication credentials for the given realm
        * 
  -     * @see #getProxyCredentials(String)
  -     * @see #setCredentials(String, Credentials)
  +     * @see #getProxyCredentials(String,String)
  +     * @see #setCredentials(String, String, Credentials)
        * 
        */
       public synchronized void setProxyCredentials(
  
  
  
  1.10      +3 -3      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/package.html,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- package.html	17 Dec 2002 02:41:38 -0000	1.9
  +++ package.html	13 Jul 2003 13:54:50 -0000	1.10
  @@ -82,12 +82,12 @@
            <dd>
               an enumeration of HttpStatus codes.
            </dd>
  -         <dt>{@link org.apache.commons.httpclient.RequestOutputStream}</dt>
  +         <dt>{@link org.apache.commons.httpclient.ChunkedOutputStream}</dt>
            <dd>
               an {@link java.io.OutputStream} wrapper supporting the "chunked"
               transfer encoding.
            </dd>
  -         <dt>{@link org.apache.commons.httpclient.ResponseInputStream}</dt>
  +         <dt>{@link org.apache.commons.httpclient.ChunkedInputStream}</dt>
            <dd>
               an {@link java.io.InputStream} wrapper supporting the "chunked"
               transfer encoding.
  
  
  
  1.5       +21 -113   jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthChallengeParser.java
  
  Index: AuthChallengeParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/AuthChallengeParser.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- AuthChallengeParser.java	6 Apr 2003 22:31:53 -0000	1.4
  +++ AuthChallengeParser.java	13 Jul 2003 13:54:51 -0000	1.5
  @@ -63,8 +63,12 @@
   
   package org.apache.commons.httpclient.auth;
   
  -import java.util.Map;
   import java.util.HashMap;
  +import java.util.List;
  +import java.util.Map;
  +
  +import org.apache.commons.httpclient.NameValuePair;
  +import org.apache.commons.httpclient.util.ParameterParser;
   
   /**
    * This class provides utility methods for parsing HTTP www and proxy authentication 
  @@ -92,12 +96,12 @@
           if (challengeStr == null) {
               throw new IllegalArgumentException("Challenge may not be null"); 
           }
  -        int i = challengeStr.indexOf(' ');
  +        int idx = challengeStr.indexOf(' ');
           String s = null; 
  -        if (i == -1) {
  +        if (idx == -1) {
               s = challengeStr;
           } else {
  -            s = challengeStr.substring(0, i);
  +            s = challengeStr.substring(0, idx);
           }
           if (s.equals("")) {
               throw new MalformedChallengeException("Invalid challenge: " + challengeStr);
  @@ -121,114 +125,18 @@
           if (challengeStr == null) {
               throw new IllegalArgumentException("Challenge may not be null"); 
           }
  -        int i = challengeStr.indexOf(' ');
  -        if (i == -1) {
  +        int idx = challengeStr.indexOf(' ');
  +        if (idx == -1) {
               throw new MalformedChallengeException("Invalid challenge: " + challengeStr);
           }
  -
  -        Map elements = new HashMap();
  -
  -        i++;
  -        int len = challengeStr.length();
  -
  -        String name = null;
  -        String value = null;
  -
  -        StringBuffer buffer = new StringBuffer();
  -
  -        boolean parsingName = true;
  -        boolean inQuote = false;
  -        boolean gotIt = false;
  -
  -        while (i < len) {
  -            // Parse one char at a time 
  -            char ch = challengeStr.charAt(i);
  -            i++;
  -            // Process the char
  -            if (parsingName) {
  -                // parsing name
  -                if (ch == '=') {
  -                    name = buffer.toString().trim();
  -                    parsingName = false;
  -                    buffer.setLength(0);
  -                } else if (ch == ',') {
  -                    name = buffer.toString().trim();
  -                    value = null;
  -                    gotIt = true;
  -                    buffer.setLength(0);
  -                } else {
  -                    buffer.append(ch);
  -                }
  -                // Have I reached the end of the challenge string?
  -                if (i == len) {
  -                    name = buffer.toString().trim();
  -                    value = null;
  -                    gotIt = true;
  -                }
  -            } else {
  -                //parsing value
  -                if (!inQuote) {
  -                    // Value is not quoted or not found yet
  -                    if (ch == ',') {
  -                        value = buffer.toString().trim();
  -                        gotIt = true;
  -                        buffer.setLength(0);
  -                    } else {
  -                        // no value yet
  -                        if (buffer.length() == 0) {
  -                            if (ch == ' ') {
  -                                //discard
  -                            } else if (ch == '\t') {
  -                                //discard
  -                            } else if (ch == '\n') {
  -                                //discard
  -                            } else if (ch == '\r') {
  -                                //discard
  -                            } else {
  -                                // otherwise add to the buffer
  -                                buffer.append(ch);
  -                                if (ch == '"') {
  -                                    inQuote = true;
  -                                }
  -                            }
  -                        } else {
  -                            // already got something
  -                            // just keep on adding to the buffer
  -                            buffer.append(ch);
  -                        }
  -                    }
  -                } else {
  -                    // Value is quoted
  -                    // Keep on adding until closing quote is encountered
  -                    buffer.append(ch);
  -                    if (ch == '"') {
  -                        inQuote = false;
  -                    }
  -                }
  -                // Have I reached the end of the challenge string?
  -                if (i == len) {
  -                    value = buffer.toString().trim();
  -                    gotIt = true;
  -                }
  -            }
  -            if (gotIt) {
  -                // Got something
  -                if ((name == null) || (name.equals(""))) {
  -                    throw new MalformedChallengeException("Invalid challenge: " + challengeStr);
  -                }
  -                // Strip quotes when present
  -                if ((value != null) && (value.length() > 1)) {
  -                    if ((value.charAt(0) == '"') 
  -                     && (value.charAt(value.length() - 1) == '"')) {
  -                        value = value.substring(1, value.length() - 1);  
  -                     }
  -                }
  -                
  -                elements.put(name, value);
  -                parsingName = true;
  -                gotIt = false;
  -            }
  +        Map map = new HashMap();
  +        ParameterParser parser = new ParameterParser();
  +        List params = parser.parse(
  +            challengeStr.substring(idx + 1, challengeStr.length()), ',');
  +        for (int i = 0; i < params.size(); i++) {
  +            NameValuePair param = (NameValuePair)params.get(i);
  +            map.put(param.getName().toLowerCase(), param.getValue());
           }
  -        return elements;
  +        return map;
       }
   }
  
  
  
  1.8       +6 -6      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java
  
  Index: HttpAuthenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- HttpAuthenticator.java	26 May 2003 22:07:22 -0000	1.7
  +++ HttpAuthenticator.java	13 Jul 2003 13:54:51 -0000	1.8
  @@ -261,7 +261,7 @@
        * 
        * @throws AuthenticationException when a parsing or other error occurs
   
  -     * @see HttpState#setCredentials(String,Credentials)
  +     * @see HttpState#setCredentials(String,String,Credentials)
        */
       public static boolean authenticateProxyDefault(
           HttpMethod method, 
  @@ -342,7 +342,7 @@
        * 
        * @throws AuthenticationException when a parsing or other error occurs
   
  -     * @see HttpState#setCredentials(String,Credentials)
  +     * @see HttpState#setCredentials(String,String,Credentials)
        */
       public static boolean authenticate(
           AuthScheme authscheme, 
  @@ -374,7 +374,7 @@
        * 
        * @throws AuthenticationException when a parsing or other error occurs
   
  -     * @see HttpState#setCredentials(String,Credentials)
  +     * @see HttpState#setCredentials(String,String,Credentials)
        */
       public static boolean authenticateProxy(
           AuthScheme authscheme, 
  
  
  
  1.17      +29 -20    jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/cookie/CookieSpecBase.java
  
  Index: CookieSpecBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/cookie/CookieSpecBase.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- CookieSpecBase.java	12 Jun 2003 19:12:16 -0000	1.16
  +++ CookieSpecBase.java	13 Jul 2003 13:54:51 -0000	1.17
  @@ -70,7 +70,6 @@
   import org.apache.commons.httpclient.Cookie;
   import org.apache.commons.httpclient.Header;
   import org.apache.commons.httpclient.HeaderElement;
  -import org.apache.commons.httpclient.HttpException;
   import org.apache.commons.httpclient.NameValuePair;
   import org.apache.commons.httpclient.util.DateParseException;
   import org.apache.commons.httpclient.util.DateParser;
  @@ -166,14 +165,7 @@
               path = PATH_DELIM;
           }
           host = host.toLowerCase();
  -    
  -        HeaderElement[] headerElements = null;
  -        try {
  -            headerElements = HeaderElement.parse(header);
  -        } catch (HttpException e) {
  -            throw new MalformedCookieException(e.getMessage());
  -        } 
  -    
  +
           String defaultPath = path;    
           int lastSlashIndex = defaultPath.lastIndexOf(PATH_DELIM);
           if (lastSlashIndex >= 0) {
  @@ -183,6 +175,31 @@
               }
               defaultPath = defaultPath.substring(0, lastSlashIndex);
           }
  +
  +        HeaderElement[] headerElements = null;
  +
  +        boolean isNetscapeCookie = false; 
  +        int i1 = header.toLowerCase().indexOf("expires=");
  +        if (i1 != -1) {
  +            i1 += "expires=".length();
  +            int i2 = header.indexOf(";", i1);
  +            if (i2 == -1) {
  +                i2 = header.length(); 
  +            }
  +            try {
  +                DateParser.parseDate(header.substring(i1, i2));
  +                isNetscapeCookie = true; 
  +            } catch(DateParseException e) {
  +                // Does not look like a valid expiry date
  +            }
  +        }
  +        if (isNetscapeCookie) {
  +            headerElements = new HeaderElement[] {
  +                    new HeaderElement(header.toCharArray())
  +            };
  +        } else {
  +            headerElements = HeaderElement.parseElements(header.toCharArray());
  +        }
           
           Cookie[] cookies = new Cookie[headerElements.length];
   
  @@ -330,14 +347,6 @@
               if (paramValue == null) {
                   throw new MalformedCookieException(
                       "Missing value for expires attribute");
  -            }
  -            // trim single quotes around expiry if present
  -            // see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5279
  -            if (paramValue.length() > 1 
  -                && paramValue.startsWith("'") 
  -                && paramValue.endsWith("'")) {
  -                paramValue 
  -                    = paramValue.substring (1, paramValue.length() - 1);
               }
   
               try {
  
  
  
  1.4       +12 -3     jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/DateParser.java
  
  Index: DateParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/DateParser.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- DateParser.java	26 May 2003 21:51:37 -0000	1.3
  +++ DateParser.java	13 Jul 2003 13:54:51 -0000	1.4
  @@ -144,6 +144,15 @@
           if (dateValue == null) {
               throw new IllegalArgumentException("dateValue is null");
           }
  +
  +        // trim single quotes around date if present
  +        // see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5279
  +        if (dateValue.length() > 1 
  +            && dateValue.startsWith("'") 
  +            && dateValue.endsWith("'"))
  +        {
  +            dateValue = dateValue.substring (1, dateValue.length() - 1);
  +        }
           
           SimpleDateFormat dateParser = null;
           
  
  
  
  1.1                  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/util/ParameterParser.java
  
  Index: ParameterParser.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.commons.httpclient.util;
  import java.util.ArrayList;
  import java.util.List;
  
  import org.apache.commons.httpclient.NameValuePair;
  
  /**
   * A simple parser intended to parse sequences of name/value pairs.
   * Parameter values are exptected to be enclosed in quotes if they 
   * contain unsafe characters, such as '=' characters or separators.
   * Parameter values are optional and can be omitted. 
   * 
   * <p>
   *  <code>param1 = value; param2 = "anything goes; really"; param3</code>
   * </p>
   * 
   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
   */
  
  public class ParameterParser {
      
      /** String to be parsed */
      private char[] chars = null;
      
      /** Current position in the string */    
      private int pos = 0;
  
      /** Maximum position in the string */    
      private int len = 0;
  
      /** Start of a token */
      private int i1 = 0;
  
      /** End of a token */
      private int i2 = 0;
      
      /** Default ParameterParser constructor */
      public ParameterParser() {
          super();
      }
  
  
      /** Are there any characters left to parse? */
      private boolean hasChar() {
          return this.pos < this.len;
      }
  
      
      /** A helper method to process the parsed token. */
      private String getToken(boolean quoted) {
          // Trim leading white spaces
          while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) {
              i1++;
          }
          // Trim trailing white spaces
          while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) {
              i2--;
          }
          // Strip away quotes if necessary
          if (quoted) {
              if (((i2 - i1) >= 2) && 
                  (chars[i1] == '"') &&
                  (chars[i2 - 1] == '"') ) {
                  i1++;
                  i2--;
              }
          }
          String result = null;
          if (i2 > i1) {
              result = new String(chars, i1, i2 - i1);
          }
          return result;
      }
  
  
      /** Is given character present in the array of characters? */
      private boolean isOneOf(char ch, char[] charray) {
          boolean result = false;
          for (int i = 0; i < charray.length; i ++) {
              if (ch == charray[i]) {
                  result = true;
                  break;
              }
          }
          return result;
      }
      
      
      /** Parse out a token until any of the given terminators
       * is encountered. */
      private String parseToken(final char[] terminators) {
          char ch;
          i1 = pos;
          i2 = pos;
          while (hasChar()) {
              ch = chars[pos];
              if (isOneOf(ch, terminators)) {
                  break;
              }
              i2++;
              pos++;
          }
          return getToken(false);
      }
      
      
      /** Parse out a token until any of the given terminators
       * is encountered. Special characters in quoted tokens
       * are escaped. */
      private String parseQuotedToken(final char[] terminators) {
          char ch;
          i1 = pos;
          i2 = pos;
          boolean quoted = false;
          while (hasChar()) {
              ch = chars[pos];
              if (!quoted && isOneOf(ch, terminators)) {
                  break;
              }
              if (ch == '"') {
                  quoted = !quoted;
              }
              i2++;
              pos++;
          }
          return getToken(true);
      }
      
      /** 
       * Extracts a list of {@link NameValuePair}s from the given string.
       *
       * @param str the string that contains a sequence of name/value pairs
       * @return a list of {@link NameValuePair}s
       * 
       */
      public List parse(final String str, char separator) {
  
          if (str == null) {
              return new ArrayList();
          }
          return parse(str.toCharArray(), separator);
      }
  
      /** 
       * Extracts a list of {@link NameValuePair}s from the given array of 
       * characters.
       *
       * @param chars the array of characters that contains a sequence of 
       * name/value pairs
       * 
       * @return a list of {@link NameValuePair}s
       */
      public List parse(final char[] chars, char separator) {
  
          if (chars == null) {
              return new ArrayList();
          }
          return parse(chars, 0, chars.length, separator);
      }
  
  
      /** 
       * Extracts a list of {@link NameValuePair}s from the given array of 
       * characters.
       *
       * @param chars the array of characters that contains a sequence of 
       * name/value pairs
       * @param offset - the initial offset.
       * @param length - the length.
       * 
       * @return a list of {@link NameValuePair}s
       */
      public List parse(final char[] chars, int offset, int length, char separator) {
  
          if (chars == null) {
              return new ArrayList();
          }
          List params = new ArrayList();
          this.chars = chars;
          this.pos = offset;
          this.len = length;
          
          String paramName = null;
          String paramValue = null;
          boolean done = false;
          while (hasChar()) {
              paramName = parseToken(new char[] {'=', separator});
              paramValue = null;
              if (hasChar() && (chars[pos] == '=')) {
                  pos++; // skip '='
                  paramValue = parseQuotedToken(new char[] {separator});
              }
              if (hasChar() && (chars[pos] == separator)) {
                  pos++; // skip separator
              }
              if ((paramName != null) && (paramName.length() > 0)) {
                  params.add(new NameValuePair(paramName, paramValue));
              }
          }        
          return params;
      }
  }
  
  
  
  1.6       +27 -6     jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHeaderElement.java
  
  Index: TestHeaderElement.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHeaderElement.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- TestHeaderElement.java	28 Jan 2003 04:40:23 -0000	1.5
  +++ TestHeaderElement.java	13 Jul 2003 13:54:51 -0000	1.6
  @@ -70,6 +70,7 @@
    * @author Rodney Waldhoff
    * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
    * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
  + * @author <a href="mailto:oleg@ural.ru">oleg Kalnichevski</a>
    * @version $Id$
    */
   public class TestHeaderElement extends TestNVP {
  @@ -108,7 +109,7 @@
           // this is derived from the old main method in HeaderElement
           String headerValue = "name1 = value1; name2; name3=\"value3\" , name4=value4; " +
               "name5=value5, name6= ; name7 = value7; name8 = \" value8\"";
  -        HeaderElement[] elements = HeaderElement.parse(headerValue);
  +        HeaderElement[] elements = HeaderElement.parseElements(headerValue);
           // there are 3 elements
           assertEquals(3,elements.length);
           // 1st element
  @@ -129,12 +130,32 @@
           assertEquals("value5",elements[1].getParameters()[0].getValue());
           // 3rd element
           assertEquals("name6",elements[2].getName());
  -        assertTrue(null == elements[2].getValue());
  +        assertEquals(null,elements[2].getValue());
           // 3rd element has 2 getParameters()
           assertEquals(2,elements[2].getParameters().length);
           assertEquals("name7",elements[2].getParameters()[0].getName());
           assertEquals("value7",elements[2].getParameters()[0].getValue());
           assertEquals("name8",elements[2].getParameters()[1].getName());
           assertEquals(" value8",elements[2].getParameters()[1].getValue());
  +    }
  +
  +    public void testFringeCase1() throws Exception {
  +        String headerValue = "name1 = value1,";
  +        HeaderElement[] elements = HeaderElement.parseElements(headerValue);
  +        assertEquals("Number of elements", 1, elements.length);
  +    }
  +
  +
  +    public void testFringeCase2() throws Exception {
  +        String headerValue = "name1 = value1, ";
  +        HeaderElement[] elements = HeaderElement.parseElements(headerValue);
  +        assertEquals("Number of elements", 1, elements.length);
  +    }
  +
  +
  +    public void testFringeCase3() throws Exception {
  +        String headerValue = ",, ,, ,";
  +        HeaderElement[] elements = HeaderElement.parseElements(headerValue);
  +        assertEquals("Number of elements", 0, elements.length);
       }
   }
  
  
  
  1.23      +5 -4      jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java
  
  Index: TestNoHost.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- TestNoHost.java	17 Apr 2003 11:34:19 -0000	1.22
  +++ TestNoHost.java	13 Jul 2003 13:54:51 -0000	1.23
  @@ -87,6 +87,7 @@
           suite.addTest(TestCookie.suite());
           suite.addTest(TestNVP.suite());
           suite.addTest(TestHeader.suite());
  +        suite.addTest(TestParameterParser.suite());
           suite.addTest(TestHeaderElement.suite());
           suite.addTest(TestChallengeParser.suite());
           suite.addTest(TestAuthenticator.suite());
  
  
  
  1.1                  jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestParameterParser.java
  
  Index: TestParameterParser.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.commons.httpclient;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  
  import java.util.List;
  
  import org.apache.commons.httpclient.util.ParameterParser;
  
  /**
   * Unit tests for {@link ParameterParser}.
   *
   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
   */
  public class TestParameterParser extends TestCase {
  
      // ------------------------------------------------------------ Constructor
      public TestParameterParser(String testName) {
          super(testName);
      }
  
      // ------------------------------------------------------------------- Main
      public static void main(String args[]) {
          String[] testCaseName = { TestParameterParser.class.getName() };
          junit.textui.TestRunner.main(testCaseName);
      }
  
      // ------------------------------------------------------- TestCase Methods
  
      public static Test suite() {
          return new TestSuite(TestParameterParser.class);
      }
  
  
      public void testParsing() {
          String s = 
            "test; test1 =  stuff   ; test2 =  \"stuff; stuff\"; test3=\"stuff";
          ParameterParser  parser = new ParameterParser();
          List params = parser.parse(s, ';');
          assertEquals("test", ((NameValuePair)params.get(0)).getName());
          assertEquals(null, ((NameValuePair)params.get(0)).getValue());
          assertEquals("test1", ((NameValuePair)params.get(1)).getName());
          assertEquals("stuff", ((NameValuePair)params.get(1)).getValue());
          assertEquals("test2", ((NameValuePair)params.get(2)).getName());
          assertEquals("stuff; stuff", ((NameValuePair)params.get(2)).getValue());
          assertEquals("test3", ((NameValuePair)params.get(3)).getName());
          assertEquals("\"stuff", ((NameValuePair)params.get(3)).getValue());
  
          s = "  test  , test1=stuff   ,  , test2=, test3, ";
          params = parser.parse(s, ',');
          assertEquals("test", ((NameValuePair)params.get(0)).getName());
          assertEquals(null, ((NameValuePair)params.get(0)).getValue());
          assertEquals("test1", ((NameValuePair)params.get(1)).getName());
          assertEquals("stuff", ((NameValuePair)params.get(1)).getValue());
          assertEquals("test2", ((NameValuePair)params.get(2)).getName());
          assertEquals(null, ((NameValuePair)params.get(2)).getValue());
          assertEquals("test3", ((NameValuePair)params.get(3)).getName());
          assertEquals(null, ((NameValuePair)params.get(3)).getValue());
  
          s = "  test";
          params = parser.parse(s, ';');
          assertEquals("test", ((NameValuePair)params.get(0)).getName());
          assertEquals(null, ((NameValuePair)params.get(0)).getValue());
  
          s = "  ";
          params = parser.parse(s, ';');
          assertEquals(0, params.size());
  
          s = " = stuff ";
          params = parser.parse(s, ';');
          assertEquals(0, params.size());
      }
  }
  
  
  

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