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 2003/02/11 04:23:05 UTC

cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient SimpleHttpConnection.java SimpleHttpMethod.java TestStreams.java

jsdever     2003/02/10 19:23:05

  Modified:    httpclient/src/java/org/apache/commons/httpclient
                        ChunkedInputStream.java HttpConnection.java
                        HttpMethodBase.java
               httpclient/src/test/org/apache/commons/httpclient
                        SimpleHttpConnection.java SimpleHttpMethod.java
                        TestStreams.java
  Log:
  Multivalued headers.
  
  Bug: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=11218
  Contributed by: Mike Becke
  
  changeLog:
   - HeaderGroup, a new class for storing headers.  This class supports multiple
      headers with the same name and it remembers header order.  I'm not a huge fan of
      the name, but it was the best I could come up with.
   - HeaderParser, a new class for parsing headers.  Header parsing code was
      duplicated in HttpMethodBase and ChunkedInputStream and was placed here.
   - HttpMethod has 3 new methods.  getRequestHeaderGroup(),
      getResponseHeaderGroup(), and getResponseFooterGroup().  This will break an
      existing extension of HttpMethod.
   - Some of the methods for accessing headers in HttpMethod have been deprecated.
   - Classes in the general codebase that use the newly deprecated methods have
      been fixed.  Some of the test cases are still using deprecated methods.
   - SimpleHttpConnection and SimpleHttpMethod have been changed to work correctly
      with the new header storage method.
  
  Revision  Changes    Path
  1.13      +18 -44    jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java
  
  Index: ChunkedInputStream.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- ChunkedInputStream.java	28 Jan 2003 04:40:20 -0000	1.12
  +++ ChunkedInputStream.java	11 Feb 2003 03:23:05 -0000	1.13
  @@ -67,6 +67,8 @@
   import java.io.IOException;
   import java.io.InputStream;
   
  +import org.apache.commons.httpclient.util.HeaderParser;
  +
   /**
    * <p>Transparently coalesces chunks of a HTTP stream that uses
    * Transfer-Encoding chunked.</p>
  @@ -84,6 +86,7 @@
    * @author Martin Elwin
    * @author Eric Johnson
    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
  + * @author Michael Becke
    *
    * @since 2.0
    *
  @@ -130,7 +133,7 @@
           this.chunkSize = getChunkSizeFromInputStream(in);
           if (chunkSize == 0) {
               eof = true;
  -            parseFooters();
  +            parseTrailerHeaders();
           }
           this.pos = 0;
       }
  @@ -140,12 +143,14 @@
        * is followed by a CRLF. The method returns -1 as soon as a chunksize of 0
        * is detected.</p>
        * 
  -     * <p> Footers are read automcatically at the end of the stream and can be
  -     * obtained with the getFooters() method.</p>
  +     * <p> Trailer headers are read automcatically at the end of the stream and
  +     * can be obtained with the getResponseFooters() method.</p>
        *
        * @return -1 of the end of the stream has been reached or the next data
        * byte
        * @throws IOException If an IO problem occurs
  +     * 
  +     * @see HttpMethod#getResponseFooters()
        */
       public int read() throws IOException {
   
  @@ -224,7 +229,7 @@
           pos = 0;
           if (chunkSize == 0) {
               eof = true;
  -            parseFooters();
  +            parseTrailerHeaders();
           }
       }
   
  @@ -306,46 +311,15 @@
       }
   
       /**
  -     * Stores the footers into map of Headers
  +     * Reads and stores the Trailer headers.
        * @throws IOException If an IO problem occurs
        */
  -    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();
  -        }
  -    }
  -
  -    /**
  -     * Read the next line from {@link #in}.
  -     * @return String The next line.
  -     * @throws IOException If an IO problem occurs.
  -     */
  -    private String readLine() throws IOException {
  -        StringBuffer buf = new StringBuffer();
  -        while (true) {
  -            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);
  +    private void parseTrailerHeaders() throws IOException {
  +        Header[] footers = HeaderParser.parseHeaders(in);
  +        
  +        for (int i = 0; i < footers.length; i++) {
  +            method.addResponseFooter(footers[i]);
           }
  -        return (buf.toString());
       }
   
       /**
  
  
  
  1.43      +42 -22    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.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- HttpConnection.java	8 Feb 2003 19:22:49 -0000	1.42
  +++ HttpConnection.java	11 Feb 2003 03:23:05 -0000	1.43
  @@ -104,11 +104,48 @@
    * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
    * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
  + * @author Michael Becke
    * 
    * @version   $Revision$ $Date$
    */
   public class HttpConnection {
   
  +    /**
  +     * Read up to <tt>"\r\n"</tt> from an (unchunked) input stream.
  +     * If the stream ends before the line terminator is found,
  +     * the last part of the string will still be returned.
  +     * '\r' and '\n' are allowed to appear individually in the stream.
  +     *
  +     * @param inputStream the stream to read from
  +     *
  +     * @throws IOException if an I/O problem occurs
  +     * @return a line from the stream
  +     * 
  +     * @since 2.0beta1
  +     */
  +    public static String readLine(InputStream inputStream) throws IOException {
  +        LOG.trace("enter HttpConnection.readLine()");
  +
  +        StringBuffer buf = new StringBuffer();
  +        int ch = inputStream.read();
  +        while (ch >= 0) {
  +            if (ch == '\r') {
  +                ch = inputStream.read();
  +                if (ch == '\n') {
  +                    break;
  +                } else {
  +                    buf.append('\r');
  +                }
  +            }
  +            buf.append((char) ch);
  +            ch = inputStream.read();
  +        }
  +        if (WIRE_LOG.isDebugEnabled()) {
  +            WIRE_LOG.debug("<< \"" + buf.toString() + (ch>0 ? "\" [\\r\\n]" : ""));
  +        }
  +        return (buf.toString());
  +    }
  +
       // ----------------------------------------------------------- Constructors
   
       /**
  @@ -857,24 +894,7 @@
           LOG.trace("enter HttpConnection.readLine()");
   
           assertOpen();
  -        StringBuffer buf = new StringBuffer();
  -        int ch = inputStream.read();
  -        while (ch >= 0) {
  -            if (ch == '\r') {
  -                ch = inputStream.read();
  -                if (ch == '\n') {
  -                    break;
  -                } else {
  -                    buf.append('\r');
  -                }
  -            }
  -            buf.append((char) ch);
  -            ch = inputStream.read();
  -        }
  -        if (WIRE_LOG.isDebugEnabled()) {
  -            WIRE_LOG.debug("<< \"" + buf.toString() + (ch>0 ? "\" [\\r\\n]" : ""));
  -        }
  -        return (buf.toString());
  +        return HttpConnection.readLine(inputStream);
       }
   
       /**
  
  
  
  1.111     +95 -158   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.110
  retrieving revision 1.111
  diff -u -r1.110 -r1.111
  --- HttpMethodBase.java	8 Feb 2003 19:22:49 -0000	1.110
  +++ HttpMethodBase.java	11 Feb 2003 03:23:05 -0000	1.111
  @@ -69,15 +69,13 @@
   import java.io.InputStream;
   import java.net.MalformedURLException;
   import java.net.URL;
  -import java.util.HashMap;
   import java.util.HashSet;
  -import java.util.Iterator;
  -import java.util.Map;
   import java.util.Set;
   import java.util.StringTokenizer;
   
   import org.apache.commons.httpclient.cookie.CookiePolicy;
   import org.apache.commons.httpclient.cookie.CookieSpec;
  +import org.apache.commons.httpclient.util.HeaderParser;
   import org.apache.commons.httpclient.util.URIUtil;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
  @@ -165,16 +163,16 @@
       // ----------------------------------------------------- Instance variables 
   
       /** My request headers, if any. */
  -    private Map requestHeaders = new HashMap();
  +    private HeaderGroup requestHeaders = new HeaderGroup();
   
       /** The Status-Line from the response. */
       private StatusLine statusLine = null;
   
       /** My response headers, if any. */
  -    private Map responseHeaders = new HashMap();
  +    private HeaderGroup responseHeaders = new HeaderGroup();
   
  -    /** My response footers, if any. */
  -    private Map responseFooters = null;
  +    /** My response trailer headers, if any. */
  +    private HeaderGroup responseTrailerHeaders = new HeaderGroup();
   
       /** Realms that we tried to authenticate to */
       private Set realms = null;
  @@ -416,12 +414,9 @@
       }
   
       /**
  -     * 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.
  +     * Add the specified request header. 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
        */
  @@ -429,9 +424,9 @@
           LOG.trace("HttpMethodBase.addRequestHeader(Header)");
   
           if (header == null) {
  -          LOG.debug("null header value ignored");
  +            LOG.debug("null header value ignored");
           } else {
  -            addRequestHeader(header.getName(), header.getValue());
  +            getRequestHeaderGroup().addHeader(header);
           }
       }
   
  @@ -440,10 +435,7 @@
        * @param footer The new footer to add.
        */
       public void addResponseFooter(Header footer) {
  -        if (responseFooters == null) { 
  -            responseFooters = new HashMap();
  -        }
  -        responseFooters.put(footer.getName().toLowerCase(), footer);
  +        getResponseTrailerHeaderGroup().addHeader(footer);
       }
   
       /**
  @@ -537,7 +529,15 @@
        * @param header the header
        */
       public void setRequestHeader(Header header) {
  -        requestHeaders.put(header.getName().toLowerCase(), header);
  +        
  +        Header[] headers = getRequestHeaderGroup().getHeaders(header.getName());
  +        
  +        for (int i = 0; i < headers.length; i++) {
  +            getRequestHeaderGroup().removeHeader(headers[i]);
  +        }
  +        
  +        getRequestHeaderGroup().addHeader(header);
  +        
       }
   
       /**
  @@ -551,8 +551,11 @@
        * @return the matching header
        */
       public Header getRequestHeader(String headerName) {
  -        return (headerName == null)
  -               ? null : (Header) (requestHeaders.get(headerName.toLowerCase()));
  +        if (headerName == null) {
  +            return null;
  +        } else {
  +            return getRequestHeaderGroup().getCondensedHeader(headerName);
  +        }
       }
   
       /**
  @@ -561,11 +564,44 @@
        * @return an array of my request headers.
        */
       public Header[] getRequestHeaders() {
  -        return (Header[]) (requestHeaders.values().toArray(
  -            new Header[requestHeaders.size()]));
  +        return getRequestHeaderGroup().getAllHeaders();
  +    }
  +
  +    /**
  +     * Gets the HeaderGroup storing the request headers.
  +     * 
  +     * @return a HeaderGroup
  +     * 
  +     * @since 2.0beta1
  +     */
  +    protected HeaderGroup getRequestHeaderGroup() {
  +        return requestHeaders;
  +    }
  +
  +    /**
  +     * Gets the HeaderGroup storing the response trailer headers as per RFC
  +     * 2616 section 3.6.1.
  +     * 
  +     * @return a HeaderGroup
  +     * 
  +     * @since 2.0beta1
  +     */
  +    protected HeaderGroup getResponseTrailerHeaderGroup() {
  +        return responseTrailerHeaders;
       }
   
       /**
  +     * Gets the HeaderGroup storing the response headers.
  +     * 
  +     * @return a HeaderGroup
  +     * 
  +     * @since 2.0beta1
  +     */
  +    protected HeaderGroup getResponseHeaderGroup() {
  +        return responseHeaders;
  +    }
  +    
  +    /**
        * Convenience method top provide access to the status code.
        *
        * @return the status code associated with the latest response.
  @@ -593,13 +629,12 @@
       }
   
       /**
  -     * Provide access to the response headers
  +     * Gets the response headers in the order in which they were read.
        *
        * @return an array of my response headers.
        */
       public Header[] getResponseHeaders() {
  -        return (Header[]) (responseHeaders.values().toArray(
  -            new Header[responseHeaders.size()]));
  +        return getResponseHeaderGroup().getAllHeaders();
       }
   
       /**
  @@ -612,10 +647,12 @@
        *
        * @return the matching header
        */
  -    public Header getResponseHeader(String headerName) {
  -        return (headerName == null)
  -               ? null
  -               : (Header) (responseHeaders.get(headerName.toLowerCase()));
  +    public Header getResponseHeader(String headerName) {        
  +        if (headerName == null) {
  +            return null;
  +        } else {
  +            return getResponseHeaderGroup().getCondensedHeader(headerName);
  +        }        
       }
   
       /**
  @@ -690,15 +727,11 @@
       }
   
       /**
  -     * Return an array of response footers.
  -     * @return <tt>null</tt> if no footers are available
  +     * Gets the response footers in the order in which they were read.
  +     * @return an array of headers
        */
       public Header[] getResponseFooters() {
  -        if (responseFooters == null) {
  -            return null;
  -        }
  -        return (Header[]) (responseFooters.values().toArray(
  -            new Header[responseFooters.size()]));
  +        return getResponseTrailerHeaderGroup().getAllHeaders();
       }
   
       /**
  @@ -711,11 +744,11 @@
        * @return the matching footer
        */
       public Header getResponseFooter(String footerName) {
  -        if (responseFooters == null) {
  +        if (footerName == null) {
               return null;
  +        } else {
  +            return getResponseTrailerHeaderGroup().getCondensedHeader(footerName);
           }
  -        return (footerName == null) ? null 
  -            : (Header) (responseFooters.get(footerName.toLowerCase()));
       }
   
       /**
  @@ -768,20 +801,7 @@
        * @param headerValue the header's value
        */
       public void addRequestHeader(String headerName, String headerValue) {
  -        // "It must be possible to combine the multiple header fields into
  -        // one "field-name: field-value" pair, without changing the
  -        // semantics of the message, by appending each subsequent field-value
  -        // to the first, each separated by a comma."
  -        //   - HTTP/1.0 (4.3)
  -        Header header = getRequestHeader(headerName);
  -        if (null == header) {
  -            // header doesn't exist already, simply create with name and value
  -            header = new Header(headerName, headerValue);
  -        } else {
  -            // header exists, add this value to the comma separated list
  -            header.setValue(getNewHeaderValue(header, headerValue));
  -        }
  -        setRequestHeader(header);
  +        addRequestHeader(new Header(headerName, headerValue));
       }
   
       /**
  @@ -1137,8 +1157,9 @@
           followRedirects = false;
           doAuthentication = true;
           queryString = null;
  -        requestHeaders.clear();
  -        responseHeaders.clear();
  +        getRequestHeaderGroup().clear();
  +        getResponseHeaderGroup().clear();
  +        getResponseTrailerHeaderGroup().clear();
           statusLine = null;
           used = false;
           http11 = true;
  @@ -1174,7 +1195,12 @@
        * @param headerName the header name
        */
       public void removeRequestHeader(String headerName) {
  -        requestHeaders.remove(headerName.toLowerCase());
  +        
  +        Header[] headers = getRequestHeaderGroup().getHeaders(headerName);
  +        for (int i = 0; i < headers.length; i++) {
  +            getRequestHeaderGroup().removeHeader(headers[i]);
  +        }
  +        
       }
   
       // ---------------------------------------------------------------- Queries
  @@ -1835,55 +1861,9 @@
           LOG.trace("enter HttpMethodBase.readResponseHeaders(HttpState,"
               + "HttpConnection)");
   
  -        responseHeaders.clear();
  -
  -        String name = null;
  -        String value = null;
  -        for (; ;) {
  -            String line = conn.readLine();
  -            if ((line == null) || (line.length() < 1)) {
  -                break;
  -            }
  -
  -            // Parse the header name and value
  -            // Check for folded headers first
  -            // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2
  -            // discussion on folded headers
  -            boolean isFolded = false;
  -            if ((line.charAt(0) == ' ') || (line.charAt(0) == '\t')) {
  -                // we have continuation folded header
  -                // so append value
  -                isFolded = true;
  -                value = line.substring(1).trim();
  -            } else {
  -                // Otherwise we should have normal HTTP header line
  -                // Parse the header name and value
  -                int colon = line.indexOf(":");
  -                if (colon < 0) {
  -                    throw new HttpException("Unable to parse header: " + line);
  -                }
  -                name = line.substring(0, colon).trim();
  -                value = line.substring(colon + 1).trim();
  -            }
  -            Header header = getResponseHeader(name);
  -            if (null == header) {
  -                header = new Header(name, value);
  -            } else {
  -                String oldvalue = header.getValue();
  -                if (null != oldvalue) {
  -                    if (isFolded) {
  -                        // LWS becomes space plus extended value
  -                        header = new Header(name, oldvalue + " " + value);
  -                    } else {
  -                        // Append additional header value
  -                        header = new Header(name, oldvalue + ", " + value);
  -                    }
  -                } else {
  -                    header = new Header(name, value);
  -                }
  -            }
  -            setResponseHeader(header);
  -        }
  +        getResponseHeaderGroup().clear();
  +        Header[] headers = HeaderParser.parseHeaders(conn.getResponseInputStream());
  +        getResponseHeaderGroup().setHeaders(headers);
       }
   
       /**
  @@ -2048,9 +2028,10 @@
           LOG.trace("enter HttpMethodBase.writeRequestHeaders(HttpState,"
               + "HttpConnection)");
           addRequestHeaders(state, conn);
  -        Iterator it = requestHeaders.values().iterator();
  -        while (it.hasNext()) {
  -            conn.print(((Header) it.next()).toExternalForm());
  +
  +        Header[] headers = getRequestHeaders();
  +        for (int i = 0; i < headers.length; i++) {
  +            conn.print(headers[i].toExternalForm());
           }
       }
   
  @@ -2136,50 +2117,6 @@
               return false;
           }
           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
  -     * message, by appending each subsequent field-value to the first, each
  -     * separated by a comma."
  -     * //TODO: This method is trying to make up for deficiencies in Header.
  -     *
  -     * @param existingHeader the current header
  -     * @param value DOCUMENT ME!
  -     *
  -     * @return DOCUMENT ME!
  -     */
  -    private String getNewHeaderValue(Header existingHeader, String value) {
  -        String existingValue = existingHeader.getValue();
  -        if (existingValue == null) {
  -            existingValue = "";
  -        }
  -        String newValue = value;
  -        if (value == null) {
  -            newValue = "";
  -        }
  -        return existingValue + ", " + newValue;
  -    }
  -
  -    /**
  -     * Sets the specified response header.
  -     * Logs a warning if the header name is null.
  -     *
  -     * @param header the header to set.
  -     *
  -     * @since 2.0
  -     */
  -    private void setResponseHeader(Header header) {
  -        if (header == null) {
  -            return;
  -        }
  -        if (header.getName() == null) {
  -            LOG.warn("Invalid header found");
  -        } else {
  -            responseHeaders.put(header.getName().toLowerCase(), header);
  -        }
       }
   
       /**
  
  
  
  1.9       +38 -27    jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/SimpleHttpConnection.java
  
  Index: SimpleHttpConnection.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/SimpleHttpConnection.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- SimpleHttpConnection.java	31 Jan 2003 23:23:17 -0000	1.8
  +++ SimpleHttpConnection.java	11 Feb 2003 03:23:05 -0000	1.9
  @@ -63,24 +63,24 @@
   
   package org.apache.commons.httpclient;
   
  -import org.apache.commons.httpclient.protocol.Protocol;
  -import org.apache.commons.logging.Log;
  -import org.apache.commons.logging.LogFactory;
  -
  -import java.io.BufferedReader;
   import java.io.ByteArrayInputStream;
   import java.io.ByteArrayOutputStream;
   import java.io.IOException;
   import java.io.InputStream;
   import java.io.OutputStream;
  -import java.io.StringReader;
  +import java.io.OutputStreamWriter;
   import java.util.Vector;
   
  +import org.apache.commons.httpclient.protocol.Protocol;
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
  +
   
   /**
    * For test-nohost testing purposes only.
    *
    * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
  + * @author Michael Becke
    */
   class SimpleHttpConnection extends HttpConnection {
   
  @@ -90,8 +90,9 @@
   
       Vector headers = new Vector();
       Vector bodies = new Vector();
  -    BufferedReader headerReader = null;
  -    ByteArrayInputStream bodyInputStream = null;
  +
  +    ByteArrayInputStream inputStream;
  +
       ByteArrayOutputStream bodyOutputStream = null;
   
       public void addResponse(String header) {
  @@ -122,26 +123,40 @@
       }
   
       public void assertOpen() throws IllegalStateException {
  -        if (bodyInputStream == null) {
  +        if (inputStream == null) {
               throw new IllegalStateException();
           }
       }
   
       public void assertNotOpen() throws IllegalStateException{
  -        if (bodyInputStream != null) {
  +        if (inputStream != null) {
               throw new IllegalStateException();
           }
       }
       
       public void open() throws IOException {
  -        if (headerReader != null) return;
  +        if (inputStream != null) return;
   
           try{
               log.debug("hit: " + hits);
  -            headerReader = new BufferedReader(
  -                    new StringReader((String)headers.elementAt(hits)));
  -            bodyInputStream = new ByteArrayInputStream(
  -              HttpConstants.getContentBytes((String)bodies.elementAt(hits)));
  +            
  +            // write the header to a byte array
  +            ByteArrayOutputStream headerOutputStream = new ByteArrayOutputStream();
  +            OutputStreamWriter writer = new OutputStreamWriter( headerOutputStream );
  +            writer.write((String) headers.elementAt(hits));
  +            // terminate the headers
  +            writer.write("\r\n");
  +            writer.close();
  +
  +            byte[] headerContent = headerOutputStream.toByteArray();
  +            byte[] bodyContent = HttpConstants.getContentBytes((String)bodies.elementAt(hits));
  +
  +            // combine the header and body content so they can be read from one steam
  +            byte[] content = new byte[headerContent.length + bodyContent.length];
  +            System.arraycopy(headerContent, 0, content, 0, headerContent.length);
  +            System.arraycopy(bodyContent, 0, content, headerContent.length, bodyContent.length);         
  +
  +            inputStream = new ByteArrayInputStream( content );
               bodyOutputStream = new ByteArrayOutputStream();
               hits++;
           } catch (ArrayIndexOutOfBoundsException aiofbe) {
  @@ -151,13 +166,9 @@
       }
   
       public void close() {
  -        if (headerReader != null) {
  -            try { headerReader.close(); } catch(IOException e) {}
  -            headerReader = null;
  -        }
  -        if (bodyInputStream != null) {
  -            try { bodyInputStream.close(); } catch(IOException e) {}
  -            bodyInputStream = null;
  +        if (inputStream != null) {
  +            try { inputStream.close(); } catch(IOException e) {}
  +            inputStream = null;
           }
           if (bodyOutputStream != null) {
               try { bodyOutputStream.close(); } catch(IOException e) {}
  @@ -175,7 +186,7 @@
   
       public String readLine()
       throws IOException, IllegalStateException {
  -        String str = headerReader.readLine();
  +        String str = HttpConnection.readLine(inputStream);
           log.debug("read: " + str);
           return str;
       }
  @@ -187,7 +198,7 @@
   
       
       public InputStream getResponseInputStream() {
  -        return bodyInputStream;
  +        return inputStream;
       }
   
       public OutputStream getRequestOutputStream() {
  
  
  
  1.5       +42 -20    jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/SimpleHttpMethod.java
  
  Index: SimpleHttpMethod.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/SimpleHttpMethod.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- SimpleHttpMethod.java	23 Jan 2003 22:48:25 -0000	1.4
  +++ SimpleHttpMethod.java	11 Feb 2003 03:23:05 -0000	1.5
  @@ -96,26 +96,48 @@
   		return "Simple";
   	}
   
  -    public Header getResponseHeader(String name) {
  -        try {
  -            if(name.equalsIgnoreCase(header.getName())) {
  -                return header;
  -            } else {
  -                return super.getResponseHeader(name);
  -            }
  -        } catch(NullPointerException e) {
  -            return super.getResponseHeader(name);
  +    /**
  +     * Makes sure any respose header that exists has been added to the response
  +     * header group.
  +     */
  +    private void ensureResponseHeaderIsSet() {
  +        if ( header != null ) {
  +            super.getResponseHeaderGroup().addHeader(header);
  +            header = null;
           }
       }
   
  +    /**
  +     * @see HttpMethod#execute(HttpState, HttpConnection)
  +     */
  +    public int execute(HttpState state, HttpConnection connection)
  +        throws HttpException, IOException {
  +        return super.execute(state, connection);
  +    }
  +
  +    /**
  +     * @see HttpMethod#getResponseHeader(String)
  +     * @deprecated
  +     */
  +    public Header getResponseHeader(String headerName) {
  +        ensureResponseHeaderIsSet();
  +        return super.getResponseHeader(headerName);
  +    }
   
  -	public int execute(HttpState state, HttpConnection conn)
  -	throws HttpException, IOException{
  -		return super.execute(state, conn);
  -	}
  +    /**
  +     * @see HttpMethod#getResponseHeaderGroup()
  +     */
  +    protected HeaderGroup getResponseHeaderGroup() {
  +        ensureResponseHeaderIsSet();
  +        return super.getResponseHeaderGroup();
  +    }
  +
  +    /**
  +     * @see HttpMethod#getResponseHeaders()
  +     */
  +    public Header[] getResponseHeaders() {
  +        ensureResponseHeaderIsSet();
  +        return super.getResponseHeaders();
  +    }
   
  -	public void addRequestHeaders(HttpState state, HttpConnection conn)
  -	throws HttpException, IOException{
  -		super.addRequestHeaders(state, conn);
  -	}
   }
  
  
  
  1.9       +5 -3      jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestStreams.java
  
  Index: TestStreams.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestStreams.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- TestStreams.java	23 Jan 2003 22:48:27 -0000	1.8
  +++ TestStreams.java	11 Feb 2003 03:23:05 -0000	1.9
  @@ -101,6 +101,8 @@
           footer = method.getResponseFooter("footer2");
           assertEquals(footer.getValue(), "fghij");
   
  +        // recycle the method so that it can be reused below
  +        method.recycle();
   
           //Test for when buffer is smaller than chunk size.
           in = new ChunkedInputStream(new ByteArrayInputStream(HttpConstants.getBytes(correctInput)), method);
  
  
  

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


Re: cvs commit: jakarta-commons/httpclient/src/test/org/apache/commons/httpclient SimpleHttpConnection.java SimpleHttpMethod.java TestStreams.java

Posted by Michael Becke <be...@u.washington.edu>.
Jeff,

Looks like HeaderGroup and HeaderParser didn't make it into cvs:)

Mike

On Monday, February 10, 2003, at 10:23 PM, jsdever@apache.org wrote:

> jsdever     2003/02/10 19:23:05
>
>   Modified:    httpclient/src/java/org/apache/commons/httpclient
>                         ChunkedInputStream.java HttpConnection.java
>                         HttpMethodBase.java
>                httpclient/src/test/org/apache/commons/httpclient
>                         SimpleHttpConnection.java SimpleHttpMethod.java
>                         TestStreams.java
>   Log:
>   Multivalued headers.
>
>   Bug: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=11218
>   Contributed by: Mike Becke
>
>   changeLog:
>    - HeaderGroup, a new class for storing headers.  This class  
> supports multiple
>       headers with the same name and it remembers header order.  I'm  
> not a huge fan of
>       the name, but it was the best I could come up with.
>    - HeaderParser, a new class for parsing headers.  Header parsing  
> code was
>       duplicated in HttpMethodBase and ChunkedInputStream and was  
> placed here.
>    - HttpMethod has 3 new methods.  getRequestHeaderGroup(),
>       getResponseHeaderGroup(), and getResponseFooterGroup().  This  
> will break an
>       existing extension of HttpMethod.
>    - Some of the methods for accessing headers in HttpMethod have been  
> deprecated.
>    - Classes in the general codebase that use the newly deprecated  
> methods have
>       been fixed.  Some of the test cases are still using deprecated  
> methods.
>    - SimpleHttpConnection and SimpleHttpMethod have been changed to  
> work correctly
>       with the new header storage method.
>
>   Revision  Changes    Path
>   1.13      +18 -44     
> jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ 
> ChunkedInputStream.java
>
>   Index: ChunkedInputStream.java
>   ===================================================================
>   RCS file:  
> /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/ 
> httpclient/ChunkedInputStream.java,v
>   retrieving revision 1.12
>   retrieving revision 1.13
>   diff -u -r1.12 -r1.13
>   --- ChunkedInputStream.java	28 Jan 2003 04:40:20 -0000	1.12
>   +++ ChunkedInputStream.java	11 Feb 2003 03:23:05 -0000	1.13
>   @@ -67,6 +67,8 @@
>    import java.io.IOException;
>    import java.io.InputStream;
>
>   +import org.apache.commons.httpclient.util.HeaderParser;
>   +
>    /**
>     * <p>Transparently coalesces chunks of a HTTP stream that uses
>     * Transfer-Encoding chunked.</p>
>   @@ -84,6 +86,7 @@
>     * @author Martin Elwin
>     * @author Eric Johnson
>     * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike  
> Bowler</a>
>   + * @author Michael Becke
>     *
>     * @since 2.0
>     *
>   @@ -130,7 +133,7 @@
>            this.chunkSize = getChunkSizeFromInputStream(in);
>            if (chunkSize == 0) {
>                eof = true;
>   -            parseFooters();
>   +            parseTrailerHeaders();
>            }
>            this.pos = 0;
>        }
>   @@ -140,12 +143,14 @@
>         * is followed by a CRLF. The method returns -1 as soon as a  
> chunksize of 0
>         * is detected.</p>
>         *
>   -     * <p> Footers are read automcatically at the end of the stream  
> and can be
>   -     * obtained with the getFooters() method.</p>
>   +     * <p> Trailer headers are read automcatically at the end of  
> the stream and
>   +     * can be obtained with the getResponseFooters() method.</p>
>         *
>         * @return -1 of the end of the stream has been reached or the  
> next data
>         * byte
>         * @throws IOException If an IO problem occurs
>   +     *
>   +     * @see HttpMethod#getResponseFooters()
>         */
>        public int read() throws IOException {
>
>   @@ -224,7 +229,7 @@
>            pos = 0;
>            if (chunkSize == 0) {
>                eof = true;
>   -            parseFooters();
>   +            parseTrailerHeaders();
>            }
>        }
>
>   @@ -306,46 +311,15 @@
>        }
>
>        /**
>   -     * Stores the footers into map of Headers
>   +     * Reads and stores the Trailer headers.
>         * @throws IOException If an IO problem occurs
>         */
>   -    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();
>   -        }
>   -    }
>   -
>   -    /**
>   -     * Read the next line from {@link #in}.
>   -     * @return String The next line.
>   -     * @throws IOException If an IO problem occurs.
>   -     */
>   -    private String readLine() throws IOException {
>   -        StringBuffer buf = new StringBuffer();
>   -        while (true) {
>   -            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);
>   +    private void parseTrailerHeaders() throws IOException {
>   +        Header[] footers = HeaderParser.parseHeaders(in);
>   +
>   +        for (int i = 0; i < footers.length; i++) {
>   +            method.addResponseFooter(footers[i]);
>            }
>   -        return (buf.toString());
>        }
>
>        /**
>
>
>
>   1.43      +42 -22     
> 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.42
>   retrieving revision 1.43
>   diff -u -r1.42 -r1.43
>   --- HttpConnection.java	8 Feb 2003 19:22:49 -0000	1.42
>   +++ HttpConnection.java	11 Feb 2003 03:23:05 -0000	1.43
>   @@ -104,11 +104,48 @@
>     * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
>     * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike  
> Bowler</a>
>     * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
>   + * @author Michael Becke
>     *
>     * @version   $Revision$ $Date$
>     */
>    public class HttpConnection {
>
>   +    /**
>   +     * Read up to <tt>"\r\n"</tt> from an (unchunked) input stream.
>   +     * If the stream ends before the line terminator is found,
>   +     * the last part of the string will still be returned.
>   +     * '\r' and '\n' are allowed to appear individually in the  
> stream.
>   +     *
>   +     * @param inputStream the stream to read from
>   +     *
>   +     * @throws IOException if an I/O problem occurs
>   +     * @return a line from the stream
>   +     *
>   +     * @since 2.0beta1
>   +     */
>   +    public static String readLine(InputStream inputStream) throws  
> IOException {
>   +        LOG.trace("enter HttpConnection.readLine()");
>   +
>   +        StringBuffer buf = new StringBuffer();
>   +        int ch = inputStream.read();
>   +        while (ch >= 0) {
>   +            if (ch == '\r') {
>   +                ch = inputStream.read();
>   +                if (ch == '\n') {
>   +                    break;
>   +                } else {
>   +                    buf.append('\r');
>   +                }
>   +            }
>   +            buf.append((char) ch);
>   +            ch = inputStream.read();
>   +        }
>   +        if (WIRE_LOG.isDebugEnabled()) {
>   +            WIRE_LOG.debug("<< \"" + buf.toString() + (ch>0 ? "\"  
> [\\r\\n]" : ""));
>   +        }
>   +        return (buf.toString());
>   +    }
>   +
>        // -----------------------------------------------------------  
> Constructors
>
>        /**
>   @@ -857,24 +894,7 @@
>            LOG.trace("enter HttpConnection.readLine()");
>
>            assertOpen();
>   -        StringBuffer buf = new StringBuffer();
>   -        int ch = inputStream.read();
>   -        while (ch >= 0) {
>   -            if (ch == '\r') {
>   -                ch = inputStream.read();
>   -                if (ch == '\n') {
>   -                    break;
>   -                } else {
>   -                    buf.append('\r');
>   -                }
>   -            }
>   -            buf.append((char) ch);
>   -            ch = inputStream.read();
>   -        }
>   -        if (WIRE_LOG.isDebugEnabled()) {
>   -            WIRE_LOG.debug("<< \"" + buf.toString() + (ch>0 ? "\"  
> [\\r\\n]" : ""));
>   -        }
>   -        return (buf.toString());
>   +        return HttpConnection.readLine(inputStream);
>        }
>
>        /**
>
>
>
>   1.111     +95 -158    
> 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.110
>   retrieving revision 1.111
>   diff -u -r1.110 -r1.111
>   --- HttpMethodBase.java	8 Feb 2003 19:22:49 -0000	1.110
>   +++ HttpMethodBase.java	11 Feb 2003 03:23:05 -0000	1.111
>   @@ -69,15 +69,13 @@
>    import java.io.InputStream;
>    import java.net.MalformedURLException;
>    import java.net.URL;
>   -import java.util.HashMap;
>    import java.util.HashSet;
>   -import java.util.Iterator;
>   -import java.util.Map;
>    import java.util.Set;
>    import java.util.StringTokenizer;
>
>    import org.apache.commons.httpclient.cookie.CookiePolicy;
>    import org.apache.commons.httpclient.cookie.CookieSpec;
>   +import org.apache.commons.httpclient.util.HeaderParser;
>    import org.apache.commons.httpclient.util.URIUtil;
>    import org.apache.commons.logging.Log;
>    import org.apache.commons.logging.LogFactory;
>   @@ -165,16 +163,16 @@
>        // -----------------------------------------------------  
> Instance variables
>
>        /** My request headers, if any. */
>   -    private Map requestHeaders = new HashMap();
>   +    private HeaderGroup requestHeaders = new HeaderGroup();
>
>        /** The Status-Line from the response. */
>        private StatusLine statusLine = null;
>
>        /** My response headers, if any. */
>   -    private Map responseHeaders = new HashMap();
>   +    private HeaderGroup responseHeaders = new HeaderGroup();
>
>   -    /** My response footers, if any. */
>   -    private Map responseFooters = null;
>   +    /** My response trailer headers, if any. */
>   +    private HeaderGroup responseTrailerHeaders = new HeaderGroup();
>
>        /** Realms that we tried to authenticate to */
>        private Set realms = null;
>   @@ -416,12 +414,9 @@
>        }
>
>        /**
>   -     * 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.
>   +     * Add the specified request header. 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
>         */
>   @@ -429,9 +424,9 @@
>            LOG.trace("HttpMethodBase.addRequestHeader(Header)");
>
>            if (header == null) {
>   -          LOG.debug("null header value ignored");
>   +            LOG.debug("null header value ignored");
>            } else {
>   -            addRequestHeader(header.getName(), header.getValue());
>   +            getRequestHeaderGroup().addHeader(header);
>            }
>        }
>
>   @@ -440,10 +435,7 @@
>         * @param footer The new footer to add.
>         */
>        public void addResponseFooter(Header footer) {
>   -        if (responseFooters == null) {
>   -            responseFooters = new HashMap();
>   -        }
>   -        responseFooters.put(footer.getName().toLowerCase(), footer);
>   +        getResponseTrailerHeaderGroup().addHeader(footer);
>        }
>
>        /**
>   @@ -537,7 +529,15 @@
>         * @param header the header
>         */
>        public void setRequestHeader(Header header) {
>   -        requestHeaders.put(header.getName().toLowerCase(), header);
>   +
>   +        Header[] headers =  
> getRequestHeaderGroup().getHeaders(header.getName());
>   +
>   +        for (int i = 0; i < headers.length; i++) {
>   +            getRequestHeaderGroup().removeHeader(headers[i]);
>   +        }
>   +
>   +        getRequestHeaderGroup().addHeader(header);
>   +
>        }
>
>        /**
>   @@ -551,8 +551,11 @@
>         * @return the matching header
>         */
>        public Header getRequestHeader(String headerName) {
>   -        return (headerName == null)
>   -               ? null : (Header)  
> (requestHeaders.get(headerName.toLowerCase()));
>   +        if (headerName == null) {
>   +            return null;
>   +        } else {
>   +            return  
> getRequestHeaderGroup().getCondensedHeader(headerName);
>   +        }
>        }
>
>        /**
>   @@ -561,11 +564,44 @@
>         * @return an array of my request headers.
>         */
>        public Header[] getRequestHeaders() {
>   -        return (Header[]) (requestHeaders.values().toArray(
>   -            new Header[requestHeaders.size()]));
>   +        return getRequestHeaderGroup().getAllHeaders();
>   +    }
>   +
>   +    /**
>   +     * Gets the HeaderGroup storing the request headers.
>   +     *
>   +     * @return a HeaderGroup
>   +     *
>   +     * @since 2.0beta1
>   +     */
>   +    protected HeaderGroup getRequestHeaderGroup() {
>   +        return requestHeaders;
>   +    }
>   +
>   +    /**
>   +     * Gets the HeaderGroup storing the response trailer headers as  
> per RFC
>   +     * 2616 section 3.6.1.
>   +     *
>   +     * @return a HeaderGroup
>   +     *
>   +     * @since 2.0beta1
>   +     */
>   +    protected HeaderGroup getResponseTrailerHeaderGroup() {
>   +        return responseTrailerHeaders;
>        }
>
>        /**
>   +     * Gets the HeaderGroup storing the response headers.
>   +     *
>   +     * @return a HeaderGroup
>   +     *
>   +     * @since 2.0beta1
>   +     */
>   +    protected HeaderGroup getResponseHeaderGroup() {
>   +        return responseHeaders;
>   +    }
>   +
>   +    /**
>         * Convenience method top provide access to the status code.
>         *
>         * @return the status code associated with the latest response.
>   @@ -593,13 +629,12 @@
>        }
>
>        /**
>   -     * Provide access to the response headers
>   +     * Gets the response headers in the order in which they were  
> read.
>         *
>         * @return an array of my response headers.
>         */
>        public Header[] getResponseHeaders() {
>   -        return (Header[]) (responseHeaders.values().toArray(
>   -            new Header[responseHeaders.size()]));
>   +        return getResponseHeaderGroup().getAllHeaders();
>        }
>
>        /**
>   @@ -612,10 +647,12 @@
>         *
>         * @return the matching header
>         */
>   -    public Header getResponseHeader(String headerName) {
>   -        return (headerName == null)
>   -               ? null
>   -               : (Header)  
> (responseHeaders.get(headerName.toLowerCase()));
>   +    public Header getResponseHeader(String headerName) {
>   +        if (headerName == null) {
>   +            return null;
>   +        } else {
>   +            return  
> getResponseHeaderGroup().getCondensedHeader(headerName);
>   +        }
>        }
>
>        /**
>   @@ -690,15 +727,11 @@
>        }
>
>        /**
>   -     * Return an array of response footers.
>   -     * @return <tt>null</tt> if no footers are available
>   +     * Gets the response footers in the order in which they were  
> read.
>   +     * @return an array of headers
>         */
>        public Header[] getResponseFooters() {
>   -        if (responseFooters == null) {
>   -            return null;
>   -        }
>   -        return (Header[]) (responseFooters.values().toArray(
>   -            new Header[responseFooters.size()]));
>   +        return getResponseTrailerHeaderGroup().getAllHeaders();
>        }
>
>        /**
>   @@ -711,11 +744,11 @@
>         * @return the matching footer
>         */
>        public Header getResponseFooter(String footerName) {
>   -        if (responseFooters == null) {
>   +        if (footerName == null) {
>                return null;
>   +        } else {
>   +            return  
> getResponseTrailerHeaderGroup().getCondensedHeader(footerName);
>            }
>   -        return (footerName == null) ? null
>   -            : (Header)  
> (responseFooters.get(footerName.toLowerCase()));
>        }
>
>        /**
>   @@ -768,20 +801,7 @@
>         * @param headerValue the header's value
>         */
>        public void addRequestHeader(String headerName, String  
> headerValue) {
>   -        // "It must be possible to combine the multiple header  
> fields into
>   -        // one "field-name: field-value" pair, without changing the
>   -        // semantics of the message, by appending each subsequent  
> field-value
>   -        // to the first, each separated by a comma."
>   -        //   - HTTP/1.0 (4.3)
>   -        Header header = getRequestHeader(headerName);
>   -        if (null == header) {
>   -            // header doesn't exist already, simply create with  
> name and value
>   -            header = new Header(headerName, headerValue);
>   -        } else {
>   -            // header exists, add this value to the comma separated  
> list
>   -            header.setValue(getNewHeaderValue(header, headerValue));
>   -        }
>   -        setRequestHeader(header);
>   +        addRequestHeader(new Header(headerName, headerValue));
>        }
>
>        /**
>   @@ -1137,8 +1157,9 @@
>            followRedirects = false;
>            doAuthentication = true;
>            queryString = null;
>   -        requestHeaders.clear();
>   -        responseHeaders.clear();
>   +        getRequestHeaderGroup().clear();
>   +        getResponseHeaderGroup().clear();
>   +        getResponseTrailerHeaderGroup().clear();
>            statusLine = null;
>            used = false;
>            http11 = true;
>   @@ -1174,7 +1195,12 @@
>         * @param headerName the header name
>         */
>        public void removeRequestHeader(String headerName) {
>   -        requestHeaders.remove(headerName.toLowerCase());
>   +
>   +        Header[] headers =  
> getRequestHeaderGroup().getHeaders(headerName);
>   +        for (int i = 0; i < headers.length; i++) {
>   +            getRequestHeaderGroup().removeHeader(headers[i]);
>   +        }
>   +
>        }
>
>        //  
> ----------------------------------------------------------------  
> Queries
>   @@ -1835,55 +1861,9 @@
>            LOG.trace("enter  
> HttpMethodBase.readResponseHeaders(HttpState,"
>                + "HttpConnection)");
>
>   -        responseHeaders.clear();
>   -
>   -        String name = null;
>   -        String value = null;
>   -        for (; ;) {
>   -            String line = conn.readLine();
>   -            if ((line == null) || (line.length() < 1)) {
>   -                break;
>   -            }
>   -
>   -            // Parse the header name and value
>   -            // Check for folded headers first
>   -            // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2
>   -            // discussion on folded headers
>   -            boolean isFolded = false;
>   -            if ((line.charAt(0) == ' ') || (line.charAt(0) ==  
> '\t')) {
>   -                // we have continuation folded header
>   -                // so append value
>   -                isFolded = true;
>   -                value = line.substring(1).trim();
>   -            } else {
>   -                // Otherwise we should have normal HTTP header line
>   -                // Parse the header name and value
>   -                int colon = line.indexOf(":");
>   -                if (colon < 0) {
>   -                    throw new HttpException("Unable to parse  
> header: " + line);
>   -                }
>   -                name = line.substring(0, colon).trim();
>   -                value = line.substring(colon + 1).trim();
>   -            }
>   -            Header header = getResponseHeader(name);
>   -            if (null == header) {
>   -                header = new Header(name, value);
>   -            } else {
>   -                String oldvalue = header.getValue();
>   -                if (null != oldvalue) {
>   -                    if (isFolded) {
>   -                        // LWS becomes space plus extended value
>   -                        header = new Header(name, oldvalue + " " +  
> value);
>   -                    } else {
>   -                        // Append additional header value
>   -                        header = new Header(name, oldvalue + ", " +  
> value);
>   -                    }
>   -                } else {
>   -                    header = new Header(name, value);
>   -                }
>   -            }
>   -            setResponseHeader(header);
>   -        }
>   +        getResponseHeaderGroup().clear();
>   +        Header[] headers =  
> HeaderParser.parseHeaders(conn.getResponseInputStream());
>   +        getResponseHeaderGroup().setHeaders(headers);
>        }
>
>        /**
>   @@ -2048,9 +2028,10 @@
>            LOG.trace("enter  
> HttpMethodBase.writeRequestHeaders(HttpState,"
>                + "HttpConnection)");
>            addRequestHeaders(state, conn);
>   -        Iterator it = requestHeaders.values().iterator();
>   -        while (it.hasNext()) {
>   -            conn.print(((Header) it.next()).toExternalForm());
>   +
>   +        Header[] headers = getRequestHeaders();
>   +        for (int i = 0; i < headers.length; i++) {
>   +            conn.print(headers[i].toExternalForm());
>            }
>        }
>
>   @@ -2136,50 +2117,6 @@
>                return false;
>            }
>            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
>   -     * message, by appending each subsequent field-value to the  
> first, each
>   -     * separated by a comma."
>   -     * //TODO: This method is trying to make up for deficiencies in  
> Header.
>   -     *
>   -     * @param existingHeader the current header
>   -     * @param value DOCUMENT ME!
>   -     *
>   -     * @return DOCUMENT ME!
>   -     */
>   -    private String getNewHeaderValue(Header existingHeader, String  
> value) {
>   -        String existingValue = existingHeader.getValue();
>   -        if (existingValue == null) {
>   -            existingValue = "";
>   -        }
>   -        String newValue = value;
>   -        if (value == null) {
>   -            newValue = "";
>   -        }
>   -        return existingValue + ", " + newValue;
>   -    }
>   -
>   -    /**
>   -     * Sets the specified response header.
>   -     * Logs a warning if the header name is null.
>   -     *
>   -     * @param header the header to set.
>   -     *
>   -     * @since 2.0
>   -     */
>   -    private void setResponseHeader(Header header) {
>   -        if (header == null) {
>   -            return;
>   -        }
>   -        if (header.getName() == null) {
>   -            LOG.warn("Invalid header found");
>   -        } else {
>   -            responseHeaders.put(header.getName().toLowerCase(),  
> header);
>   -        }
>        }
>
>        /**
>
>
>
>   1.9       +38 -27     
> jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/ 
> SimpleHttpConnection.java
>
>   Index: SimpleHttpConnection.java
>   ===================================================================
>   RCS file:  
> /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/ 
> httpclient/SimpleHttpConnection.java,v
>   retrieving revision 1.8
>   retrieving revision 1.9
>   diff -u -r1.8 -r1.9
>   --- SimpleHttpConnection.java	31 Jan 2003 23:23:17 -0000	1.8
>   +++ SimpleHttpConnection.java	11 Feb 2003 03:23:05 -0000	1.9
>   @@ -63,24 +63,24 @@
>
>    package org.apache.commons.httpclient;
>
>   -import org.apache.commons.httpclient.protocol.Protocol;
>   -import org.apache.commons.logging.Log;
>   -import org.apache.commons.logging.LogFactory;
>   -
>   -import java.io.BufferedReader;
>    import java.io.ByteArrayInputStream;
>    import java.io.ByteArrayOutputStream;
>    import java.io.IOException;
>    import java.io.InputStream;
>    import java.io.OutputStream;
>   -import java.io.StringReader;
>   +import java.io.OutputStreamWriter;
>    import java.util.Vector;
>
>   +import org.apache.commons.httpclient.protocol.Protocol;
>   +import org.apache.commons.logging.Log;
>   +import org.apache.commons.logging.LogFactory;
>   +
>
>    /**
>     * For test-nohost testing purposes only.
>     *
>     * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
>   + * @author Michael Becke
>     */
>    class SimpleHttpConnection extends HttpConnection {
>
>   @@ -90,8 +90,9 @@
>
>        Vector headers = new Vector();
>        Vector bodies = new Vector();
>   -    BufferedReader headerReader = null;
>   -    ByteArrayInputStream bodyInputStream = null;
>   +
>   +    ByteArrayInputStream inputStream;
>   +
>        ByteArrayOutputStream bodyOutputStream = null;
>
>        public void addResponse(String header) {
>   @@ -122,26 +123,40 @@
>        }
>
>        public void assertOpen() throws IllegalStateException {
>   -        if (bodyInputStream == null) {
>   +        if (inputStream == null) {
>                throw new IllegalStateException();
>            }
>        }
>
>        public void assertNotOpen() throws IllegalStateException{
>   -        if (bodyInputStream != null) {
>   +        if (inputStream != null) {
>                throw new IllegalStateException();
>            }
>        }
>
>        public void open() throws IOException {
>   -        if (headerReader != null) return;
>   +        if (inputStream != null) return;
>
>            try{
>                log.debug("hit: " + hits);
>   -            headerReader = new BufferedReader(
>   -                    new  
> StringReader((String)headers.elementAt(hits)));
>   -            bodyInputStream = new ByteArrayInputStream(
>   -               
> HttpConstants.getContentBytes((String)bodies.elementAt(hits)));
>   +
>   +            // write the header to a byte array
>   +            ByteArrayOutputStream headerOutputStream = new  
> ByteArrayOutputStream();
>   +            OutputStreamWriter writer = new OutputStreamWriter(  
> headerOutputStream );
>   +            writer.write((String) headers.elementAt(hits));
>   +            // terminate the headers
>   +            writer.write("\r\n");
>   +            writer.close();
>   +
>   +            byte[] headerContent = headerOutputStream.toByteArray();
>   +            byte[] bodyContent =  
> HttpConstants.getContentBytes((String)bodies.elementAt(hits));
>   +
>   +            // combine the header and body content so they can be  
> read from one steam
>   +            byte[] content = new byte[headerContent.length +  
> bodyContent.length];
>   +            System.arraycopy(headerContent, 0, content, 0,  
> headerContent.length);
>   +            System.arraycopy(bodyContent, 0, content,  
> headerContent.length, bodyContent.length);
>   +
>   +            inputStream = new ByteArrayInputStream( content );
>                bodyOutputStream = new ByteArrayOutputStream();
>                hits++;
>            } catch (ArrayIndexOutOfBoundsException aiofbe) {
>   @@ -151,13 +166,9 @@
>        }
>
>        public void close() {
>   -        if (headerReader != null) {
>   -            try { headerReader.close(); } catch(IOException e) {}
>   -            headerReader = null;
>   -        }
>   -        if (bodyInputStream != null) {
>   -            try { bodyInputStream.close(); } catch(IOException e) {}
>   -            bodyInputStream = null;
>   +        if (inputStream != null) {
>   +            try { inputStream.close(); } catch(IOException e) {}
>   +            inputStream = null;
>            }
>            if (bodyOutputStream != null) {
>                try { bodyOutputStream.close(); } catch(IOException e)  
> {}
>   @@ -175,7 +186,7 @@
>
>        public String readLine()
>        throws IOException, IllegalStateException {
>   -        String str = headerReader.readLine();
>   +        String str = HttpConnection.readLine(inputStream);
>            log.debug("read: " + str);
>            return str;
>        }
>   @@ -187,7 +198,7 @@
>
>
>        public InputStream getResponseInputStream() {
>   -        return bodyInputStream;
>   +        return inputStream;
>        }
>
>        public OutputStream getRequestOutputStream() {
>
>
>
>   1.5       +42 -20     
> jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/ 
> SimpleHttpMethod.java
>
>   Index: SimpleHttpMethod.java
>   ===================================================================
>   RCS file:  
> /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/ 
> httpclient/SimpleHttpMethod.java,v
>   retrieving revision 1.4
>   retrieving revision 1.5
>   diff -u -r1.4 -r1.5
>   --- SimpleHttpMethod.java	23 Jan 2003 22:48:25 -0000	1.4
>   +++ SimpleHttpMethod.java	11 Feb 2003 03:23:05 -0000	1.5
>   @@ -96,26 +96,48 @@
>    		return "Simple";
>    	}
>
>   -    public Header getResponseHeader(String name) {
>   -        try {
>   -            if(name.equalsIgnoreCase(header.getName())) {
>   -                return header;
>   -            } else {
>   -                return super.getResponseHeader(name);
>   -            }
>   -        } catch(NullPointerException e) {
>   -            return super.getResponseHeader(name);
>   +    /**
>   +     * Makes sure any respose header that exists has been added to  
> the response
>   +     * header group.
>   +     */
>   +    private void ensureResponseHeaderIsSet() {
>   +        if ( header != null ) {
>   +            super.getResponseHeaderGroup().addHeader(header);
>   +            header = null;
>            }
>        }
>
>   +    /**
>   +     * @see HttpMethod#execute(HttpState, HttpConnection)
>   +     */
>   +    public int execute(HttpState state, HttpConnection connection)
>   +        throws HttpException, IOException {
>   +        return super.execute(state, connection);
>   +    }
>   +
>   +    /**
>   +     * @see HttpMethod#getResponseHeader(String)
>   +     * @deprecated
>   +     */
>   +    public Header getResponseHeader(String headerName) {
>   +        ensureResponseHeaderIsSet();
>   +        return super.getResponseHeader(headerName);
>   +    }
>
>   -	public int execute(HttpState state, HttpConnection conn)
>   -	throws HttpException, IOException{
>   -		return super.execute(state, conn);
>   -	}
>   +    /**
>   +     * @see HttpMethod#getResponseHeaderGroup()
>   +     */
>   +    protected HeaderGroup getResponseHeaderGroup() {
>   +        ensureResponseHeaderIsSet();
>   +        return super.getResponseHeaderGroup();
>   +    }
>   +
>   +    /**
>   +     * @see HttpMethod#getResponseHeaders()
>   +     */
>   +    public Header[] getResponseHeaders() {
>   +        ensureResponseHeaderIsSet();
>   +        return super.getResponseHeaders();
>   +    }
>
>   -	public void addRequestHeaders(HttpState state, HttpConnection conn)
>   -	throws HttpException, IOException{
>   -		super.addRequestHeaders(state, conn);
>   -	}
>    }
>
>
>
>   1.9       +5 -3       
> jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/ 
> TestStreams.java
>
>   Index: TestStreams.java
>   ===================================================================
>   RCS file:  
> /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/ 
> httpclient/TestStreams.java,v
>   retrieving revision 1.8
>   retrieving revision 1.9
>   diff -u -r1.8 -r1.9
>   --- TestStreams.java	23 Jan 2003 22:48:27 -0000	1.8
>   +++ TestStreams.java	11 Feb 2003 03:23:05 -0000	1.9
>   @@ -101,6 +101,8 @@
>            footer = method.getResponseFooter("footer2");
>            assertEquals(footer.getValue(), "fghij");
>
>   +        // recycle the method so that it can be reused below
>   +        method.recycle();
>
>            //Test for when buffer is smaller than chunk size.
>            in = new ChunkedInputStream(new  
> ByteArrayInputStream(HttpConstants.getBytes(correctInput)), method);
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


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