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 ol...@apache.org on 2008/09/21 15:07:49 UTC
svn commit: r697507 - in /james/mime4j/trunk/src:
main/java/org/apache/james/mime4j/io/
main/java/org/apache/james/mime4j/parser/
test/java/org/apache/james/mime4j/parser/
Author: olegk
Date: Sun Sep 21 06:07:49 2008
New Revision: 697507
URL: http://svn.apache.org/viewvc?rev=697507&view=rev
Log:
MIME4J-57:
* Added javadocs to the MimeEntityConfig class
* Made sure the max line length limit is correctly enforced for folded lines
* Added max header limit check; intended as a protection from a DoS condition if a message contains too many headers (more than 1000)
Added:
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java (with props)
Modified:
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.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/MaxHeaderLimitException.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java?rev=697507&view=auto
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java (added)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java Sun Sep 21 06:07:49 2008
@@ -0,0 +1,35 @@
+/****************************************************************
+ * 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 org.apache.james.mime4j.MimeException;
+
+/**
+ * Signals a I/O error due to the header count exceeding the maximum limit.
+ */
+public class MaxHeaderLimitException extends MimeException {
+
+ private static final long serialVersionUID = 2154269045186186769L;
+
+ public MaxHeaderLimitException(final String message) {
+ super(message);
+ }
+
+}
Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java?rev=697507&r1=697506&r2=697507&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java Sun Sep 21 06:07:49 2008
@@ -30,6 +30,8 @@
import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
import org.apache.james.mime4j.descriptor.MutableBodyDescriptor;
import org.apache.james.mime4j.io.LineReaderInputStream;
+import org.apache.james.mime4j.io.MaxHeaderLimitException;
+import org.apache.james.mime4j.io.MaxLineLimitException;
import org.apache.james.mime4j.util.ByteArrayBuffer;
import org.apache.james.mime4j.util.CharArrayBuffer;
import org.apache.james.mime4j.util.MessageUtils;
@@ -55,6 +57,7 @@
private int lineCount;
private String field, fieldName, fieldValue;
private boolean endOfHeader;
+ private int headerCount;
private static final BitSet fieldChars = new BitSet();
@@ -92,6 +95,7 @@
this.fieldbuf = new CharArrayBuffer(64);
this.lineCount = 0;
this.endOfHeader = false;
+ this.headerCount = 0;
}
public int getState() {
@@ -121,12 +125,16 @@
if (endOfHeader) {
return;
}
+ int maxLineLen = config.getMaxLineLen();
LineReaderInputStream instream = getDataStream();
fieldbuf.clear();
for (;;) {
// If there's still data stuck in the line buffer
// copy it to the field buffer
int len = linebuf.length();
+ if (maxLineLen > 0 && fieldbuf.length() + len >= maxLineLen) {
+ throw new MaxLineLimitException("Maximum line length limit exceeded");
+ }
if (len > 0) {
fieldbuf.append(linebuf, 0, len);
}
@@ -160,11 +168,17 @@
}
protected boolean parseField() throws IOException {
+ int maxHeaderLimit = config.getMaxHeaderCount();
for (;;) {
if (endOfHeader) {
return false;
}
+ if (headerCount >= maxHeaderLimit) {
+ throw new MaxHeaderLimitException("Maximum header limit exceeded");
+ }
+
fillFieldBuffer();
+ headerCount++;
// Strip away line delimiter
int len = fieldbuf.length();
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=697507&r1=697506&r2=697507&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 Sun Sep 21 06:07:49 2008
@@ -19,6 +19,7 @@
package org.apache.james.mime4j.parser;
+import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.util.CharArrayBuffer;
/**
@@ -29,12 +30,14 @@
private boolean maximalBodyDescriptor;
private boolean strictParsing;
private int maxLineLen;
+ private int maxHeaderCount;
public MimeEntityConfig() {
super();
this.maximalBodyDescriptor = false;
this.strictParsing = false;
this.maxLineLen = 1000;
+ this.maxHeaderCount = 1000;
}
public boolean isMaximalBodyDescriptor() {
@@ -45,22 +48,73 @@
this.maximalBodyDescriptor = maximalBodyDescriptor;
}
- public boolean isStrictParsing() {
- return this.strictParsing;
- }
-
+ /**
+ * Defines whether minor violations of the MIME specification should be
+ * tolerated or should result in a {@link MimeException}. If this parameter
+ * is set to <code>true</code>, a strict interpretation of the MIME
+ * specification will be enforced, If this parameter is set to <code>false</code>
+ * minor violations will result in a warning in the log.
+ *
+ * @return value of the strict parsing mode
+ */
public void setStrictParsing(boolean strictParsing) {
this.strictParsing = strictParsing;
}
+ /**
+ * Returns the value of the strict parsing mode
+ * @see #setStrictParsing(boolean)
+ *
+ * @return value of the strict parsing mode
+ */
+ public boolean isStrictParsing() {
+ return this.strictParsing;
+ }
+
+ /**
+ * Sets the maximum line length limit. Parsing of a MIME entity will be terminated
+ * with a {@link MimeException} if a line is encountered that exceeds the maximum
+ * length limit. If this parameter is set to a non positive value the line length
+ * check will be disabled.
+ *
+ * @param maximum line length limit
+ */
public void setMaxLineLen(int maxLineLen) {
this.maxLineLen = maxLineLen;
}
+ /**
+ * Returns the maximum line length limit
+ * @see #setMaxLineLen(int)
+ *
+ * @return value of the the maximum line length limit
+ */
public int getMaxLineLen() {
return this.maxLineLen;
}
+ /**
+ * Sets the maximum header limit. Parsing of a MIME entity will be terminated
+ * with a {@link MimeException} if the number of headers exceeds the maximum
+ * limit. If this parameter is set to a non positive value the header limit check
+ * will be disabled.
+ *
+ * @param maximum header limit
+ */
+ public void setMaxHeaderCount(int maxHeaderCount) {
+ this.maxHeaderCount = maxHeaderCount;
+ }
+
+ /**
+ * Returns the maximum header limit
+ * @see #setMaxHeaderCount(int)
+ *
+ * @return value of the the maximum header limit
+ */
+ public int getMaxHeaderCount() {
+ return this.maxHeaderCount;
+ }
+
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
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=697507&r1=697506&r2=697507&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 Sun Sep 21 06:07:49 2008
@@ -23,6 +23,8 @@
import org.apache.commons.io.IOUtils;
import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
+import org.apache.james.mime4j.io.MaxHeaderLimitException;
+import org.apache.james.mime4j.io.MaxLineLimitException;
import org.apache.james.mime4j.io.RootInputStream;
import org.apache.james.mime4j.parser.EntityStateMachine;
import org.apache.james.mime4j.parser.EntityStates;
@@ -329,4 +331,156 @@
assertEquals(EntityStates.T_END_OF_STREAM, entity.getState());
}
+ public void testMaxLineLimitCheck() throws Exception {
+ String message =
+ "To: Road Runner <ru...@example.org>\r\n" +
+ "From: Wile E. Cayote <wi...@example.org>\r\n" +
+ "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+ "Subject: Mail\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "\r\n" +
+ "a very important message";
+ 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.setMaxLineLen(50);
+ 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());
+ try {
+ entity.advance();
+ fail("MaxLineLimitException should have been thrown");
+ } catch (MaxLineLimitException expected) {
+ }
+ }
+
+ public void testMaxLineLimitCheckFoldedLines() throws Exception {
+ String message =
+ "To: Road Runner <ru...@example.org>\r\n" +
+ "From: Wile E. Cayote <wi...@example.org>\r\n" +
+ "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+ "Subject: Mail\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ " xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "\r\n" +
+ "a very important message";
+ 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.setMaxLineLen(50);
+ 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());
+ try {
+ entity.advance();
+ fail("MaxLineLimitException should have been thrown");
+ } catch (MaxLineLimitException expected) {
+ }
+ }
+
+ public void testMaxHeaderCount() throws Exception {
+ String message =
+ "To: Road Runner <ru...@example.org>\r\n" +
+ "From: Wile E. Cayote <wi...@example.org>\r\n" +
+ "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+ "Subject: Mail\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "\r\n" +
+ "a very important message";
+ 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.setMaxHeaderCount(20);
+ 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());
+
+ for (int i = 0; i < 20; i++) {
+ entity.advance();
+ assertEquals(EntityStates.T_FIELD, entity.getState());
+ }
+ try {
+ entity.advance();
+ fail("MaxHeaderLimitException should have been thrown");
+ } catch (MaxHeaderLimitException expected) {
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org