Author: jochen
Date: Tue Jun 26 17:59:16 2007
New Revision: 551000

URL: http://svn.apache.org/viewvc?view=rev&rev=551000
Log:
Short files could cause an unexpected end of the item stream.
PR: FILEUPLOAD-135
Submitted-By: Alexander Sova <[EMAIL PROTECTED]>

Modified:
    jakarta/commons/proper/fileupload/trunk/pom.xml
    jakarta/commons/proper/fileupload/trunk/src/changes/changes.xml
    
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
    
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java
    
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
    
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/StreamingTest.java

Modified: jakarta/commons/proper/fileupload/trunk/pom.xml
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/pom.xml?view=diff&rev=551000&r1=550999&r2=551000
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/pom.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/pom.xml Tue Jun 26 17:59:16 2007
@@ -105,6 +105,10 @@
       <email>[EMAIL PROTECTED]</email>
     </contributor>
     <contributor>
+      <name>Alexander Sova</name>
+      <email>[EMAIL PROTECTED]</email>
+    </contributor>
+    <contributor>
       <name>Thomas Vandahl</name>
       <email>[EMAIL PROTECTED]</email>
     </contributor>

Modified: jakarta/commons/proper/fileupload/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/changes/changes.xml?view=diff&rev=551000&r1=550999&r2=551000
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/changes/changes.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/src/changes/changes.xml Tue Jun 26 
17:59:16 2007
@@ -64,56 +64,50 @@
           due-to="Thomas Vandahl" due-to-email="[EMAIL PROTECTED]">
         DiskFileItem.toString() could throw an NPE.
       </action>
+      <action dev="jochen" type="fix" issue="FILEUPLOAD-135"
+          due-to="Alexander Sova" due-to-email="[EMAIL PROTECTED]">
+        Short files could cause an unexpected end of the item stream.
+      </action>
     </release>
 
        <release version="1.2" date="2007-02-13">
-
       <action dev="jochen" type="fix" due-to="Aaron Freeman"
            due-to-email="[EMAIL PROTECTED]">
         Made Streams.asString static.
       </action>
-
          <action dev="jochen" type="update" issue="FILEUPLOAD-109">
            Eliminated duplicate code.
          </action>
-
          <action dev="jochen" type="add" issue="FILEUPLOAD-112">
            Added a streaming API.
          </action>
-
          <action dev="jochen" type="fix" issue="FILEUPLOAD-93">
            Eliminated the necessity of a content-length header.
          </action>
-
       <action dev="jochen" type="fix" issue="FILEUPLOAD-108"
           due-to="Amichai Rothman" due-to-email="[EMAIL PROTECTED]">
         Eliminated the limitation of a maximum size for a single
         header line. (The total size of all headers is already
         limited, so there's no need for another limit.)      
       </action>
-
       <action dev="jochen" type="add" issue="FILEUPLOAD-87">
         Added the ProgressListener, which allows to implement a
         progress bar.
       </action>
-
       <action dev="jochen" type="add" issue="FILEUPLOAD-111"
           due-to="Amichai Rothman" due-to-email="[EMAIL PROTECTED]">
         Added support for header continuation lines.
       </action>
-
       <action dev="jochen" type="add" issue="FILEUPLOAD-88"
           due-to="Andrey Aristarkhov" due-to-email="[EMAIL PROTECTED]">
         It is now possible to limit the actual file size and not
         the request size.
       </action>
-
       <action dev="jochen" type="add" issue="FILEUPLOAD-120"
           due-to="Henry Yandell" due-to-email="[EMAIL PROTECTED]">
         Added the FileCleanerCleanup as an example for how to close
         down the FileCleaner's reaper thread nicely.
       </action>
-
       <action dev="jochen" type="fix" issue="FILEUPLOAD-123">
         A descriptive NPE is now thrown, if the FileItemFactory
         has not been set.

Modified: 
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java?view=diff&rev=551000&r1=550999&r2=551000
==============================================================================
--- 
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
 (original)
+++ 
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
 Tue Jun 26 17:59:16 2007
@@ -92,4 +92,8 @@
             cause.printStackTrace(writer);
         }
     }
+
+    public Throwable getCause() {
+        return cause;
+    }
 }

Modified: 
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java?view=diff&rev=551000&r1=550999&r2=551000
==============================================================================
--- 
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java
 (original)
+++ 
jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java
 Tue Jun 26 17:59:16 2007
@@ -21,6 +21,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
 
 import org.apache.commons.fileupload.util.Closeable;
 import org.apache.commons.fileupload.util.Streams;
@@ -202,13 +203,6 @@
         CR, LF, DASH, DASH};
 
 
-    /**
-     * The number of bytes, over and above the boundary size, to use for the
-     * keep region.
-     */
-    private static final int KEEP_REGION_PAD = 3;
-
-
     // ----------------------------------------------------------- Data members
 
 
@@ -341,7 +335,7 @@
         // body-data tokens.
         this.boundary = new byte[boundary.length + BOUNDARY_PREFIX.length];
         this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;
-        this.keepRegion = boundary.length + KEEP_REGION_PAD;
+        this.keepRegion = this.boundary.length;
         System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0,
                 BOUNDARY_PREFIX.length);
         System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
@@ -421,8 +415,7 @@
      *
      * @throws IOException if there is no more data available.
      */
-    public byte readByte()
-    throws IOException {
+    public byte readByte() throws IOException {
         // Buffer depleted ?
         if (head == tail) {
             head = 0;
@@ -432,7 +425,9 @@
                 // No more data available.
                 throw new IOException("No more data is available");
             }
-            notifier.noteBytesRead(tail);
+            if(notifier != null) {
+                notifier.noteBytesRead(tail);
+            }
         }
         return buffer[head++];
     }
@@ -855,7 +850,7 @@
                 throw new FileItemStream.ItemSkippedException();
             }
             if (available() == 0) {
-                if (makeAvailable() == 0) {
+                if (makeAvailable() == 0) {                         
                     return -1;
                 }
             }
@@ -957,18 +952,28 @@
 
             // Refill buffer with new data.
             head = 0;
-            int bytesRead = input.read(buffer, pad, bufSize - pad);
-            if (bytesRead == -1) {
-                // The last pad amount is left in the buffer.
-                // Boundary can't be in there so signal an error
-                // condition.
-                throw new MalformedStreamException(
-                "Stream ended unexpectedly");
+            tail = pad;
+
+            for(;;) {
+                int bytesRead = input.read(buffer, tail, bufSize - tail);
+                if (bytesRead == -1) {
+                    // The last pad amount is left in the buffer.
+                    // Boundary can't be in there so signal an error
+                    // condition.
+                    throw new MalformedStreamException("Stream ended 
unexpectedly");
+                }
+                if(notifier != null) {
+                    notifier.noteBytesRead(bytesRead);
+                }
+                tail += bytesRead;
+
+                findSeparator();
+                int av = available();
+
+                if (av > 0 || pos != -1) {
+                    return av;
+                }
             }
-            notifier.noteBytesRead(bytesRead);
-            tail = pad + bytesRead;
-            findSeparator();
-            return available();
         }
 
         /**

Modified: 
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java?view=diff&rev=551000&r1=550999&r2=551000
==============================================================================
--- 
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
 (original)
+++ 
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
 Tue Jun 26 17:59:16 2007
@@ -544,5 +544,10 @@
                {
                        return in.read();
                }
+
+               public int read(byte b[], int off, int len) throws IOException 
+               {
+                   return in.read(b, off, len);
+               }
        }
 }

Modified: 
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/StreamingTest.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/StreamingTest.java?view=diff&rev=551000&r1=550999&r2=551000
==============================================================================
--- 
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/StreamingTest.java
 (original)
+++ 
jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/StreamingTest.java
 Tue Jun 26 17:59:16 2007
@@ -21,11 +21,11 @@
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStreamWriter;
 import java.util.Iterator;
 import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 
-import org.apache.commons.fileupload.FileUploadBase.FileUploadIOException;
 import org.apache.commons.fileupload.FileUploadBase.IOFileUploadException;
 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
@@ -87,7 +87,7 @@
      * Tests, whether an IOException is properly delegated.
      */
     public void testIOException()
-               throws IOException, FileUploadException {
+               throws IOException {
        byte[] request = newRequest();
        InputStream stream = new FilterInputStream(new 
ByteArrayInputStream(request)){
                private int num;
@@ -111,10 +111,43 @@
        };
        try {
                parseUpload(stream, request.length);
-       } catch (IOFileUploadException e) {
+               fail("Expected IOException");
+       } catch (FileUploadException e) {
                assertTrue(e.getCause() instanceof IOException);
                assertEquals("123", e.getCause().getMessage());
-       }
+        }     
+    }         
+
+    /**
+     * Test for FILEUPLOAD-135
+     */
+    public void testFILEUPLOAD135()
+            throws IOException, FileUploadException
+    {
+        byte[] request = newShortRequest();
+        final ByteArrayInputStream bais = new ByteArrayInputStream(request);
+        List fileItems = parseUpload(new InputStream() {
+            public int read()
+            throws IOException
+            {
+                return bais.read();
+            }
+            public int read(byte b[], int off, int len) throws IOException 
+            {
+                return bais.read(b, off, Math.min(len, 3));
+            }
+
+        }, request.length);
+        Iterator fileIter = fileItems.iterator();
+        assertTrue(fileIter.hasNext());
+        FileItem item = (FileItem) fileIter.next();
+        assertEquals("field", item.getFieldName());
+        byte[] bytes = item.get();
+        assertEquals(3, bytes.length);
+        assertEquals((byte)'1', bytes[0]);
+        assertEquals((byte)'2', bytes[1]);
+        assertEquals((byte)'3', bytes[2]);
+        assertTrue(!fileIter.hasNext());
     }
 
     private List parseUpload(byte[] bytes) throws FileUploadException {
@@ -134,24 +167,46 @@
         return fileItems;
     }
 
+    private String getHeader(String pField) {
+        return "-----1234\r\n"
+            + "Content-Disposition: form-data; name=\"" + pField + "\"\r\n"
+            + "\r\n";
+
+    }
+
+    private String getFooter() {
+        return "-----1234--\r\n";
+    }
+
+    private byte[] newShortRequest() throws IOException {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final OutputStreamWriter osw = new OutputStreamWriter(baos, 
"US-ASCII");
+        osw.write(getHeader("field"));
+        osw.write("123");
+        osw.write("\r\n");
+        osw.write(getFooter());
+        osw.close();
+        return baos.toByteArray();
+    }
+
     private byte[] newRequest() throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final OutputStreamWriter osw = new OutputStreamWriter(baos, 
"US-ASCII");
         int add = 16;
         int num = 0;
         for (int i = 0;  i < 16384;  i += add) {
             if (++add == 32) {
                 add = 16;
             }
-            String header = "-----1234\r\n"
-                + "Content-Disposition: form-data; name=\"field" + (num++) + 
"\"\r\n"
-                + "\r\n";
-            baos.write(header.getBytes("US-ASCII"));
+            osw.write(getHeader("field" + (num++)));
+            osw.flush();
             for (int j = 0;  j < i;  j++) {
                 baos.write((byte) j);
             }
-            baos.write("\r\n".getBytes("US-ASCII"));
+            osw.write("\r\n");
         }
-        baos.write("-----1234--\r\n".getBytes("US-ASCII"));
+        osw.write(getFooter());
+        osw.close();
         return baos.toByteArray();
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to