/**************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you under the Apache License, Version 2.0 (the * * "License"); you may not use this file except in compliance * * with the License. You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * * KIND, either express or implied. See the License for the * * specific language governing permissions and limitations * * under the License. * ****************************************************************/ package org.apache.james.mime4j.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import org.apache.james.mime4j.io.BufferedLineReaderInputStream; import org.apache.james.mime4j.io.LineReaderInputStream; import org.apache.james.mime4j.io.MimeBoundaryInputStream; import org.apache.james.mime4j.util.ByteArrayBuffer; import junit.framework.TestCase; public class MimeBoundaryInputStreamTest extends TestCase { 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()); } public void testLenientLineDelimiterReading() throws IOException { String text = "Line 1\r\nLine 2\n--boundary\n" + "Line 3\r\nLine 4\n--boundary--\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", read(mime2, 5)); 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. */ 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 { StringBuilder sb = new StringBuilder(); int b = 0; while ((b = is.read()) != -1) { sb.append((char) b); } return sb.toString(); } private String read(InputStream is, int bufsize) throws IOException { StringBuilder sb = new StringBuilder(); 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. */ public void testImmediateBoundary() throws IOException { String text = "--boundary\r\n"; ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes()); BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); MimeBoundaryInputStream stream = new MimeBoundaryInputStream(buffer, "boundary"); assertEquals(-1, stream.read()); text = "\r\n--boundary\r\n"; bis = new ByteArrayInputStream(text.getBytes()); buffer = new BufferedLineReaderInputStream(bis, 4096); stream = new MimeBoundaryInputStream(buffer, "boundary"); assertEquals(-1, stream.read()); } /** * Tests that hasMoreParts behave as expected. */ public void testHasMoreParts() throws IOException { String text = "--boundary--\r\n"; ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes()); BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); MimeBoundaryInputStream stream = new MimeBoundaryInputStream(buffer, "boundary"); assertEquals(-1, stream.read()); assertTrue(stream.isLastPart()); } /** * Tests that a stream containing only a boundary is empty. */ public void testPrefixIsBoundary() throws IOException { String text = "Line 1\r\n\r\n--boundaryyada\r\n"; ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes()); BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); MimeBoundaryInputStream stream = 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"); assertEquals(-1, stream.read()); } public void testBasicReadLine() throws Exception { String[] teststrs = new String[5]; teststrs[0] = "Hello\r\n"; teststrs[1] = "This string should be much longer than the size of the input buffer " + "which is only 20 bytes for this test\r\n"; StringBuilder sb = new StringBuilder(); for (int i = 0; i < 15; i++) { sb.append("123456789 "); } sb.append("and stuff like that\r\n"); teststrs[2] = sb.toString(); teststrs[3] = "\r\n"; teststrs[4] = "And goodbye\r\n"; String term = "\r\n--1234\r\n"; ByteArrayOutputStream outstream = new ByteArrayOutputStream(); for (String teststr : teststrs) { outstream.write(teststr.getBytes("US-ASCII")); } outstream.write(term.getBytes("US-ASCII")); byte[] raw = outstream.toByteArray(); BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(raw), 20); LineReaderInputStream instream = new MimeBoundaryInputStream(inbuffer, "1234"); ByteArrayBuffer linebuf = new ByteArrayBuffer(8); for (String teststr : teststrs) { linebuf.clear(); instream.readLine(linebuf); String s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals(teststr, s); } assertEquals(-1, instream.readLine(linebuf)); assertEquals(-1, instream.readLine(linebuf)); } public void testReadEmptyLine() throws Exception { String teststr = "01234567890123456789\n\n\r\n\r\r\n\n\n\n\n\n--1234\r\n"; byte[] raw = teststr.getBytes("US-ASCII"); BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(raw), 20); LineReaderInputStream instream = new MimeBoundaryInputStream(inbuffer, "1234"); ByteArrayBuffer linebuf = new ByteArrayBuffer(8); linebuf.clear(); instream.readLine(linebuf); String s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("01234567890123456789\n", s); linebuf.clear(); instream.readLine(linebuf); s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("\n", s); linebuf.clear(); instream.readLine(linebuf); s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("\r\n", s); linebuf.clear(); instream.readLine(linebuf); s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("\r\r\n", s); linebuf.clear(); instream.readLine(linebuf); s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("\n", s); linebuf.clear(); instream.readLine(linebuf); s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("\n", s); linebuf.clear(); instream.readLine(linebuf); s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("\n", s); linebuf.clear(); instream.readLine(linebuf); s = new String(linebuf.toByteArray(), "US-ASCII"); assertEquals("\n", s); assertEquals(-1, instream.readLine(linebuf)); 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) { } } }