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>