hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Michael Becke <be...@u.washington.edu>
Subject Re: [PATCH] PostMethod & PutMethod revision (take 1)
Date Wed, 29 Jan 2003 18:03:30 GMT
Hi Oleg,

Just a quick question.  Why do we want to keep from having to calculate 
the content length? Is this just for the case of when the Post content 
is set via setRequestBody(InputStream)?

Thanks,

Mike

Kalnichevski, Oleg wrote:
> Bug fixes:
> 
> http://nagoya.apache.org/bugzilla/show_bug.cgi?id=11095
> 
> Changelog:
> 
> - Abstract EntityEnclosingMethod class has been introduced to encapsulate common behaviour of all entity enclosing methods 
> - Limited "Expect: 100-continue" support in all entity enclosing methods (HttpClient hangs indefinitely if status code 100 is not sent when expected)
> - Support for chunk encoded requests in all entity enclosing methods
> - More robust (or so I'd like to hope) request content buffering logic
> - PostMethod inherited from EntityEnclosingMethod class
> - PutMethod inherited from EntityEnclosingMethod class
> 
> To be done next:
> 
> http://nagoya.apache.org/bugzilla/show_bug.cgi?id=11653
> http://nagoya.apache.org/bugzilla/show_bug.cgi?id=14731
> 
> Feedback, critique welcome as always. Feel free to start throwing bad tomatoes at me
> 
> Cheers
> 
> Oleg
> 
> 
> ------------------------------------------------------------------------
> 
> Index: java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java
> ===================================================================
> RCS file: java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java
> diff -N java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ java/org/apache/commons/httpclient/methods/EntityEnclosingMethod.java	29 Jan 2003 16:12:02 -0000
> @@ -0,0 +1,512 @@
> +/*
> + * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/GetMethod.java,v 1.21 2003/01/23 22:48:06 jsdever Exp $
> + * $Revision: 1.21 $
> + * $Date: 2003/01/23 22:48:06 $
> + * ====================================================================
> + *
> + * The Apache Software License, Version 1.1
> + *
> + * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
> + * reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + *
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in
> + *    the documentation and/or other materials provided with the
> + *    distribution.
> + *
> + * 3. The end-user documentation included with the redistribution, if
> + *    any, must include the following acknowlegement:
> + *       "This product includes software developed by the
> + *        Apache Software Foundation (http://www.apache.org/)."
> + *    Alternately, this acknowlegement may appear in the software itself,
> + *    if and wherever such third-party acknowlegements normally appear.
> + *
> + * 4. The names "The Jakarta Project", "Commons", and "Apache Software
> + *    Foundation" must not be used to endorse or promote products derived
> + *    from this software without prior written permission. For written
> + *    permission, please contact apache@apache.org.
> + *
> + * 5. Products derived from this software may not be called "Apache"
> + *    nor may "Apache" appear in their names without prior written
> + *    permission of the Apache Group.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
> + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + * ====================================================================
> + *
> + * This software consists of voluntary contributions made by many
> + * individuals on behalf of the Apache Software Foundation.  For more
> + * information on the Apache Software Foundation, please see
> + * <http://www.apache.org/>.
> + *
> + * [Additional notices, if required by prior licensing conditions]
> + *
> + */
> +
> +package org.apache.commons.httpclient.methods;
> +
> +import java.io.File;
> +import java.io.IOException;
> +import java.io.OutputStream;
> +import java.io.ByteArrayOutputStream;
> +import java.io.InputStream;
> +import java.io.ByteArrayInputStream;
> +import java.io.Reader;
> +import java.io.InputStreamReader;
> +import java.io.UnsupportedEncodingException;
> +
> +import org.apache.commons.httpclient.HttpConstants;
> +import org.apache.commons.httpclient.HttpConnection;
> +import org.apache.commons.httpclient.HttpException;
> +import org.apache.commons.httpclient.HttpState;
> +import org.apache.commons.httpclient.HttpStatus;
> +import org.apache.commons.httpclient.ChunkedOutputStream;
> +import org.apache.commons.httpclient.ContentLengthInputStream;
> +import org.apache.commons.logging.Log;
> +import org.apache.commons.logging.LogFactory;
> +
> +/**
> + * This abstract class serves as a foundation for all HTTP methods 
> + * that can enclose an entity within requests 
> + *
> + * @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
> + * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
> + * @since 2.0
> + */
> +
> +public abstract class EntityEnclosingMethod extends GetMethod
> +{
> +    // ----------------------------------------- Static variables/initializers
> +
> +    /**
> +     * The content length will be calculated automatically. This implies
> +     * buffering of the content.
> +     */
> +    public static final int CONTENT_LENGTH_AUTO = -2;
> +
> +    /**
> +     * The request will use chunked transfer encoding. Content length is not
> +     * calculated and the content is not buffered.<br>
> +     */
> +    public static final int CONTENT_LENGTH_CHUNKED = -1;
> +
> +    /** Log object for this class. */
> +    private static final Log log = LogFactory.getLog(EntityEnclosingMethod.class);
> +
> +    /** The buffered request body, if any. */
> +    private byte[] buffer = null;
> +
> +    /** The unbuffered request body, if any. */
> +    private InputStream requestBodyStream = null;
> +
> +    /** Counts how often the request was sent to the server. */
> +    private int repeatCount = 0;
> +
> +    /** The content length of the <code>requestBodyStream</code> or one of
> +     *  <code>CONTENT_LENGTH_AUTO</code> and <code>CONTENT_LENGTH_CHUNKED</code>.
> +     */
> +    private int requestContentLength = CONTENT_LENGTH_AUTO;
> +
> +    private boolean useExpectHeader = true;
> +    
> +    // ----------------------------------------------------------- Constructors
> +
> +    /**
> +     * No-arg constructor.
> +     *
> +     * @since 2.0
> +     */
> +    public EntityEnclosingMethod() {
> +        super();
> +        setFollowRedirects(false);
> +    }
> +
> +    /**
> +     * Constructor specifying a URI.
> +     *
> +     * @param uri either an absolute or relative URI
> +     *
> +     * @since 2.0
> +     */
> +    public EntityEnclosingMethod(String uri) {
> +        super(uri);
> +        setFollowRedirects(false);
> +    }
> +
> +    /**
> +     * Constructor specifying a URI and a tempDir.
> +     *
> +     * @param uri either an absolute or relative URI
> +     * @param tempDir directory to store temp files in
> +     *
> +     * @since 2.0
> +     */
> +    public EntityEnclosingMethod(String uti, String tempDir) {
> +        super(uti, tempDir);
> +        setFollowRedirects(false);
> +    }
> +
> +    /**
> +     * Constructor specifying a URI, tempDir and tempFile.
> +     *
> +     * @param uri either an absolute or relative URI
> +     * @param tempDir directory to store temp files in
> +     * @param tempFile file to store temporary data in
> +     *
> +     * @since 2.0
> +     */
> +    public EntityEnclosingMethod(String uri, String tempDir, String tempFile) {
> +        super(uri, tempDir, tempFile);
> +        setFollowRedirects(false);
> +    }
> +
> +
> +    /**
> +     * Returns the useExpectHeader.
> +     * @return boolean
> +     */
> +    public boolean getUseExpectHeader()
> +    {
> +        return this.useExpectHeader;
> +    }
> +
> +    /**
> +     * Sets the useExpectHeader.
> +     * @param useExpectHeader The useExpectHeader to set
> +     */
> +    public void setUseExpectHeader(boolean value)
> +    {
> +        this.useExpectHeader = value;
> +    }
> +
> +    /** 
> +     * Returns true if request body has been buffered. Otherwise returns false.
> +     *
> +     * @since 2.0
> +     */
> +    
> +    protected boolean hasBufferedRequestBody() {
> +        return this.buffer != null;
> +    }
> +
> +    /** 
> +     * Returns true if request body has been set. Otherwise returns false.
> +     *
> +     * @since 2.0
> +     */
> +
> +    protected boolean hasRequestBody() {
> +        return (this.requestBodyStream != null) || (this.buffer != null);
> +    }
> +
> +    /**
> +     * Sets length information about the request body.
> +     *
> +     * <p>
> +     * Note: If you specify a content length the request is unbuffered. This
> +     * prevents redirection and 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>
> +     *
> +     * @param length size in bytes or any of CONTENT_LENGTH_AUTO,
> +     *        CONTENT_LENGTH_CHUNKED. If number of bytes or CONTENT_LENGTH_CHUNKED
> +     *        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.
> +     *        If CONTENT_LENGTH_AUTO is specified the request will be buffered
> +     *        before it is sent over the network.
> +     *
> +     * @since 2.0
> +     */
> +
> +    public void setRequestContentLength(int length) {
> +        log.trace("enter EntityEnclosingMethod.setRequestContentLength(int)");
> +        this.requestContentLength = length;
> +    }
> +
> +    /**
> +     * 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
> +     */
> +
> +    protected int getRequestContentLength() {
> +        log.trace("enter EntityEnclosingMethod.getRequestContentLength()");
> +
> +        if (this.requestContentLength != CONTENT_LENGTH_AUTO) {
> +            return this.requestContentLength;
> +        }
> +        bufferContent();
> +        if (this.buffer != null) {
> +            return this.buffer.length;
> +        }
> +        else {
> +            return 0;
> +        }
> +    }
> +
> +    /**
> +     * Sets the request body to be the specified inputstream.
> +     *
> +     * @param body Request body content as {@link java.io.InputStream}
> +     *
> +     * @since 2.0
> +     */
> +
> +    public void setRequestBody(InputStream body) {
> +        log.trace("enter EntityEnclosingMethod.setRequestBody(InputStream)");
> +        this.requestBodyStream = body;
> +        this.buffer = null;
> +    }
> +
> +    /**
> +     * Gets the request body as a stream.
> +     *
> +     * @return The request body {@link java.io.InputStream} if it has been set.
> +     *
> +     * @throws IllegalStateException if request body is not buferred
> +     * 
> +     * @since 2.0
> +     */
> +
> +    public InputStream getRequestBody() {
> +        log.trace("enter EntityEnclosingMethod.getRequestBody()");
> +        if (this.buffer != null) {
> +            return new ByteArrayInputStream(this.buffer); 
> +        }
> +        else {
> +            return this.requestBodyStream;
> +        }
> +    }
> +
> +    /**
> +     * Sets the request body to be the specified string.
> +     *
> +     * @param body Request body content as a string
> +     *
> +     * @since 2.0
> +     */
> +
> +    public void setRequestBody(String body) {
> +        log.trace("enter EntityEnclosingMethod.setRequestBody(String)");
> +
> +        if (body == null) {
> +            this.requestBodyStream = null;
> +            this.buffer = null;
> +            return;
> +        }
> +        this.buffer = HttpConstants.getContentBytes(body, getRequestCharSet());
> +    }
> +
> +    /**
> +     * Gets the request body as a string.
> +     *
> +     * @return the request body as a string
> +     * 
> +     * @throws IOException when i/o errors occur reading the request
> +     * @throws IllegalStateException if request body is not buferred
> +     *
> +     * @since 2.0
> +     */
> +
> +    public String getRequestBodyAsString() throws IOException {
> +        log.trace("enter EntityEnclosingMethod.getRequestBodyAsString()");
> +        Reader instream = null;
> +        try {
> +            instream = new InputStreamReader(getRequestBody(), getRequestCharSet());
> +        }
> +        catch(UnsupportedEncodingException e) {
> +            if (log.isWarnEnabled()) {
> +                log.warn("Unsupported encoding: " + e.getMessage());
> +            }
> +            instream = new InputStreamReader(getRequestBody());
> +        }
> +        StringBuffer buffer = new StringBuffer();
> +        char[] tmp = new char[4096];
> +        int l = 0;
> +        while((l = instream.read(tmp)) >= 0) {
> +            buffer.append(tmp, 0, l);
> +        }
> +        return buffer.toString();
> +    }
> +
> +
> +    /**
> +     * Override the method of {@link HttpMethodBase}
> +     * to set the <tt>Expect</tt> header if it has
> +     * not already been set, in addition to the "standard"
> +     * set of headers.
> +     *
> +     * @throws HttpException when a protocol error occurs or state is invalid
> +     * @throws IOException when i/o errors occur reading the response
> +     * 
> +     * @since 2.0
> +     */
> +
> +    protected void addRequestHeaders(HttpState state, HttpConnection conn)
> +    throws IOException, HttpException {
> +        log.trace("enter EntityEnclosingMethod.addRequestHeaders(HttpState, HttpConnection)");
> +        
> +        if (!isHttp11() && getUseExpectHeader()) {
> +            throw new HttpException(
> +                "100-continue not allowed for HTTP/1.0");
> +        }
> +
> +        super.addRequestHeaders(state, conn);
> +        // Send expectation header, provided there's something to be sent
> +        if(isHttp11() && hasRequestBody()) {
> +            if (getRequestHeader("Expect") == null) {
> +                setRequestHeader("Expect", "100-continue");
> +            }
> +        }
> +    }
> +
> +    /**
> +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> +     * to write request parameters as the request body.  The input stream will
> +     * be truncated after the specified content length.
> +     *
> +     * @param state the client state
> +     * @param conn the connection to write to
> +     *
> +     * @return <tt>true</tt>
> +     * @throws IOException when i/o errors occur reading the response
> +     * @throws HttpException when a protocol error occurs or state is invalid
> +     *
> +     * @since 2.0
> +     */
> +    
> +    protected boolean writeRequestBody(HttpState state, HttpConnection conn)
> +    throws IOException, HttpException {
> +        log.trace(
> +            "enter EntityEnclosingMethod.writeRequestBody(HttpState, HttpConnection)");
> +        
> +        if (getStatusLine() == null) {
> +             return false;
> +        }
> +        if (getRequestHeader("Expect") != null) {
> +            if (getStatusLine().getStatusCode() != HttpStatus.SC_CONTINUE) {
> +                return false;
> +            }
> +        }
> +
> +        int contentLength = getRequestContentLength();
> +
> +        if ((contentLength == CONTENT_LENGTH_CHUNKED) && !isHttp11()) {
> +            throw new HttpException(
> +                "Chunked transfer encoding not allowed for HTTP/1.0");
> +        }
> +        InputStream instream = getRequestBody();
> +        if (instream == null) {
> +            return true;
> +        }
> +
> +        if ((this.repeatCount > 0) && (this.buffer == null)) {
> +            throw new HttpException(
> +                "Unbuffered entity enclosing request can not be repeated.");
> +        }
> +
> +        this.repeatCount++;
> +
> +        OutputStream outstream = conn.getRequestOutputStream();
> +        if (contentLength == CONTENT_LENGTH_CHUNKED) {
> +            outstream = new ChunkedOutputStream(outstream);
> +        }
> +        if (contentLength >= 0) {
> +            // don't need a watcher here - we're reading from something local,
> +            // not server-side.
> +            instream = new ContentLengthInputStream(instream, contentLength);
> +        }
> +
> +        byte[] tmp = new byte[4096];
> +        int total = 0;
> +        int i = 0;
> +        while ((i = instream.read(tmp)) >= 0) {
> +            outstream.write(tmp, 0, i);
> +            total += i;
> +        }
> +        // This is hardly the most elegant solution to closing chunked stream
> +        if (outstream instanceof ChunkedOutputStream) {
> +            ((ChunkedOutputStream)outstream).writeClosingChunk();
> +        }
> +        if ((contentLength > 0) && (total < contentLength)) {
> +            throw new IOException("Unexpected end of input stream after "
> +                + total + " bytes (expected " + contentLength + " bytes)");
> +        }
> +        return true;
> +    }
> +
> +    /**
> +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> +     * to clear my request body.
> +     *
> +     * @since 2.0
> +     */
> +    public void recycle() {
> +        log.trace("enter EntityEnclosingMethod.recycle()");
> +        super.recycle();
> +        this.requestContentLength = CONTENT_LENGTH_AUTO;
> +        this.requestBodyStream = null;
> +        this.buffer = null;
> +        this.repeatCount = 0;
> +    }
> +
> +    /**
> +     * Buffers the request body and calculates the content length. If the
> +     * method was called earlier it returns immediately.
> +     *
> +     * @since 2.0
> +     */
> +    
> +    protected void bufferContent() {
> +        log.trace("enter EntityEnclosingMethod.bufferContent()");
> +
> +        if (this.buffer != null) {
> +            return;
> +        }
> +        if (this.requestBodyStream == null) {
> +            return;
> +        }
> +        try {
> +            ByteArrayOutputStream tmp = new ByteArrayOutputStream();
> +            byte[] data = new byte[4096];
> +            int l = 0;
> +            while ((l = this.requestBodyStream.read(data)) >= 0) {
> +                tmp.write(data, 0, l);
> +            }
> +            this.buffer = tmp.toByteArray();
> +            this.requestBodyStream = null;
> +        } catch (IOException e) {
> +            if (log.isErrorEnabled()) {
> +                log.error(e.toString(), e );
> +            }
> +            this.buffer = null;
> +            this.requestBodyStream = null;
> +        }
> +    }
> +}
> Index: java/org/apache/commons/httpclient/methods/PostMethod.java
> ===================================================================
> RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v
> retrieving revision 1.34
> diff -u -r1.34 PostMethod.java
> --- java/org/apache/commons/httpclient/methods/PostMethod.java	28 Jan 2003 22:25:26 -0000	1.34
> +++ java/org/apache/commons/httpclient/methods/PostMethod.java	29 Jan 2003 16:12:02 -0000
> @@ -1,8 +1,7 @@
>  /*
> - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v 1.34 2003/01/28 22:25:26 jsdever Exp $
> - * $Revision: 1.34 $
> - * $Date: 2003/01/28 22:25:26 $
> - *
> + * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v 1.33 2003/01/23 22:48:08 jsdever Exp $
> + * $Revision: 1.33 $
> + * $Date: 2003/01/23 22:48:08 $
>   * ====================================================================
>   *
>   * The Apache Software License, Version 1.1
> @@ -60,27 +59,21 @@
>   * [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.io.OutputStream;
> +import java.io.ByteArrayInputStream;
> +import java.util.Vector;
>  import java.util.Iterator;
>  import java.util.List;
> -import java.util.Vector;
> -
>  import org.apache.commons.httpclient.HttpConstants;
> -import org.apache.commons.httpclient.Header;
>  import org.apache.commons.httpclient.HttpConnection;
>  import org.apache.commons.httpclient.HttpException;
>  import org.apache.commons.httpclient.HttpState;
> +import org.apache.commons.httpclient.Header;
>  import org.apache.commons.httpclient.NameValuePair;
>  import org.apache.commons.httpclient.URIException;
> -import org.apache.commons.httpclient.ChunkedOutputStream;
> -import org.apache.commons.httpclient.ContentLengthInputStream;
>  import org.apache.commons.httpclient.util.URIUtil;
>  import org.apache.commons.logging.Log;
>  import org.apache.commons.logging.LogFactory;
> @@ -116,54 +109,24 @@
>   * @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�
> - * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
> + * @author Ortwin Glück
> + * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
>   * @since 1.0
>   */
> -public class PostMethod extends GetMethod {
> -    //~ Static variables/initializers ������������������������������������������
> -
> -    /**
> -     * The content length will be calculated automatically. This implies
> -     * buffering of the content.
> -     */
> -    public static final int CONTENT_LENGTH_AUTO = -2;
> -
> -    /**
> -     * The request will use chunked transfer encoding. Content length is not
> -     * calculated and the content is not buffered.<br>
> -     */
> -    public static final int CONTENT_LENGTH_CHUNKED = -1;
> -
> +public class PostMethod extends EntityEnclosingMethod {
>      // -------------------------------------------------------------- Constants
>  
>      /** Log object for this class. */
> -    private static final Log LOG = LogFactory.getLog(PostMethod.class);
> +    private static final Log log = LogFactory.getLog(PostMethod.class);
>  
>      /** The Content-Type header for www-form-urlcoded. */
> -    private static final Header CONTENT_TYPE = new Header("Content-Type",
> +    static final Header CONTENT_TYPE = new Header("Content-Type",
>          "application/x-www-form-urlencoded");
>  
> -    /** The buffered request body. */
> -    protected ByteArrayOutputStream buffer = null;
> -
> -    /** The unbuffered request body. */
> -    protected InputStream requestBody = null;
> -
>      /** The buffered request body consisting of <code>NameValuePair</code>s */
>      protected Vector parameters = new Vector();
>  
> -    /** Counts how often the request was sent to the server. */
> -    protected int repeatCount = 0;
> -
> -    /**
> -     * The content length of the <code>requestBody</code> or one of
> -     * <code>{@link #CONTENT_LENGTH_AUTO}</code> and
> -     * <code>{@link #CONTENT_LENGTH_CHUNKED}</code>.
> -     */
> -    protected int requestContentLength = CONTENT_LENGTH_AUTO;
> -
> -    //~ Constructors �����������������������������������������������������������
> +    // ----------------------------------------------------------- Constructors
>  
>      /**
>       * No-arg constructor.
> @@ -195,8 +158,8 @@
>       *
>       * @since 1.0
>       */
> -    public PostMethod(String uri, String tempDir) {
> -        super(uri, tempDir);
> +    public PostMethod(String uti, String tempDir) {
> +        super(uti, tempDir);
>          setFollowRedirects(false);
>      }
>  
> @@ -216,8 +179,6 @@
>  
>      // ----------------------------------------------------------- Constructors
>  
> -    //~ Methods ����������������������������������������������������������������
> -
>      /**
>       * A POST request can only be redirected if input is buffered. Overrides
>       * method of {@link org.apache.commons.httpclient.HttpMethodBase}.
> @@ -228,11 +189,7 @@
>       * @since 2.0
>       */
>      public boolean getFollowRedirects() {
> -        if (!super.getFollowRedirects()) {
> -            return false;
> -        }
> -
> -        return (buffer != null);
> +        return (hasBufferedRequestBody() && super.getFollowRedirects());
>      }
>  
>      // ----------------------------------------------------- Instance Methods
> @@ -252,24 +209,23 @@
>       * Set the value of parameter with parameterName to parameterValue. Does
>       * not preserve the initial insertion order.
>       *
> -     * @param parameterName DOCUMENT ME!
> -     * @param parameterValue DOCUMENT ME!
> +     * @param parameterName name of the parameter
> +     * @param parameterValue value of the parameter
>       *
>       * @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 void setParameter(String parameterName, String parameterValue) 
> -        throws IllegalStateException {
> -        LOG.trace("enter PostMethod.setParameter(String, String)");
> +    public void setParameter(String parameterName, String parameterValue) {
> +        log.trace("enter PostMethod.setParameter(String, String)");
>  
> -        if (null != requestBody) {
> +        if (hasRequestBody()) {
>              throw new IllegalStateException("Request body already generated.");
>          }
> -
>          removeParameter(parameterName, parameterValue);
>          addParameter(parameterName, parameterValue);
>      }
> @@ -278,7 +234,7 @@
>       * 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!
> +     * @param paramName name of the parameter
>       *
>       * @return If a parameter exists with the name argument, the coresponding
>       *         NameValuePair is returned.  Otherwise null.
> @@ -286,7 +242,7 @@
>       * @since 2.0
>       */
>      public NameValuePair getParameter(String paramName) {
> -        LOG.trace("enter PostMethod.getParameter(String)");
> +        log.trace("enter PostMethod.getParameter(String)");
>  
>          if (paramName == null) {
>              return null;
> @@ -301,7 +257,6 @@
>                  return parameter;
>              }
>          }
> -
>          return null;
>      }
>  
> @@ -317,7 +272,7 @@
>       * @see #getParameter(java.lang.String)
>       */
>      public NameValuePair[] getParameters() {
> -        LOG.trace("enter PostMethod.getParameters()");
> +        log.trace("enter PostMethod.getParameters()");
>  
>          int numPairs = parameters.size();
>          Object[] objectArr = parameters.toArray();
> @@ -331,142 +286,6 @@
>      }
>  
>      /**
> -     * 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 Request content as a string
> -     *
> -     * @throws IllegalStateException if request params have been added
> -     *
> -     * @since 2.0
> -     */
> -    public void setRequestBody(String body) throws IllegalStateException {
> -        LOG.trace("enter PostMethod.setRequestBody(String)");
> -
> -        if (!parameters.isEmpty()) {
> -            throw new IllegalStateException(
> -                "Request parameters have already been added.");
> -        }
> -
> -        if (body == null) {
> -            this.requestBody = null;
> -            return;
> -        }
> -
> -        this.requestBody = new ByteArrayInputStream(
> -          HttpConstants.getContentBytes(body, getRequestCharSet()));
> -    }
> -
> -    /**
> -     * 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) throws IllegalStateException {
> -        LOG.trace("enter PostMethod.getRequestBody(InputStream)");
> -
> -        if (!parameters.isEmpty()) {
> -            throw new IllegalStateException(
> -                "Request parameters have already been added.");
> -        }
> -
> -        this.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.
> -     *
> -     * @return the request body as a string
> -     * @throws IOException If an IO problem occurs.
> -     *
> -     * @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
> -     * prevents redirection and 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>
> -     *
> -     * @param length size in bytes or any of CONTENT_LENGTH_AUTO,
> -     *        CONTENT_LENGTH_CHUNKED. If number of bytes or CONTENT_LENGTH_CHUNKED
> -     *        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.
> -     *        If CONTENT_LENGTH_AUTO is specified the request will be buffered
> -     *        before it is sent over the network.
> -     * @throws RuntimeException if chunked transfer encoding is requested for
> -     *         a HTTP 1.0 request
> -     *
> -     * @since 2.0
> -     */
> -    public void setRequestContentLength(int length) 
> -        throws RuntimeException {
> -        //TODO: We should be throwing a more specific exception than this.
> -            
> -        LOG.trace("enter PostMethod.setRequestContentLength(int)");
> -
> -        if ((length == CONTENT_LENGTH_CHUNKED) && !isHttp11()) {
> -            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.
> @@ -478,12 +297,10 @@
>       *
>       * @since 1.0
>       */
> -    public void addParameter(String paramName, String paramValue) 
> -        throws IllegalStateException, IllegalArgumentException {
> -            
> -        LOG.trace("enter PostMethod.addParameter(String, String)");
> +    public void addParameter(String paramName, String paramValue) {
> +        log.trace("enter PostMethod.addParameter(String, String)");
>  
> -        if (null != requestBody) {
> +        if (hasRequestBody()) {
>              throw new IllegalStateException("Request body already generated.");
>          }
>  
> @@ -508,18 +325,14 @@
>       * @since 2.0
>       * @see #addParameter(String,String)
>       */
> -    public void addParameter(NameValuePair param) 
> -        throws IllegalStateException, IllegalArgumentException {
> -            
> -        LOG.trace("enter PostMethod.addParameter(NameValuePair)");
> +    public void addParameter(NameValuePair param) {
> +        log.trace("enter PostMethod.addParameter(NameValuePair)");
>  
> -        if (null != requestBody) {
> +        if (hasRequestBody()) {
>              throw new IllegalStateException("Request body already generated.");
>          }
> -
> -        if (null == param) {
> -            throw new IllegalArgumentException(
> -                "Argument to addParameter(NameValuePair) cannot be null");
> +        if (param == null) {
> +            throw new IllegalArgumentException("NameValuePair may not be null");
>          } else {
>              addParameter(param.getName(), param.getValue());
>          }
> @@ -537,17 +350,14 @@
>       * @since 2.0
>       * @see #addParameter(org.apache.commons.httpclient.NameValuePair)
>       */
> -    public void addParameters(NameValuePair[] parameters) 
> -        throws IllegalStateException {
> -            
> -        LOG.trace("enter PostMethod.addParameters(NameValuePair[])");
> +    public void addParameters(NameValuePair[] parameters) {
> +        log.trace("enter PostMethod.addParameters(NameValuePair[])");
>  
> -        if (null != requestBody) {
> +        if (hasRequestBody()) {
>              throw new IllegalStateException("Request body already generated.");
>          }
> -
> -        if (null == parameters) {
> -            LOG.warn("Attempt to addParameters(null) ignored");
> +        if (parameters == null) {
> +            log.warn("Attempt to addParameters(null) ignored");
>          } else {
>              for (int i = 0; i < parameters.length; i++) {
>                  addParameter(parameters[i]);
> @@ -556,22 +366,6 @@
>      }
>  
>      /**
> -     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> -     * to clear my request body.
> -     *
> -     * @since 1.0
> -     */
> -    public void recycle() {
> -        LOG.trace("enter PostMethod.recycle()");
> -        super.recycle();
> -        requestBody = null;
> -        requestContentLength = CONTENT_LENGTH_AUTO;
> -        buffer = null;
> -        repeatCount = 0;
> -        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
> @@ -587,20 +381,16 @@
>       *
>       * @since 2.0
>       */
> -    public boolean removeParameter(String paramName) 
> -        throws IllegalArgumentException, IllegalStateException {
> -            
> -        LOG.trace("enter PostMethod.removeParameter(String)");
> +    public boolean removeParameter(String paramName) {
> +        log.trace("enter PostMethod.removeParameter(String)");
>  
> -        if (null != requestBody) {
> +        if (hasRequestBody()) {
>              throw new IllegalStateException("Request body already generated.");
>          }
> -
>          if (paramName == null) {
>              throw new IllegalArgumentException(
>                  "Argument passed to removeParameter(String) cannot be null");
>          }
> -
>          boolean removed = true;
>          Iterator iter = parameters.iterator();
>  
> @@ -612,7 +402,6 @@
>                  removed = true;
>              }
>          }
> -
>          return removed;
>      }
>  
> @@ -632,19 +421,17 @@
>       *
>       * @since 2.0
>       */
> -    public boolean removeParameter(String paramName, String paramValue)
> -        throws IllegalArgumentException, IllegalStateException {
> -            
> -        LOG.trace("enter PostMethod.removeParameter(String, String)");
> +    public boolean removeParameter(String paramName, String paramValue) {
> +        log.trace("enter PostMethod.removeParameter(String, String)");
>  
> -        if (null != requestBody) {
> +        if (hasRequestBody()) {
>              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) {
> +            throw new IllegalArgumentException("Parameter name may not be null");
> +        }
> +        if (paramValue == null) {
> +            throw new IllegalArgumentException("Parameter value may not be null");
>          }
>  
>          Iterator iter = parameters.iterator();
> @@ -655,221 +442,220 @@
>              if (paramName.equals(pair.getName())
>                  && paramValue.equals(pair.getValue())) {
>                  iter.remove();
> -
>                  return true;
>              }
>          }
> -
>          return false;
>      }
>  
>      /**
> -     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> -     * to return the length of the request body.
> +     * Encode the list of parameters into a query string.
>       *
> -     * @return number of bytes in the request body
> +     * @param params the list of query name and value
> +     *
> +     * @return the query string
>       *
>       * @since 2.0
>       */
> -    protected int getRequestContentLength() {
> -        LOG.trace("enter PostMethod.getRequestContentLength()");
> +    protected static String generateRequestBody(List params) {
> +        log.trace("enter PostMethod.generateRequestBodyAsString(List)");
>  
> -        if (null == requestBody) {
> -            requestBody = generateRequestBody(parameters);
> -            bufferContent();
> -        }
> -
> -        if (requestContentLength != CONTENT_LENGTH_AUTO) {
> -            return requestContentLength;
> -        }
> +        Iterator it = params.iterator();
> +        StringBuffer buff = new StringBuffer();
>  
> -        bufferContent();
> +        while (it.hasNext()) {
> +            NameValuePair parameter = (NameValuePair) it.next();
>  
> -        return requestContentLength;
> +            String queryName = null;
> +            try {
> +                queryName = URIUtil.encodeWithinQuery(parameter.getName());
> +            } catch (URIException urie) {
> +                log.error("encoding error within query name", urie);
> +                queryName = parameter.getName();
> +            }
> +            buff.append(queryName).append("=");
> +            String queryValue = null;
> +            try {
> +                queryValue = URIUtil.encodeWithinQuery(parameter.getValue());
> +            } catch (URIException urie) {
> +                log.error("encoding error within query value", urie);
> +                queryValue = parameter.getValue();
> +            }
> +            buff.append(queryValue);
> +            if (it.hasNext()) {
> +                buff.append("&");
> +            }
> +        }
> +        return buff.toString();
>      }
>  
>      /**
> -     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> -     * to  also add <tt>Content-Type</tt> header when appropriate.
> +     * Sets the request body to be the specified string.
>       *
> -     * @param state DOCUMENT ME!
> -     * @param conn DOCUMENT ME!
> -     * @throws IOException DOCUMENT ME!
> -     * @throws HttpException DOCUMENT ME!
> +     * <p>
> +     * Once this method has been invoked,  the request parameters  cannot be
> +     * altered until I am {@link #recycle recycled}.
> +     * </p>
> +     *
> +     * @param body Request body content as a string
> +     *
> +     * @throws IllegalStateException if request params have been added
>       *
>       * @since 2.0
>       */
> -    protected void addRequestHeaders(HttpState state, HttpConnection conn)
> -    throws IOException, HttpException {
> -        super.addRequestHeaders(state, conn);
> +    public void setRequestBody(String body) {
> +        log.trace("enter PostMethod.setRequestBody(String)");
>  
>          if (!parameters.isEmpty()) {
> -            //there are some parameters, so set the contentType header
> -            setRequestHeader(CONTENT_TYPE);
> +            throw new IllegalStateException(
> +                "Request parameters have already been added.");
>          }
> +        super.setRequestBody(body);
>      }
>  
>      /**
> -     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> -     * to write request parameters as the request body.  The input stream will
> -     * be truncated after the specified content length.
> +     * Sets the request body to be the specified inputstream.
>       *
> -     * @param state DOCUMENT ME!
> -     * @param conn DOCUMENT ME!
> +     * <p>
> +     * Once this method has been invoked,  the request parameters  cannot be
> +     * altered until I am {@link #recycle recycled}.
> +     * </p>
>       *
> -     * @return always returns true
> +     * @param body Request body content as {@link java.io.InputStream}
>       *
> -     * @throws IOException if the stream ends before the specified content
> -     *         length. <p>
> -     * @throws HttpException DOCUMENT ME!
> +     * @throws IllegalStateException if request params have been added
>       *
>       * @since 2.0
>       */
> -    protected boolean writeRequestBody(HttpState state, HttpConnection conn)
> -    throws IOException, HttpException {
> -        LOG.trace(
> -            "enter PostMethod.writeRequestBody(HttpState, HttpConnection)");
> +    public void setRequestBody(InputStream body) {
> +        log.trace("enter PostMethod.getRequestBody(InputStream)");
>  
> -        if (null == requestBody) {
> -            requestBody = generateRequestBody(parameters);
> +        if (!parameters.isEmpty()) {
> +            throw new IllegalStateException(
> +                "Request parameters have already been added.");
>          }
> +        super.setRequestBody(body);
> +    }
>  
> -        if ((repeatCount > 0) && (buffer == null)) {
> -            throw new HttpException(
> -                "Sorry, unbuffered POST request can not be repeated.");
> +    /**
> +     * 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 (!parameters.isEmpty()) {
> +            return new ByteArrayInputStream(
> +              HttpConstants.getContentBytes(
> +                generateRequestBody(parameters), getRequestCharSet()));
>          }
> +        else {
> +            return super.getRequestBody();
> +        }
> +    }
>  
> -        repeatCount++;
> -
> -        InputStream instream = this.requestBody;
> -        OutputStream outstream = conn.getRequestOutputStream();
> +    /**
> +     * Gets the request body string as it would be if it was executed.
> +     *
> +     * @return the request body as a string
> +     * 
> +     * @throws IOException when i/o errors occur reading the request
> +     *
> +     * @since 2.0
> +     */
>  
> -        if (this.requestContentLength == CONTENT_LENGTH_CHUNKED) {
> -            outstream = new ChunkedOutputStream(outstream);
> +    public String getRequestBodyAsString() throws IOException {
> +        log.trace("enter PostMethod.getRequestBody()");
> +        if (!parameters.isEmpty()) {
> +            return generateRequestBody(parameters);
>          }
> -        if (this.requestContentLength >= 0) {
> -            // don't need a watcher here - we're reading from something local,
> -            // not server-side.
> -            instream = new ContentLengthInputStream(instream, this.requestContentLength);
> +        else {
> +            return super.getRequestBodyAsString();
>          }
> +    }
>  
> -        byte[] tmp = new byte[4096];
> -        int total = 0;
> -        int i = 0;
> -        while ((i = instream.read(tmp)) >= 0) {
> -            outstream.write(tmp, 0, i);
> -            total += i;
> -        }
> -        if (outstream instanceof ChunkedOutputStream) {
> -            ((ChunkedOutputStream) outstream).writeClosingChunk();
> -        }
> -        if ((this.requestContentLength > 0) && (total < this.requestContentLength)) {
> -            throw new IOException("Unexpected end of input stream after "
> -                + total + " bytes (expected " 
> -                + this.requestContentLength + " bytes)");
> -        }
> +    /**
> +     * 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
> +     */
> +    protected int getRequestContentLength() {
> +        log.trace("enter PostMethod.getRequestContentLength()");
>  
> -        if (buffer != null) {
> -            //restore buffered content for repeated requests
> -            requestBody = new ByteArrayInputStream(buffer.toByteArray());
> +        if (!hasRequestBody()) {
> +            super.setRequestBody(generateRequestBody(parameters));
> +            bufferContent();
>          }
> -
> -        return true;
> +        return super.getRequestContentLength();
>      }
>  
> -
>      /**
> -     * Encode the list of parameters into a query stream.
> -     *
> -     * @param params the list of query name and value
> +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> +     * to  also add <tt>Content-Type</tt> header when appropriate.
>       *
> -     * @return the query stream
> +     * @param state the client state
> +     * @param conn the {@link HttpConnection} the headers will eventually be
> +     *        written to
> +     * @throws IOException when an error occurs writing the request
> +     * @throws HttpException when a HTTP protocol error occurs
>       *
> -     * @since 1.0
> +     * @since 2.0
>       */
> -    protected InputStream generateRequestBody(List params) {
> -        LOG.trace("enter PostMethod.generateRequestBody(List)");
> -        String body = generateRequestBodyAsString(params);
> +    
> +    protected void addRequestHeaders(HttpState state, HttpConnection conn)
> +    throws IOException, HttpException {
> +        super.addRequestHeaders(state, conn);
>  
> -        return new ByteArrayInputStream(
> -          HttpConstants.getContentBytes(body, getRequestCharSet()));
> +        if (!parameters.isEmpty()) {
> +            //there are some parameters, so set the contentType header
> +            setRequestHeader(CONTENT_TYPE);
> +        }
>      }
>  
> -
> -    // ------------------------------------------------------------Class Methods
> -
>      /**
> -     * Encode the list of parameters into a query string.
> +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> +     * to write request parameters as the request body.  The input stream will
> +     * be truncated after the specified content length.
> +     * 
> +     * @param state the client state
> +     * @param conn the connection to write to
>       *
> -     * @param params the list of query name and value
> +     * @return always returns true
>       *
> -     * @return the query string
> +     * @throws IOException if the stream ends before the specified content
> +     *         length. <p>
> +     * @throws HttpException when a protocol error occurs or state is invalid
>       *
>       * @since 2.0
>       */
> -    protected static String generateRequestBodyAsString(List params) {
> -        LOG.trace("enter PostMethod.generateRequestBodyAsString(List)");
>  
> -        Iterator it = params.iterator();
> -        StringBuffer buff = new StringBuffer();
> -
> -        while (it.hasNext()) {
> -            NameValuePair parameter = (NameValuePair) it.next();
> +    protected boolean writeRequestBody(HttpState state, HttpConnection conn)
> +    throws IOException, HttpException {
> +        log.trace(
> +            "enter PostMethod.writeRequestBody(HttpState, HttpConnection)");
>  
> -            String queryName = null;
> -            try {
> -                queryName = URIUtil.encodeWithinQuery(parameter.getName());
> -            } catch (URIException urie) {
> -                LOG.error("encoding error within query name", urie);
> -                queryName = parameter.getName();
> -            }
> -            buff.append(queryName).append("=");
> -            String queryValue = null;
> -            try {
> -                queryValue = URIUtil.encodeWithinQuery(parameter.getValue());
> -            } catch (URIException urie) {
> -                LOG.error("encoding error within query value", urie);
> -                queryValue = parameter.getValue();
> -            }
> -            buff.append(queryValue);
> -            if (it.hasNext()) {
> -                buff.append("&");
> -            }
> +        if (!hasRequestBody()) {
> +            super.setRequestBody(generateRequestBody(parameters));
>          }
> -        return buff.toString();
> +        return super.writeRequestBody(state, conn);
>      }
>  
>      /**
> -     * Buffers the request body and calculates the content length. If the
> -     * method was called earlier it returns immediately.
> +     * Override method of {@link org.apache.commons.httpclient.HttpMethodBase}
> +     * to clear my request body.
>       *
>       * @since 1.0
>       */
> -    private void bufferContent() {
> -        LOG.trace("enter PostMethod.bufferContent()");
> -
> -        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) {
> -            requestBody = null;
> -            requestContentLength = 0;
> -        }
> +    public void recycle() {
> +        log.trace("enter PostMethod.recycle()");
> +        super.recycle();
> +        this.parameters.clear();
>      }
> +
>  }
> Index: java/org/apache/commons/httpclient/methods/PutMethod.java
> ===================================================================
> RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PutMethod.java,v
> retrieving revision 1.20
> diff -u -r1.20 PutMethod.java
> --- java/org/apache/commons/httpclient/methods/PutMethod.java	28 Jan 2003 22:25:28 -0000	1.20
> +++ java/org/apache/commons/httpclient/methods/PutMethod.java	29 Jan 2003 16:12:02 -0000
> @@ -1,8 +1,7 @@
>  /*
> - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PutMethod.java,v 1.20 2003/01/28 22:25:28 jsdever Exp $
> - * $Revision: 1.20 $
> - * $Date: 2003/01/28 22:25:28 $
> - *
> + * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PutMethod.java,v 1.19 2003/01/23 22:48:09 jsdever Exp $
> + * $Revision: 1.19 $
> + * $Date: 2003/01/23 22:48:09 $
>   * ====================================================================
>   *
>   * The Apache Software License, Version 1.1
> @@ -63,34 +62,15 @@
>  
>  package org.apache.commons.httpclient.methods;
>  
> -import org.apache.commons.httpclient.HttpConstants;
> -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.httpclient.HttpStatus;
> -import org.apache.commons.logging.Log;
> -import org.apache.commons.logging.LogFactory;
> -
> -import java.io.ByteArrayInputStream;
> -import java.io.ByteArrayOutputStream;
> -import java.io.File;
> -import java.io.FileInputStream;
> -import java.io.IOException;
> -import java.io.InputStream;
> -import java.io.OutputStream;
> -import java.net.URL;
> -
> -
>  /**
>   * PUT Method.
>   *
>   * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
> - * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
> + * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
>   *
>   * @since 1.0
>   */
> -public class PutMethod extends HttpMethodBase {
> +public class PutMethod extends EntityEnclosingMethod {
>  
>  
>      // ----------------------------------------------------------- Constructors
> @@ -118,28 +98,6 @@
>          setFollowRedirects(false);
>      }
>  
> -
> -    // ------------------------------------------------------- Instance Methods
> -
> -
> -    /**
> -     * Request body content to be sent.
> -     */
> -    private byte[] data = null;
> -
> -
> -    /**
> -    * Request body content to be sent.
> -     */
> -    private File file = null;
> -
> -
> -    /**
> -     * Request body content to be sent.
> -     */
> -    private URL url = null;
> -
> -
>      // --------------------------------------------------------- Public Methods
>  
>      /**
> @@ -151,187 +109,4 @@
>      public String getName() {
>          return "PUT";
>      }
> -
> -    /**
> -     * Set my request body content to the contents of a file.
> -     *
> -     * @param file The file
> -     * @throws IOException if an IO problem occurs
> -     * @since 2.0
> -     */
> -    public void setRequestBody(File file) throws IOException {
> -        checkNotUsed();
> -        this.file = file;
> -    }
> -
> -    /**
> -     * Set my request body content to the resource at the specified URL.
> -     *
> -     * @param url The URL
> -     * @throws IOException If an IO problem occurs.
> -     * @since 2.0
> -     */
> -    public void setRequestBody(URL url) throws IOException {
> -        checkNotUsed();
> -        this.url = url;
> -    }
> -
> -    /**
> -     * Set my request body content to the contents of a byte array.
> -     *
> -     * @param bodydata The new content.
> -     * @since 2.0
> -     */
> -    public void setRequestBody(byte[] bodydata) {
> -        checkNotUsed();
> -        this.data = bodydata;
> -    }
> -
> -    /**
> -     * Set my request body content to the contents of a string.
> -     *
> -     * @param bodydata The new content
> -     * @since 2.0
> -     */
> -    public void setRequestBody(String bodydata) {
> -        checkNotUsed();
> -        setRequestBody(HttpConstants.getContentBytes(bodydata, getRequestCharSet()));
> -    }
> -
> -    /**
> -     * Set my request body content to the contents of an input stream. The
> -     * contents will be buffered into memory. To upload large entities, it is
> -     * recommended to first buffer the data into a temporary file, and then send
> -     * that file.
> -     *
> -     * @param is The input stream.
> -     * @throws IOException If an IO problem occurs
> -     * @since 2.0
> -     */
> -    public void setRequestBody(InputStream is) throws IOException {
> -        LOG.trace("enter PutMethod.setRequestBody(InputStream)");
> -
> -        checkNotUsed();
> -        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);
> -        }
> -        data = os.toByteArray();
> -    }
> -
> -
> -    // ------------------------------------------------- HttpMethodBase Methods
> -
> -    /**
> -     * Override the method of {@link HttpMethodBase} to set the <tt>Expect</tt>
> -     * header if it has not already been set, in addition to the "standard" set
> -     * of headers.
> -     * 
> -     * @param state The state.
> -     * @param conn The connection.
> -     * @throws IOException If an IO problem occurs
> -     * @throws HttpException Never.
> -     * @since 2.0
> -     */
> -    protected void addRequestHeaders(HttpState state, HttpConnection conn)
> -    throws IOException, HttpException {
> -        // TODO: Determine why this method is declared to throw HttpException
> -        // since it never actually does throw it.
> -        LOG.trace("enter PutMethod.addRequestHeaders(HttpState, HttpConnection)");
> -
> -        super.addRequestHeaders(state, conn);
> -        // Send expectation header
> -        if (isHttp11() && null == getRequestHeader("expect")) {
> -            setRequestHeader("Expect", "100-continue");
> -        }
> -    }
> -
> -    /**
> -     * Override the method of {@link HttpMethodBase} to not send any data until
> -     * the <tt>100 Continue</tt> status has not be read.
> -     *
> -     * @param state The state
> -     * @param conn The connection
> -     * @return true if the data was written.
> -     * @throws IOException If an IO problem occurs
> -     * @throws HttpException This doesn't ever seem to be thrown.
> -     * @since 2.0
> -     */
> -    protected boolean writeRequestBody(HttpState state, HttpConnection conn)
> -    throws IOException, HttpException {
> -        LOG.trace("enter PutMethod.writeRequestBody(HttpState, HttpConnection)");
> -         if (getStatusLine() == null) {
> -             return false;
> -         }
> -         if (null != getRequestHeader("expect") 
> -             && getStatusLine().getStatusCode() != HttpStatus.SC_CONTINUE) {
> -            return false;
> -        }
> -        OutputStream out = conn.getRequestOutputStream((isHttp11() 
> -            && (null == getRequestHeader("Content-Length"))));
> -
> -        InputStream inputStream = null;
> -        if (file != null && file.exists()) {
> -            inputStream = new FileInputStream(file);
> -        } else if (url != null) {
> -            inputStream = url.openConnection().getInputStream();
> -        } else if (data != null) {
> -            inputStream = new ByteArrayInputStream(data);
> -        } else {
> -            return true;
> -        }
> -
> -        byte[] buffer = new byte[4096];
> -        int nb = 0;
> -        while (true) {
> -            nb = inputStream.read(buffer);
> -            if (nb == -1) {
> -                break;
> -            }
> -            out.write(buffer, 0, nb);
> -        }
> -        out.flush();
> -        return true;
> -    }
> -
> -    /**
> -     * Override the method of {@link HttpMethodBase}
> -     * to return the appropriate content length.
> -     *
> -     * @return the content length
> -     * @since 2.0
> -     */
> -    protected int getRequestContentLength() {
> -        LOG.trace("enter PutMethod.getRequestContentLength()");
> -
> -        if (null != data) {
> -            return data.length;
> -        } else if (null != file && file.exists()) {
> -            return (int) (file.length());
> -        } else if (url != null) {
> -            return -1;
> -        } else {
> -            return 0;
> -        }
> -    }
> -
> -    /**
> -     *
> -     * @since 1.0
> -     */
> -    public void recycle() {
> -        super.recycle();
> -        data = null;
> -        url = null;
> -        file = null;
> -    }
> -
> -    /** Log object for this class. */
> -    private static final Log LOG = LogFactory.getLog(PutMethod.class);
>  }
> 
> 
> ------------------------------------------------------------------------
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org


Mime
View raw message