commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d...@apache.org
Subject cvs commit: jakarta-commons/httpclient/src/java/org/apache/commons/httpclient HttpUrlMethod.java HttpMultiClient.java Authenticator.java
Date Sun, 01 Sep 2002 01:27:37 GMT
dion        2002/08/31 18:27:37

  Modified:    httpclient/src/java/org/apache/commons/httpclient/methods
                        PostMethod.java HeadMethod.java GetMethod.java
               httpclient/src/java/org/apache/commons/httpclient
                        HttpUrlMethod.java HttpMultiClient.java
                        Authenticator.java
  Log:
  Reformatting with Jalopy
  
  Revision  Changes    Path
  1.17      +457 -333  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java
  
  Index: PostMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- PostMethod.java	8 Aug 2002 21:51:36 -0000	1.16
  +++ PostMethod.java	1 Sep 2002 01:27:37 -0000	1.17
  @@ -59,9 +59,16 @@
    * [Additional notices, if required by prior licensing conditions]
    *
    */
  -
   package org.apache.commons.httpclient.methods;
   
  +import java.io.ByteArrayInputStream;
  +import java.io.ByteArrayOutputStream;
  +import java.io.IOException;
  +import java.io.InputStream;
  +import java.util.Iterator;
  +import java.util.List;
  +import java.util.Vector;
  +
   import org.apache.commons.httpclient.Header;
   import org.apache.commons.httpclient.HttpConnection;
   import org.apache.commons.httpclient.HttpException;
  @@ -71,43 +78,46 @@
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   
  -import java.util.Vector;
  -import java.io.ByteArrayInputStream;
  -import java.io.ByteArrayOutputStream;
  -import java.io.InputStream;
  -import java.io.IOException;
  -import java.util.Iterator;
  -import java.util.List;
  -import java.util.Vector;
  -
   /**
  - * POST Method.
  - * This class encapsulates the HTTP POST specification.  According to
  - * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
  - * <blockquote>The POST method is used to request that the origin server accept the
  - * entity enclosed in the request as a new subordinate of the resource
  - * identified by the Request-URI in the Request-Line. POST is designed
  - * to allow a uniform method to cover the following functions:
  - * <ul><li>Annotation of existing resources;
  - *     <li>Posting a message to a bulletin board, newsgroup, mailing list,
  - *         or similar group of articles;
  - *     <li>Providing a block of data, such as the result of submitting a
  - *         form, to a data-handling process;
  - *     <li>Extending a database through an append operation.
  + * POST Method. This class encapsulates the HTTP POST specification.  According
  + * to <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>:
  + * <blockquote>
  + * The POST method is used to request that the origin server accept the entity
  + * enclosed in the request as a new subordinate of the resource identified by
  + * the Request-URI in the Request-Line. POST is designed to allow a uniform
  + * method to cover the following functions:
  + * 
  + * <ul>
  + * <li>
  + * Annotation of existing resources;
  + * </li>
  + * <li>
  + * Posting a message to a bulletin board, newsgroup, mailing list, or similar
  + * group of articles;
  + * </li>
  + * <li>
  + * Providing a block of data, such as the result of submitting a form, to a
  + * data-handling process;
  + * </li>
  + * <li>
  + * Extending a database through an append operation.
  + * </li>
    * </ul>
  + * 
    * </blockquote>
  - *
  + * 
    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
    * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
    * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    * @author Ortwin GlЧck
  - *
    * @since 1.0
    */
   public class PostMethod extends GetMethod {
  +    //~ Static variables/initializers ииииииииииииииииииииииииииииииииииииииииии
  +
       /**
  -     * The content length will be calculated automatically. This implies buffering
  -     * of the content.
  +     * The content length will be calculated automatically. This implies
  +     * buffering of the content.
        */
       public static final int CONTENT_LENGTH_AUTO = -2;
   
  @@ -118,11 +128,37 @@
        */
       public static final int CONTENT_LENGTH_CHUNKED = -1;
   
  +    // -------------------------------------------------------------- Constants
  +
  +    /** Log object for this class. */
  +    private static final Log log = LogFactory.getLog(PostMethod.class);
  +
  +    /** The Content-Type header for www-form-urlcoded. */
  +    static final Header CONTENT_TYPE = new Header("Content-Type", 
  +        "application/x-www-form-urlencoded");
  +
  +    /** DOCUMENT ME! */
  +    private ByteArrayOutputStream buffer = null;
  +
  +    /** DOCUMENT ME! */
  +    private InputStream requestBody = null;
  +
  +    /** DOCUMENT ME! */
  +    private Vector parameters = new Vector();
  +
  +    /** DOCUMENT ME! */
  +    private int repeatCount = 0;
  +
  +    /** DOCUMENT ME! */
  +    private int requestContentLength = CONTENT_LENGTH_AUTO;
  +
  +    //~ Constructors иииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
  +
       // ----------------------------------------------------------- Constructors
   
       /**
        * No-arg constructor.
  -     *
  +     * 
        * @since 1.0
        */
       public PostMethod() {
  @@ -132,8 +168,9 @@
   
       /**
        * Path-setting constructor.
  +     * 
        * @param path the path to request
  -     *
  +     * 
        * @since 1.0
        */
       public PostMethod(String path) {
  @@ -143,9 +180,10 @@
   
       /**
        * Path and temp directory constructor.
  +     * 
        * @param path the path to request
        * @param tempDir directory to store temp files in
  -     *
  +     * 
        * @since 1.0
        */
       public PostMethod(String path, String tempDir) {
  @@ -155,10 +193,11 @@
   
       /**
        * Path, temp directory and temp file constructor.
  +     * 
        * @param path the path to request
        * @param tempDir directory to store temp files in
        * @param tempFile file to store temporary data in
  -     *
  +     * 
        * @since 1.0
        */
       public PostMethod(String path, String tempDir, String tempFile) {
  @@ -166,13 +205,32 @@
           setFollowRedirects(false);
       }
   
  +    //~ Methods ииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
  +
  +    /**
  +     * A POST request can only be redirected if input is buffered. Overrides
  +     * method of {@link org.apache.commons.httpclient.HttpMethodBase}.
  +     * 
  +     * @return true if request is buffered and <code>setFollowRedirects</code>
  +     *         was set to <code>true</code>.
  +     * 
  +     * @since 2.0
  +     */
  +    public boolean getFollowRedirects() {
  +        if (!super.getFollowRedirects()) {
  +            return false;
  +        }
  +
  +        return (buffer == null);
  +    }
   
       // ----------------------------------------------------- Instance Methods
   
       /**
        * Returns <tt>"POST"</tt>.
  +     * 
        * @return <tt>"POST"</tt>
  -     *
  +     * 
        * @since 2.0
        */
       public String getName() {
  @@ -180,509 +238,575 @@
       }
   
       /**
  -     * A POST request can only be redirected if input is buffered.
  -     * Overrides method of {@link org.apache.commons.httpclient.HttpMethodBase}.
  -     * @return true if request is buffered and <code>setFollowRedirects</code>
  -     * was set to <code>true</code>.
  -     *
  +     * Set the value of parameter with parameterName to parameterValue. Does
  +     * not preserve the initial insertion order.
  +     * 
  +     * @param parameterName DOCUMENT ME!
  +     * @param parameterValue DOCUMENT ME!
  +     * 
  +     * @throws IllegalStateException if my request body has already been
  +     *         generated.
  +     * 
        * @since 2.0
  +     * @deprecated use {@link #removeParameter(String,String)} followed by
  +     *             {@link #addParameter(String,String)}.
        */
  -    public boolean getFollowRedirects() {
  -        if (!super.getFollowRedirects()) return false;
  -        return (buffer == null);
  +    public void setParameter(String parameterName, String parameterValue) {
  +        log.trace("enter PostMethod.setParameter(String, String)");
  +
  +        if (null != requestBody) {
  +            throw new IllegalStateException("Request body already generated.");
  +        }
  +
  +        removeParameter(parameterName, parameterValue);
  +        addParameter(parameterName, parameterValue);
       }
   
  +    /**
  +     * Gets the parameter of the specified name. If there exists more than one
  +     * parameter with the name paramName, then only the first one is returned.
  +     * 
  +     * @param paramName DOCUMENT ME!
  +     * 
  +     * @return If a parameter exists with the name argument, the coresponding
  +     *         NameValuePair is returned.  Otherwise null.
  +     * 
  +     * @since 2.0
  +     */
  +    public NameValuePair getParameter(String paramName) {
  +        log.trace("enter PostMethod.getParameter(String)");
  +
  +        if (paramName == null) {
  +            return null;
  +        }
  +
  +        Iterator iter = parameters.iterator();
  +
  +        while (iter.hasNext()) {
  +            NameValuePair parameter = (NameValuePair) iter.next();
  +
  +            if (paramName.equals(parameter.getName())) {
  +                return parameter;
  +            }
  +        }
  +
  +        return null;
  +    }
   
       /**
  -     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
  -     * to clear my request body.
  -     *
  -     * @since 1.0
  +     * Gets the parameters currently added to the PostMethod. If there are no
  +     * parameters, a valid array is returned with zero elements. The returned
  +     * array object contains an array of pointers to  the internal data
  +     * members. TODO: is it ok to return internal data?
  +     * 
  +     * @return An array of the current parameters
  +     * 
  +     * @since 2.0
  +     * @see #getParameter(java.lang.String)
        */
  -    public void recycle() {
  -        log.trace("enter PostMethod.recycle()");
  -        super.recycle();
  -        requestBody = null;
  -        requestContentLength = CONTENT_LENGTH_AUTO;
  -        buffer = null;
  -        parameters.clear();
  +    public NameValuePair[] getParameters() {
  +        log.trace("enter PostMethod.getParameters()");
  +
  +        int numPairs = parameters.size();
  +        Object[] objectArr = parameters.toArray();
  +        NameValuePair[] nvPairArr = new NameValuePair[numPairs];
  +
  +        for (int i = 0; i < numPairs; i++) {
  +            nvPairArr[i] = (NameValuePair) objectArr[i];
  +        }
  +
  +        return nvPairArr;
       }
   
       /**
  -     * Set the value of parameter with parameterName to parameterValue.
  -     * Does not preserve the initial insertion order.
  -     *
  -     * @throws IllegalStateException if my request body has already been generated.
  -     * @deprecated use {@link #removeParameter(String,String)} followed by 
  -     * {@link #addParameter(String,String)}.
  -     *
  +     * Sets the request body to be the specified string.
  +     * 
  +     * <p>
  +     * Once this method has been invoked,  the request parameters  cannot be
  +     * altered until I am {@link #recycle recycled}.
  +     * </p>
  +     * 
  +     * @param body DOCUMENT ME!
  +     * 
  +     * @throws IllegalStateException if request params have been added
  +     * 
        * @since 2.0
  +     * @deprecated This method converts characters to bytes in a platform
  +     *             dependent encoding. Use {@link
  +     *             #setRequestBody(java.io.InputStream)} instead.
        */
  -    public void setParameter(String parameterName, String parameterValue) {
  -        log.trace("enter PostMethod.setParameter(String, String)");
  +    public void setRequestBody(String body) {
  +        log.trace("enter PostMethod.setRequestBody(String)");
   
  -        if(null != requestBody) {
  -            throw new IllegalStateException("Request body already generated.");
  +        if (!parameters.isEmpty()) {
  +            throw new IllegalStateException(
  +                "Request parameters have already been added.");
  +        }
  +
  +        requestBody = new ByteArrayInputStream(body.getBytes());
  +    }
  +
  +    /**
  +     * Sets the request body to be the specified inputstream.
  +     * 
  +     * <p>
  +     * Once this method has been invoked,  the request parameters  cannot be
  +     * altered until I am {@link #recycle recycled}.
  +     * </p>
  +     * 
  +     * @param body DOCUMENT ME!
  +     * 
  +     * @throws IllegalStateException if request params have been added
  +     * 
  +     * @since 2.0
  +     */
  +    public void setRequestBody(InputStream body) {
  +        log.trace("enter PostMethod.getRequestBody(InputStream)");
  +
  +        if (!parameters.isEmpty()) {
  +            throw new IllegalStateException(
  +                "Request parameters have already been added.");
  +        }
  +
  +        requestBody = body;
  +    }
  +
  +    /**
  +     * Gets the requestBody as it would be if it was executed.
  +     * 
  +     * @return The request body if it has been set.  The generated  request
  +     *         body from the paramters if they exist.  Null otherwise.
  +     * 
  +     * @since 2.0
  +     */
  +    public InputStream getRequestBody() {
  +        log.trace("enter PostMethod.getRequestBody()");
  +
  +        if (requestBody != null) {
  +            return requestBody;
  +        } else if (!parameters.isEmpty()) {
  +            return generateRequestBody(parameters);
  +        } else {
  +            return null;
           }
  -        removeParameter(parameterName, parameterValue);
  -        addParameter(parameterName, parameterValue);
  +    }
  +
  +    /**
  +     * DOCUMENT ME!
  +     * 
  +     * @return the request body as a string
  +     * @throws IOException DOCUMENT ME!
  +     * 
  +     * @since 2.0
  +     */
  +    public String getRequestBodyAsString() throws IOException {
  +        log.trace("enter PostMethod.getRequestBodyAsString()");
  +
  +        StringBuffer buffer = new StringBuffer();
  +        InputStream requestBody = getRequestBody();
  +        int data = requestBody.read();
  +
  +        while (data != -1) {
  +            buffer.append((char) data);
  +            data = requestBody.read();
  +        }
  +
  +        return buffer.toString();
       }
   
       /**
        * Sets length information about the request body.
  -     * <p>Note: If you specify a content length the request is unbuffered. This
  +     * 
  +     * <p>
  +     * Note: If you specify a content length the request is unbuffered. This
        * prevents automatic retry if a request fails the first time. This means
  -     * that the HttpClient can not perform authorization automatically but will
  -     * throw an Exception. You will have to set the necessary 'Authorization' or
  -     * 'Proxy-Authorization' headers manually.</p>
  -     *
  +     * that the HttpClient can not perform authorization automatically but
  +     * will throw an Exception. You will have to set the necessary
  +     * 'Authorization' or 'Proxy-Authorization' headers manually.
  +     * </p>
  +     * 
        * @param length size in bytes or any of CONTENT_LENGTH_AUTO,
  -     * CONTENT_LENGTH_CHUNKED. If number of bytes is specified the content will
  -     * not be buffered internally and the Content-Length header of the request
  -     * will be used. In this case the user is responsible to supply the correct
  -     * content length.
  -     *
  +     *        CONTENT_LENGTH_CHUNKED. If number of bytes is specified the
  +     *        content will not be buffered internally and the Content-Length
  +     *        header of the request will be used. In this case the user is
  +     *        responsible to supply the correct content length.
  +     * @throws RuntimeException DOCUMENT ME!
  +     * 
        * @since 2.0
        */
       public void setRequestContentLength(int length) {
           log.trace("enter PostMethod.setRequestContentLength(int)");
   
           if ((length == CONTENT_LENGTH_CHUNKED) && !isHttp11()) {
  -            throw new RuntimeException("Chunked transfer encoding not allowed for HTTP/1.0");
  +            throw new RuntimeException(
  +                "Chunked transfer encoding not allowed for HTTP/1.0");
           }
  +
           requestContentLength = length;
       }
   
       /**
        * Add a new parameter to be used in the POST request body.
  -     *
  +     * 
        * @param paramName The parameter name to add.
        * @param paramValue The parameter value to add.
  -     * @throws IllegalStateException if my request body has already been generated.
  +     * 
  +     * @throws IllegalStateException if my request body has already been
  +     *         generated.
        * @throws IllegalArgumentException if either argument is null
  -     *
  +     * 
        * @since 1.0
        */
       public void addParameter(String paramName, String paramValue) {
           log.trace("enter PostMethod.addParameter(String, String)");
   
  -        if(null != requestBody) {
  +        if (null != requestBody) {
               throw new IllegalStateException("Request body already generated.");
           }
  -        if (paramName == null || paramValue == null){
  -            throw new IllegalArgumentException("Arguments to addParameter(String, String) cannot be null");
  -        }else{
  +
  +        if ((paramName == null) || (paramValue == null)) {
  +            throw new IllegalArgumentException(
  +                "Arguments to addParameter(String, String) cannot be null");
  +        } else {
               parameters.add(new NameValuePair(paramName, paramValue));
           }
       }
   
  -
       /**
        * Add a new parameter to be used in the POST request body.
  -     *
  -     * @param parameter The parameter to add.
  -     * @throws IllegalStateException if my request body has already been generated.
  -     * @throws IllegalArgumentException if the argument is null or contains null values
  -     * @see #addParameter(String,String)
  -     *
  +     * 
  +     * @param param The parameter to add.
  +     * 
  +     * @throws IllegalStateException if my request body has already been
  +     *         generated.
  +     * @throws IllegalArgumentException if the argument is null or contains
  +     *         null values
  +     * 
        * @since 2.0
  +     * @see #addParameter(String,String)
        */
       public void addParameter(NameValuePair param) {
           log.trace("enter PostMethod.addParameter(NameValuePair)");
   
  -        if(null != requestBody) {
  +        if (null != requestBody) {
               throw new IllegalStateException("Request body already generated.");
           }
  -        if(null == param){
  -            throw new IllegalArgumentException("Argument to addParameter(NameValuePair) cannot be null");
  -        }else{
  +
  +        if (null == param) {
  +            throw new IllegalArgumentException(
  +                "Argument to addParameter(NameValuePair) cannot be null");
  +        } else {
               addParameter(param.getName(), param.getValue());
           }
       }
   
       /**
  -     * Add an Array of parameters to be used in the POST request body.
  -     * Logs a warning if the parameters argument is null.
  -     *
  -     * @param parameter The array of parameters to add.
  -     * @throws IllegalStateException if my request body has already been generated.
  -     * @see #addParameter(org.apache.commons.httpclient.NameValuePair)
  -     *
  +     * Add an Array of parameters to be used in the POST request body. Logs a
  +     * warning if the parameters argument is null.
  +     * 
  +     * @param parameters The array of parameters to add.
  +     * 
  +     * @throws IllegalStateException if my request body has already been
  +     *         generated.
  +     * 
        * @since 2.0
  +     * @see #addParameter(org.apache.commons.httpclient.NameValuePair)
        */
       public void addParameters(NameValuePair[] parameters) {
           log.trace("enter PostMethod.addParameters(NameValuePair[])");
   
  -        if(null != requestBody) {
  +        if (null != requestBody) {
               throw new IllegalStateException("Request body already generated.");
           }
  -        if(null == parameters){
  +
  +        if (null == parameters) {
               log.warn("Attempt to addParameters(null) ignored");
  -        }else{
  -            for (int i=0; i<parameters.length; i++){
  +        } else {
  +            for (int i = 0; i < parameters.length; i++) {
                   addParameter(parameters[i]);
               }
           }
       }
   
  -
  -    /**
  -     * Gets the parameter of the specified name.
  -     *
  -     * If there exists more than one parameter with the name paramName,
  -     * then only the first one is returned.
  -     * 
  -     * @return If a parameter exists with the name argument, the coresponding
  -     * NameValuePair is returned.  Otherwise null.
  -     *
  -     * @since 2.0
  -     */
  -    public NameValuePair getParameter(String paramName){
  -        log.trace("enter PostMethod.getParameter(String)");
  -
  -        if (paramName == null){
  -            return null;
  -        }
  -        Iterator iter = parameters.iterator();
  -        while(iter.hasNext()){
  -            NameValuePair parameter = (NameValuePair)iter.next();
  -            if (paramName.equals(parameter.getName())){
  -                return parameter;
  -            }
  -        }
  -        return null;
  -    }
  -
       /**
  -     * Gets the parameters currently added to the PostMethod.
  -     *
  -     * If there are no parameters, a valid array is returned with
  -     * zero elements.
  -     * The returned array object contains an array of pointers to 
  -     * the internal data members.
  -     * TODO: is it ok to return internal data?
  +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
  +     * to clear my request body.
        * 
  -     * @return An array of the current parameters
  -     * @see #getParameter(java.lang.String)
  -     *
  -     * @since 2.0
  +     * @since 1.0
        */
  -    public NameValuePair[] getParameters(){
  -        log.trace("enter PostMethod.getParameters()");
  -
  -        int numPairs = parameters.size();
  -        Object[] objectArr= parameters.toArray();
  -        NameValuePair[] nvPairArr = new NameValuePair[numPairs];
  -        for(int i=0; i<numPairs; i++){
  -            nvPairArr[i] = (NameValuePair)objectArr[i];
  -        }
  -        return nvPairArr;
  +    public void recycle() {
  +        log.trace("enter PostMethod.recycle()");
  +        super.recycle();
  +        requestBody = null;
  +        requestContentLength = CONTENT_LENGTH_AUTO;
  +        buffer = null;
  +        parameters.clear();
       }
   
       /**
  -     * Removes all parameters with the given paramName.
  -     * If there is more than one parameter with the given paramName, all
  -     * of them are removed.  If there is just one, it is removed.  If there
  -     * are none, then the request is ignored.
  +     * Removes all parameters with the given paramName. If there is more than
  +     * one parameter with the given paramName, all of them are removed.  If
  +     * there is just one, it is removed.  If there are none, then the request
  +     * is ignored.
        * 
        * @param paramName The parameter name to remove.
  +     * 
        * @return true if at least one parameter was removed
  -     * @throws IllegalStateException if my request body has already been generated.
  -     *
  +     * 
  +     * @throws IllegalStateException if my request body has already been
  +     *         generated.
  +     * @throws IllegalArgumentException When the parameter name passed is null
  +     * 
        * @since 2.0
        */
       public boolean removeParameter(String paramName) {
           log.trace("enter PostMethod.removeParameter(String)");
   
  -        if(null != requestBody) {
  +        if (null != requestBody) {
               throw new IllegalStateException("Request body already generated.");
           }
  -        if (paramName == null){
  -            throw new IllegalArgumentException("Argument passed to removeParameter(String) cannot be null");
  +
  +        if (paramName == null) {
  +            throw new IllegalArgumentException(
  +                "Argument passed to removeParameter(String) cannot be null");
           }
  +
           boolean removed = true;
           Iterator iter = parameters.iterator();
  -        while(iter.hasNext()){
  -            NameValuePair pair = (NameValuePair)iter.next();
  -            if (paramName.equals(pair.getName())){
  +
  +        while (iter.hasNext()) {
  +            NameValuePair pair = (NameValuePair) iter.next();
  +
  +            if (paramName.equals(pair.getName())) {
                   iter.remove();
                   removed = true;
               }
           }
  +
           return removed;
       }
   
       /**
  -     * Removes all parameter with the given paramName and paramValue.
  -     * If there is more than one parameter with the given paramName, only
  -     * one is removed.  If there are none, then the request is ignored.
  -     *
  +     * Removes all parameter with the given paramName and paramValue. If there
  +     * is more than one parameter with the given paramName, only one is
  +     * removed.  If there are none, then the request is ignored.
  +     * 
        * @param paramName The parameter name to remove.
        * @param paramValue The parameter value to remove.
  +     * 
        * @return true if a parameter was removed.
  -     * @throws IllegalStateException if my request body has already been generated.
  -     *
  +     * 
  +     * @throws IllegalStateException if my request body has already been
  +     *         generated.
  +     * @throws IllegalArgumentException when param name or value are null
  +     * 
        * @since 2.0
        */
       public boolean removeParameter(String paramName, String paramValue) {
           log.trace("enter PostMethod.removeParameter(String, String)");
   
  -        if(null != requestBody) {
  +        if (null != requestBody) {
               throw new IllegalStateException("Request body already generated.");
           }
  -        if (paramName == null || paramValue == null){
  -            throw new IllegalArgumentException("Argument passed to removeParameter(String,String) cannot be null");
  +
  +        if ((paramName == null) || (paramValue == null)) {
  +            throw new IllegalArgumentException(
  +                "Argument passed to removeParameter(String,String) cannot be "
  +                + "null");
           }
  +
           Iterator iter = parameters.iterator();
  -        while(iter.hasNext()){
  -            NameValuePair pair = (NameValuePair)iter.next();
  -            if (paramName.equals(pair.getName()) && paramValue.equals(pair.getValue())){
  +
  +        while (iter.hasNext()) {
  +            NameValuePair pair = (NameValuePair) iter.next();
  +
  +            if (paramName.equals(pair.getName())
  +                && paramValue.equals(pair.getValue())) {
                   iter.remove();
  +
                   return true;
               }
           }
  +
           return false;
       }
   
  -    /** 
  -     * Sets the request body to be the specified string.
  +    /**
  +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
  +     * to return the length of the request body.
        * 
  -     * <p>Once this method has been invoked,  the request parameters 
  -     * cannot be altered until I am {@link #recycle recycled}.
  +     * @return number of bytes in the request body
        * 
  -     * @throws IllegalStateException if request params have been added
  -     * @deprecated This method converts characters to bytes in a platform dependent
  -     * encoding. Use {@link #setRequestBody(java.io.InputStream)} instead.
  -     *
        * @since 2.0
        */
  -    public void setRequestBody(String body) {
  -        log.trace("enter PostMethod.setRequestBody(String)");
  +    protected int getRequestContentLength() {
  +        log.trace("enter PostMethod.getRequestContentLength()");
   
  -        if(!parameters.isEmpty()) {
  -            throw new IllegalStateException("Request parameters have already been added.");
  +        if (null == requestBody) {
  +            requestBody = generateRequestBody(parameters);
  +            bufferContent();
           }
  -        requestBody = new ByteArrayInputStream(body.getBytes());
  -    }
   
  -    /** 
  -     * Sets the request body to be the specified inputstream.
  -     * 
  -     * <p>Once this method has been invoked,  the request parameters 
  -     * cannot be altered until I am {@link #recycle recycled}.
  -     * 
  -     * @throws IllegalStateException if request params have been added
  -     *
  -     * @since 2.0
  -     */
  -    public void setRequestBody(InputStream body) {
  -        log.trace("enter PostMethod.getRequestBody(InputStream)");
  -	
  -        if(!parameters.isEmpty()) {
  -            throw new IllegalStateException("Request parameters have already been added.");
  +        if (requestContentLength != CONTENT_LENGTH_AUTO) {
  +            return requestContentLength;
           }
  -        requestBody = body;
  -    }
   
  -    /**
  -     * Gets the requestBody as it would be if it was executed.
  -     *
  -     * @return The request body if it has been set.  The generated 
  -     * request body from the paramters if they exist.  Null otherwise.
  -     *
  -     * @since 2.0
  -     */
  -    public InputStream getRequestBody() {
  -        log.trace("enter PostMethod.getRequestBody()");
  -
  -        if (requestBody != null) {
  -            return requestBody;
  -        } else if (!parameters.isEmpty()) {
  -            return generateRequestBody(parameters);
  -        } else {
  -            return null;
  -        }
  -    }
  -    
  -    /**
  -     * @return the request body as a string
  -     *
  -     * @since 2.0
  -     */
  -    public String getRequestBodyAsString() throws IOException{
  -        log.trace("enter PostMethod.getRequestBodyAsString()");
  +        bufferContent();
   
  -        StringBuffer buffer = new StringBuffer();
  -        InputStream requestBody = getRequestBody();
  -        int data = requestBody.read();
  -        while (data != -1) {
  -            buffer.append((char) data);
  -            data = requestBody.read();
  -        }
  -        return buffer.toString();
  +        return requestContentLength;
       }
   
  -
       /**
  -     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase} to 
  -     * also add <tt>Content-Type</tt> header
  -     * when appropriate.
  -     *
  +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
  +     * to  also add <tt>Content-Type</tt> header when appropriate.
  +     * 
  +     * @param state DOCUMENT ME!
  +     * @param conn DOCUMENT ME!
  +     * @throws IOException DOCUMENT ME!
  +     * @throws HttpException DOCUMENT ME!
  +     * 
        * @since 2.0
        */
       protected void addRequestHeaders(HttpState state, HttpConnection conn)
       throws IOException, HttpException {
  -        super.addRequestHeaders(state,conn);
  -        if(!parameters.isEmpty()) { //there are some parameters, so set the contentType header
  +        super.addRequestHeaders(state, conn);
  +
  +        if (!parameters.isEmpty()) { 
  +            //there are some parameters, so set the contentType header
               setRequestHeader(CONTENT_TYPE);
           }
       }
   
  -    
       /**
        * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
  -     * to write request parameters as the request body.
  +     * to write request parameters as the request body.  The input stream will
  +     * be truncated after the specified content length.
  +     * 
  +     * @param state DOCUMENT ME!
  +     * @param conn DOCUMENT ME!
        * 
  -     * The input stream will be truncated after the specified content length.
  -     * @throws IOException if the stream ends before the specified content length.
  -     *
  -     * <p>Once this method has been invoked,  the request parameters 
  -     * cannot be altered until I am {@link #recycle recycled}.
  -     *
        * @return always returns true
  -     *
  +     * 
  +     * @throws IOException if the stream ends before the specified content
  +     *         length. <p>
  +     * @throws HttpException DOCUMENT ME!
  +     * 
        * @since 2.0
        */
       protected boolean writeRequestBody(HttpState state, HttpConnection conn)
       throws IOException, HttpException {
  -        log.trace("enter PostMethod.writeRequestBody(HttpState, HttpConnection)");
  +        log.trace(
  +            "enter PostMethod.writeRequestBody(HttpState, HttpConnection)");
   
  -        if(null == requestBody) {
  +        if (null == requestBody) {
               requestBody = generateRequestBody(parameters);
           }
  +
           if ((repeatCount > 0) && (buffer == null)) {
  -            throw new HttpException("Sorry, unbuffered POST request can not be repeated.");
  +            throw new HttpException(
  +                "Sorry, unbuffered POST request can not be repeated.");
           }
  +
           repeatCount++;
   
           byte[] data = new byte[10000];
           int l = requestBody.read(data);
           int total = 0;
  +
           while (l > 0) {
  -            if ((requestContentLength > 0) && (total + l > requestContentLength)) {
  +            if ((requestContentLength > 0)
  +                && (total + l > requestContentLength)) {
                   l = requestContentLength - total;
                   conn.write(data, 0, l);
  +
                   break;
               }
  +
               conn.write(data, 0, l);
               total += l;
               l = requestBody.read(data);
           }
  +
           if ((requestContentLength > 0) && (total < requestContentLength)) {
               throw new IOException("unexpected end of input stream");
           }
  +
           if (buffer != null) {
               //restore buffered content for repeated requests
               requestBody = new ByteArrayInputStream(buffer.toByteArray());
           }
  +
           return true;
       }
   
  +    // ------------------------------------------------------------Class Methods
   
       /**
  -     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
  -     * to return the length of the request body.
  -     *
  -     * @return number of bytes in the request body
  -     *
  -     * @since 2.0
  +     * Encode the list of parameters into a urlencoded string.
  +     * TODO: consider moving this out into URIUtil.
  +     * 
  +     * @param params DOCUMENT ME!
  +     * 
  +     * @return urlencoded string
  +     * 
  +     * @since 1.0
        */
  -    protected int getRequestContentLength() {
  -        log.trace("enter PostMethod.getRequestContentLength()");
  +    static InputStream generateRequestBody(List params) {
  +        log.trace("enter PostMethod.generateRequestBody(List)");
   
  -        if(null == requestBody) {
  -            requestBody = generateRequestBody(parameters);
  -            bufferContent();
  -        }
  +        Iterator it = params.iterator();
  +        StringBuffer sb = new StringBuffer();
   
  -        if (requestContentLength != CONTENT_LENGTH_AUTO) {
  -            return requestContentLength;
  -        }
  +        while (it.hasNext()) {
  +            NameValuePair parameter = (NameValuePair) it.next();
   
  -        bufferContent();
   
  -        return requestContentLength;
  +            //TODO: make sure these encodings conform to the RFC
  +            sb.append(URIUtil.encode(parameter.getName(), 
  +                                     URIUtil.queryStringValueSafe(), false));
  +            sb.append("=");
  +            sb.append(URIUtil.encode(parameter.getValue(), 
  +                                     URIUtil.queryStringValueSafe(), true));
  +
  +            if (it.hasNext()) {
  +                sb.append("&");
  +            }
  +        }
  +
  +        return new ByteArrayInputStream(sb.toString().getBytes());
       }
   
       /**
  -     * Buffers the request body and calculates the content length.
  -     * If the method was called earlier it returns immediately.
  -     *
  +     * Buffers the request body and calculates the content length. If the
  +     * method was called earlier it returns immediately.
  +     * 
        * @since 1.0
        */
       private void bufferContent() {
           log.trace("enter PostMethod.bufferContent()");
   
  -        if (buffer != null) return;
  +        if (buffer != null) {
  +            return;
  +        }
  +
           try {
               buffer = new ByteArrayOutputStream();
  +
               byte[] data = new byte[10000];
               int l = requestBody.read(data);
               int total = 0;
  +
               while (l > 0) {
                   buffer.write(data, 0, l);
                   total += l;
                   l = requestBody.read(data);
               }
  +
               requestBody = new ByteArrayInputStream(buffer.toByteArray());
               requestContentLength = total;
  -        } catch(IOException e) {
  +        } catch (IOException e) {
               requestBody = null;
               requestContentLength = 0;
           }
       }
  -
  -    // -------------------------------------------------------------- Class Methods
  -
  -    /** 
  -     * Encode the list of parameters into a urlencoded string.
  -     *
  -     * TODO: consider moving this out into URIUtil.
  -     * @return urlencoded string
  -     *
  -     * @since 1.0
  -     */
  -    static InputStream generateRequestBody(List params) {
  -        log.trace("enter PostMethod.generateRequestBody(List)");
  -
  -        Iterator it = params.iterator();
  -        StringBuffer sb = new StringBuffer();
  -        while(it.hasNext()) {
  -            NameValuePair parameter = (NameValuePair)it.next();
  -            //TODO: make sure these encodings conform to the RFC
  -            sb.append(URIUtil.encode(parameter.getName(), URIUtil.queryStringValueSafe(), false));
  -            sb.append("=");
  -            sb.append(URIUtil.encode(parameter.getValue(), URIUtil.queryStringValueSafe(), true));
  -            if (it.hasNext()){ 
  -                sb.append("&");
  -            }
  -        }
  -        return new ByteArrayInputStream(sb.toString().getBytes());
  -    }
  -
  -    // -------------------------------------------------------------- Instance Variables 
  -
  -    private InputStream requestBody = null;
  -    private Vector parameters = new Vector();
  -    private int requestContentLength = CONTENT_LENGTH_AUTO;
  -    private ByteArrayOutputStream buffer = null;
  -    private int repeatCount = 0;
  -
  -    // -------------------------------------------------------------- Constants
  -
  -    /** Log object for this class. */
  -    private static final Log log = LogFactory.getLog(PostMethod.class);
  -
  -    /** The Content-Type header for www-form-urlcoded. */
  -    static final Header CONTENT_TYPE = new Header ("Content-Type","application/x-www-form-urlencoded");
  -}
  +}
  \ No newline at end of file
  
  
  
  1.11      +43 -46    jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/HeadMethod.java
  
  Index: HeadMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/HeadMethod.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- HeadMethod.java	8 Aug 2002 21:51:36 -0000	1.10
  +++ HeadMethod.java	1 Sep 2002 01:27:37 -0000	1.11
  @@ -59,48 +59,45 @@
    * [Additional notices, if required by prior licensing conditions]
    *
    */
  -
   package org.apache.commons.httpclient.methods;
   
  +import java.io.IOException;
  +
   import org.apache.commons.httpclient.HttpConnection;
   import org.apache.commons.httpclient.HttpException;
   import org.apache.commons.httpclient.HttpMethodBase;
   import org.apache.commons.httpclient.HttpState;
  -
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   
  -import java.io.IOException;
  -
  -
   /**
    * HEAD Method.
  - *
  + * 
    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
  - *
    * @since 1.0
    */
  -public class HeadMethod
  -    extends HttpMethodBase {
  -
  +public class HeadMethod extends HttpMethodBase {
  +    //~ Static variables/initializers ииииииииииииииииииииииииииииииииииииииииии
   
  -    // ----------------------------------------------------------- Constructors
  +    /** Log object for this class. */
  +    private static final Log log = LogFactory.getLog(HeadMethod.class);
   
  +    //~ Constructors иииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
   
       /**
        * No-arg constructor.
  -     *
  +     * 
        * @since 1.0
        */
       public HeadMethod() {
           setFollowRedirects(true);
       }
   
  -
       /**
        * Path-setting constructor.
  +     * 
        * @param path the path to request
  -     *
  +     * 
        * @since 1.0
        */
       public HeadMethod(String path) {
  @@ -108,26 +105,13 @@
           setFollowRedirects(true);
       }
   
  -
  -    // ---------------------------------------------------------------- Methods
  -
  -
  -    /** Override recycle to reset redirects default.
  -     *
  -     * @since 1.0
  -     */
  -    public void recycle() {
  -         super.recycle();
  -         setFollowRedirects(true);
  -     }
  -
  -
  -    // --------------------------------------------------- WebdavMethod Methods
  +    //~ Methods ииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
   
       /**
        * Returns <tt>"HEAD"</tt>.
  +     * 
        * @return <tt>"HEAD"</tt>
  -     *
  +     * 
        * @since 2.0
        */
       public String getName() {
  @@ -135,22 +119,35 @@
       }
   
       /**
  -     * Overrides {@link HttpMethodBase} method to
  -     * <i>not</i> read a response body, despite the
  -     * presence of a <tt>Content-Length</tt> or
  +     * Override recycle to reset redirects default.
  +     * 
  +     * @since 1.0
  +     */
  +    public void recycle() {
  +        super.recycle();
  +        setFollowRedirects(true);
  +    }
  +
  +    /**
  +     * Overrides {@link HttpMethodBase} method to <i>not</i> read a response
  +     * body, despite the presence of a <tt>Content-Length</tt> or
        * <tt>Transfer-Encoding</tt> header.
  -     *
  +     * 
  +     * @param state shared http state
  +     * @param conn the http connection to read from
  +     * 
  +     * @throws IOException when there's an error reading data
  +     * @throws HttpException never FIXME
  +     * 
        * @since 2.0
        */
       protected void readResponseBody(HttpState state, HttpConnection conn)
       throws IOException, HttpException {
  -        log.trace("enter HeadMethod.readResponseBody(HttpState, HttpConnection)");
  -        return; // despite the possible presence of a content-length header, HEAD returns no response body
  -    }
  -
  +        log.trace(
  +            "enter HeadMethod.readResponseBody(HttpState, HttpConnection)");
   
  -    // -------------------------------------------------------------- Class Variables
  -
  -    /** Log object for this class. */
  -    private static final Log log = LogFactory.getLog(HeadMethod.class);
  -}
  +        // despite the possible presence of a content-length header, 
  +        // HEAD returns no response body
  +        return;
  +    }
  +}
  \ No newline at end of file
  
  
  
  1.16      +193 -178  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/GetMethod.java
  
  Index: GetMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/GetMethod.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- GetMethod.java	8 Aug 2002 21:51:36 -0000	1.15
  +++ GetMethod.java	1 Sep 2002 01:27:37 -0000	1.16
  @@ -59,15 +59,8 @@
    * [Additional notices, if required by prior licensing conditions]
    *
    */
  -
   package org.apache.commons.httpclient.methods;
   
  -import org.apache.commons.httpclient.HttpConnection;
  -import org.apache.commons.httpclient.HttpMethodBase;
  -import org.apache.commons.httpclient.HttpState;
  -import org.apache.commons.logging.Log;
  -import org.apache.commons.logging.LogFactory;
  -
   import java.io.ByteArrayInputStream;
   import java.io.ByteArrayOutputStream;
   import java.io.File;
  @@ -78,18 +71,22 @@
   import java.io.OutputStream;
   import java.net.URLEncoder;
   
  +import org.apache.commons.httpclient.HttpConnection;
  +import org.apache.commons.httpclient.HttpMethodBase;
  +import org.apache.commons.httpclient.HttpState;
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
   
   /**
  - * GET Method.
  - * Implements an HTTP GET request.
  - *
  + * GET Method. Implements an HTTP GET request.
  + * 
    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
    * @author Sung-Gu Park
    * @author Sean C. Sullivan
  - *
    * @since 1.0
    */
   public class GetMethod extends HttpMethodBase {
  +    //~ Static variables/initializers ииииииииииииииииииииииииииииииииииииииииии
   
       // -------------------------------------------------------------- Constants
   
  @@ -99,23 +96,43 @@
       /** Temporary directory. */
       private static final String TEMP_DIR = "temp/";
   
  -    // ----------------------------------------------------------- Constructors
  +    //~ Instance variables иииииииииииииииииииииииииииииииииииииииииииииииииииии
  +
  +    /** File which contains the buffered data. */
  +    private File fileData;
  +
  +    /** Temporary directory to use. */
  +    private String tempDir = TEMP_DIR;
  +
  +    /** Temporary file to use. */
  +    private String tempFile = null;
  +
  +    /** If we're not using the HD, we're using a memory byte buffer. */
  +    private byte[] memoryData;
  +
  +    // ----------------------------------------------------- Instance Variables
   
  +    /** By default, the get method will buffer read data to the memory. */
  +    private boolean useDisk = false;
  +
  +    //~ Constructors иииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
  +
  +    // ----------------------------------------------------------- Constructors
   
       /**
        * No-arg constructor.
  -     *
  +     * 
        * @since 1.0
        */
       public GetMethod() {
           setFollowRedirects(true);
       }
   
  -
       /**
        * Path-setting constructor.
  +     * 
        * @param path the path to request
  -     *
  +     * 
        * @since 1.0
        */
       public GetMethod(String path) {
  @@ -124,12 +141,12 @@
           setFollowRedirects(true);
       }
   
  -
       /**
        * Constructor.
  +     * 
        * @param path the path to request
        * @param tempDir the directory in which to store temporary files
  -     *
  +     * 
        * @since 1.0
        */
       public GetMethod(String path, String tempDir) {
  @@ -142,10 +159,11 @@
   
       /**
        * Constructor.
  +     * 
        * @param path the path to request
        * @param tempDir the directory in which to store temporary files
        * @param tempFile the file (under tempDir) to buffer contents to
  -     *
  +     * 
        * @since 1.0
        */
       public GetMethod(String path, String tempDir, String tempFile) {
  @@ -159,9 +177,10 @@
   
       /**
        * Constructor.
  +     * 
        * @param path the path to request
  -     * @param tempFile the file to buffer contents to
  -     *
  +     * @param fileData the file to buffer contents to
  +     * 
        * @since 1.0
        */
       public GetMethod(String path, File fileData) {
  @@ -172,72 +191,140 @@
           setFollowRedirects(true);
       }
   
  -    // ----------------------------------------------------- Instance Variables
  +    //~ Methods ииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
   
       /**
  -     * By default, the get method will buffer read data to the memory.
  +     * File data setter.
  +     * 
  +     * @param fileData the file to buffer data to
  +     * 
  +     * @since 1.0
        */
  -    protected boolean useDisk = false;
  -
  +    public void setFileData(File fileData) {
  +        checkNotUsed();
  +        this.fileData = fileData;
  +    }
   
       /**
  -     * If we're not using the HD, we're using a memory byte buffer.
  +     * File data getter.
  +     * 
  +     * @return the file being used for buffering data
  +     * 
  +     * @since 1.0
        */
  -    protected byte[] memoryData;
  +    public File getFileData() {
  +        return fileData;
  +    }
   
  +    // --------------------------------------------------------- Public Methods
   
       /**
  -     * File which contains the buffered data.
  +     * Returns <tt>"GET"</tt>.
  +     * 
  +     * @return <tt>"GET"</tt>
  +     * 
  +     * @since 2.0
        */
  -    protected File fileData;
  -
  +    public String getName() {
  +        return "GET";
  +    }
   
       /**
  -     * Temporary directory to use.
  +     * Return my response body, if any, as a byte array. Otherwise return
  +     * <tt>null</tt>.
  +     * 
  +     * @return the response body as a byte array
  +     * 
  +     * @since 2.0
        */
  -    protected String tempDir = TEMP_DIR;
  +    public byte[] getResponseBody() {
  +        log.trace("enter GetMethod.getResponseBody()");
   
  +        checkUsed();
   
  -    /**
  -     * Temporary file to use.
  -     */
  -    protected String tempFile = null;
  +        if (useDisk) {
  +            try {
  +                InputStream is = new FileInputStream(fileData);
  +                byte[] buffer = new byte[4096];
  +                ByteArrayOutputStream os = new ByteArrayOutputStream();
  +                int nb = 0;
   
  +                while (true) {
  +                    nb = is.read(buffer);
   
  -    // ------------------------------------------------------------- Properties
  +                    if (nb == -1) {
  +                        break;
  +                    }
   
  +                    os.write(buffer, 0, nb);
  +                }
  +
  +                is.close();
  +
  +                return os.toByteArray();
  +            } catch (IOException e) {
  +                log.error("Exception in GetMethod.getResponseBody() while "
  +                          + "retrieving data from file \"" + fileData + "\".",
  +                          e);
  +
  +                return null;
  +            }
  +        } else {
  +            return memoryData;
  +        }
  +    }
   
       /**
  -     * Buffer the response in a file or not. The default is false.
  -     *
  -     * @param useDisk If true the entire response will be buffered in a
  -     * temporary file.
  -     *
  -     * @since 1.0
  +     * Return my response body, if any, as an {@link InputStream}. Otherwise
  +     * return <tt>null</tt>.
  +     * 
  +     * @return a stream to read the response from
  +     * 
  +     * @throws IOException when there is an error reading the response
  +     * 
  +     * @since 2.0
        */
  -    public void setUseDisk(boolean useDisk) {
  -        checkNotUsed();
  -        this.useDisk = useDisk;
  -    }
  +    public InputStream getResponseBodyAsStream() throws IOException {
  +        log.trace("enter GetMethod.getResponseBodyAsStream()");
  +
  +        checkUsed();
   
  +        if (useDisk) {
  +            return new FileInputStream(fileData);
  +        } else {
  +            if (null == memoryData) {
  +                return null;
  +            } else {
  +                return new ByteArrayInputStream(memoryData);
  +            }
  +        }
  +    }
   
       /**
  -     * Tells if the response will be buffered in a file.
  -     *
  -     * @param boolean If true the entire response will be buffered in a
  -     * temporary file.
  -     *
  -     * @since 1.0
  +     * Return the response body as a String
  +     * 
  +     * @return Return my response body, if any, as a {@link String}. Otherwise
  +     *         return <tt>null</tt>.
  +     * 
  +     * @since 2.0
        */
  -    public boolean getUseDisk() {
  -        return useDisk;
  +    public String getResponseBodyAsString() {
  +        log.trace("enter GetMethod.getResponseBodyAsString()");
  +
  +        byte[] data = getResponseBody();
  +
  +        if (null == data) {
  +            return null;
  +        } else {
  +            return new String(data);
  +        }
       }
   
       /**
        * Temporary directory setter.
  -     *
  +     * 
        * @param tempDir New value of tempDir
  -     *
  +     * 
        * @since 1.0
        */
       public void setTempDir(String tempDir) {
  @@ -246,22 +333,22 @@
           setUseDisk(true);
       }
   
  -
       /**
        * Temporary directory getter.
  -     *
  +     * 
  +     * @return the current temporary directory
  +     * 
        * @since 1.0
        */
       public String getTempDir() {
           return tempDir;
       }
   
  -
       /**
        * Temporary file setter.
  -     *
  +     * 
        * @param tempFile New value of tempFile
  -     *
  +     * 
        * @since 1.0
        */
       public void setTempFile(String tempFile) {
  @@ -269,57 +356,49 @@
           this.tempFile = tempFile;
       }
   
  -
       /**
        * Temporary file getter.
  -     *
  +     * 
  +     * @return the current temporary file
  +     * 
        * @since 1.0
        */
       public String getTempFile() {
           return tempFile;
       }
   
  +    // ------------------------------------------------------------- Properties
   
       /**
  -     * File data getter.
  -     *
  +     * Buffer the response in a file or not. The default is false.
  +     * 
  +     * @param useDisk If true the entire response will be buffered in a
  +     *        temporary file.
  +     * 
        * @since 1.0
        */
  -    public File getFileData() {
  -        return fileData;
  +    public void setUseDisk(boolean useDisk) {
  +        checkNotUsed();
  +        this.useDisk = useDisk;
       }
   
  -
       /**
  -     * File data setter.
  -     *
  +     * Tells if the response will be buffered in a file.
  +     * 
  +     * @return true if the response will be buffered
  +     * 
        * @since 1.0
        */
  -    public void setFileData(File fileData) {
  -        checkNotUsed();
  -        this.fileData = fileData;
  +    public boolean getUseDisk() {
  +        return useDisk;
       }
   
  -
  -    // --------------------------------------------------------- Public Methods
  -
       /**
  -     * Returns <tt>"GET"</tt>.
  -     * @return <tt>"GET"</tt>
  -     *
  -     * @since 2.0
  -     */
  -    public String getName() {
  -        return "GET";
  -    }
  -
  -
  -   /** 
        * Override recycle to reset redirects default.
  -     *
  +     * 
        * @since 1.0
        */
  -   public void recycle() {
  +    public void recycle() {
           log.trace("enter GetMethod.recycle()");
   
           super.recycle();
  @@ -328,118 +407,54 @@
           setFollowRedirects(true);
       }
   
  -   /**
  -     * Return my response body, if any,
  -     * as a byte array.
  -     * Otherwise return <tt>null</tt>.
  -     *
  -     * @since 2.0
  -     */
  -   public byte[] getResponseBody() {
  -       log.trace("enter GetMethod.getResponseBody()");
  -
  -       checkUsed();
  -       if(useDisk) {
  -           try {
  -               InputStream is = new FileInputStream(fileData);
  -               byte[] buffer = new byte[4096];
  -               ByteArrayOutputStream os = new ByteArrayOutputStream();
  -               int nb = 0;
  -               while (true) {
  -                   nb = is.read(buffer);
  -                   if (nb == -1)
  -                       break;
  -                   os.write(buffer, 0, nb);
  -               }
  -               is.close();
  -               return os.toByteArray();
  -           } catch(IOException e) {
  -               log.error("Exception in GetMethod.getResponseBody() while retrieving data from file \"" + fileData + "\".",e);
  -               return null;
  -           }
  -       } else {
  -           return memoryData;
  -       }
  -   }
  -
  -   /**
  -    * Return my response body, if any,
  -    * as a {@link String}.
  -    * Otherwise return <tt>null</tt>.
  -     *
  -     * @since 2.0
  -    */
  -   public String getResponseBodyAsString() {
  -       log.trace("enter GetMethod.getResponseBodyAsString()");
  -
  -       byte[] data = getResponseBody();
  -       if(null == data) {
  -           return null;
  -       } else {
  -           return new String(data);
  -       }
  -   }
  -
  -
  -    /**
  -     * Return my response body, if any,
  -     * as an {@link InputStream}.
  -     * Otherwise return <tt>null</tt>.
  -     *
  -     * @since 2.0
  -     */
  -    public InputStream getResponseBodyAsStream()
  -    throws IOException {
  -        log.trace("enter GetMethod.getResponseBodyAsStream()");
  -
  -        checkUsed();
  -        if (useDisk) {
  -            return new FileInputStream(fileData);
  -        } else {
  -            if(null == memoryData) {
  -                return null;
  -            } else {
  -                return new ByteArrayInputStream(memoryData);
  -            }
  -        }
  -    }
  -
  -
       // ----------------------------------------------------- HttpMethod Methods
   
       /**
  -     * Overrides method in {@link HttpMethodBase} to
  -     * write data to the appropriate buffer.
  -     *
  +     * Overrides method in {@link HttpMethodBase} to write data to the
  +     * appropriate buffer.
  +     * 
  +     * @param state the shared http state
  +     * @param conn the connection to read data from
  +     * 
  +     * @throws IOException when there are problems reading from the connection
  +     * 
        * @since 2.0
        */
       protected void readResponseBody(HttpState state, HttpConnection conn)
  -    throws IOException {
  -        log.trace("enter GetMethod.readResponseBody(HttpState, HttpConnection)");
  +                             throws IOException {
  +        log.trace("enter GetMethod.readResponseBody(HttpState, "
  +            + "HttpConnection)");
   
           OutputStream out = null;
  +
           if (useDisk) {
               if (fileData == null) {
                   // Create a temporary file on the HD
                   File dir = new File(tempDir);
                   dir.deleteOnExit();
                   dir.mkdirs();
  +
                   String tempFileName = null;
  +
                   if (tempFile == null) {
                       String encodedPath = URLEncoder.encode(getPath());
                       int length = encodedPath.length();
  +
                       if (length > 200) {
  -                        encodedPath =
  -                            encodedPath.substring(length - 190, length);
  +                        encodedPath = encodedPath.substring(length - 190, 
  +                                                            length);
                       }
  +
                       tempFileName = System.currentTimeMillis() + "-"
  -                        + encodedPath + ".tmp";
  +                                   + encodedPath + ".tmp";
                   } else {
                       tempFileName = tempFile;
                   }
  +
                   fileData = new File(tempDir, tempFileName);
                   fileData.deleteOnExit();
               }
  +
               out = new FileOutputStream(fileData);
           } else {
               out = new ByteArrayOutputStream();
  @@ -453,4 +468,4 @@
   
           out.close();
       }
  -}
  +}
  \ No newline at end of file
  
  
  
  1.4       +21 -20    jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpUrlMethod.java
  
  Index: HttpUrlMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpUrlMethod.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- HttpUrlMethod.java	28 Jul 2002 18:08:57 -0000	1.3
  +++ HttpUrlMethod.java	1 Sep 2002 01:27:37 -0000	1.4
  @@ -59,36 +59,37 @@
    * [Additional notices, if required by prior licensing conditions]
    *
    */
  -
   package org.apache.commons.httpclient;
   
   import java.net.MalformedURLException;
   
   /**
  - * HttpUrlMethod extends HttpMethod.  HttpMethod only contains
  - * the path portion of a URL and gets the host:port from the connection
  - * maintained in HttpCleint.  HttpUrlMethod is initialized with a fully
  - * specified URL and is used with HttpMultiClient.  HttpMultiClient 
  - * chooses the appropriate HttpConnectoin (via HttpConnectionManager)
  - * based on the host and port in the URL.
  - *
  + * HttpUrlMethod extends HttpMethod.  HttpMethod only contains the path portion
  + * of a URL and gets the host:port from the connection maintained in
  + * HttpCleint.  HttpUrlMethod is initialized with a fully specified URL and is
  + * used with HttpMultiClient.  HttpMultiClient  chooses the appropriate
  + * HttpConnectoin (via HttpConnectionManager) based on the host and port in
  + * the URL.
  + * 
    * @author Marc A. Saegesser
    */
  -public interface HttpUrlMethod extends HttpMethod
  -{
  +public interface HttpUrlMethod extends HttpMethod {
  +    //~ Methods ииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
  +
       /**
  -     * Sets the URL.  Calls the underlying HttpMethod.setPath()
  -     * with the url's path.  If the url contains a query string
  -     * the underlying HttpMethod.setQueryString() is called.
  -     *
  +     * Sets the URL.  Calls the underlying HttpMethod.setPath() with the url's
  +     * path.  If the url contains a query string the underlying
  +     * HttpMethod.setQueryString() is called.
  +     * 
        * @param url - the URL for this request.
  +     * @throws MalformedURLException when the {@link URL} can't be created
        */
  -    public void setUrl(String url) throws MalformedURLException;
  +    void setUrl(String url) throws MalformedURLException;
   
       /**
        * Returns this request's URL.
        * 
        * @return the request's URL.
        */
  -    public String getUrl();
  -}
  +    String getUrl();
  +}
  \ No newline at end of file
  
  
  
  1.14      +18 -12    jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMultiClient.java
  
  Index: HttpMultiClient.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMultiClient.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- HttpMultiClient.java	28 Jul 2002 18:08:57 -0000	1.13
  +++ HttpMultiClient.java	1 Sep 2002 01:27:37 -0000	1.14
  @@ -98,7 +98,7 @@
       private int timeoutConnection = 0;
       /** how long to wait for a request to complete */
       private int timeoutRequest = 0;
  -
  +    /** factory for ssl connections */
       private SSLSocketFactory sslSocketFactory = null;
   
       // ----------------------------------------------------------- Constructors
  @@ -176,12 +176,15 @@
       }
   
       /**
  -     * Sets the connection timeout.  The connection timeout is how long (in milliseconds) HttpMultiClient
  -     * will block in executeMethod waiting for connection to the requested server to
  -     * become available.  Setting the connection timeout to 0 will cause executeMethod() to
  +     * Sets the connection timeout. The connection timeout is how long (in
  +     * milliseconds) HttpMultiClient will block in executeMethod waiting for 
  +     * a connection to the requested server to become available.
  +     * <br />
  +     * Setting the connection timeout to 0 will cause executeMethod() to
        * block indefinitely (this is the default behaviour).
        *
  -     * @param timeout the time, in milliseconds, to block waiting for an available connection
  +     * @param timeout the time, in milliseconds, to block waiting for an 
  +     *      available connection
        * @see #getConnectionTimeout
        * @see #executeMethod
        */
  @@ -200,8 +203,9 @@
       }
   
       /**
  -     * Sets the request timeout.  The executeMethod method calls HttpConnection.setSoTimeout()
  -     * with this value before executing the request.
  +     * Sets the request timeout. The executeMethod method calls 
  +     * HttpConnection.setSoTimeout() with this value before executing the 
  +     * request.
        *
        * @param timeout the SoTimeout value, in milliseconds
        * @see #getRequestTimeout
  @@ -256,8 +260,10 @@
   
       /**
        * Specifies an alternative factory for SSL sockets.
  -     * @see HttpConnection#setSSLSocketFactory(SSLSocketFactory) HttpConnection.setSSLSocketFactory
  -     * @param sslSocketFactory a living instance of the alternative SSLSocketFactory
  +     * @see HttpConnection#setSSLSocketFactory(SSLSocketFactory) HttpConnection
  +     *      setSSLSocketFactory
  +     * @param sslSocketFactory a living instance of the alternative
  +     *      SSLSocketFactory
        */
       public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
           this.sslSocketFactory = sslSocketFactory;
  
  
  
  1.26      +509 -407  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Authenticator.java
  
  Index: Authenticator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Authenticator.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- Authenticator.java	25 Aug 2002 16:28:44 -0000	1.25
  +++ Authenticator.java	1 Sep 2002 01:27:37 -0000	1.26
  @@ -59,44 +59,44 @@
    * [Additional notices, if required by prior licensing conditions]
    *
    */
  -
   package org.apache.commons.httpclient;
   
  -import org.apache.commons.logging.Log;
  -import org.apache.commons.logging.LogFactory;
  -
   import java.security.MessageDigest;
   import java.util.Hashtable;
   import java.util.StringTokenizer;
   
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
  +
   /**
  - * Utility methods for HTTP authorization and authentication.
  + * Utility methods for HTTP authorization and authentication.  This class
  + * provides utility methods for generating responses to HTTP www and proxy
  + * authentication challenges.
    * 
  - * This class provides utility methods for generating
  - * responses to HTTP www and proxy authentication challenges.
    * <p>
  - * Preemptive authentication can be turned on by using the property value of 
  + * Preemptive authentication can be turned on by using the property value of
    * #PREEMPTIVE_PROPERTY.  If left unspecified, it has the default value of
    * #PREEMPTIVE_DEFAULT.  This configurable behaviour conforms to rcf2617:
    * <blockquote>
  - *  A client SHOULD assume that all paths at or deeper than the depth of
  - *  the last symbolic element in the path field of the Request-URI also
  - *      are within the protection space specified by the Basic realm value of
  - *      the current challenge. A client MAY preemptively send the
  - *      corresponding Authorization header with requests for resources in
  - *      that space without receipt of another challenge from the server.
  - *      Similarly, when a client sends a request to a proxy, it may reuse a
  - *      userid and password in the Proxy-Authorization header field without
  - *      receiving another challenge from the proxy server.
  + * A client SHOULD assume that all paths at or deeper than the depth of the
  + * last symbolic element in the path field of the Request-URI also are within
  + * the protection space specified by the Basic realm value of the current
  + * challenge. A client MAY preemptively send the corresponding Authorization
  + * header with requests for resources in that space without receipt of another
  + * challenge from the server. Similarly, when a client sends a request to a
  + * proxy, it may reuse a userid and password in the Proxy-Authorization header
  + * field without receiving another challenge from the proxy server.
    * </blockquote>
  - *
  + * </p>
  + * 
  + * @version $Revision$ $Date$
    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
    * @author Rodney Waldhoff
    * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    * @author Ortwin GlЧck
  - * @version $Revision$ $Date$
    */
   class Authenticator {
  +    //~ Static variables/initializers ииииииииииииииииииииииииииииииииииииииииии
   
       /** <tt>org.apache.commons.httpclient.Authenticator</tt> log. */
       private static final Log log = LogFactory.getLog(Authenticator.class);
  @@ -104,378 +104,481 @@
       /** Base 64 encoder. */
       private static Base64 base64 = new Base64();
   
  -    /** 
  -     * The boolean property name to turn on preemptive authentication. 
  -     */
  +    /** The boolean property name to turn on preemptive authentication. */
       static final String PREEMPTIVE_PROPERTY = 
           "httpclient.authentication.preemptive";
   
  -    /**
  -     * The default property value for #PREEMPTIVE_PROPERTY.
  -     */
  +    /** The default property value for #PREEMPTIVE_PROPERTY. */
       static final String PREEMPTIVE_DEFAULT = "false";
   
  -    /**
  -     * The www authenticate challange header
  -     */
  +    /** The www authenticate challange header */
       public static final String WWW_AUTH = "WWW-Authenticate";
   
  -    /**
  -     * The www authenticate response header
  -     */
  +    /** The www authenticate response header */
       public static final String WWW_AUTH_RESP = "Authorization";
   
  -    /**
  -     * The proxy authenticate challange header
  -     */
  +    /** The proxy authenticate challange header */
       public static final String PROXY_AUTH = "Proxy-Authenticate";
   
  +    /** The proxy authenticate response header */
  +    public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
  +
       /**
  -     * The proxy authenticate response header
  +     * Hexa values used when creating 32 character long digest in HTTP Digest
  +     * in case of authentication.
  +     * 
  +     * @see #encode(byte[])
        */
  -    public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
  +    private static final char[] HEXADECIMAL = {
  +        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 
  +        'e', 'f'
  +    };
   
  +    //~ Methods ииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииииии
   
       /**
  -     * Add requisite authentication credentials to the given <i>method</i>
  -     * in the given <i>state</i> if possible.
  -     *
  +     * Creates an MD5 response digest.
  +     * 
  +     * @param uname Username
  +     * @param pwd Password
  +     * @param dCreds Hashtable containing necessary header parameters to
  +     *        construct the digest. It must/can contain: uri, realm, nonce,
  +     *        cnonce, qop, nc.
  +     * 
  +     * @return The created digest as string. This will be the response tag's
  +     *         value in the Authentication HTTP header.
  +     * @throws HttpException when MD5 is an unsupported algorithm
  +     * 
  +     * @todo + Add createDigest() method 
  +     */
  +    public static String createDigest(String uname, String pwd, 
  +                                      Hashtable dCreds)
  +                               throws HttpException {
  +        log.trace("enter Authenticator.createDigest(String, String, "
  +            + "Hashtable)");
  +
  +        final String digAlg = "MD5";
  +
  +        // Collecting required tokens
  +        String uri = removeQuotes((String) dCreds.get("uri"));
  +        String realm = removeQuotes((String) dCreds.get("realm"));
  +        String nonce = removeQuotes((String) dCreds.get("nonce"));
  +        String nc = removeQuotes((String) dCreds.get("nc"));
  +        String cnonce = removeQuotes((String) dCreds.get("cnonce"));
  +        String qop = removeQuotes((String) dCreds.get("qop"));
  +        String method = (String) dCreds.get("methodname");
  +
  +        if (qop != null) {
  +            qop = "auth";
  +        }
  +
  +        MessageDigest md5Helper;
  +
  +        try {
  +            md5Helper = MessageDigest.getInstance(digAlg);
  +        } catch (Exception e) {
  +            log.error("ERROR! Unsupported algorithm in HTTP Digest "
  +                      + "authentication: " + digAlg, e);
  +            throw new HttpException("Unsupported algorithm in HTTP Digest "
  +                                    + "authentication: " + digAlg);
  +        }
  +
  +        // Calculating digest according to rfc 2617
  +        String a2 = method + ":" + uri;
  +        String md5a2 = encode(md5Helper.digest(a2.getBytes()));
  +        String digestValue = uname + ":" + realm + ":" + pwd;
  +        String md5a1 = encode(md5Helper.digest(digestValue.getBytes()));
  +        String serverDigestValue;
  +
  +        if (qop == null) {
  +            serverDigestValue = md5a1 + ":" + nonce + ":" + md5a2;
  +        } else {
  +            serverDigestValue = md5a1 + ":" + nonce + ":" + nc + ":" + cnonce
  +                                + ":" + qop + ":" + md5a2;
  +        }
  +
  +        String serverDigest = encode(md5Helper.digest(
  +                                             serverDigestValue.getBytes()));
  +
  +        return serverDigest;
  +    }
  +
  +    /**
  +     * Add requisite authentication credentials to the given <i>method</i> in
  +     * the given <i>state</i> if possible.
  +     * 
        * @param method the HttpMethod which requires authentication
        * @param state the HttpState object providing Credentials
  -     *
  -     * @throws HttpException when a parsing or other error occurs
  -     * @throws UnsupportedOperationException when the challenge type is not supported
  +     * 
        * @return true if the Authenticate response header was added
  -     *
  +     * 
  +     * @throws HttpException when a parsing or other error occurs
  +     * @throws UnsupportedOperationException when the challenge type is not
  +     *         supported
  +     * 
        * @see HttpState#setCredentials(String,Credentials)
        * @see #authenticate(HttpMethod,HttpState,Header,String)
        */
  -    static boolean authenticate(HttpMethod method, HttpState state) 
  -    throws HttpException, UnsupportedOperationException {
  +    static boolean authenticate(HttpMethod method, HttpState state)
  +                         throws HttpException, UnsupportedOperationException {
           log.trace("enter Authenticator.authenticate(HttpMethod, HttpState)");
   
           Header challengeHeader = method.getResponseHeader(WWW_AUTH);
  +
           return authenticate(method, state, challengeHeader, WWW_AUTH_RESP);
       }
   
       /**
  -     * Add requisite proxy authentication credentials to the given <i>method</i>
  -     * in the given <i>state</i> if possible.
  -     *
  +     * Add requisite proxy authentication credentials to the given
  +     * <i>method</i> in the given <i>state</i> if possible.
  +     * 
        * @param method the HttpMethod which requires authentication
        * @param state the HttpState object providing Credentials
  -     *
  -     * @throws HttpException when a parsing or other error occurs
  -     * @throws UnsupportedOperationException when the given challenge type is not supported
  +     * 
        * @return true if the Authenticate response header was added
  -     *
  +     * 
  +     * @throws HttpException when a parsing or other error occurs
  +     * @throws UnsupportedOperationException when the given challenge type is
  +     *         not supported
  +     * 
        * @see HttpState#setProxyCredentials(String,Credentials)
        * @see #authenticate(HttpMethod,HttpState,Header,String)
        */
  -    static boolean authenticateProxy(HttpMethod method, HttpState state) 
  -    throws HttpException, UnsupportedOperationException {
  -        log.trace("enter Authenticator.authenticateProxy(HttpMethod, HttpState)");
  +    static boolean authenticateProxy(HttpMethod method, HttpState state)
  +                              throws HttpException, 
  +                                     UnsupportedOperationException {
  +        log.trace("enter Authenticator.authenticateProxy(HttpMethod, "
  +                  + "HttpState)");
   
           Header challengeHeader = method.getResponseHeader(PROXY_AUTH);
  +
           return authenticate(method, state, challengeHeader, PROXY_AUTH_RESP);
       }
   
  -
       /**
  -     * Add requisite authentication credentials to the given
  -     * <i>method</i> using the given the <i>challengeHeader</i>.
  -     *
  -     * Currently <b>Basic</b> and <b>Digest</b> authentication are supported.
  -     * If the challengeHeader is null, the default authentication credentials
  -     * will be sent.
  -     *
  -     * @param method the http method to add the authentication header to
  -     * @param challengeHeader the header the web server created to challenge the credentials
  -     * @param state the http state object providing {@link Credentials}
  -     * @param respHeader the response header to add (e.g. proxy or standard)
  -     *
  -     * @throws HttpException when an error occurs parsing the challenge
  -     * @throws UnsupportedOperationException when the given challenge type is not supported
  -     * @return true if a response header was added
  -     *
  -     * @see #basic
  -     * @see #digest
  -     * @see HttpMethod#addRequestHeader
  +     * Return a Basic <tt>Authorization</tt> header value for the given {@link
  +     * UsernamePasswordCredentials}.
  +     * 
  +     * @param cred the credentials to encode
  +     * 
  +     * @return the credentials as a Basic Authentication string
        */
  -    private static boolean authenticate(HttpMethod method, HttpState state, Header authenticateHeader, String respHeader) 
  -    throws HttpException, UnsupportedOperationException {
  -
  -        log.trace("enter Authenticator.authenticate(HttpMethod, HttpState, Header, String)");
  -
  -        //check the preemptive policy
  -        //TODO: this needs to be a service from some configuration class
  -        String preemptive_str = System.getProperties().getProperty(
  -                PREEMPTIVE_PROPERTY, PREEMPTIVE_DEFAULT);
  -        preemptive_str = preemptive_str.trim().toLowerCase();
  -
  -        if (! (preemptive_str.equals("true") || preemptive_str.equals("false")) ){ //property problem
  -            log.warn("Configuration property " + PREEMPTIVE_PROPERTY + 
  -                    " must be either true or false.  Using default: " + PREEMPTIVE_DEFAULT);
  -            preemptive_str = PREEMPTIVE_DEFAULT;
  -        }
  -        boolean preemptive = ("true".equals(preemptive_str));
  -
  -        //if there is no challenge, attempt to use preemptive authorization
  -        if (authenticateHeader == null){
  -            if (preemptive){ 
  -                log.debug("Preemptively sending default basic credentials");
  -                try{
  -                    Header requestHeader = Authenticator.basic(null, state, respHeader);
  -                    method.addRequestHeader(requestHeader);
  -                    return true;
  -                } catch (HttpException httpe) {
  -                    log.debug("No default credentials to preemptively send");
  -                    return false;
  -                }
  -            } else { //no challenge and no default creds so do nothing
  -                return false;
  -            }
  -        }
  -        log.debug("Attempting to authenticate header: " + authenticateHeader);
  -
  -
  -        // XXX: Get the challenge from the header
  -        String authenticateValue = authenticateHeader.getValue();
  -
  -
  -        // TODO: Use regular expression pattern matching to parse the challenge
  -        //FIXME: This fails if the contents of a challenge contains a ','
  -        StringTokenizer challengeTok = new StringTokenizer(authenticateValue, ",");
  -        Hashtable challengeMap = new Hashtable(7);
  -        while(challengeTok.hasMoreTokens()){
  -            
  -            // Parse the authentication scheme from the challenge
  -            String chall = challengeTok.nextToken();
  -            StringTokenizer authTok = new StringTokenizer(chall, " ");
  -            String authScheme = authTok.nextToken();
  -
  -            // Store the challenge keyed on the lower case authenticaion scheme
  -            challengeMap.put(authScheme.toLowerCase(), chall);
  -        }
  -
  -        Header requestHeader = null;
  -        if (challengeMap.containsKey("digest")) {
  -            String challenge = (String)challengeMap.get("digest");
  -            String realm = parseRealmFromChallenge(challenge);
  -            requestHeader = Authenticator.digest(realm, method, state, respHeader);
  -        } else if (challengeMap.containsKey("basic")) {
  -            String challenge = (String)challengeMap.get("basic");
  -            String realm = parseRealmFromChallenge(challenge);
  -            requestHeader = Authenticator.basic(realm, state, respHeader);
  -        } else if (challengeMap.size() == 0) {
  -            throw new HttpException("No authentication scheme found in '" +
  -                    authenticateValue);
  -        } else {
  -            throw new UnsupportedOperationException("Requested authentication scheme " +
  -                    challengeMap.keySet() + " is unsupported");
  -        }
  -
  -        //Add the header and return the result
  -        if(requestHeader != null) {  // add the header
  -            method.addRequestHeader(requestHeader);
  -            return true;
  -        } else {  // don't add the header
  -            return false;
  -        } 
  -
  -    } 
  -
  +    static String basic(UsernamePasswordCredentials cred) {
  +        log.trace("enter Authenticator.basic(UsernamePasswordCredentials)");
   
  -    /** 
  -     * Parse the realm from the authentication challenge
  -     */
  -    private static String parseRealmFromChallenge(String challenge)
  -    throws HttpException {
  -        // FIXME: Note that this won't work if there is more than one realm within the challenge
  -        try{
  -            StringTokenizer strtok = new StringTokenizer(challenge, "=");
  -            String realmName = strtok.nextToken().trim();
  -            String realm =  strtok.nextToken().trim();
  -            int firstq = realm.indexOf('"');
  -            int lastq = realm.lastIndexOf('"');
  -            if (firstq+1 < lastq) {
  -                realm = realm.substring(firstq+1, lastq);
  -            }
  -            log.debug("Parsed realm '" + realm + "' from challenge '" + challenge + "'");
  -            return realm;
  -        } catch (Exception ex) {
  -            throw new HttpException("Failed to parse realm from challenge '" + challenge + "'");
  -        }
  +        String authString = cred.getUserName() + ":" + cred.getPassword();
   
  +        return "Basic " + new String(base64.encode(authString.getBytes()));
       }
   
  -
  -
       /**
  -     * Create a Basic <tt>Authorization</tt> header for the given
  -     * <i>realm</i> and <i>state</i> to the given <i>method</i>.
  -     *
  +     * Create a Basic <tt>Authorization</tt> header for the given <i>realm</i>
  +     * and <i>state</i> to the given <i>method</i>.
  +     * 
        * @param realm the basic realm to authenticate to
        * @param state a {@link HttpState} object providing {@link Credentials}
        * @param respHeader the header's name to store the authentication response
  -     * in. PROXY_AUTH_RESP will force the proxy credentials to be used.
  -     *
  +     *        in. PROXY_AUTH_RESP will force the proxy credentials to be used.
  +     * 
        * @return a basic <tt>Authorization</tt> header
  -     *
  +     * 
        * @throws HttpException when no matching credentials are available
        */
       static Header basic(String realm, HttpState state, String respHeader)
  -    throws HttpException {
  +                 throws HttpException {
           log.trace("enter Authenticator.basic(String, HttpState, String)");
   
           boolean proxy = PROXY_AUTH_RESP.equals(respHeader);
           UsernamePasswordCredentials cred = null;
  +
           try {
  -            cred = (UsernamePasswordCredentials) ( proxy ?
  -                    state.getProxyCredentials(realm) :
  -                    state.getCredentials(realm));
  -        } catch(ClassCastException e) {
  -            throw new HttpException("UsernamePasswordCredentials required for Basic authentication.");
  +            cred = (UsernamePasswordCredentials) (proxy
  +                ? state.getProxyCredentials(realm)
  +                : state.getCredentials(realm));
  +        } catch (ClassCastException e) {
  +            throw new HttpException("UsernamePasswordCredentials required for "
  +                                    + "Basic authentication.");
           }
   
  -        if(null == cred) {
  -            throw new HttpException("No credentials available for the Basic authentication realm \'" + 
  -                    realm + "\'");
  +        if (null == cred) {
  +            throw new HttpException("No credentials available for the Basic "
  +                                    + "authentication realm \'" + realm + "\'");
           } else {
               return new Header(respHeader, Authenticator.basic(cred));
           }
       }
   
       /**
  -     * Return a Basic <tt>Authorization</tt> header value for the
  -     * given {@link UsernamePasswordCredentials}.
  -     */
  -    static String basic(UsernamePasswordCredentials cred)
  -    throws HttpException {
  -        log.trace("enter Authenticator.basic(UsernamePasswordCredentials)");
  -
  -        String authString = cred.getUserName() + ":" + cred.getPassword();
  -        return "Basic " + new String(base64.encode(authString.getBytes()));
  -    }
  -
  -    /**
  -     * Create a Digest <tt>Authorization</tt> header for the given
  -     * <i>realm</i> and <i>state</i> to the given <i>method</i>.
  -     *
  +     * Create a Digest <tt>Authorization</tt> header for the given <i>realm</i>
  +     * and <i>state</i> to the given <i>method</i>.
  +     * 
        * @param realm the basic realm to authenticate to
  +     * @param method the {@link HttpMethod request} requiring the digest
        * @param state a {@link HttpState} object providing {@link Credentials}
        * @param respHeader the header's name to store the authentication response
  -     * in. PROXY_AUTH_RESP will force the proxy credentials to be used.
  -     *
  +     *        in. PROXY_AUTH_RESP will force the proxy credentials to be used.
  +     * 
        * @return a digest <tt>Authorization</tt> header
  -     *
  +     * 
        * @throws HttpException when no matching credentials are available
        */
  -    static Header digest(String realm, HttpMethod method, HttpState state, String respHeader) 
  -    throws HttpException {
  -        log.trace("enter Authenticator.digest(String, HttpMethod, HttpState, String)");
  +    static Header digest(String realm, HttpMethod method, HttpState state, 
  +                         String respHeader) throws HttpException {
  +        log.trace("enter Authenticator.digest(String, HttpMethod, HttpState, "
  +                  + "String)");
   
           boolean proxy = PROXY_AUTH_RESP.equals(respHeader);
           UsernamePasswordCredentials cred = null;
  +
           try {
  -            cred = (UsernamePasswordCredentials) ( proxy ?
  -                    state.getProxyCredentials(realm) :
  -                    state.getCredentials(realm));
  -        } catch(ClassCastException e) {
  -            throw new HttpException("UsernamePasswordCredentials required for Digest authentication.");
  -        }
  -        if(null == cred) {
  -            if(log.isInfoEnabled()) {
  -                log.info("No credentials found for realm \"" + realm + "\", attempting to use default credentials.");
  +            cred = (UsernamePasswordCredentials) (proxy
  +                ? state.getProxyCredentials(realm)
  +                : state.getCredentials(realm));
  +        } catch (ClassCastException e) {
  +            throw new HttpException("UsernamePasswordCredentials required for "
  +                                    + "Digest authentication.");
  +        }
  +
  +        if (null == cred) {
  +            if (log.isInfoEnabled()) {
  +                log.info("No credentials found for realm \"" + realm + "\", "
  +                         + "attempting to use default credentials.");
               }
  +
               try {
  -                cred = (UsernamePasswordCredentials)( proxy ?
  -                        state.getProxyCredentials(null) :
  -                        state.getCredentials(null));
  -            } catch(ClassCastException e) {
  -                throw new HttpException("UsernamePasswordCredentials required for Digest authentication.");
  +                cred = (UsernamePasswordCredentials) (proxy
  +                    ? state.getProxyCredentials(null)
  +                    : state.getCredentials(null));
  +            } catch (ClassCastException e) {
  +                throw new HttpException("UsernamePasswordCredentials required "
  +                                        + "for Digest authentication.");
               }
           }
  -        if(null == cred) {
  -            throw new HttpException("No credentials available for the Digest authentication realm \"" + realm + "\"/");
  +
  +        if (null == cred) {
  +            throw new HttpException("No credentials available for the Digest "
  +                + "authentication realm \"" + realm + "\"/");
           } else {
               Hashtable headers = getHTTPDigestCredentials(method, proxy);
  -            headers.put( "cnonce", "\""+createCnonce()+"\"");
  -            headers.put( "nc", "00000001");
  -            headers.put( "uri", method.getPath() );
  -            headers.put( "methodname", method.getName() );
  +            headers.put("cnonce", "\"" + createCnonce() + "\"");
  +            headers.put("nc", "00000001");
  +            headers.put("uri", method.getPath());
  +            headers.put("methodname", method.getName());
  +
               return new Header(respHeader, Authenticator.digest(cred, headers));
           }
       }
   
       /**
  -     * Return a Digest <tt>Authorization</tt> header value for the
  -     * given {@link UsernamePasswordCredentials}.
  +     * Return a Digest <tt>Authorization</tt> header value for the given {@link
  +     * UsernamePasswordCredentials}.
  +     * @param cred Credentials to create the digest with
  +     * @param headers The headers for the current request
  +     * 
  +     * @return a string containing the authorization header for digest
  +     * @throws HttpException When a recoverable error occurs
  +     */
  +    static String digest(UsernamePasswordCredentials cred, Hashtable headers)
  +                  throws HttpException {
  +        log.trace("enter Authenticator.digest(UsernamePasswordCredentials, "
  +                  + "Hashtable)");
  +
  +        String digest = createDigest(cred.getUserName(), cred.getPassword(), 
  +                                     headers);
  +
  +        return "Digest "
  +               + createDigestHeader(cred.getUserName(), headers, digest);
  +    }
  +
  +    /**
  +     * Processes the authenticate HTTP header received from the server that
  +     * requires Digest authentication.
  +     * 
  +     * @param method The HTTP method.
  +     * @param proxy true if authorizing for a proxy
  +     * 
  +     * @return The parameters from the authenticate header as a Hashtable or
  +     *         empty Hashtable if there is no valid authorization.
  +     * 
  +     * @since 2.0
  +     * @see #processDigestToken(String,java.util.Hashtable)
  +     * @see PROXY_AUTH
  +     * @see WWW_AUTH
        */
  -    static String digest(UsernamePasswordCredentials cred, Hashtable headers) 
  -    throws HttpException {
  -        log.trace("enter Authenticator.digest(UsernamePasswordCredentials, Hashtable)");
  +    private static Hashtable getHTTPDigestCredentials(HttpMethod method, 
  +                                                      boolean proxy) {
  +        log.trace("enter Authenticator.getHTTPDigestCredentials(HttpMethod, "
  +            + "boolean)");
  +
  +        //Determine wether to use proxy or www header
  +        String authName = proxy ? PROXY_AUTH : WWW_AUTH;
  +        String authHeader = null;
   
  -        String digest = createDigest(cred.getUserName(), cred.getPassword(), headers);
  -        return "Digest " + createDigestHeader(cred.getUserName(), headers, digest);
  +        //Get the authorization header value
  +        try {
  +            authHeader = method.getResponseHeader(authName).getValue();
  +            authHeader = authHeader.substring(7).trim();
  +        } catch (NullPointerException npe) {
  +            return new Hashtable(0);
  +        }
  +
  +        //Hashtable of digest tokens
  +        Hashtable ht = new Hashtable(17);
  +
  +        //parse the authenticate header
  +        int i = 0;
  +        int j = authHeader.indexOf(",");
  +
  +        while (j >= 0) {
  +            processDigestToken(authHeader.substring(i, j), ht);
  +            i = j + 1;
  +            j = authHeader.indexOf(",", i);
  +        }
  +
  +        if (i < authHeader.length()) {
  +            processDigestToken(authHeader.substring(i), ht);
  +        }
  +
  +        return ht;
       }
   
       /**
  -     * @todo + Add createDigest() method
  -     * Creates an MD5 response digest.
  -     *
  -     * @param uname Username
  -     * @param pwd Password
  -     * @param dCreds Hashtable containing necessary header parameters to
  -     * construct the digest. It must/can contain: uri, realm, nonce, cnonce,
  -     * qop, nc.
  -     * @return The created digest as string. This will be the response tag's
  -     * value in the Authentication HTTP header.
  +     * Add requisite authentication credentials to the given <i>method</i>
  +     * using the given the <i>challengeHeader</i>. Currently <b>Basic</b> and
  +     * <b>Digest</b> authentication are supported. If the challengeHeader is
  +     * null, the default authentication credentials will be sent.
  +     * 
  +     * @param method the http method to add the authentication header to
  +     * @param authenticateHeader the header the web server created to challenge
  +     *        the credentials
  +     * @param state the http state object providing {@link Credentials}
  +     * @param respHeader the response header to add (e.g. proxy or standard)
  +     * 
  +     * @return true if a response header was added
  +     * 
  +     * @throws HttpException when an error occurs parsing the challenge
  +     * @throws UnsupportedOperationException when the given challenge type is
  +     *         not supported
  +     * 
  +     * @see #basic
  +     * @see #digest
  +     * @see HttpMethod#addRequestHeader
        */
  -    public static String createDigest(String uname, String pwd, Hashtable dCreds) 
  -    throws HttpException {
  -        log.trace("enter Authenticator.createDigest(String, String, Hashtable)");
  +    private static boolean authenticate(HttpMethod method, HttpState state, 
  +                                        Header authenticateHeader, 
  +                                        String respHeader)
  +                                 throws HttpException, 
  +                                        UnsupportedOperationException {
  +        log.trace("enter Authenticator.authenticate(HttpMethod, HttpState, "
  +                  + "Header, String)");
   
  -        final String digAlg = "MD5";
  +        //check the preemptive policy
  +        //TODO: this needs to be a service from some configuration class
  +        String preemptiveDefault = System.getProperties()
  +                                      .getProperty(PREEMPTIVE_PROPERTY, 
  +                                                   PREEMPTIVE_DEFAULT);
  +        preemptiveDefault = preemptiveDefault.trim().toLowerCase();
  +
  +        if (!(preemptiveDefault.equals("true") 
  +            || preemptiveDefault.equals("false"))) { //property problem
  +            log.warn("Configuration property " + PREEMPTIVE_PROPERTY
  +                     + " must be either true or false.  Using default: "
  +                     + PREEMPTIVE_DEFAULT);
  +            preemptiveDefault = PREEMPTIVE_DEFAULT;
  +        }
   
  -        // Collecting required tokens
  -        String uri = removeQuotes((String)dCreds.get("uri"));
  -        String realm = removeQuotes((String)dCreds.get("realm"));
  -        String nonce = removeQuotes((String)dCreds.get("nonce"));
  -        String nc = removeQuotes((String)dCreds.get("nc"));
  -        String cnonce = removeQuotes((String)dCreds.get("cnonce"));
  -        String qop = removeQuotes((String)dCreds.get("qop"));
  -        String method = (String)dCreds.get( "methodname" );
  -        if (qop!=null) qop = "auth";
  +        boolean preemptive = ("true".equals(preemptiveDefault));
   
  -        MessageDigest md5Helper;
  -        try {
  -            md5Helper = MessageDigest.getInstance(digAlg);
  -        } catch (Exception e) {
  -            log.error("ERROR! Unsupported algorithm in HTTP Digest authentication: "+digAlg);
  -            HttpException he = new HttpException("Unsupported algorithm in HTTP Digest authentication: "+digAlg);
  -            throw he;
  +        //if there is no challenge, attempt to use preemptive authorization
  +        if (authenticateHeader == null) {
  +            if (preemptive) {
  +                log.debug("Preemptively sending default basic credentials");
  +
  +                try {
  +                    Header requestHeader = Authenticator.basic(null, state, 
  +                                                               respHeader);
  +                    method.addRequestHeader(requestHeader);
  +
  +                    return true;
  +                } catch (HttpException httpe) {
  +                    if (log.isDebugEnabled()) {
  +                        log.debug("No default credentials to preemptively"
  +                            + " send");
  +                    }
  +
  +                    return false;
  +                }
  +            } else { //no challenge and no default creds so do nothing
  +
  +                return false;
  +            }
           }
   
  -        // Calculating digest according to rfc 2617
  -        String a2 = method + ":" + uri;
  -        String md5a2 = encode(md5Helper.digest(a2.getBytes()));
  -        String digestValue = uname + ":" + realm + ":" + pwd;
  -        String md5a1 = encode(md5Helper.digest(digestValue.getBytes()));
  -        String serverDigestValue;
  -        if (qop==null) serverDigestValue = md5a1 + ":" + nonce + ":" + md5a2;
  -        else serverDigestValue = md5a1 + ":" + nonce + ":" + nc + ":" +
  -            cnonce + ":" + qop + ":" + md5a2;
  -        String serverDigest = encode(md5Helper.digest(serverDigestValue.getBytes()));
  -        return serverDigest;
  +        if (log.isDebugEnabled()) {
  +            log.debug("Attempting to authenticate header: "
  +                      + authenticateHeader);
  +        }
  +
  +        // XXX: Get the challenge from the header
  +        String authenticateValue = authenticateHeader.getValue();
  +
  +        // TODO: Use regular expression pattern matching to parse the challenge
  +        //FIXME: This fails if the contents of a challenge contains a ','
  +        StringTokenizer challengeTok = new StringTokenizer(authenticateValue, 
  +                                                           ",");
  +        Hashtable challengeMap = new Hashtable(7);
  +
  +        while (challengeTok.hasMoreTokens()) {
  +            // Parse the authentication scheme from the challenge
  +            String chall = challengeTok.nextToken();
  +            StringTokenizer authTok = new StringTokenizer(chall, " ");
  +            String authScheme = authTok.nextToken();
  +
  +
  +            // Store the challenge keyed on the lower case authenticaion scheme
  +            challengeMap.put(authScheme.toLowerCase(), chall);
  +        }
  +
  +        Header requestHeader = null;
  +
  +        if (challengeMap.containsKey("digest")) {
  +            String challenge = (String) challengeMap.get("digest");
  +            String realm = parseRealmFromChallenge(challenge);
  +            requestHeader = Authenticator.digest(realm, method, state, 
  +                                                 respHeader);
  +        } else if (challengeMap.containsKey("basic")) {
  +            String challenge = (String) challengeMap.get("basic");
  +            String realm = parseRealmFromChallenge(challenge);
  +            requestHeader = Authenticator.basic(realm, state, respHeader);
  +        } else if (challengeMap.size() == 0) {
  +            throw new HttpException("No authentication scheme found in '"
  +                                    + authenticateValue);
  +        } else {
  +            throw new UnsupportedOperationException("Requested authentication "
  +                                                    + "scheme "
  +                                                    + challengeMap.keySet()
  +                                                    + " is unsupported");
  +        }
  +
  +        //Add the header and return the result
  +        if (requestHeader != null) { // add the header
  +            method.addRequestHeader(requestHeader);
  +
  +            return true;
  +        } else { // don't add the header
  +
  +            return false;
  +        }
       }
   
       /**
  -     * @todo + Add createCnonce() method
        * Creates a random cnonce value based on the current time.
  -     *
  +     * 
        * @return The cnonce value as String.
  -     * @throws AxisFault if MD5 algorithm is not supported.
  +     * 
  +     * @throws HttpException if MD5 algorithm is not supported.
  +     * 
  +     * @todo + Add createCnonce() method
        */
       private static String createCnonce() throws HttpException {
           log.trace("enter Authenticator.createCnonce()");
  @@ -483,184 +586,183 @@
           String cnonce;
           final String digAlg = "MD5";
           MessageDigest md5Helper;
  +
           try {
               md5Helper = MessageDigest.getInstance(digAlg);
           } catch (Exception e) {
  -            log.error("ERROR! Unsupported algorithm in HTTP Digest authentication: "+digAlg);
  -            HttpException he = new HttpException("Unsupported algorithm in HTTP Digest authentication: "+digAlg);
  -            throw he;
  +            log.error("ERROR! Unsupported algorithm in HTTP Digest "
  +                      + "authentication: " + digAlg);
  +            throw new HttpException("Unsupported algorithm in HTTP Digest "
  +                                    + "authentication: " + digAlg);
           }
  +
           cnonce = Long.toString(System.currentTimeMillis());
           cnonce = encode(md5Helper.digest(cnonce.getBytes()));
  +
           return cnonce;
       }
   
       /**
  -     * @todo + Add createDigestHeader() method
        * Creates the header information that must be specified after the "Digest"
        * string in the HTTP Authorization header (digest-response in RFC2617).
  -     *
  +     * 
        * @param uname Username
        * @param dCreds Hashtable containing header information (uri, realm,
  -     * nonce, nc, cnonce, opaque, qop).
  +     *        nonce, nc, cnonce, opaque, qop).
        * @param digest The response tag's value as String.
  +     * 
        * @return The digest-response as String.
  +     * 
  +     * @todo + Add createDigestHeader() method 
        */
  -    private static String createDigestHeader(String uname, Hashtable dCreds, String digest) {
  -        log.trace("enter Authenticator.createDigestHeader(String, Hashtable, String)");
  +    private static String createDigestHeader(String uname, Hashtable dCreds, 
  +                                             String digest) {
  +        log.trace("enter Authenticator.createDigestHeader(String, Hashtable, "
  +            + "String)");
   
           StringBuffer sb = new StringBuffer();
  -        String uri = removeQuotes((String)dCreds.get("uri"));
  -        String realm = removeQuotes((String)dCreds.get("realm"));
  -        String nonce = removeQuotes((String)dCreds.get("nonce"));
  -        String nc = removeQuotes((String)dCreds.get("nc"));
  -        String cnonce = removeQuotes((String)dCreds.get("cnonce"));
  -        String opaque = removeQuotes((String)dCreds.get("opaque"));
  +        String uri = removeQuotes((String) dCreds.get("uri"));
  +        String realm = removeQuotes((String) dCreds.get("realm"));
  +        String nonce = removeQuotes((String) dCreds.get("nonce"));
  +        String nc = removeQuotes((String) dCreds.get("nc"));
  +        String cnonce = removeQuotes((String) dCreds.get("cnonce"));
  +        String opaque = removeQuotes((String) dCreds.get("opaque"));
           String response = digest;
  -        String qop= removeQuotes((String)dCreds.get("qop"));
  -        if (qop!=null) qop = "auth";    //we only support auth
  -        String algorithm = "MD5";       //we only support MD5
  -
  -        sb.append("username=\""+uname+"\"")
  -            .append(", realm=\""+realm+"\"")
  -            .append(", nonce=\""+nonce+"\"")
  -            .append(", uri=\""+uri+"\"")
  -            .append((qop==null?"":", qop=\""+qop+"\""))
  -            .append(", algorithm=\""+algorithm+"\"")
  -            .append((qop==null?"":", nc="+nc))
  -            .append((qop==null?"":", cnonce=\""+cnonce+"\""))
  -            .append(", response=\""+response+"\"")
  -            .append(opaque==null?"":", opaque=\""+opaque+"\"");
  -        return sb.toString();
  -    }
  +        String qop = removeQuotes((String) dCreds.get("qop"));
   
  -    /**
  -     * Takes a <CODE>String</CODE> and cuts its prefix until the first double
  -     * quotation mark and its suffix from the last double quotation mark (and cuts
  -     * also the quotation marks).
  -     *
  -     * @param str the <CODE>String</CODE> from which the prefix and suffix is to
  -     *    be cut.
  -     *
  -     * @return the stumped <CODE>String</CODE> if the format of <CODE>str</CODE>
  -     * is <CODE>*"*"*</CODE>. Otherwise the return value is same as
  -     * <CODE>str</CODE>
  -     */
  -    private static String removeQuotes(String str) {
  -        log.trace("enter Authenticator.removeQuotes(String)");
  +        if (qop != null) {
  +            qop = "auth"; //we only support auth
  +        }
   
  -        if (str == null)
  -            return null;
  +        String algorithm = "MD5"; //we only support MD5
   
  -        int fqpos = str.indexOf("\"")+1;
  -        int lqpos = str.lastIndexOf("\"");
  -        if (fqpos > 0 && lqpos > fqpos)
  -            return str.substring(fqpos,lqpos);
  -        else
  -            return str;
  +        sb.append("username=\"" + uname + "\"")
  +          .append(", realm=\"" + realm + "\"")
  +          .append(", nonce=\"" + nonce + "\"").append(", uri=\"" + uri + "\"")
  +          .append(((qop == null)            ? "" : ", qop=\"" + qop + "\""))
  +          .append(", algorithm=\"" + algorithm + "\"")
  +          .append(((qop == null)            ? "" : ", nc=" + nc))
  +          .append(((qop == null)            ? "" : ", cnonce=\"" + cnonce
  +                      + "\"")).append(", response=\"" + response + "\"")
  +          .append((opaque == null)           ? "" : ", opaque=\"" + opaque
  +                  + "\"");
  +
  +        return sb.toString();
       }
   
       /**
  -     * @todo + Add encode() method
  -     * Encodes the 128 bit (16 bytes) MD5 digest into a 32 characters log
  +     * Encodes the 128 bit (16 bytes) MD5 digest into a 32 characters long 
        * <CODE>String</CODE> according to RFC 2617.
  -     *
  +     * 
        * @param binaryData array containing the digest
  +     * 
        * @return encoded MD5, or <CODE>null</CODE> if encoding failed
  +     * 
  +     * @todo + Add encode() method 
        */
  -    private static String encode( byte[] binaryData ) {
  +    private static String encode(byte[] binaryData) {
           log.trace("enter Authenticator.encode(byte[])");
   
  -        if (binaryData.length != 16)
  +        if (binaryData.length != 16) {
               return null;
  +        }
   
           char[] buffer = new char[32];
   
  -        for (int i=0; i<16; i++) {
  +        for (int i = 0; i < 16; i++) {
               int low = (int) (binaryData[i] & 0x0f);
               int high = (int) ((binaryData[i] & 0xf0) >> 4);
  -            buffer[i*2] = hexadecimal[high];
  -            buffer[i*2 + 1] = hexadecimal[low];
  +            buffer[i * 2] = HEXADECIMAL[high];
  +            buffer[(i * 2) + 1] = HEXADECIMAL[low];
           }
   
           return new String(buffer);
       }
   
       /**
  -     * Hexa values used when creating 32 character long digest in HTTP Digest in
  -     * case of authentication.
  -     *
  -     * @see #encode(byte[])
  -     */
  -    private static final char[] hexadecimal = 
  -    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  -
  -    /**
  -     * Processes the authenticate HTTP header received from the server that
  -     * requires Digest authentication.
  -     *
  -     * @param method The HTTP method.
  -     * @param proxy true if authorizing for a proxy
  -     * @return The parameters from the authenticate header as a Hashtable
  -     *  or empty Hashtable if there is no valid authorization.
  -     *
  -     * @see #processDigestToken(String,java.util.Hashtable)
  -     * @see PROXY_AUTH
  -     * @see WWW_AUTH
  -     * @since 2.0
  +     * Parse the realm from the authentication challenge
  +     * 
  +     * @param challenge the authentication challenge
  +     * 
  +     * @return the realm
  +     * 
  +     * @throws HttpException when the realm can't be parsed
        */
  -    private static Hashtable getHTTPDigestCredentials(HttpMethod method, boolean proxy) {
  -        log.trace("enter Authenticator.getHTTPDigestCredentials(HttpMethod, boolean)");
  -
  -        //Determine wether to use proxy or www header
  -        String authName = proxy ? PROXY_AUTH : WWW_AUTH;
  -        String authHeader = null;
  -
  -        //Get the authorization header value
  -        try{
  -            authHeader = method.getResponseHeader(authName).getValue();
  -            authHeader = authHeader.substring(7).trim();
  -        } catch (NullPointerException npe){
  -            return new Hashtable(0);
  -        }
  +    private static String parseRealmFromChallenge(String challenge)
  +                                           throws HttpException {
  +        // FIXME: Note that this won't work if there is more than one realm
  +        // within the challenge
  +        try {
  +            StringTokenizer strtok = new StringTokenizer(challenge, "=");
  +            String realmName = strtok.nextToken().trim();
  +            String realm = strtok.nextToken().trim();
  +            int firstq = realm.indexOf('"');
  +            int lastq = realm.lastIndexOf('"');
   
  -        //Hashtable of digest tokens
  -        Hashtable ht = new Hashtable(17);
  +            if ((firstq + 1) < lastq) {
  +                realm = realm.substring(firstq + 1, lastq);
  +            }
   
  -        //parse the authenticate header
  -        int i = 0;
  -        int j = authHeader.indexOf(",");
  -        while(j >= 0) {
  -            processDigestToken(authHeader.substring(i,j), ht);
  -            i = j+1;
  -            j = authHeader.indexOf(",",i);
  -        }
  +            if (log.isDebugEnabled()) {
  +                log.debug("Parsed realm '" + realm + "' from challenge '"
  +                          + challenge + "'");
  +            }
   
  -        if (i < authHeader.length()) {
  -            processDigestToken(authHeader.substring(i), ht);
  +            return realm;
  +        } catch (Exception ex) {
  +            throw new HttpException("Failed to parse realm from challenge '"
  +                                    + challenge + "'");
           }
  -        return ht;
       }
   
       /**
  -     * @todo + Add processDigestToken() method
  -     * Takes an entry of <CODE>"xxx=yyy"</CODE> format, partitions into a key and
  -     * a value (key will be the left side, value will be the right side of the
  -     * equal sign) and places that into a <CDE>Hashtable</CODE>.
  -     *
  +     * Takes an entry of <CODE>"xxx=yyy"</CODE> format, partitions into a key
  +     * and a value (key will be the left side, value will be the right side of
  +     * the equal sign) and places that into a <CODE>Hashtable</CODE>.
  +     * 
        * @param token the entry to be processed
        * @param ht the <CODE>java.util.Hashtable</CODE> into which the processed
  -     *    entry is placed (only if it has <CODE>"xxx=yyy"</CODE> format).
  +     *        entry is placed (only if it has <CODE>"xxx=yyy"</CODE> format).
  +     * 
  +     * @todo + Add processDigestToken() method 
        */
       private static void processDigestToken(String token, Hashtable ht) {
           log.trace("enter Authenticator.processDigestToken(String, Hashtable)");
   
           int eqpos = token.indexOf("=");
   
  -        if (eqpos > 0 && eqpos < token.length()-1)
  -            ht.put(token.substring(0,eqpos).trim(),token.substring(eqpos+1).trim());
  +        if ((eqpos > 0) && (eqpos < (token.length() - 1))) {
  +            ht.put(token.substring(0, eqpos).trim(), 
  +                   token.substring(eqpos + 1).trim());
  +        }
       }
   
  +    /**
  +     * Takes a <CODE>String</CODE> and cuts its prefix until the first double
  +     * quotation mark and its suffix from the last double quotation mark (and
  +     * cuts also the quotation marks).
  +     * 
  +     * @param str the <CODE>String</CODE> from which the prefix and suffix is
  +     *        to be cut.
  +     * 
  +     * @return the stumped <CODE>String</CODE> if the format of
  +     *         <CODE>str</CODE> is <CODE>""</CODE>. Otherwise the return value
  +     *         is same as <CODE>str</CODE>
  +     */
  +    private static String removeQuotes(String str) {
  +        log.trace("enter Authenticator.removeQuotes(String)");
  +
  +        if (str == null) {
  +            return null;
  +        }
   
  +        int fqpos = str.indexOf("\"") + 1;
  +        int lqpos = str.lastIndexOf("\"");
   
  -}
  +        if ((fqpos > 0) && (lqpos > fqpos)) {
  +            return str.substring(fqpos, lqpos);
  +        } else {
  +            return str;
  +        }
  +    }
  +}
  \ No newline at end of file
  
  
  

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


Mime
View raw message