jsdever     2002/10/28 22:40:15

  Modified:    httpclient/src/java/org/apache/commons/httpclient/methods/multipart
                        FilePart.java
               httpclient/src/test/org/apache/commons/httpclient
                        TestNoHost.java
  Added:       httpclient/src/test/org/apache/commons/httpclient
                        TestPartsNoHost.java
  Log:
  Fix for file part failing to send data on second call to send.
  Adds some nohost tests for parts.
  http://nagoya.apache.org/bugzilla/show_bug.cgi?id=13676
  Includes attachements 3495, 3624, 3625
  
  Contributed by: Adrian Sutton
  Committed by: Jeff Dever
  
  Revision  Changes    Path
  1.3       +80 -12    
jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java
  
  Index: FilePart.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FilePart.java     11 Oct 2002 05:16:32 -0000      1.2
  +++ FilePart.java     29 Oct 2002 06:40:15 -0000      1.3
  @@ -64,6 +64,7 @@
   
   import java.io.File;
   import java.io.FileInputStream;
  +import java.io.ByteArrayOutputStream;
   import java.io.InputStream;
   import java.io.OutputStream;
   import java.io.FileNotFoundException;
  @@ -82,6 +83,7 @@
    *
    * @author <a href="mailto:mattalbright@;yahoo.com">Matthew Albright</a>
    * @author <a href="mailto:jsdever@;apache.org">Jeff Dever</a>
  + * @author <a href="mailto:adrian@;ephox.com">Adrian Sutton</a>
    * 
    * @since 2.0
    *
  @@ -91,12 +93,17 @@
       //TODO: make this configurable
       static int MAX_BUFF_SIZE = 1 * 1024 * 1024;  // 1 MiBs
       
  +    private File file;
       private InputStream fileStream;
       private String fileName;    
       private long fileLength;
       
       private String name;
       private int buff_size;
  +
  +    private byte[] dataBuf = null;
  +    private boolean bufferData = true;
  +    private boolean markSupported = false;
           
       /**
        * Constructor.
  @@ -110,7 +117,8 @@
       public FilePart(String name, File file) 
       throws FileNotFoundException {
           
  -        this( name, new FileInputStream(file), file.getName(), file.length() );
  +        // We create the input stream straight from the file later on.
  +        this( name, null, file.getName(), file.length() );
   
           if (! file.isFile()) {
               throw new FileNotFoundException("File is not a normal file.");
  @@ -119,16 +127,24 @@
           if (! file.canRead()) {
               throw new FileNotFoundException("File is not readable.");
           }
  +
  +        this.file = file;
  +        this.bufferData = false;
               
       }
       
       /**
  -     * FilePart Constructor.
  +     * FilePart Constructor.  This constructor should generally be
  +     * avoided in favour of FilePart(String, java.io.File) as
  +     * using an InputStream requires data to be buffered in RAM in case
  +     * it needs to be resent.
        *
        * @param name the name for this part
        * @param fileInputStream an input stream for reading the file content
        * @param fileName the name of the file
        * @param fileLength the number of bytes contained in the file
  +     * @see #getBufferData()
  +     * @see #setBufferData(boolean)
        */
       public FilePart(
           String name, 
  @@ -145,7 +161,12 @@
           this.fileStream = fileInputStream;
           this.fileName = fileName;
           this.fileLength = fileLength;
  -        
  +        // We need to cast fileLength to an int to call mark(int) on the
  +        // input stream, so we must ensure that the file length will fit
  +        // into an int before trying to use mark and reset.
  +        this.markSupported = fileInputStream.markSupported() &&
  +            fileLength <= Integer.MAX_VALUE;
  +        this.bufferData = !markSupported;
       }
           
       protected void sendHeader(OutputStream out) 
  @@ -190,18 +211,65 @@
               buff = new byte[(new Long(lengthOfData())).intValue()];
           }
           
  -        int len;
  -
  -        while ((len = fileStream.read(buff)) != -1)
  -        {
  -            out.write(buff, 0, len);
  +        InputStream is = fileStream;
  +        if (markSupported) {
  +            fileStream.mark((int)fileLength);
  +        }
  +        if (file != null) {
  +            is = new FileInputStream(file);
  +        }
  +        if (dataBuf != null) {
  +            // Send the buffered data from a previous send.
  +            out.write(dataBuf, 0, dataBuf.length);
  +        } else {
  +            int len;
  +            ByteArrayOutputStream bufferStream = null;
  +            if (bufferData) {
  +                bufferStream = new ByteArrayOutputStream();
  +            }
  +            while ((len = is.read(buff)) != -1) {
  +                out.write(buff, 0, len);
  +                if (bufferData) {
  +                    bufferStream.write(buff, 0, len);
  +                }
  +            }
  +            if (bufferData) {
  +                dataBuf = bufferStream.toByteArray();
  +            }
  +            if (markSupported) {
  +                fileStream.reset();
  +            }
           }
  -
       }
       
       protected long lengthOfData() 
       throws IOException {
           return fileLength;
       }    
  +
  +    /** 
  +     * Sets whether or not to buffer the data from the input stream so
  +     * that it can be resent if nessecary during the connection.  Note
  +     * that this has no effect if this FilePart was constructed from a
  +     * File object as a new FileInputStream will always be opened for
  +     * each request.
  +     * 
  +     * @param bufferData true if the data should be buffered in memory.
  +     * @see #getBufferData()
  +     */
  +    public void setBufferData(boolean bufferData) {
  +        this.bufferData = bufferData;
  +    }
  +
  +    /** 
  +     * Returns whether or not data from the input stream is buffered in
  +     * memory for this FilePart.
  +     * 
  +     * @return true if the data will be buffered in memory.
  +     * @see #setBufferData(boolean)
  +     */
  +    public boolean getBufferData() {
  +        return bufferData && file == null;
  +    }
   }
   
  
  
  
  1.14      +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.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- TestNoHost.java   25 Oct 2002 10:15:52 -0000      1.13
  +++ TestNoHost.java   29 Oct 2002 06:40:15 -0000      1.14
  @@ -100,6 +100,7 @@
           suite.addTest(TestRequestHeaders.suite());
           suite.addTest(TestStreams.suite());
           suite.addTest(TestStatusLine.suite());
  +        suite.addTest(TestPartsNoHost.suite());
           return suite;
       }
   
  
  
  
  1.1                  
jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestPartsNoHost.java
  
  Index: TestPartsNoHost.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestPartsNoHost.java,v
 1.1 2002/10/29 06:40:15 jsdever Exp $
   * $Revision: 1.1 $
   * $Date: 2002/10/29 06:40:15 $
   * ====================================================================
   *
   * 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", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 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.IOException;
  import java.io.InputStreamReader;
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.FileWriter;
  import java.io.FileInputStream;
  import java.io.File;
  import java.io.PrintWriter;
  import java.io.Reader;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  import org.apache.commons.httpclient.methods.multipart.FilePart;
  import org.apache.commons.httpclient.methods.multipart.StringPart;
  
  /**
   * @author <a href="mailto:adrian@;ephox.com">Adrian Sutton</a>
   * @version $Revision: 1.1 $ $Date: 2002/10/29 06:40:15 $
   */
  public class TestPartsNoHost extends TestCase {
  
      static final String PART_DATA = "This is the part data.";
      static final String NAME = "name";
  
      // ------------------------------------------------------------ Constructor
  
      public TestPartsNoHost(String testName) {
          super(testName);
      }
  
      // ------------------------------------------------------- TestCase Methods
  
      public static Test suite() {
          return new TestSuite(TestMethodsNoHost.class);
      }
  
      // ----------------------------------------------------------------- Tests
  
      public void testFilePartResendsFileData() throws Exception {
          File file = createTempTestFile();
          FilePart part = new FilePart(NAME, file);
          part.setBufferData(false); // Don't buffer in RAM.
          ByteArrayOutputStream stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp1 = stream.toString();
          stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp2 = stream.toString();
          file.delete();
          assertEquals(resp1, resp2);
      }
  
      public void testFilePartResendsStreamDataNoMark() throws Exception {
          File file = createTempTestFile();
          FileInputStream is = new FileInputStream(file);
          FilePart part = new FilePart(NAME, is, file.getName(), file.length());
          ByteArrayOutputStream stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp1 = stream.toString();
          stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp2 = stream.toString();
          file.delete();
          assertEquals(resp1, resp2);
      }
  
      public void testFilePartResendsStreamDataWithMark() throws Exception {
          byte[] byteData = PART_DATA.getBytes();
          ByteArrayInputStream is = new ByteArrayInputStream(byteData);
          FilePart part = new FilePart(NAME, is, NAME, byteData.length);
          part.setBufferData(false);
          ByteArrayOutputStream stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp1 = stream.toString();
          stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp2 = stream.toString();
          assertEquals(resp1, resp2);
      }
  
      public void testFilePartNoBuffer() throws Exception {
          File file = createTempTestFile();
          FilePart part = new FilePart(NAME, file);
          part.setBufferData(false);
          ByteArrayOutputStream stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp1 = stream.toString();
          stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp2 = stream.toString();
          file.delete();
          assertTrue(resp2.length() < resp1.length());
      }
  
      public void testStringPartResendsData() throws Exception {
          StringPart part = new StringPart(NAME, PART_DATA);
          ByteArrayOutputStream stream = new ByteArrayOutputStream();
          part.send(stream);
          String resp1 = stream.toString();
          stream = new ByteArrayOutputStream();
          String resp2 = stream.toString();
          assertEquals(resp1, resp2);
      }
  
      /** Writes PART_DATA out to a temporary file and returns the file it
       * was written to.
       * @return the File object representing the file the data was
       * written to.
       */
      private File createTempTestFile() throws IOException {
          File file = File.createTempFile("FilePartTest", ".txt");
          PrintWriter out = new PrintWriter(new FileWriter(file));
          out.println(PART_DATA);
          out.flush();
          out.close();
          return file;
      }
  }
  
  
  

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

Reply via email to