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 rd...@apache.org on 2007/09/08 16:35:07 UTC

svn commit: r573847 - in /james/mime4j/trunk/src: main/java/org/apache/james/mime4j/MimeParseEventException.java main/java/org/apache/james/mime4j/MimeTokenStream.java test/java/org/apache/james/mime4j/StrictMimeTokenStreamTest.java

Author: rdonkin
Date: Sat Sep  8 07:35:06 2007
New Revision: 573847

URL: http://svn.apache.org/viewvc?rev=573847&view=rev
Log:
Add support for strict validation. Implemented by adding event monitor. Developed in https://issues.apache.org/jira/browse/MIME4J-23.

Added:
    james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeParseEventException.java
    james/mime4j/trunk/src/test/java/org/apache/james/mime4j/StrictMimeTokenStreamTest.java
Modified:
    james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java

Added: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeParseEventException.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeParseEventException.java?rev=573847&view=auto
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeParseEventException.java (added)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeParseEventException.java Sat Sep  8 07:35:06 2007
@@ -0,0 +1,48 @@
+/****************************************************************
+ * 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;
+
+/**
+ * Indicates that strict parsing has been enabled 
+ * and an optional invality has been found in the input.
+ * {@link #getEvent()} indicates the type of invalidity.
+ */
+public class MimeParseEventException extends MimeException {
+    
+    private static final long serialVersionUID = 4632991604246852302L;
+    private final MimeTokenStream.Event event;
+    
+    /**
+     * Constructs an exception 
+     * @param event <code>MimeTokenStream.Event</code>, not null
+     */
+    public MimeParseEventException(final MimeTokenStream.Event event) {
+        super(event.toString());
+        this.event = event;
+    }
+
+    /**
+     * Gets the causal parse event.
+     * @return <code>MimeTokenStream.Event</code>, not null
+     */
+    public MimeTokenStream.Event getEvent() {
+        return event;
+    }
+}

Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java?rev=573847&r1=573846&r2=573847&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/MimeTokenStream.java Sat Sep  8 07:35:06 2007
@@ -168,6 +168,57 @@
             fieldChars.set(i);
         }
     }
+    
+    /**
+     * Creates a stream that strictly validates the input.
+     * @return <code>MimeTokenStream</code> which throws a 
+     * <code>MimeException</code> whenever possible issues 
+     * are dedicated in the input
+     */
+    public static final MimeTokenStream createStrictValidationStream() {
+        return new MimeTokenStream(true);
+    }
+    
+    /**
+     * Enumerates events which can be monitored.
+     */
+    public final static class Event { 
+
+        /** Indicates that a body part ended prematurely. */
+        public static final Event MIME_BODY_PREMATURE_END 
+            = new Event("Body part ended prematurely. " +
+                    "Boundary detected in header or EOF reached."); 
+        /** Indicates that unexpected end of headers detected.*/
+        public static final Event HEADERS_PREMATURE_END 
+            = new Event("Unexpected end of headers detected. " +
+                    "Higher level boundary detected or EOF reached.");
+        
+        private final String code;
+        
+        private Event(final String code) {
+            super();
+            this.code = code;
+        }
+        
+        public int hashCode() {
+            return code.hashCode();
+        }
+
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            final Event other = (Event) obj;
+            return code.equals(other.code);
+        }
+        
+        public String toString() {
+            return code;
+        }
+    }
 
     abstract static class StateMachine {
         int state;
@@ -208,15 +259,10 @@
             state = parseField() ? T_FIELD : T_END_HEADER;
         }
 
-        private int setParseBodyPartState() throws IOException {
+        private int setParseBodyPartState() throws IOException, MimeException {
             cursor.advanceToBoundary();
             if (cursor.isEnded()) {
-                if (log.isWarnEnabled()) {
-                    log.warn("Line " + cursor.getLineNumber() 
-                            + ": Body part ended prematurely. "
-                            + "Higher level boundary detected or "
-                            + "EOF reached.");
-                }
+                monitor(Event.MIME_BODY_PREMATURE_END);
             } else {
                 if (cursor.moreMimeParts()) {
                     final String boundary = body.getBoundary();
@@ -296,7 +342,7 @@
             return state;
         }
 
-        private void initHeaderParsing() throws IOException {
+        private void initHeaderParsing() throws IOException, MimeException {
             body = newBodyDescriptor(parent);
             startLineNumber = lineNumber = cursor.getLineNumber();
 
@@ -314,10 +360,8 @@
                 prev = curr == '\r' ? prev : curr;
             }
             
-            if (curr == -1 && log.isWarnEnabled()) {
-                log.warn("Line " + cursor.getLineNumber()  
-                        + ": Unexpected end of headers detected. "
-                        + "Boundary detected in header or EOF reached.");
+            if (curr == -1) {
+                monitor(Event.HEADERS_PREMATURE_END);
             }
         }
 
@@ -386,12 +430,27 @@
         }
     }
     
+    private final boolean strictParsing;
     private int state = T_END_OF_STREAM;
     private Cursor cursor;
     private StateMachine currentStateMachine;
     private final List entities = new ArrayList();
     private boolean raw;
-
+    
+    /**
+     * Constructs a standard (lax) stream.
+     * Optional validation events will be logged only.
+     * Use {@link #createStrictValidationStream()} to create
+     * a stream that strictly validates the input.
+     */
+    public MimeTokenStream() {
+        this(false);
+    }
+    
+    private MimeTokenStream(final boolean strictParsing) {
+        this.strictParsing = strictParsing;
+    }
+    
     /** Instructs the {@code MimeTokenStream} to parse the given streams contents.
      * If the {@code MimeTokenStream} has already been in use, resets the streams
      * internal state.
@@ -436,7 +495,7 @@
     public void setRaw(boolean raw) {
         this.raw = raw;
     }
-    
+
     /**
      * Finishes the parsing and stops reading lines.
      * NOTE: No more lines will be parsed but the parser
@@ -502,6 +561,70 @@
                 return ((Entity) currentStateMachine).fieldValue;
             default:
                 throw new IllegalStateException("Expected state to be T_FIELD.");
+        }
+    }
+
+    /**
+     * Monitors the given event.
+     * Subclasses may override to perform actions upon events.
+     * Base implementation logs at warn.
+     * @param event <code>Event</code>, not null
+     * @throws MimeException subclasses may elect to throw this exception upon
+     * invalid content
+     * @throws IOException subclasses may elect to throw this exception
+     */
+    protected void monitor(Event event) throws MimeException, IOException {
+        if (strictParsing) {
+            throw new MimeParseEventException(event);
+        } else {
+            warn(event);
+        }
+    }
+    
+    /**
+     * Creates an indicative message suitable for display
+     * based on the given event and the current state of the system.
+     * @param event <code>Event</code>, not null
+     * @return message suitable for use as a message in an exception
+     * or for logging
+     */
+    protected String message(Event event) {
+        String preamble = "";
+        try {
+            preamble = "Line " + cursor.getLineNumber() + ": ";
+        } catch (IOException e) {
+            log.debug("Cannot get event line number.", e);
+        }
+
+        final String message;
+        if (event == null) {
+            message = "Event is unexpectedly null.";
+        } else {
+            message = event.toString();
+        }
+        final String result = preamble + message;
+        return result;
+    }
+    
+    /**
+     * Logs (at warn) an indicative message based on the given event 
+     * and the current state of the system.
+     * @param event <code>Event</code>, not null
+     */
+    protected void warn(Event event) {
+        if (log.isWarnEnabled()) {
+            log.warn(message(event));
+        }
+    }
+    
+    /**
+     * Logs (at debug) an indicative message based on the given event
+     * and the current state of the system.
+     * @param event <code>Event</code>, not null
+     */
+    protected void debug(Event event) {
+        if (log.isDebugEnabled()) {
+            log.debug(message(event));
         }
     }
 

Added: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/StrictMimeTokenStreamTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/StrictMimeTokenStreamTest.java?rev=573847&view=auto
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/StrictMimeTokenStreamTest.java (added)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/StrictMimeTokenStreamTest.java Sat Sep  8 07:35:06 2007
@@ -0,0 +1,57 @@
+/****************************************************************
+ * 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;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+public class StrictMimeTokenStreamTest extends TestCase {
+    
+    private static final String HEADER_ONLY = "From: foo@abr.com\r\nSubject: A subject\r\n";
+    private static final String CORRECT_HEADERS = HEADER_ONLY + "\r\n";
+    
+    public void testUnexpectedEndOfHeaders() throws Exception {
+        
+        MimeTokenStream parser = MimeTokenStream.createStrictValidationStream();
+        
+        parser.parse(new ByteArrayInputStream(HEADER_ONLY.getBytes()));
+        
+        assertEquals("Headers start", MimeTokenStream.T_START_HEADER, parser.next());
+        try {
+            parser.next();
+            fail("Expected exception to be thrown");
+        } catch (MimeParseEventException e) {
+            assertEquals("Premature end of headers", MimeTokenStream.Event.HEADERS_PREMATURE_END, e.getEvent());
+        }
+     }
+    
+    public void testCorrectEndOfHeaders() throws Exception {
+        
+        MimeTokenStream parser = MimeTokenStream.createStrictValidationStream();
+        
+        parser.parse(new ByteArrayInputStream(CORRECT_HEADERS.getBytes()));
+        
+        assertEquals("Headers start", MimeTokenStream.T_START_HEADER, parser.next());
+        assertEquals("From header", MimeTokenStream.T_FIELD, parser.next());
+        assertEquals("Subject header", MimeTokenStream.T_FIELD, parser.next());
+        assertEquals("End message", MimeTokenStream.T_END_HEADER, parser.next());
+     }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: svn commit: r573847 - in /james/mime4j/trunk/src: main/java/org/apache/james/mime4j/MimeParseEventException.java main/java/org/apache/james/mime4j/MimeTokenStream.java test/java/org/apache/james/mime4j/StrictMimeTokenStreamTest.java

Posted by Stefano Bagnara <ap...@bago.org>.
rdonkin@apache.org ha scritto:
> Author: rdonkin
> Date: Sat Sep  8 07:35:06 2007
> New Revision: 573847
> 
> URL: http://svn.apache.org/viewvc?rev=573847&view=rev
> Log:
> Add support for strict validation. Implemented by adding event monitor. Developed in https://issues.apache.org/jira/browse/MIME4J-23.

I suggest you to use the JIRA identifier (MIME4J-23) as a standalone
word, otherwise svn plugin for JIRA does not recognize the commit is
about that issue and does not show it in the issue log.

I found it very useful to see svn commits related to issues in JIRA.

Stefano

PS: welcome back! :-)


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org