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();


Reply via email to