You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mime4j-dev@james.apache.org by ol...@apache.org on 2011/06/15 16:20:18 UTC

svn commit: r1136061 - in /james/mime4j/trunk/core/src: main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java main/java/org/apache/james/mime4j/stream/MimeEntity.java test/java/org/apache/james/mime4j/stream/StrictMimeTokenStreamTest.java

Author: olegk
Date: Wed Jun 15 14:20:18 2011
New Revision: 1136061

URL: http://svn.apache.org/viewvc?rev=1136061&view=rev
Log:
MIME4J-180: I/O exception is thrown in the strict parsing mode when reading from body content stream if the mime part has no end boundary; fixed recursion in MimeBoundaryInputStream#read(byte[], int, int) method

Modified:
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java
    james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/StrictMimeTokenStreamTest.java

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java?rev=1136061&r1=1136060&r2=1136061&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java Wed Jun 15 14:20:18 2011
@@ -19,6 +19,8 @@
 
 package org.apache.james.mime4j.io;
 
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeIOException;
 import org.apache.james.mime4j.util.ByteArrayBuffer;
 
 import java.io.IOException;
@@ -31,6 +33,7 @@ import java.io.IOException;
 public class MimeBoundaryInputStream extends LineReaderInputStream {
 
     private final byte[] boundary;
+    private final boolean strict;
     
     private boolean eof;
     private int limit;
@@ -55,8 +58,10 @@ public class MimeBoundaryInputStream ext
      * @param boundary Boundary string (not including leading hyphens).
      * @throws IllegalArgumentException when boundary is too long
      */
-    public MimeBoundaryInputStream(BufferedLineReaderInputStream inbuffer, String boundary) 
-            throws IOException {
+    public MimeBoundaryInputStream(
+            final BufferedLineReaderInputStream inbuffer, 
+            final String boundary, 
+            final boolean strict) throws IOException {
         super(inbuffer);
         int bufferSize = 2 * boundary.length();
         if (bufferSize < 4096) {
@@ -72,6 +77,7 @@ public class MimeBoundaryInputStream ext
         this.initialLength = -1;
         this.completed = false;
         
+        this.strict = strict;
         this.boundary = new byte[boundary.length() + 2];
         this.boundary[0] = (byte) '-';
         this.boundary[1] = (byte) '-';
@@ -84,6 +90,19 @@ public class MimeBoundaryInputStream ext
     }
 
     /**
+     * Creates a new MimeBoundaryInputStream.
+     * 
+     * @param inbuffer The underlying stream.
+     * @param boundary Boundary string (not including leading hyphens).
+     * @throws IllegalArgumentException when boundary is too long
+     */
+    public MimeBoundaryInputStream(
+            final BufferedLineReaderInputStream inbuffer, 
+            final String boundary) throws IOException {
+        this(inbuffer, boundary, false);
+    }
+    
+    /**
      * Closes the underlying stream.
      * 
      * @throws IOException on I/O errors.
@@ -104,9 +123,9 @@ public class MimeBoundaryInputStream ext
         if (completed) {
             return false;
         }
-        // System.out.println("rA!");
         if (endOfStream() && !hasData()) {
-            skipBoundary();            
+            skipBoundary();
+            verifyEndOfStream();
             return false;
         }
         return true;
@@ -117,13 +136,10 @@ public class MimeBoundaryInputStream ext
      */
     @Override
     public int read() throws IOException {
-        if (!readAllowed()) return -1;
         for (;;) {
+            if (!readAllowed()) return -1;
             if (hasData()) {
                 return buffer.read();
-            } else if (endOfStream()) {
-                skipBoundary();            
-                return -1;
             }
             fillBuffer();
         }
@@ -131,13 +147,14 @@ public class MimeBoundaryInputStream ext
     
     @Override
     public int read(byte[] b, int off, int len) throws IOException {
-        if (!readAllowed()) return -1;
-        fillBuffer();
-        if (!hasData()) {
-            return read(b, off, len);
+        for (;;) {
+            if (!readAllowed()) return -1;
+            if (hasData()) {
+                int chunk = Math.min(len, limit - buffer.pos());
+                return buffer.read(b, off, chunk);
+            }
+            fillBuffer();
         }
-        int chunk = Math.min(len, limit - buffer.pos());
-        return buffer.read(b, off, chunk);
     }
 
     @Override
@@ -155,6 +172,7 @@ public class MimeBoundaryInputStream ext
                 bytesRead = fillBuffer();
                 if (endOfStream() && !hasData()) {
                     skipBoundary();
+                    verifyEndOfStream();
                     bytesRead = -1;
                     break;
                 }
@@ -181,6 +199,12 @@ public class MimeBoundaryInputStream ext
         }
     }
     
+    private void verifyEndOfStream() throws IOException {
+        if (strict && eof && !atBoundary) {
+            throw new MimeIOException(new MimeException("Unexpected end of stream"));
+        }
+    }
+    
 	private boolean endOfStream() {
         return eof || atBoundary;
     }

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java?rev=1136061&r1=1136060&r2=1136061&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java Wed Jun 15 14:20:18 2011
@@ -215,7 +215,8 @@ class MimeEntity extends AbstractEntity 
     private void createMimePartStream() throws MimeException, IOException {
         String boundary = body.getBoundary();
         try {
-            currentMimePartStream = new MimeBoundaryInputStream(inbuffer, boundary);
+            currentMimePartStream = new MimeBoundaryInputStream(inbuffer, boundary, 
+                    config.isStrictParsing());
         } catch (IllegalArgumentException e) {
             // thrown when boundary is too long
             throw new MimeException(e.getMessage(), e);

Modified: james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/StrictMimeTokenStreamTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/StrictMimeTokenStreamTest.java?rev=1136061&r1=1136060&r2=1136061&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/StrictMimeTokenStreamTest.java (original)
+++ james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/StrictMimeTokenStreamTest.java Wed Jun 15 14:20:18 2011
@@ -22,7 +22,7 @@ package org.apache.james.mime4j.stream;
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 
-import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.MimeIOException;
 
 import junit.framework.TestCase;
 
@@ -84,13 +84,17 @@ public class StrictMimeTokenStreamTest e
         checkNextIs(EntityState.T_FIELD);
         checkNextIs(EntityState.T_END_HEADER);
         checkNextIs(EntityState.T_BODY);
-        InputStream out = parser.getInputStream();
-        assertEquals("Oh my god! Boundary is missing!\r\n", IOUtils.toString(out, "US-ASCII"));
-        checkNextIs(EntityState.T_END_BODYPART);
+        InputStream in = parser.getInputStream();
+        StringBuilder sb = new StringBuilder();
         try {
-            parser.next();
-            fail("MimeParseEventException should have been thrown");
-        } catch (MimeParseEventException expected) {
+            byte[] tmp = new byte[1024];
+            int l;
+            while ((l = in.read(tmp)) != -1) {
+                sb.append(new String(tmp, 0, l, "US-ASCII"));
+            }
+            fail("MimeIOException should have been thrown");
+        } catch (MimeIOException expected) {
+            assertEquals("Oh my god! Boundary is missing!\r\n", sb.toString());
         }
      }