Author: bago
Date: Wed Dec 30 00:41:00 2009
New Revision: 894523
URL: http://svn.apache.org/viewvc?rev=894523&view=rev
Log:
Make sure we have a single place (RawField) where we decide how to parse a
rawfield, how to build it from name/body and how to deal with the WSP after the
colon. (MIME4J-151).
Modified:
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/Fields.java
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/RawField.java
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java
Modified:
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java
Wed Dec 30 00:41:00 2009
@@ -19,19 +19,13 @@
package org.apache.james.mime4j.field;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.parser.RawField;
import org.apache.james.mime4j.util.ByteSequence;
import org.apache.james.mime4j.util.ContentUtil;
-import org.apache.james.mime4j.util.MimeUtil;
public class DefaultFieldParser extends DelegatingFieldParser {
- private static final Pattern FIELD_NAME_PATTERN = Pattern
- .compile("^([\\x21-\\x39\\x3b-\\x7e]+)[\\x20\\x09]*:");
-
private static final DefaultFieldParser PARSER = new DefaultFieldParser();
@@ -56,8 +50,8 @@
* @throws MimeException if the raw string cannot be split into field name
and body.
*/
public static ParsedField parse(final ByteSequence raw) throws
MimeException {
- String rawStr = ContentUtil.decode(raw);
- return parse(raw, rawStr);
+ RawField rawField = new RawField(raw);
+ return PARSER.parse(rawField.getName(), rawField.getBody(), raw);
}
@@ -84,23 +78,7 @@
*/
public static ParsedField parse(final String rawStr) throws MimeException {
ByteSequence raw = ContentUtil.encode(rawStr);
- return parse(raw, rawStr);
- }
-
- private static ParsedField parse(final ByteSequence raw, final String
rawStr)
- throws MimeException {
- final Matcher fieldMatcher = FIELD_NAME_PATTERN.matcher(rawStr);
- if (!fieldMatcher.find()) {
- throw new MimeException("Invalid field in string");
- }
- final String name = fieldMatcher.group(1);
-
- String body = rawStr.substring(fieldMatcher.end());
- if (body.length() > 0 && body.charAt(0) == ' ') {
- body = body.substring(1);
- }
- body = MimeUtil.unfold(body);
- return PARSER.parse(name, body, raw);
+ return parse(raw);
}
Modified:
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/Fields.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/Fields.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/Fields.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/field/Fields.java
Wed Dec 30 00:41:00 2009
@@ -30,8 +30,7 @@
import org.apache.james.mime4j.codec.EncoderUtil;
import org.apache.james.mime4j.field.address.Address;
import org.apache.james.mime4j.field.address.Mailbox;
-import org.apache.james.mime4j.util.ByteSequence;
-import org.apache.james.mime4j.util.ContentUtil;
+import org.apache.james.mime4j.parser.RawField;
import org.apache.james.mime4j.util.MimeUtil;
/**
@@ -603,9 +602,8 @@
private static <F extends ParsedField> F parse(FieldParser<F> parser,
String fieldName, String fieldBody) {
- String rawStr = MimeUtil.fold(fieldName + ": " + fieldBody, 0);
- ByteSequence raw = ContentUtil.encode(rawStr);
- return parser.parse(fieldName, fieldBody, raw);
+ RawField rawField = new RawField(fieldName, fieldBody);
+ return parser.parse(rawField.getName(), rawField.getBody(),
rawField.getRaw());
}
private static String encodeAddresses(Iterable<? extends Address>
addresses) {
Modified:
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
Wed Dec 30 00:41:00 2009
@@ -20,7 +20,6 @@
package org.apache.james.mime4j.parser;
import java.io.IOException;
-import java.util.BitSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -58,17 +57,6 @@
private boolean endOfHeader;
private int headerCount;
- private static final BitSet fieldChars = new BitSet();
-
- static {
- for (int i = 0x21; i <= 0x39; i++) {
- fieldChars.set(i);
- }
- for (int i = 0x3b; i <= 0x7e; i++) {
- fieldChars.set(i);
- }
- }
-
/**
* Internal state, not exposed.
*/
@@ -200,33 +188,14 @@
}
fieldbuf.setLength(len);
- boolean valid = true;
- boolean obsoleteSyntax = false;
-
- int pos = fieldbuf.indexOf((byte) ':');
- if (pos <= 0) {
- valid = false;
- } else {
- for (int i = 0; i < pos; i++) {
- if (!fieldChars.get(fieldbuf.byteAt(i) & 0xff)) {
- for (; i < pos; i++) {
- int j = fieldbuf.byteAt(i) & 0xff;
- if (j != 0x20 && j !=
0x09) {
- valid = false;
- break;
- } else {
- obsoleteSyntax
= true;
- }
- }
- }
- }
- }
- if (valid) {
- if (obsoleteSyntax) warn(Event.OBSOLETE_HEADER);
- field = new RawField(fieldbuf, pos);
+ try {
+ field = new RawField(fieldbuf);
+ if (field.isObsoleteSyntax()) {
+ warn(Event.OBSOLETE_HEADER);
+ }
body.addField(field);
return true;
- } else {
+ } catch (MimeException e) {
monitor(Event.INVALID_HEADER);
}
}
Modified:
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java
Wed Dec 30 00:41:00 2009
@@ -32,8 +32,6 @@
import org.apache.james.mime4j.io.LineReaderInputStream;
import org.apache.james.mime4j.io.LineReaderInputStreamAdaptor;
import org.apache.james.mime4j.io.MimeBoundaryInputStream;
-import org.apache.james.mime4j.util.ByteSequence;
-import org.apache.james.mime4j.util.ContentUtil;
import org.apache.james.mime4j.util.MimeUtil;
public class MimeEntity extends AbstractEntity {
@@ -96,8 +94,7 @@
throw new IllegalStateException("Invalid state: " +
stateToString(state));
}
skipHeader = true;
- ByteSequence raw = ContentUtil.encode("Content-Type: " + contentType);
- body.addField(new RawField(raw, 12));
+ body.addField(new RawField("Content-Type", contentType));
}
@Override
Modified:
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/RawField.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/RawField.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/RawField.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/main/java/org/apache/james/mime4j/parser/RawField.java
Wed Dec 30 00:41:00 2009
@@ -19,6 +19,9 @@
package org.apache.james.mime4j.parser;
+import java.util.BitSet;
+
+import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.util.ByteSequence;
import org.apache.james.mime4j.util.ContentUtil;
import org.apache.james.mime4j.util.MimeUtil;
@@ -28,15 +31,61 @@
*/
public class RawField {
- private final ByteSequence raw;
+ private static final BitSet fieldChars = new BitSet();
+
+ static {
+ for (int i = 0x21; i <= 0x39; i++) {
+ fieldChars.set(i);
+ }
+ for (int i = 0x3b; i <= 0x7e; i++) {
+ fieldChars.set(i);
+ }
+ }
+
+
+ private ByteSequence raw;
private int colonIdx;
+ private int headerNameEndIdx;
private String name;
private String body;
+ private final boolean obsoleteSyntax;
+
+ public RawField(String name, String body) {
+ this.name = name;
+ this.body = body;
+ this.raw = null;
+ this.obsoleteSyntax = false;
+ }
- public RawField(ByteSequence raw, int colonIdx) {
+ /**
+ * @param raw bytes
+ * @throws MimeException on malformed data
+ */
+ public RawField(ByteSequence raw) throws MimeException {
this.raw = raw;
- this.colonIdx = colonIdx;
+
+ colonIdx = -1;
+ boolean obsolete = false;
+ for (int i = 0; i < raw.length(); i++) {
+ if (!fieldChars.get(raw.byteAt(i) & 0xff)) {
+ headerNameEndIdx = i;
+ for (; i < raw.length(); i++) {
+ int j = raw.byteAt(i) & 0xff;
+ if (j == ':') {
+ colonIdx = i;
+ break;
+ } else if (j != 0x20 && j != 0x09) {
+ throw new MimeException("Invalid header");
+ } else {
+ obsolete = true;
+ }
+ }
+ break;
+ }
+ }
+ if (colonIdx == -1) throw new MimeException("Invalid header. No colon
found.");
+ obsoleteSyntax = obsolete;
}
public String getName() {
@@ -56,25 +105,32 @@
}
public ByteSequence getRaw() {
+ if (raw == null) {
+ raw = ContentUtil.encode(MimeUtil.fold(name+": "+body, 0));
+ }
return raw;
}
@Override
public String toString() {
- return getName() + ':' + getBody();
+ return getName() + ": " + getBody();
}
private String parseName() {
// make sure we ignore ending WSP (obsolete rfc822 syntax)
- int endIdx = colonIdx;
- while (endIdx > 0 && raw.byteAt(endIdx - 1) == 0x20 ||
raw.byteAt(endIdx - 1) == 0x09) endIdx--;
- return ContentUtil.decode(raw, 0, endIdx);
+ return ContentUtil.decode(raw, 0, headerNameEndIdx);
}
private String parseBody() {
int offset = colonIdx + 1;
+ // if the header body starts with a space we remove it.
+ if (raw.length() > offset + 1 && (raw.byteAt(offset) & 0xff) == 0x20)
offset++;
int length = raw.length() - offset;
return MimeUtil.unfold(ContentUtil.decode(raw, offset, length));
}
+ public boolean isObsoleteSyntax() {
+ return obsoleteSyntax;
+ }
+
}
Modified:
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java
Wed Dec 30 00:41:00 2009
@@ -21,9 +21,7 @@
import junit.framework.TestCase;
-import org.apache.james.mime4j.field.Field;
import org.apache.james.mime4j.parser.RawField;
-import org.apache.james.mime4j.util.ByteSequence;
public abstract class BaseTestForBodyDescriptors extends TestCase {
@@ -214,26 +212,9 @@
private static final class TestField extends RawField {
- private final String name;
- private final String body;
-
- public TestField(String name, String body){
- super(null, -1);
- this.name = name;
- this.body = body;
- }
-
- public String getName() {
- return name;
- }
-
- public String getBody() {
- return body;
- }
-
- public ByteSequence getRaw() {
- throw new UnsupportedOperationException();
+ public TestField(String name, String body){
+ super(name, body);
}
-
+
}
}
Modified:
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/message/HeaderTest.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
Wed Dec 30 00:41:00 2009
@@ -53,7 +53,9 @@
Field field = header.getField("Hello");
assertNotNull(field);
- assertEquals(hello, field.getBody());
+ // field.getBody is already a 7 bit ASCII string, after MIME4J-151
+ // assertEquals(hello, field.getBody());
+ assertEquals("Gr?ezi_z?m?", field.getBody());
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
Modified:
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java
URL:
http://svn.apache.org/viewvc/james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java?rev=894523&r1=894522&r2=894523&view=diff
==============================================================================
---
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java
(original)
+++
james/mime4j/branches/cycleclean/core/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java
Wed Dec 30 00:41:00 2009
@@ -66,23 +66,23 @@
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("To", entity.getField().getName());
- assertEquals(" Road Runner <[email protected]>",
entity.getField().getBody());
+ assertEquals("Road Runner <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("From", entity.getField().getName());
- assertEquals(" Wile E. Cayote <[email protected]>",
entity.getField().getBody());
+ assertEquals("Wile E. Cayote <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Date", entity.getField().getName());
- assertEquals(" Tue, 12 Feb 2008 17:34:09 +0000 (GMT)",
entity.getField().getBody());
+ assertEquals("Tue, 12 Feb 2008 17:34:09 +0000 (GMT)",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Subject", entity.getField().getName());
- assertEquals(" Mail", entity.getField().getBody());
+ assertEquals("Mail", entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Content-Type", entity.getField().getName());
- assertEquals(" text/plain", entity.getField().getBody());
+ assertEquals("text/plain", entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_END_HEADER, entity.getState());
try {
@@ -145,11 +145,11 @@
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("To", entity.getField().getName());
- assertEquals(" Road Runner <[email protected]>",
entity.getField().getBody());
+ assertEquals("Road Runner <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("From", entity.getField().getName());
- assertEquals(" Wile E. Cayote <[email protected]>",
entity.getField().getBody());
+ assertEquals("Wile E. Cayote <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Date", entity.getField().getName());
@@ -161,7 +161,7 @@
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Content-Type", entity.getField().getName());
- assertEquals(" text/plain", entity.getField().getBody());
+ assertEquals("text/plain", entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_END_HEADER, entity.getState());
try {
@@ -231,23 +231,23 @@
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("To", entity.getField().getName());
- assertEquals(" Road Runner <[email protected]>",
entity.getField().getBody());
+ assertEquals("Road Runner <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("From", entity.getField().getName());
- assertEquals(" Wile E. Cayote <[email protected]>",
entity.getField().getBody());
+ assertEquals("Wile E. Cayote <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Date", entity.getField().getName());
- assertEquals(" Tue, 12 Feb 2008 17:34:09 +0000 (GMT)",
entity.getField().getBody());
+ assertEquals("Tue, 12 Feb 2008 17:34:09 +0000 (GMT)",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Subject", entity.getField().getName());
- assertEquals(" Mail", entity.getField().getBody());
+ assertEquals("Mail", entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Content-Type", entity.getField().getName());
- assertEquals(" multipart/mixed;boundary=1729",
entity.getField().getBody());
+ assertEquals("multipart/mixed;boundary=1729",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_END_HEADER, entity.getState());
entity.advance();
@@ -265,7 +265,7 @@
p1.advance();
assertEquals(EntityStates.T_FIELD, p1.getState());
assertEquals("Content-Type", p1.getField().getName());
- assertEquals(" text/plain; charset=US-ASCII", p1.getField().getBody());
+ assertEquals("text/plain; charset=US-ASCII", p1.getField().getBody());
p1.advance();
assertEquals(EntityStates.T_END_HEADER, p1.getState());
p1.advance();
@@ -285,7 +285,7 @@
p2.advance();
assertEquals(EntityStates.T_FIELD, p2.getState());
assertEquals("Content-Type", p2.getField().getName());
- assertEquals(" text/plain; charset=US-ASCII", p2.getField().getBody());
+ assertEquals("text/plain; charset=US-ASCII", p2.getField().getBody());
p2.advance();
assertEquals(EntityStates.T_END_HEADER, p2.getState());
p2.advance();
@@ -346,23 +346,23 @@
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("To", entity.getField().getName());
- assertEquals(" Road Runner <[email protected]>",
entity.getField().getBody());
+ assertEquals("Road Runner <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("From", entity.getField().getName());
- assertEquals(" Wile E. Cayote <[email protected]>",
entity.getField().getBody());
+ assertEquals("Wile E. Cayote <[email protected]>",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Date", entity.getField().getName());
- assertEquals(" Tue, 12 Feb 2008 17:34:09 +0000 (GMT)",
entity.getField().getBody());
+ assertEquals("Tue, 12 Feb 2008 17:34:09 +0000 (GMT)",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Subject", entity.getField().getName());
- assertEquals(" Mail", entity.getField().getBody());
+ assertEquals("Mail", entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_FIELD, entity.getState());
assertEquals("Content-Type", entity.getField().getName());
- assertEquals(" multipart/mixed;boundary=1729",
entity.getField().getBody());
+ assertEquals("multipart/mixed;boundary=1729",
entity.getField().getBody());
entity.advance();
assertEquals(EntityStates.T_END_HEADER, entity.getState());
entity.advance();