You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by js...@apache.org on 2002/09/02 16:52:48 UTC

cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient TestStreams.java TestNoHost.java TestWebappBase.java TestWebappParameters.java TestWebappRedirect.java

jsdever     2002/09/02 07:52:48

  Modified:    httpclient/src/java/org/apache/commons/httpclient
                        HttpConnection.java HttpMethod.java
                        HttpMethodBase.java HttpMultiClient.java
               httpclient/src/java/org/apache/commons/httpclient/methods
                        GetMethod.java
               httpclient/src/test/org/apache/commons/httpclient
                        TestNoHost.java TestWebappBase.java
                        TestWebappParameters.java TestWebappRedirect.java
  Added:       httpclient/src/java/org/apache/commons/httpclient
                        AutoCloseInputStream.java ChunkedInputStream.java
                        ContentLengthInputStream.java
                        WireLogInputStream.java
               httpclient/src/test/org/apache/commons/httpclient
                        TestStreams.java
  Log:
  Allow for unbuffered input streams.
  
  This monolithic patch contains:
  - unbuffered input streams
  - webapp tests fixed (including patches by Ryan Lubke)
  - authentication retry bug
  
  Contributed by: Ortwin Gluck
  
  Revision  Changes    Path
  1.19      +5 -5      jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java
  
  Index: HttpConnection.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- HttpConnection.java	20 Aug 2002 23:22:48 -0000	1.18
  +++ HttpConnection.java	2 Sep 2002 14:52:47 -0000	1.19
  @@ -457,7 +457,7 @@
       throws IOException, IllegalStateException {
           log.trace("enter HttpConnection.getRequestOutputStream(HttpMethod)");
           assertOpen();
  -        return new ResponseInputStream(_input,method);
  +        return _input;
       }
   
       /**
  
  
  
  1.15      +21 -4     jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethod.java
  
  Index: HttpMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethod.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- HttpMethod.java	28 Jul 2002 18:08:57 -0000	1.14
  +++ HttpMethod.java	2 Sep 2002 14:52:47 -0000	1.15
  @@ -239,6 +239,18 @@
       public Header getResponseHeader(String headerName);
   
       /**
  +     * Return an array of my response footers
  +     * @return <tt>null</tt> if no footers are available
  +     */
  +    public Header[] getResponseFooters();
  +
  +    /**
  +     * Return the specified response footer.
  +     * Note that footer-name matching is case insensitive.
  +     */
  +    public Header getResponseFooter(String footerName);
  +
  +    /**
        * Return my response body, if any,
        * as a byte array.
        * Otherwise return <tt>null</tt>.
  @@ -286,4 +298,9 @@
        * once this method has been called.
        */
       public void recycle();
  +
  +    /**
  +     * Use this method internally to add footers.
  +     */
  +    public void addResponseFooter(Header footer);
   }
  
  
  
  1.52      +246 -89   jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java
  
  Index: HttpMethodBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v
  retrieving revision 1.51
  retrieving revision 1.52
  diff -u -r1.51 -r1.52
  --- HttpMethodBase.java	1 Sep 2002 14:28:15 -0000	1.51
  +++ HttpMethodBase.java	2 Sep 2002 14:52:47 -0000	1.52
  @@ -68,6 +68,7 @@
   import java.io.OutputStream;
   import java.net.URL;
   import java.util.Date;
  +import java.util.Map;
   import java.util.HashMap;
   import java.util.HashSet;
   import java.util.Iterator;
  @@ -184,7 +185,15 @@
   
       /** My response headers, if any. */
       private HashMap responseHeaders = new HashMap();
  -    // ----------------------------------------------------- Instance Variables
  +
  +    /** My response footers, if any. */
  +    private Map responseFooters = null;
  +
  +    /** Realms that we tried to authenticate to */
  +    private Set realms = null;
  +
  +    /** Proxy Realms that we tried to authenticate to */
  +    private Set proxyRealms = null;
   
       /** My request path. */
       private String path = null;
  @@ -196,6 +205,9 @@
       private String statusText = null;
   
       /** The response body, assuming it has not be intercepted by a sub-class. */
  +    private InputStream responseStream = null;
  +
  +    /** Buffer for the response */
       private byte[] responseBody = null;
   
       /** Whether or not the request body has been sent. */
  @@ -303,6 +315,34 @@
       }
   
       /**
  +     * Add the specified request header.
  +     *
  +     * If a header of the same name already exists, the new value will be
  +     * appended onto the the existing value list. 
  +     * A <i>header</i> value of <code>null</code> will be ignored. 
  +     * Note that header-name matching is case insensitive.
  +     *
  +     * @param header the header to add to the request
  +     */
  +    public void addRequestHeader(Header header) {
  +        log.trace("HttpMethodBase.addRequestHeader(Header)");
  +
  +        if (header == null) {
  +          log.debug("null header value ignored");
  +        } else {
  +            addRequestHeader(header.getName(), header.getValue());
  +        }
  +    }
  +
  +    /**
  +     * adds a response footer to the internal list
  +     */
  +    public void addResponseFooter(Header footer) {
  +        if (responseFooters == null) responseFooters = new HashMap();
  +        responseFooters.put(footer.getName().toLowerCase(), footer);
  +    }
  +
  +    /**
        * Get the path part of my request.
        * 
        * @return the path to request or "/" if the path is blank.
  @@ -403,36 +443,30 @@
       }
   
       /**
  -     * Return my response body, if any, as a byte array. Otherwise return
  -     * <tt>null</tt>.
  +     * Provide access to the status code.
        * 
  -     * @return the response body
  +     * @return the status code associated with the latest response.
        */
  -    public byte[] getResponseBody() {
  -        return responseBody;
  +    public int getStatusCode() {
  +        return statusCode;
       }
   
       /**
  -     * Return my response body, if any, as an {@link InputStream}. Otherwise
  -     * return <tt>null</tt>.
  -     * 
  -     * @return the response body as an {@link InputStream}
  -     * 
  -     * @throws IOException when there are errors obtaining the response
  +     * Checks if response data is available.
  +     * @return true if response data is available, false otherwise.
        */
  -    public InputStream getResponseBodyAsStream() throws IOException {
  -        return (null == responseBody)
  -               ? null : new ByteArrayInputStream(responseBody);
  +    private boolean responseAvailable() {
  +        return (responseBody != null) || (responseStream != null);
       }
   
       /**
  -     * Gets the response body as a string.
  +     * Provide access to the response headers
        * 
  -     * @return my response body, if any, as a {@link String}. Otherwise return
  -     *         <tt>null</tt>.
  +     * @return an array of my response headers.
        */
  -    public String getResponseBodyAsString() {
  -        return (null == responseBody) ? null : new String(responseBody);
  +    public Header[] getResponseHeaders() {
  +        return (Header[]) (responseHeaders.values().toArray(
  +            new Header[responseHeaders.size()]));
       }
   
       /**
  @@ -452,22 +486,98 @@
       }
   
       /**
  -     * Provide access to the response headers
  +     * Return my response body, if any, as a byte array.
  +     * Otherwise return <tt>null</tt>.
  +     */
  +    public byte[] getResponseBody() {
  +        if (responseBody == null) {
  +            try {
  +                ByteArrayOutputStream os = new ByteArrayOutputStream();
  +                InputStream is = getResponseBodyAsStream();
  +                byte[] buffer = new byte[10000];
  +                int len;
  +                while ((len = is.read(buffer)) > 0) {
  +                    os.write(buffer, 0, len);
  +                }
  +                responseBody = os.toByteArray();
  +                setResponseStream(null);
  +                log.debug("buffering response body");
  +            } catch(IOException e) {
  +                log.error("getResponseBody failed", e);
  +                responseBody = null;
  +            }
  +        }
  +        return responseBody;
  +    }
  +
  +    /**
  +     * Return my response body, if any, as an {@link InputStream}. Otherwise
  +     * return <tt>null</tt>.
        * 
  -     * @return an array of my response headers.
  +     * @return the response body as an {@link InputStream}
  +     * 
  +     * @throws IOException when there are errors obtaining the response
        */
  -    public Header[] getResponseHeaders() {
  -        return (Header[]) (responseHeaders.values().toArray(
  -            new Header[responseHeaders.size()]));
  +    public InputStream getResponseBodyAsStream() throws IOException {
  +        if (responseStream != null) {
  +            return responseStream;
  +        }
  +        if (responseBody != null) {
  +            responseStream = new ByteArrayInputStream(responseBody);
  +            log.debug("re-creating response stream from byte array");
  +            return responseStream;
  +        }
  +        return null;
       }
   
       /**
  -     * Provide access to the status code.
  +     * Gets the response body as a string.
        * 
  -     * @return the status code associated with the latest response.
  +     * <b>Note:</b> The string conversion done on the data is done with the
  +     * default character encoding.  The use of this method may be non-portable.
  +     *
  +     * @return my response body, if any, as a {@link String}. Otherwise return
  +     *         <tt>null</tt>.
        */
  -    public int getStatusCode() {
  -        return statusCode;
  +    public String getResponseBodyAsString() {
  +        //FIXME: Take into account any character encoding information and
  +        //use the correct (rather than default) encoding.
  +        return responseAvailable() ? new String(getResponseBody()) : null;
  +    }
  +
  +
  +    /**
  +     * Return an array of response footers.
  +     * @return <tt>null</tt> if no footers are available
  +     */
  +    public Header[] getResponseFooters() {
  +        if (responseFooters == null) {
  +            return null;
  +        }
  +        return (Header[])(responseFooters.values().toArray(
  +            new Header[responseFooters.size()]));
  +    }
  +
  +    /**
  +     * Get the response footer associated with the given name.
  +     * Footer name matching is case insensitive.
  +     * <tt>null</tt> will be returned if either <i>footerName</i> is
  +     * <tt>null</tt> or there is no matching header for <i>footerName</i>
  +     * or there are no footers available.
  +     * @param footerName the footer name to match
  +     * @return the matching footer
  +     */
  +    public Header getResponseFooter(String footerName) {
  +        if (responseFooters == null) {
  +            return null;
  +        }
  +        return (footerName == null) ? null :
  +            (Header)(responseFooters.get(footerName.toLowerCase()));
  +    }
  +
  +
  +    protected void setResponseStream(InputStream responseStream) {
  +        this.responseStream = responseStream;
       }
   
       /**
  @@ -528,7 +638,13 @@
           setRequestHeader(header);
       }
   
  +
       /**
  +     * Close the provided HTTP connection, if:
  +     *  http 1.0 and not using the 'connect' method, or
  +     *  http 1.1 and the Connection: close header is sent
  +     *
  +     * @param connection the HTTP connection to process
        * Add the specified request header. If a header of the same name already
        * exists, the new value will be appended onto the the existing value
        * list.  A <i>header</i> value of <code>null</code> will be ignored. Note
  @@ -536,14 +652,32 @@
        * 
        * @param header the header to add to the request
        */
  -    public void addRequestHeader(Header header) {
  -        log.trace("HttpMethodBase.addRequestHeader(Header)");
  +    private void closeConnection(HttpConnection connection) {
  +        if (shouldCloseConnection(connection)) {
  +            connection.close();
  +        }
  +    }
   
  -        if (header == null) {
  -            log.debug("null header value ignored");
  +    private boolean shouldCloseConnection(HttpConnection connection) {
  +        if (!http11) {
  +            if (getName().equals(ConnectMethod.NAME) && 
  +                    (statusCode == HttpStatus.SC_OK)) {
  +                log.debug("Will leave connection open for tunneling");
  +                return false;
  +            } else {
  +                log.debug("Should close connection since using HTTP/1.0, " +
  +                        "ConnectMethod and status is OK");
  +                return true;
  +            }
           } else {
  -            addRequestHeader(header.getName(), header.getValue());
  +            Header connectionHeader = getResponseHeader("connection");
  +            if (null != connectionHeader
  +                && "close".equalsIgnoreCase(connectionHeader.getValue())) {
  +                log.debug("Should close connection since \"Connection: close\" header found.");
  +                return true;
  +            }
           }
  +        return false;
       }
   
       /**
  @@ -594,6 +728,8 @@
           }
   
           Set visited = new HashSet();
  +        realms = new HashSet();
  +        proxyRealms = new HashSet();
           int forwardCount = 0; //protect from an infinite loop
   
           while (forwardCount++ < maxForwards) {
  @@ -607,9 +743,6 @@
               //if SC_CONTINUE write the request body
               writeRemainingRequestBody(state, conn);
   
  -            //close connection if required
  -            closeConnection(conn);
  -
               switch (statusCode) {
                   case HttpStatus.SC_UNAUTHORIZED:
                   case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
  @@ -642,20 +775,20 @@
                                     + "'");
                       }
   
  -                    URL url; //the new url
  +                    URL url = null; //the new url
   
  -                    if (isStrictMode()) {
  -                        //rfc2616 demands the location value be a complete URI
  -                        //Location       = "Location" ":" absoluteURI
  -                        try {
  -                            url = new URL(location);
  -                        } catch (Exception ex) {
  -                            log.warn("Redirected location '"
  -                                     + locationHeader.getValue()
  -                                     + "' is not acceptable in strict mode");
  -                            return statusCode;
  +                    //rfc2616 demands the location value be a complete URI
  +                    //Location       = "Location" ":" absoluteURI
  +                    try {
  +                        url = new URL(location);
  +                    } catch (Exception ex) {
  +                        if (isStrictMode()) {
  +                            log.error("Redirected location '" + locationHeader.getValue() +
  +                                    "' is not acceptable in strict mode");
  +                            return statusCode; //should we throw an exception?
                           }
  -                    } else { //not strict mode
  +                    }
  +                    if (url == null) {
                           //try to construct the new url based on the current url
                           try {
                               URL currentUrl = new URL(conn.getProtocol(), 
  @@ -714,16 +847,23 @@
                       return statusCode;
               } //end of switch
   
  +/*
  +    Revisiting may be desired. We do not know about the server's internal state.
  +
               //check to see if we have visited this url before
               if (visited.contains(generateVisitedKey(conn))) {
                   log.error("Link " + generateVisitedKey(conn) + "' revisited");
                   return statusCode;
               }
               visited.add(generateVisitedKey(conn));
  +*/
  +
  +            //close connection if required
  +            closeConnection(conn);
           } //end of loop
   
           log.error("Narrowly avoided an infinite loop in execute");
  -        return statusCode;
  +        throw new HttpException("Maximum redirects ("+ maxForwards +") exceeded");
       }
   
       /**
  @@ -1301,8 +1441,7 @@
                                       OutputStream out)
       throws IOException {
           log.trace(
  -            "enter HttpMethodBase.readResponseBody(HttpState, HttpConnection)");
  -
  +            "enter HttpMethodBase.readResponseBody(HttpState, HttpConnection, OutputStream)");
           responseBody = null;
           int expectedLength = 0;
           int foundLength = 0;
  @@ -1366,6 +1505,55 @@
       }
   
       /**
  +     * Read the response body from the given {@link HttpConnection}.
  +     * <p>
  +     * The current implementation returns an appropriate stream
  +     * (according to the values of the
  +     * <tt>Content-Length</tt> and <tt>Transfer-Encoding</tt>
  +     * headers, if any).
  +     * <p>
  +     *
  +     * @see #readResponse
  +     * @see #processResponseBody
  +     *
  +     * @param state the client state
  +     * @param conn the {@link HttpConnection} to read the response from
  +     * @returns InputStream to read the response body from
  +     */
  +    private InputStream _readResponseBody(HttpState state, HttpConnection conn) throws IOException {
  +        log.trace("enter HttpMethodBase.readResponseBody(HttpState, HttpConnection)");
  +
  +        responseBody = null; // is this desired?
  +        Header lengthHeader = getResponseHeader("Content-Length");
  +        Header transferEncodingHeader = getResponseHeader("Transfer-Encoding");
  +        InputStream is = conn.getResponseInputStream(this);
  +        if (wireLog.isDebugEnabled()) {
  +            is = new WireLogInputStream(is);
  +        }
  +        InputStream result = null;
  +        if (null != lengthHeader) {
  +            try {
  +                int expectedLength = Integer.parseInt(lengthHeader.getValue());
  +                result = new ContentLengthInputStream(is, expectedLength);
  +            } catch(NumberFormatException e) {
  +                // ignored
  +            }
  +        } else if (null != transferEncodingHeader) {
  +            if ("chunked".equalsIgnoreCase(transferEncodingHeader.getValue())) {
  +                result = new ChunkedInputStream(is, this);
  +            }
  +        } else if(canResponseHaveBody(statusCode) && !getName().equals(ConnectMethod.NAME)){
  +            result = is;
  +        }
  +        if (result == null) return null;
  +
  +        if (shouldCloseConnection(conn)) {
  +            result = new AutoCloseInputStream(result, conn);
  +        }
  +        return result;
  +    }
  +
  +    /**
        * Read response headers from the given {@link HttpConnection}, populating
        * the response headers map.
        * 
  @@ -1711,6 +1899,7 @@
           return true;
       }
   
  +
       /**
        * "It must be possible to combine the multiple header fields into one
        * "field-name: field-value" pair, without changing the semantics of the
  @@ -1772,35 +1961,6 @@
       }
   
       /**
  -     * Close the provided HTTP connection, if: http 1.0 and not using the
  -     * 'connect' method, or http 1.1 and the Connection: close header is sent
  -     * 
  -     * @param connection the HTTP connection to process
  -     */
  -    private void closeConnection(HttpConnection connection) {
  -        log.trace("enter closeConnection(HttpConnection)");
  -
  -        if (!http11) {
  -            if (getName().equals(ConnectMethod.NAME)
  -                && (statusCode == HttpStatus.SC_OK)) {
  -                log.debug("Leaving connection open for tunneling");
  -            } else {
  -                log.debug("Closing connection since using HTTP/1.0, "
  -                          + "ConnectMethod and status is OK");
  -                connection.close();
  -            }
  -        } else {
  -            Header connectionHeader = getResponseHeader("connection");
  -            if ((null != connectionHeader)
  -                && "close".equalsIgnoreCase(connectionHeader.getValue())) {
  -                log.debug("Closing connection since \"Connection: close\" "
  -                    + "header found.");
  -                connection.close();
  -            }
  -        }
  -    }
  -
  -    /**
        * Generates a key used for idenifying visited URLs.
        * 
        * @param conn DOCUMENT ME!
  @@ -1827,9 +1987,6 @@
           log.trace("enter HttpMethodBase.processAuthenticationResponse("
               + "HttpState, HttpConnection)");
   
  -        Set realms = new HashSet();
  -        Set proxyRealms = new HashSet();
  -
           // handle authentication required
           Header wwwauth = null;
           Set realmsUsed = null;
  @@ -1995,4 +2152,4 @@
               readResponse(state, connection);
           }
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.15      +4 -4      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.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- HttpMultiClient.java	1 Sep 2002 01:27:37 -0000	1.14
  +++ HttpMultiClient.java	2 Sep 2002 14:52:48 -0000	1.15
  @@ -93,7 +93,7 @@
       /** manager of http connections on a host:port basis */
       private HttpConnectionManager mgr = new HttpConnectionManager();
       /** specifies strict HTTP compliance */
  -    private boolean strictMode = true;
  +    private boolean strictMode = false; //experimental features off
       /** how long to wait for a connection to become available */
       private int timeoutConnection = 0;
       /** how long to wait for a request to complete */
  
  
  
  1.1                  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/AutoCloseInputStream.java
  
  Index: AutoCloseInputStream.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/AutoCloseInputStream.java,v 1.1 2002/09/02 14:52:47 jsdever Exp $
   * $Revision: 1.1 $
   * $Date: 2002/09/02 14:52:47 $
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 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", "HttpClient", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.commons.httpclient;
  
  import java.io.*;
  
  /**
   * Closes a HttpConnection as soon as the end of the stream is reached.
   * @author Ortwin Gl�ck
   *
   * @since 2.0
   */
  
  class AutoCloseInputStream extends FilterInputStream {
      private HttpConnection conn;
  
      public AutoCloseInputStream(InputStream in, HttpConnection conn) {
          super(in);
          this.conn = conn;
      }
  
      public int read() throws java.io.IOException {
          int l = super.read();
          if (l == -1) conn.close();
          return l;
      }
  
      public int read(byte[] b, int off, int len) throws java.io.IOException {
          int l = super.read(b,  off,  len);
          if (l == -1) conn.close();
          return l;
      }
  
      public int read(byte[] b) throws java.io.IOException {
          int l = super.read(b);
          if (l == -1) conn.close();
          return l;
      }
  }
  
  
  1.1                  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java
  
  Index: ChunkedInputStream.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java,v 1.1 2002/09/02 14:52:47 jsdever Exp $
   * $Revision: 1.1 $
   * $Date: 2002/09/02 14:52:47 $
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 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", "HttpClient", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.commons.httpclient;
  
  import java.io.*;
  import java.util.*;
  
  /**
   * <p>Transparently coalesces chunks of a HTTP stream that uses Transfer-Encoding
   * chunked.</p>
   * @author Ortwin Gl�ck
   * @since 2.0
   */
  
  public class ChunkedInputStream extends InputStream {
      private InputStream in;
      private int chunkSize, pos;
      private boolean eof = false;
      private static final String HTTP_ENC = "US-ASCII";
      private HttpMethod method;
  
      public ChunkedInputStream(InputStream in, HttpMethod method) throws IOException {
          this.in = in;
          this.method = method;
          this.chunkSize = getChunkSize();
          this.pos = 0;
      }
  
      /**
       * Returns all the data in a chunked stream in coalesced form. A chunk is
       * followed by a CRLF. The method returns -1 as soon as a chunksize of 0 is
       * detected.
       * Footers are read automcatically at the end of the stream and can be obtained
       * with the getFooters() method.
       *
       * @return -1 of the end of the stream has been reached or the next data byte
       * @throws IOException
       */
      public int read() throws IOException {
          if (eof) return -1;
          if (pos >= chunkSize) {
              nextChunk();
              if (eof) return -1;
          }
          pos++;
          return in.read();
      }
  
      public int read(byte[] b, int off, int len) throws java.io.IOException {
          if (eof) return -1;
          if (pos >= chunkSize) {
              nextChunk();
              if (eof) return -1;
          }
          len = Math.min(len, chunkSize);
          int count = in.read(b, off, len);
          pos += count;
          return count;
      }
  
      public int read(byte[] b) throws java.io.IOException {
          return read(b, 0, b.length);
      }
  
      private void nextChunk() throws IOException {
          int cr = in.read();
          int lf = in.read();
          if ((cr != '\r') &&
              (lf != '\n')) throw new IOException("CRLF expected at end of chunk: "+cr+"/"+lf);
          chunkSize = getChunkSize();
          pos = 0;
          if (chunkSize == 0) {
              eof = true;
              parseFooters();
          }
      }
  
      /**
       * Expects the stream to start with a chunksize in hex with optional comments
       * after a semicolon. The line must end with a CRLF:
       * "a3; some comment\r\n"
       * Positions the stream at the start of the next line.
       *
       * @return the chunk size as integer
       * @throws IOException when the chunk size could not be parsed
       */
      private int getChunkSize() throws IOException {
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          int b = in.read();
          int state = 0;
          while (state != 2) {
              if (b == -1) throw new IOException("chunked stream ended unexpectedly");
              switch (state) {
                  case 0:
                      if (b == '\r') state = 1;
                      break;
                  case 1:
                      if (b == '\n') state = 2;
                      else state = 0;
                      break;
                  default: throw new RuntimeException("assertion failed");
              }
              if (state == 0) baos.write(b);
              if (state != 2) b = in.read();
          }
  
          //parse data
          String dataString = new String(baos.toByteArray(), HTTP_ENC);
          int separator = dataString.indexOf(';');
          if (separator > 0) dataString = dataString.substring(0, separator).trim();
  
          int result;
          try {
              result = Integer.parseInt(dataString, 16);
          } catch(NumberFormatException e) {
              throw new IOException("Bad chunk size: "+dataString);
          }
          return result;
      }
  
      /**
       * Stores the footers into map of Headers
       */
      private void parseFooters() throws IOException {
          String line = readLine();
          while ((line != null) && (!line.equals(""))) {
              int colonPos = line.indexOf(':');
              if (colonPos != -1) {
                  String key = line.substring(0, colonPos).trim();
                  String val = line.substring(colonPos+1).trim();
                  Header footer = new Header(key, val);
                  method.addResponseFooter(footer);
              }
              line = readLine();
          }
      }
  
      private String readLine() throws IOException {
          StringBuffer buf = new StringBuffer();
          for(;;) {
              int ch = in.read();
              if(ch < 0) {
                  if(buf.length() == 0) {
                      return null;
                  } else {
                      break;
                  }
              } else if (ch == '\r') {
                  continue;
              } else if (ch == '\n') {
                  break;
              }
              buf.append((char)ch);
          }
          return (buf.toString());
      }
  
      public void close() throws IOException {
          in.close();
      }
  }
  
  
  1.1                  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ContentLengthInputStream.java
  
  Index: ContentLengthInputStream.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ContentLengthInputStream.java,v 1.1 2002/09/02 14:52:47 jsdever Exp $
   * $Revision: 1.1 $
   * $Date: 2002/09/02 14:52:47 $
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 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", "HttpClient", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.commons.httpclient;
  
  import java.io.*;
  
  /**
   * Cuts the wrapped InputStream off after a specified number of bytes.
   *
   * @author Ortwin Gl�ck
   * @since 2.0
   */
  
  public class ContentLengthInputStream extends FilterInputStream {
      private int contentLength;
      private int pos = 0;
  
      /**
       * Creates a new length limited stream
       *
       * @param in The stream to wrap
       * @param contentLength The maximum number of bytes that can be read from
       * the stream. Subsequent read operations will return -1.
       */
      public ContentLengthInputStream(InputStream in, int contentLength) {
          super(in);
          this.contentLength = contentLength;
      }
  
      public int read() throws java.io.IOException {
          if (pos > contentLength) return -1;
          pos++;
          return super.read();
      }
  
  
      public int read(byte[] b, int off, int len) throws java.io.IOException {
          if (pos > contentLength) return -1;
          if (pos + len > contentLength) {
              len = contentLength - pos;
          }
          int count = super.read(b, off, len);
          pos += count;
          return count;
      }
  
  
      public int read(byte[] b) throws java.io.IOException {
          return read(b, 0, b.length);
      }
  
  }
  
  
  1.1                  jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/WireLogInputStream.java
  
  Index: WireLogInputStream.java
  ===================================================================
  package org.apache.commons.httpclient;
  
  import java.io.*;
  import org.apache.commons.logging.*;
  
  /**
   * Logs all data read to the wire log.
   *
   * @author Ortwin Gl�ck
   * @since 2.0
   */
  
  public class WireLogInputStream extends FilterInputStream {
      /** Log for any wire messages. */
      private static final Log wireLog = LogFactory.getLog("httpclient.wire");
  
      public WireLogInputStream(InputStream in) {
          super(in);
      }
  
      public int read(byte[] b, int off, int len) throws java.io.IOException {
          int l = super.read(b,  off,  len);
          wireLog.debug("<< "+ new String(b, off, len));
          return l;
      }
  
      public int read() throws java.io.IOException {
          int l = super.read();
          if (l > 0) wireLog.debug("<< "+ (char) l);
          return l;
      }
  
      public int read(byte[] b) throws java.io.IOException {
          int l = super.read(b);
          wireLog.debug("<< "+ new String(b));
          return l;
      }
  }
  
  
  1.17      +52 -110   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.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- GetMethod.java	1 Sep 2002 01:27:37 -0000	1.16
  +++ GetMethod.java	2 Sep 2002 14:52:48 -0000	1.17
  @@ -74,6 +74,7 @@
   import org.apache.commons.httpclient.HttpConnection;
   import org.apache.commons.httpclient.HttpMethodBase;
   import org.apache.commons.httpclient.HttpState;
  +import org.apache.commons.httpclient.HttpException;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   
  @@ -96,7 +97,8 @@
       /** Temporary directory. */
       private static final String TEMP_DIR = "temp/";
   
  -    //~ Instance variables �����������������������������������������������������
  +
  +    // ----------------------------------------------------- Instance Variables
   
       /** File which contains the buffered data. */
       private File fileData;
  @@ -107,11 +109,6 @@
       /** 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;
   
  @@ -241,37 +238,7 @@
           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 super.getResponseBody();
       }
   
       /**
  @@ -288,37 +255,9 @@
           log.trace("enter GetMethod.getResponseBodyAsStream()");
   
           checkUsed();
  -
  -        if (useDisk) {
  -            return new FileInputStream(fileData);
  -        } else {
  -            if (null == memoryData) {
  -                return null;
  -            } else {
  -                return new ByteArrayInputStream(memoryData);
  -            }
  -        }
  +        return super.getResponseBodyAsStream();
       }
   
  -    /**
  -     * 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 String getResponseBodyAsString() {
  -        log.trace("enter GetMethod.getResponseBodyAsString()");
  -
  -        byte[] data = getResponseBody();
  -
  -        if (null == data) {
  -            return null;
  -        } else {
  -            return new String(data);
  -        }
  -    }
   
       /**
        * Temporary directory setter.
  @@ -402,7 +341,6 @@
           log.trace("enter GetMethod.recycle()");
   
           super.recycle();
  -        this.memoryData = null;
           this.fileData = null;
           setFollowRedirects(true);
       }
  @@ -421,51 +359,55 @@
        * @since 2.0
        */
       protected void readResponseBody(HttpState state, HttpConnection conn)
  -                             throws IOException {
  -        log.trace("enter GetMethod.readResponseBody(HttpState, "
  -            + "HttpConnection)");
  +    throws IOException, HttpException {
  +        log.trace("enter GetMethod.readResponseBody(HttpState, HttpConnection)");
   
  -        OutputStream out = null;
  +        super.readResponseBody(state, conn);
   
  +        
  +        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);
  -                    }
  -
  -                    tempFileName = System.currentTimeMillis() + "-"
  -                                   + encodedPath + ".tmp";
  -                } else {
  -                    tempFileName = tempFile;
  -                }
  -
  -                fileData = new File(tempDir, tempFileName);
  -                fileData.deleteOnExit();
  +            out = new FileOutputStream(createTempFile());
  +            InputStream in = getResponseBodyAsStream();
  +            byte[] buffer = new byte[10000];
  +            int len ;
  +            while ((len = in.read(buffer)) > 0) {
  +                out.write(buffer, 0, len);
               }
  -
  -            out = new FileOutputStream(fileData);
  -        } else {
  -            out = new ByteArrayOutputStream();
  +            out.close();
  +            setResponseStream(new FileInputStream(createTempFile()));
           }
  +    }
   
  -        readResponseBody(state, conn, out);
  -
  -        if (!useDisk) {
  -            memoryData = ((ByteArrayOutputStream) out).toByteArray();
  +    /**
  +     * Returns the file buffer, creating it if necessary. The created file is
  +     * deleted when the VM exits.
  +     * @return Temporary file to hold the data buffer.
  +     */
  +    private File createTempFile() {
  +        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);
  +                }
  +                tempFileName = System.currentTimeMillis() + "-"
  +                    + encodedPath + ".tmp";
  +            } else {
  +                tempFileName = tempFile;
  +            }
  +            fileData = new File(tempDir, tempFileName);
  + 
  +            fileData = new File(tempDir, tempFileName);
  +            fileData.deleteOnExit();
           }
  -
  -        out.close();
  +        return fileData;
       }
  -}
  \ No newline at end of file
  +}
  
  
  
  1.11      +5 -4      jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java
  
  Index: TestNoHost.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestNoHost.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- TestNoHost.java	2 Aug 2002 11:38:12 -0000	1.10
  +++ TestNoHost.java	2 Sep 2002 14:52:48 -0000	1.11
  @@ -97,6 +97,7 @@
           suite.addTest(TestHttpState.suite());
           suite.addTest(TestResponseHeaders.suite());
           suite.addTest(TestRequestHeaders.suite());
  +        suite.addTest(TestStreams.suite());
           return suite;
       }
   
  
  
  
  1.3       +8 -7      jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappBase.java
  
  Index: TestWebappBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappBase.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestWebappBase.java	4 Oct 2001 17:49:13 -0000	1.2
  +++ TestWebappBase.java	2 Sep 2002 14:52:48 -0000	1.3
  @@ -72,12 +72,13 @@
    * <p>
    * The webapp should be deployed in the context "httpclienttest"
    * on a servlet engine running on port 8080 on the localhost
  - * (IP 127.0.0.1).
  + * (name localhost).
    * <p>
    * You can change the assumed port by setting the
    * "httpclient.test.localPort" property.
    * You can change the assumed host by setting the
  - * "httpclient.test.localHost" property.
  + * "httpclient.test.localHost" property. A DNS name is preferred over
  + * an IP address here.
    * You can change the assumed context by setting the
    * "httpclient.test.webappContext" property.
    *
  @@ -93,7 +94,7 @@
       // -------------------------------------------------------------- Constants
   
       protected static final String context = System.getProperty("httpclient.test.webappContext","httpclienttest");
  -    protected static final String host = System.getProperty("httpclient.test.localHost","127.0.0.1");
  +    protected static final String host = System.getProperty("httpclient.test.localHost","localhost");
       protected static final int port;
       static {
           String portString = System.getProperty("httpclient.test.localPort","8080");
  
  
  
  1.4       +5 -5      jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappParameters.java
  
  Index: TestWebappParameters.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappParameters.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TestWebappParameters.java	4 Feb 2002 15:26:43 -0000	1.3
  +++ TestWebappParameters.java	2 Sep 2002 14:52:48 -0000	1.4
  @@ -210,7 +210,7 @@
           }
           assertTrue(method.getResponseBodyAsString().indexOf("<title>Param Servlet: GET</title>") >= 0);
           assertEquals(200,method.getStatusCode());
  -        assertTrue(method.getResponseBodyAsString().indexOf("<p>QueryString=\"param-without-value\"</p>") >= 0);
  +        assertTrue(method.getResponseBodyAsString().indexOf("<p>QueryString=\"param-without-value=\"</p>") >= 0);
       }
   
       /**
  
  
  
  1.6       +4 -5      jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappRedirect.java
  
  Index: TestWebappRedirect.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestWebappRedirect.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- TestWebappRedirect.java	23 Jul 2002 14:39:14 -0000	1.5
  +++ TestWebappRedirect.java	2 Sep 2002 14:52:48 -0000	1.6
  @@ -213,7 +213,6 @@
           HttpClient client = new HttpClient();
           client.startSession(host, port);
           PutMethod method = new PutMethod("/" + context + "/redirect");
  -        method.setFollowRedirects(true);
           method.setQueryString("to=" + URLEncoder.encode("http://" + host + ":" + port + "/" + context + "/body?foo=bar&bar=foo"));
           method.setRequestBody("This is data to be sent in the body of an HTTP PUT.");
           try {
  
  
  
  1.1                  jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestStreams.java
  
  Index: TestStreams.java
  ===================================================================
  
  package org.apache.commons.httpclient;
  
  import java.io.*;
  import java.util.Map;
  import junit.framework.*;
  
  
  public class TestStreams extends TestCase {
  
      public TestStreams(String testName) {
          super(testName);
      }
  
      public void testChunkedInputStream() throws IOException {
          String correct = "10; this is comments\r\n1234567890123456\r\n5\r\n12345\r\n0\r\nFooter1: abcde\r\nFooter2: fghij\r\n";
          HttpMethod method = new SimpleHttpMethod();
          InputStream in = new ChunkedInputStream(new ByteArrayInputStream(correct.getBytes()), method);
          byte[] buffer = new byte[300];
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          int len;
          while ((len = in.read(buffer)) > 0) {
              out.write(buffer, 0, len);
          }
          String result = new String(out.toByteArray());
          assertEquals(result, "123456789012345612345");
          Header footer = method.getResponseFooter("footer1");
          assertEquals(footer.getValue(), "abcde");
          footer = method.getResponseFooter("footer2");
          assertEquals(footer.getValue(), "fghij");
      }
  
      public void testContentLengthInputStream() throws IOException {
          String correct = "1234567890123456";
          InputStream in = new ContentLengthInputStream(new ByteArrayInputStream(correct.getBytes()), 10);
          byte[] buffer = new byte[50];
          int len = in.read(buffer);
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          out.write(buffer, 0, len);
          String result = new String(out.toByteArray());
          assertEquals(result, "1234567890");
      }
  
      // ------------------------------------------------------- TestCase Methods
  
      public static Test suite() {
          return new TestSuite(TestHeader.class);
      }
  
      // ------------------------------------------------------------------- Main
      public static void main(String args[]) {
          String[] testCaseName = { TestStreams.class.getName() };
          junit.textui.TestRunner.main(testCaseName);
      }
  }
  
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>