Author: olegk Date: Mon Oct 6 15:15:39 2008 New Revision: 702290 URL: http://svn.apache.org/viewvc?rev=702290&view=rev Log: MIME4J-27: Content length limitation Support
Added: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java (with props) james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java (with props) james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java (with props) Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PartialInputStream.java james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java james/mime4j/trunk/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java Added: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java?rev=702290&view=auto ============================================================================== --- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java (added) +++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java Mon Oct 6 15:15:39 2008 @@ -0,0 +1,64 @@ +/**************************************************************** + * 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.InputStream; +import java.io.IOException; + +public class LimitedInputStream extends PositionInputStream { + + private final long limit; + + public LimitedInputStream(InputStream instream, long limit) { + super(instream); + if (limit < 0) { + throw new IllegalArgumentException("Limit may not be negative"); + } + this.limit = limit; + } + + private void enforceLimit() throws IOException { + if (position >= limit) { + throw new IOException("Input stream limit exceeded"); + } + } + + public int read() throws IOException { + enforceLimit(); + return super.read(); + } + + public int read(byte b[], int off, int len) throws IOException { + enforceLimit(); + len = Math.min(len, getBytesLeft()); + return super.read(b, off, len); + } + + public long skip(long n) throws IOException { + enforceLimit(); + n = Math.min(n, getBytesLeft()); + return super.skip(n); + } + + private int getBytesLeft() { + return (int)Math.min(Integer.MAX_VALUE, limit - position); + } + +} Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PartialInputStream.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PartialInputStream.java?rev=702290&r1=702289&r2=702290&view=diff ============================================================================== --- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PartialInputStream.java (original) +++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PartialInputStream.java Mon Oct 6 15:15:39 2008 @@ -45,12 +45,12 @@ public int read(byte b[], int off, int len) throws IOException { len = Math.min(len, getBytesLeft()); - return super.read(b, off, len); //To change body of overridden methods use File | Settings | File Templates. + return super.read(b, off, len); } public long skip(long n) throws IOException { n = Math.min(n, getBytesLeft()); - return super.skip(n); //To change body of overridden methods use File | Settings | File Templates. + return super.skip(n); } private int getBytesLeft() { Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java?rev=702290&r1=702289&r2=702290&view=diff ============================================================================== --- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java (original) +++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java Mon Oct 6 15:15:39 2008 @@ -68,13 +68,15 @@ public long skip(long n) throws IOException { final long c = in.skip(n); - position += c; + if (c > 0) + position += c; return c; } public int read(byte b[], int off, int len) throws IOException { final int c = in.read(b, off, len); - position += c; + if (c > 0) + position += c; return c; } Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java?rev=702290&r1=702289&r2=702290&view=diff ============================================================================== --- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java (original) +++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java Mon Oct 6 15:15:39 2008 @@ -27,6 +27,7 @@ import org.apache.james.mime4j.decoder.QuotedPrintableInputStream; import org.apache.james.mime4j.descriptor.BodyDescriptor; import org.apache.james.mime4j.io.BufferedLineReaderInputStream; +import org.apache.james.mime4j.io.LimitedInputStream; import org.apache.james.mime4j.io.LineReaderInputStream; import org.apache.james.mime4j.io.LineReaderInputStreamAdaptor; import org.apache.james.mime4j.io.MimeBoundaryInputStream; @@ -228,7 +229,8 @@ if (tmpbuf == null) { tmpbuf = new byte[2048]; } - while (dataStream.read(tmpbuf)!= -1) { + InputStream instream = getLimitedContentStream(); + while (instream.read(tmpbuf)!= -1) { } } } @@ -286,13 +288,22 @@ } } + private InputStream getLimitedContentStream() { + long maxContentLimit = config.getMaxContentLen(); + if (maxContentLimit >= 0) { + return new LimitedInputStream(dataStream, maxContentLimit); + } else { + return dataStream; + } + } + public InputStream getContentStream() { switch (state) { case EntityStates.T_START_MULTIPART: case EntityStates.T_PREAMBLE: case EntityStates.T_EPILOGUE: case EntityStates.T_BODY: - return this.dataStream; + return getLimitedContentStream(); default: throw new IllegalStateException("Invalid state: " + stateToString(state)); } Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java?rev=702290&r1=702289&r2=702290&view=diff ============================================================================== --- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java (original) +++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java Mon Oct 6 15:15:39 2008 @@ -31,6 +31,7 @@ private boolean strictParsing; private int maxLineLen; private int maxHeaderCount; + private long maxContentLen; public MimeEntityConfig() { super(); @@ -38,6 +39,7 @@ this.strictParsing = false; this.maxLineLen = 1000; this.maxHeaderCount = 1000; + this.maxContentLen = -1; } public boolean isMaximalBodyDescriptor() { @@ -115,6 +117,28 @@ return this.maxHeaderCount; } + /** + * Sets the maximum line length limit. Parsing of a MIME entity will be terminated + * with a [EMAIL PROTECTED] MimeException} if a content body exceeds the maximum length limit. + * If this parameter is set to a non positive value the content length + * check will be disabled. + * + * @param maxLineLen maximum line length limit + */ + public void setMaxContentLen(long maxContentLen) { + this.maxContentLen = maxContentLen; + } + + /** + * Returns the maximum content length limit + * @see #setMaxContentLen(long) + * + * @return value of the the maximum content length limit + */ + public long getMaxContentLen() { + return maxContentLen; + } + public Object clone() throws CloneNotSupportedException { return super.clone(); } Added: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java?rev=702290&view=auto ============================================================================== --- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java (added) +++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java Mon Oct 6 15:15:39 2008 @@ -0,0 +1,56 @@ +/**************************************************************** + * 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.IOException; + +import junit.framework.TestCase; + +public class LimitedInputStreamTest extends TestCase { + + public void testUpToLimitRead() throws IOException { + byte[] data = new byte[] {'0', '1', '2', '3', '4', '5', '6'}; + ByteArrayInputStream instream = new ByteArrayInputStream(data); + LimitedInputStream limitedStream = new LimitedInputStream(instream, 3); + assertEquals(0, limitedStream.getPosition()); + assertTrue(limitedStream.read() != -1); + assertEquals(1, limitedStream.getPosition()); + byte[] tmp = new byte[3]; + assertEquals(2, limitedStream.read(tmp)); + assertEquals(3, limitedStream.getPosition()); + try { + limitedStream.read(); + fail("IOException should have been thrown"); + } catch (IOException ex) { + } + try { + limitedStream.read(tmp); + fail("IOException should have been thrown"); + } catch (IOException ex) { + } + try { + limitedStream.skip(2); + fail("IOException should have been thrown"); + } catch (IOException ex) { + } + } + +} Propchange: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java?rev=702290&view=auto ============================================================================== --- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java (added) +++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java Mon Oct 6 15:15:39 2008 @@ -0,0 +1,53 @@ +/**************************************************************** + * 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.IOException; + +import junit.framework.TestCase; + +public class PositionInputStreamTest extends TestCase { + + public void testPositionCounting() throws IOException { + byte[] data = new byte[] {'0', '1', '2', '3', '4', '5', '6'}; + ByteArrayInputStream instream = new ByteArrayInputStream(data); + PositionInputStream countingStream = new PositionInputStream(instream); + assertEquals(0, countingStream.getPosition()); + assertTrue(countingStream.read() != -1); + assertEquals(1, countingStream.getPosition()); + byte[] tmp = new byte[3]; + assertEquals(3, countingStream.read(tmp)); + assertEquals(4, countingStream.getPosition()); + assertEquals(2, countingStream.skip(2)); + assertEquals(6, countingStream.getPosition()); + assertTrue(countingStream.read() != -1); + assertEquals(7, countingStream.getPosition()); + assertTrue(countingStream.read() == -1); + assertEquals(7, countingStream.getPosition()); + assertTrue(countingStream.read() == -1); + assertEquals(7, countingStream.getPosition()); + assertTrue(countingStream.read(tmp) == -1); + assertEquals(7, countingStream.getPosition()); + assertTrue(countingStream.read(tmp) == -1); + assertEquals(7, countingStream.getPosition()); + } + +} Propchange: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java?rev=702290&r1=702289&r2=702290&view=diff ============================================================================== --- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java (original) +++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java Mon Oct 6 15:15:39 2008 @@ -20,6 +20,7 @@ package org.apache.james.mime4j.parser; import java.io.ByteArrayInputStream; +import java.io.IOException; import org.apache.commons.io.IOUtils; import org.apache.james.mime4j.io.BufferedLineReaderInputStream; @@ -483,4 +484,61 @@ } } + public void testMaxContentLimitCheck() throws Exception { + String message = + "To: Road Runner <[EMAIL PROTECTED]>\r\n" + + "From: Wile E. Cayote <[EMAIL PROTECTED]>\r\n" + + "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" + + "Subject: Mail\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" + + "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n"; + byte[] raw = message.getBytes("US-ASCII"); + ByteArrayInputStream instream = new ByteArrayInputStream(raw); + RootInputStream rootStream = new RootInputStream(instream); + BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(rootStream, 12); + + MimeEntityConfig config = new MimeEntityConfig(); + config.setMaxContentLen(100); + MimeEntity entity = new MimeEntity( + rootStream, + rawstream, + null, + EntityStates.T_START_MESSAGE, + EntityStates.T_END_MESSAGE, + config); + + assertEquals(EntityStates.T_START_MESSAGE, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_START_HEADER, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_FIELD, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_FIELD, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_FIELD, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_FIELD, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_FIELD, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_END_HEADER, entity.getState()); + entity.advance(); + assertEquals(EntityStates.T_BODY, entity.getState()); + try { + IOUtils.toByteArray(entity.getContentStream()); + fail("IOException should have been thrown"); + } catch (IOException expected) { + } + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]