You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ba...@apache.org on 2008/07/17 16:03:00 UTC

svn commit: r677582 - in /james/mime4j/branches/streams-refactoring/src: main/java/org/apache/james/mime4j/ test/java/org/apache/james/mime4j/ test/java/org/apache/james/mime4j/message/

Author: bago
Date: Thu Jul 17 07:02:59 2008
New Revision: 677582

URL: http://svn.apache.org/viewvc?rev=677582&view=rev
Log:
Fix for infinite loop on very long boundary (MIME4J-55)
Patch provided by Oleg Kalnichevski.

Modified:
    james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/BufferedLineReaderInputStream.java
    james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeBoundaryInputStream.java
    james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeEntity.java
    james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/MimeBoundaryInputStreamTest.java
    james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java

Modified: james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/BufferedLineReaderInputStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/BufferedLineReaderInputStream.java?rev=677582&r1=677581&r2=677582&view=diff
==============================================================================
--- james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/BufferedLineReaderInputStream.java (original)
+++ james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/BufferedLineReaderInputStream.java Thu Jul 17 07:02:59 2008
@@ -28,7 +28,7 @@
  */
 public class BufferedLineReaderInputStream extends LineReaderInputStream {
 
-    private final byte[] buffer;
+    private byte[] buffer;
     
     private int bufpos;
     private int buflen;
@@ -46,6 +46,21 @@
         this.buflen = 0;
     }
     
+    private void expand(int newlen) {
+        byte newbuffer[] = new byte[newlen];
+        int len = this.buflen - this.bufpos;
+        if (len > 0) {
+            System.arraycopy(this.buffer, this.bufpos, newbuffer, this.bufpos, len);
+        }
+        this.buffer = newbuffer;
+    }
+    
+    public void ensureCapacity(int len) {
+        if (len > this.buffer.length) {
+            expand(len);
+        }
+    }
+    
     public int fillBuffer() throws IOException {
         // compact the buffer if necessary
         if (this.bufpos > 0) {
@@ -253,6 +268,10 @@
         return this.buflen - this.bufpos;
     }
     
+    public int capacity() {
+        return this.buffer.length;
+    }
+    
     public int skip(int n) {
         int chunk = Math.min(n, this.buflen - this.bufpos);
         this.bufpos += chunk; 

Modified: james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeBoundaryInputStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeBoundaryInputStream.java?rev=677582&r1=677581&r2=677582&view=diff
==============================================================================
--- james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeBoundaryInputStream.java (original)
+++ james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeBoundaryInputStream.java Thu Jul 17 07:02:59 2008
@@ -49,7 +49,10 @@
     public MimeBoundaryInputStream(BufferedLineReaderInputStream inbuffer, String boundary) 
             throws IOException {
         super(inbuffer);
-        this.buffer = (BufferedLineReaderInputStream) in;
+        if (inbuffer.capacity() <= boundary.length()) {
+            throw new IllegalArgumentException("Boundary is too long");
+        }
+        this.buffer = inbuffer;
         this.eof = false;
         this.limit = -1;
         this.atBoundary = false;

Modified: james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeEntity.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeEntity.java?rev=677582&r1=677581&r2=677582&view=diff
==============================================================================
--- james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeEntity.java (original)
+++ james/mime4j/branches/streams-refactoring/src/main/java/org/apache/james/mime4j/MimeEntity.java Thu Jul 17 07:02:59 2008
@@ -162,10 +162,17 @@
     }
 
     private void createMimeStream() throws IOException {
+        String boundary = body.getBoundary();
+        int bufferSize = 2 * boundary.length();
+        if (bufferSize < 4096) {
+            bufferSize = 4096;
+        }
         if (mimeStream != null) {
-            mimeStream = new MimeBoundaryInputStream(new BufferedLineReaderInputStream(mimeStream, 4 * 1024), body.getBoundary());
+            mimeStream = new MimeBoundaryInputStream(
+                    new BufferedLineReaderInputStream(mimeStream, bufferSize), boundary);
         } else {
-            mimeStream = new MimeBoundaryInputStream(inbuffer, body.getBoundary());
+            inbuffer.ensureCapacity(bufferSize);
+            mimeStream = new MimeBoundaryInputStream(inbuffer, boundary);
         }
         dataStream = new LineReaderInputStreamAdaptor(mimeStream); 
     }

Modified: james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/MimeBoundaryInputStreamTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/MimeBoundaryInputStreamTest.java?rev=677582&r1=677581&r2=677582&view=diff
==============================================================================
--- james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/MimeBoundaryInputStreamTest.java (original)
+++ james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/MimeBoundaryInputStreamTest.java Thu Jul 17 07:02:59 2008
@@ -36,26 +36,26 @@
  * @version $Id: MimeBoundaryInputStreamTest.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
  */
 public class MimeBoundaryInputStreamTest extends TestCase {
-
-    public void testBasicReading() throws IOException {
+
+    public void testBasicReading() throws IOException {
         String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +
-                "Line 3\r\nLine 4\r\n--boundary--";
-        
-        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
-        
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
-        
-        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("Line 1\r\nLine 2", read(mime1, 5));
-        
-        assertFalse(mime1.isLastPart());
-        
-        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("Line 3\r\nLine 4", read(mime2, 5));
-
-        assertTrue(mime2.isLastPart());
-    }
-    
+                "Line 3\r\nLine 4\r\n--boundary--";
+        
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        
+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 1\r\nLine 2", read(mime1, 5));
+        
+        assertFalse(mime1.isLastPart());
+        
+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 3\r\nLine 4", read(mime2, 5));
+
+        assertTrue(mime2.isLastPart());
+    }
+    
     public void testLenientLineDelimiterReading() throws IOException {
         String text = "Line 1\r\nLine 2\n--boundary\n" +
                 "Line 3\r\nLine 4\n--boundary--\n";
@@ -75,92 +75,92 @@
         assertTrue(mime2.isLastPart());
     }
     
-    public void testBasicReadingSmallBuffer1() throws IOException {
-        String text = "yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada\r\n--boundary\r\n" +
-                "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah\r\n--boundary--";
-        
-        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
-        
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 20); 
-        
-        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada", 
-                read(mime1, 10));
-        
-        assertFalse(mime1.isLastPart());
-        
-        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah", 
-                read(mime2, 10));
-
-        assertTrue(mime2.isLastPart());
-    }
-    
-    public void testBasicReadingSmallBuffer2() throws IOException {
-        String text = "yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada\r\n--boundary\r\n" +
-                "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah\r\n--boundary--";
-        
-        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
-        
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 20); 
-        
-        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
-        
-        assertEquals("yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada", 
-                read(mime1, 25));
-        
-        assertFalse(mime1.isLastPart());
-        
-        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah", 
-                read(mime2, 25));
-
-        assertTrue(mime2.isLastPart());
-    }
-    
-    public void testBasicReadingByOneByte() throws IOException {
-        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +
-                "Line 3\r\nLine 4\r\n--boundary--";
-        
-        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
-        
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
-        
-        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("Line 1\r\nLine 2", readByOneByte(mime1));
-        
-        assertFalse(mime1.isLastPart());
-        
-        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("Line 3\r\nLine 4", readByOneByte(mime2));
-
-        assertTrue(mime2.isLastPart());
+    public void testBasicReadingSmallBuffer1() throws IOException {
+        String text = "yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada\r\n--boundary\r\n" +
+                "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah\r\n--boundary--";
+        
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 20); 
+        
+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada", 
+                read(mime1, 10));
+        
+        assertFalse(mime1.isLastPart());
+        
+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah", 
+                read(mime2, 10));
+
+        assertTrue(mime2.isLastPart());
+    }
+    
+    public void testBasicReadingSmallBuffer2() throws IOException {
+        String text = "yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada\r\n--boundary\r\n" +
+                "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah\r\n--boundary--";
+        
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 20); 
+        
+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
+        
+        assertEquals("yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada", 
+                read(mime1, 25));
+        
+        assertFalse(mime1.isLastPart());
+        
+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah", 
+                read(mime2, 25));
+
+        assertTrue(mime2.isLastPart());
+    }
+    
+    public void testBasicReadingByOneByte() throws IOException {
+        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +
+                "Line 3\r\nLine 4\r\n--boundary--";
+        
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        
+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 1\r\nLine 2", readByOneByte(mime1));
+        
+        assertFalse(mime1.isLastPart());
+        
+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 3\r\nLine 4", readByOneByte(mime2));
+
+        assertTrue(mime2.isLastPart());
     }
     
     /**
-     * Tests that a CRLF immediately preceding a boundary isn't included in
-     * the stream.
+     * Tests that a CRLF immediately preceding a boundary isn't included in
+     * the stream.
      */
-    public void testCRLFPrecedingBoundary() throws IOException {
-        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +
-                "Line 3\r\nLine 4\r\n\r\n--boundary\r\n";
-        
-        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
-        
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
-        
-        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("Line 1\r\nLine 2", read(mime1, 5));
-        
-        assertFalse(mime1.isLastPart());
-        
-        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("Line 3\r\nLine 4\r\n", read(mime2, 5));
-
-        assertFalse(mime2.isLastPart());
+    public void testCRLFPrecedingBoundary() throws IOException {
+        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +
+                "Line 3\r\nLine 4\r\n\r\n--boundary\r\n";
+        
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));
+        
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        
+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 1\r\nLine 2", read(mime1, 5));
+        
+        assertFalse(mime1.isLastPart());
+        
+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 3\r\nLine 4\r\n", read(mime2, 5));
+
+        assertFalse(mime2.isLastPart());
     }
     
-    private String readByOneByte(InputStream is) throws IOException {
+    private String readByOneByte(InputStream is) throws IOException {
         StringBuffer sb = new StringBuffer();
         int b = 0;
         while ((b = is.read()) != -1) {
@@ -168,18 +168,18 @@
         }
         return sb.toString();
     }
-
-    private String read(InputStream is, int bufsize) throws IOException {
-        StringBuffer sb = new StringBuffer();
-        int l;
-        byte[] tmp = new byte[bufsize];
-        while ((l = is.read(tmp)) != -1) {
-            for (int i = 0; i < l; i++) {
-                sb.append((char) tmp[i]);
-            }
-        }
-        return sb.toString();
-    }
+
+    private String read(InputStream is, int bufsize) throws IOException {
+        StringBuffer sb = new StringBuffer();
+        int l;
+        byte[] tmp = new byte[bufsize];
+        while ((l = is.read(tmp)) != -1) {
+            for (int i = 0; i < l; i++) {
+                sb.append((char) tmp[i]);
+            }
+        }
+        return sb.toString();
+    }
     
     /**
      * Tests that a stream containing only a boundary is empty.
@@ -188,18 +188,18 @@
         String text = "--boundary\r\n";
         
         ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
-        
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        
         MimeBoundaryInputStream stream = 
-            new MimeBoundaryInputStream(buffer, "boundary");
+            new MimeBoundaryInputStream(buffer, "boundary");
         assertEquals(-1, stream.read());
         
         text = "\r\n--boundary\r\n";
         
         bis = new ByteArrayInputStream(text.getBytes());
-        buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        buffer = new BufferedLineReaderInputStream(bis, 4096); 
         stream = 
-            new MimeBoundaryInputStream(buffer, "boundary");
+            new MimeBoundaryInputStream(buffer, "boundary");
         assertEquals(-1, stream.read());
     }
     
@@ -210,11 +210,11 @@
         String text = "--boundary--\r\n";
         
         ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
         MimeBoundaryInputStream stream = 
-            new MimeBoundaryInputStream(buffer, "boundary");
+            new MimeBoundaryInputStream(buffer, "boundary");
         assertEquals(-1, stream.read());
-        assertTrue(stream.isLastPart());
+        assertTrue(stream.isLastPart());
     }
     
     /**
@@ -224,16 +224,16 @@
         String text = "Line 1\r\n\r\n--boundaryyada\r\n";
         
         ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());
-        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 
         MimeBoundaryInputStream stream = 
-            new MimeBoundaryInputStream(buffer, "boundary");
-        assertEquals("Line 1\r\n", read(stream, 100));
+            new MimeBoundaryInputStream(buffer, "boundary");
+        assertEquals("Line 1\r\n", read(stream, 100));
         
         text = "--boundaryyada\r\n";
         
         bis = new ByteArrayInputStream(text.getBytes());
-        buffer = new BufferedLineReaderInputStream(bis, 4096); 
-        stream = new MimeBoundaryInputStream(buffer, "boundary");
+        buffer = new BufferedLineReaderInputStream(bis, 4096); 
+        stream = new MimeBoundaryInputStream(buffer, "boundary");
         assertEquals(-1, stream.read());
     }
     
@@ -330,4 +330,17 @@
         assertEquals(-1, instream.readLine(linebuf));
     }
     
+    public void testboundaryLongerThanBuffer() throws IOException {
+        String text = "--looooooooooooooooooooooooooong-boundary\r\n";
+        
+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());
+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 10); 
+        
+        try {
+            new MimeBoundaryInputStream(buffer, "looooooooooooooooooooooooooong-boundary");
+            fail("IllegalArgumentException should have been thrown");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
 }

Modified: james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java?rev=677582&r1=677581&r2=677582&view=diff
==============================================================================
--- james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java (original)
+++ james/mime4j/branches/streams-refactoring/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java Thu Jul 17 07:02:59 2008
@@ -20,14 +20,7 @@
 package org.apache.james.mime4j.message;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.james.mime4j.EOLConvertingInputStream;
 import org.apache.james.mime4j.field.Field;
-import org.apache.james.mime4j.message.BinaryBody;
-import org.apache.james.mime4j.message.Body;
-import org.apache.james.mime4j.message.Entity;
-import org.apache.james.mime4j.message.Message;
-import org.apache.james.mime4j.message.Multipart;
-import org.apache.james.mime4j.message.TextBody;
 import org.apache.james.mime4j.util.CharsetUtil;
 import org.apache.log4j.BasicConfigurator;
 
@@ -90,10 +83,7 @@
         
         System.out.println("Parsing " + f.getName());
         
-        InputStream in = new EOLConvertingInputStream(new BufferedInputStream(
-                        new FileInputStream(f))); //, 
-        
-        Message m = new Message(in);
+        Message m = new Message(new FileInputStream(f));
         
         String prefix = f.getName().substring(0, f.getName().length() - 4);
         String xmlFileName = fileName.substring(0, fileName.length() - 4) 
@@ -104,8 +94,7 @@
                                     + "_decoded.mime4j.xml";
         String expected = null;
         try {
-            expected = IOUtils.toString(
-                    new FileInputStream(xmlFileName), "ISO8859-1");
+            expected = IOUtils.toString(new FileInputStream(xmlFileName), "ISO8859-1");
         } catch (FileNotFoundException ex) {
             writeToFile(result, mime4jFileName);
             fail("Test file not found. Generated the expected result with mime4j prefix: "+ex.getMessage());



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