Update for Jakarta EE 8 compliancy
git-svn-id: https://svn.apache.org/repos/asf/geronimo/specs/trunk@1864210 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/geronimo-javamail_1.5_spec/pom.xml b/geronimo-javamail_1.5_spec/pom.xml
index 58def12..5d514fc 100644
--- a/geronimo-javamail_1.5_spec/pom.xml
+++ b/geronimo-javamail_1.5_spec/pom.xml
@@ -91,7 +91,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>3.8.2</version>
+ <version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -100,6 +100,15 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.6.1</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<artifactSet>
diff --git a/geronimo-javamail_1.5_spec/src/main/java/javax/mail/internet/HeaderTokenizer.java b/geronimo-javamail_1.5_spec/src/main/java/javax/mail/internet/HeaderTokenizer.java
index 5359e8c..bc47f60 100644
--- a/geronimo-javamail_1.5_spec/src/main/java/javax/mail/internet/HeaderTokenizer.java
+++ b/geronimo-javamail_1.5_spec/src/main/java/javax/mail/internet/HeaderTokenizer.java
@@ -79,18 +79,18 @@
//Return the rest of the Header.
//null is returned if we are already at end of header
public String getRemainder() {
-
+
if(pos > _headerLength) {
return null;
}
-
+
return _header.substring(pos);
}
public Token next() throws ParseException {
return readToken(NUL, false);
}
-
+
/**
* Parses the next token from this String.
* If endOfAtom is not NUL, the token extends until the
@@ -123,10 +123,10 @@
* @since JavaMail 1.5
*/
public Token next(final char endOfAtom, final boolean keepEscapes)
- throws ParseException {
+ throws ParseException {
return readToken(endOfAtom, keepEscapes);
}
-
+
public Token peek() throws ParseException {
final int start = pos;
@@ -150,7 +150,7 @@
while (++pos < _headerLength) {
// break on the first non-atom character.
final char ch = _header.charAt(pos);
-
+
if ((_delimiters.indexOf(_header.charAt(pos)) != -1 || ch < 32 || ch >= 127)) {
break;
}
@@ -179,29 +179,33 @@
} else {
return comment;
}
- // quoted literal
+
+ // quoted literal
} else if (c == '\"') {
return readQuotedString('"', keepEscapes, 1);
+
// white space, eat this and find a real token.
} else if (WHITE.indexOf(c) != -1) {
eatWhiteSpace();
return readToken(endOfAtom, keepEscapes);
+
// either a CTL or special. These characters have a self-defining token type.
} else if (c < 32 || c >= 127 || _delimiters.indexOf(c) != -1) {
-
+
if (endOfAtom != NUL && c != endOfAtom) {
return readQuotedString(endOfAtom, keepEscapes, 0);
}
-
-
+
+
pos++;
return new Token(c, String.valueOf(c));
+
} else {
// start of an atom, parse it off.
if (endOfAtom != NUL && c != endOfAtom) {
return readQuotedString(endOfAtom, keepEscapes, 0);
}
-
+
return readAtomicToken();
}
}
@@ -228,11 +232,11 @@
if (i == end) {
throw new ParseException("Invalid escape character");
}
-
+
if(keepEscapes) {
value.append("\\");
}
-
+
value.append(_header.charAt(i));
}
// line breaks are ignored, except for naked '\n' characters, which are consider
@@ -244,7 +248,7 @@
}
}
else {
-
+
// just append the ch value.
value.append(ch);
}
@@ -336,7 +340,21 @@
}
}
- throw new ParseException("Missing '\"'");
+ // we ran out of chars in the string. If the end char is a quote, then there
+ // is a missing quote somewhere
+ if (endChar == '"') {
+ throw new ParseException("Missing '\"'");
+ }
+
+ // otherwise, we can just return whatever is left
+ String value;
+ if (requiresEscaping) {
+ value = getEscapedValue(start, pos, keepEscapes);
+
+ } else {
+ value = _header.substring(start, pos);
+ }
+ return new Token(Token.QUOTEDSTRING, trimWhiteSpace(value));
}
/**
@@ -346,7 +364,54 @@
// skip to end of whitespace
while (++pos < _headerLength
&& WHITE.indexOf(_header.charAt(pos)) != -1) {
- ;
- }
+ ;
+ }
}
+
+ /**
+ * linear white spaces must be removed from quoted text or text
+ *
+ LWSP-char = SPACE / HTAB ; semantics = SPACE
+
+ linear-white-space = 1*([CRLF] LWSP-char) ; semantics = SPACE
+ ; CRLF => folding
+
+ text = <any CHAR, including bare ; => atoms, specials,
+ CR & bare LF, but NOT ; comments and
+ including CRLF> ; quoted-strings are
+ ; NOT recognized.
+
+ atom = 1*<any CHAR except specials, SPACE and CTLs>
+
+ quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
+ ; quoted chars.
+
+ qtext = <any CHAR excepting <">, ; => may be folded
+ "\" & CR, and including
+ linear-white-space>
+
+ domain-literal = "[" *(dtext / quoted-pair) "]"
+ */
+ private static String trimWhiteSpace(final String s) {
+ char c;
+ int i;
+ for (i = s.length() - 1; i >= 0; i--) {
+ if ((
+ (c = s.charAt(i)) != ' ') && // space
+ (c != '\t') && // tab
+ (c != '\r') && // CR
+ (c != '\n')) { // LF
+
+ break;
+ }
+ }
+
+ if (i <= 0) {
+ return "";
+
+ } else {
+ return s.substring(0, i + 1);
+ }
+ }
+
}
diff --git a/geronimo-javamail_1.5_spec/src/test/java/javax/mail/internet/HeaderTokenizerTest.java b/geronimo-javamail_1.5_spec/src/test/java/javax/mail/internet/HeaderTokenizerTest.java
index 13cbec3..7b87892 100644
--- a/geronimo-javamail_1.5_spec/src/test/java/javax/mail/internet/HeaderTokenizerTest.java
+++ b/geronimo-javamail_1.5_spec/src/test/java/javax/mail/internet/HeaderTokenizerTest.java
@@ -20,7 +20,6 @@
package javax.mail.internet;
import javax.mail.internet.HeaderTokenizer.Token;
-
import junit.framework.TestCase;
/**
@@ -28,10 +27,8 @@
*/
public class HeaderTokenizerTest extends TestCase {
public void testTokenizer() throws ParseException {
- final Token t;
- HeaderTokenizer ht;
- ht =
- new HeaderTokenizer("To: \"Geronimo List\" <geronimo-dev@apache.org>, \n\r Geronimo User <geronimo-user@apache.org>");
+
+ HeaderTokenizer ht = new HeaderTokenizer("To: \"Geronimo List\" <geronimo-dev@apache.org>, \n\r Geronimo User <geronimo-user@apache.org>");
validateToken(ht.peek(), Token.ATOM, "To");
validateToken(ht.next(), Token.ATOM, "To");
validateToken(ht.peek(), ':', ":");
@@ -57,11 +54,14 @@
validateToken(ht.next(), Token.ATOM, "org");
validateToken(ht.next(), '>', ">");
assertEquals(Token.EOF, ht.next().getType());
+
ht = new HeaderTokenizer(" ");
assertEquals(Token.EOF, ht.next().getType());
+
ht = new HeaderTokenizer("J2EE");
validateToken(ht.next(), Token.ATOM, "J2EE");
assertEquals(Token.EOF, ht.next().getType());
+
// test comments
doComment(true);
doComment(false);
@@ -95,23 +95,17 @@
}
public void testJavaMail15NextMethod() throws ParseException{
- HeaderTokenizer ht;
- ht =
- new HeaderTokenizer("To: \"Geronimo List\\\" <geronimo-dev@apache.org>, \n\r Geronimo User <geronimo-user@apache.org>");
+ HeaderTokenizer ht = new HeaderTokenizer("To: \"Geronimo List\\\" <geronimo-dev@apache.org>, \n\r Geronimo User <geronimo-user@apache.org>");
validateToken(ht.next('>', false), Token.QUOTEDSTRING, "To: \"Geronimo List\" <geronimo-dev@apache.org");
}
public void testJavaMail15NextMethodEscapes() throws ParseException{
- HeaderTokenizer ht;
- ht =
- new HeaderTokenizer("To: \"Geronimo List\\\" <geronimo-dev@apache.org>, \n\r Geronimo User <geronimo-user@apache.org>");
+ HeaderTokenizer ht = new HeaderTokenizer("To: \"Geronimo List\\\" <geronimo-dev@apache.org>, \n\r Geronimo User <geronimo-user@apache.org>");
validateToken(ht.next('<', true), Token.QUOTEDSTRING, "To: \"Geronimo List\\\" ");
}
public void testJavaMail15NextMethodEscapes2() throws ParseException{
- HeaderTokenizer ht;
- ht =
- new HeaderTokenizer("To: \"Geronimo List\" <geronimo-dev@apac\\he.org>, \n\r Geronimo User <geronimo-user@apache.org>");
+ HeaderTokenizer ht = new HeaderTokenizer("To: \"Geronimo List\" <geronimo-dev@apac\\he.org>, \n\r Geronimo User <geronimo-user@apache.org>");
ht.next();
ht.next();
ht.next();
@@ -119,9 +113,7 @@
}
public void testJavaMail15NextMethodEscapes3() throws ParseException{
- HeaderTokenizer ht;
- ht =
- new HeaderTokenizer("To: \"Geronimo List\" <geronimo-dev@apac\\he.org>, \n\r Geronimo User <geronimo-user@apache.org>");
+ HeaderTokenizer ht = new HeaderTokenizer("To: \"Geronimo List\" <geronimo-dev@apac\\he.org>, \n\r Geronimo User <geronimo-user@apache.org>");
ht.next();
ht.next();
ht.next();
@@ -129,18 +121,15 @@
}
public void checkTokenParse(final String text, final int type, final String value) throws ParseException {
- HeaderTokenizer ht;
- ht = new HeaderTokenizer(text, HeaderTokenizer.RFC822, false);
+ HeaderTokenizer ht = new HeaderTokenizer(text, HeaderTokenizer.RFC822, false);
validateToken(ht.next(), type, value);
}
public void checkParseError(final String text) throws ParseException {
- final Token t;
- HeaderTokenizer ht;
-
- ht = new HeaderTokenizer(text);
+ HeaderTokenizer ht = new HeaderTokenizer(text);
doNextError(ht);
+
ht = new HeaderTokenizer(text);
doPeekError(ht);
}
@@ -164,13 +153,12 @@
public void doComment(final boolean ignore) throws ParseException {
HeaderTokenizer ht;
- final Token t;
- ht =
- new HeaderTokenizer(
+ ht = new HeaderTokenizer(
"Apache(Geronimo)J2EE",
HeaderTokenizer.RFC822,
ignore);
validateToken(ht.next(), Token.ATOM, "Apache");
+
if (!ignore) {
validateToken(ht.next(), Token.COMMENT, "Geronimo");
}
@@ -182,6 +170,8 @@
"Apache(Geronimo (Project))J2EE",
HeaderTokenizer.RFC822,
ignore);
+
+
validateToken(ht.next(), Token.ATOM, "Apache");
if (!ignore) {
validateToken(ht.next(), Token.COMMENT, "Geronimo (Project)");
@@ -194,4 +184,122 @@
assertEquals(type, token.getType());
assertEquals(value, token.getValue());
}
+
+ private transient TestCase[] testCases = { new TestCase(';', "a=b c", "b c"),
+ new TestCase(';', "a=b c; d=e f", "b c"),
+ new TestCase(';', "a=\"b c\"; d=e f", "b c") };
+
+ private transient TestCase[] testCasesEsc = {
+ new TestCase(';', "a=b \\c", "b \\c"),
+ new TestCase(';', "a=b c; d=e f", "b c"),
+ new TestCase(';', "a=\"b \\c\"; d=e f", "b \\c") };
+
+ public void testNext() throws Exception {
+
+ final String value = "ggere, /tmp/mail.out, +mailbox, ~user/mailbox, ~/mailbox, /PN=x400.address/PRMD=ibmmail/ADMD=ibmx400/C=us/@mhs-mci.ebay, " +
+ "C'est bien moche <paris@france>, Mad Genius <george@boole>, two@weeks (It Will Take), /tmp/mail.out, laborious (But Bug Free), " +
+ "cannot@waste (My, Intellectual, Cycles), users:get,what,they,deserve;, it (takes, no (time, at) all), " +
+ "if@you (could, see (almost, as, (badly, you) would) agree), famous <French@physicists>, " +
+ "it@is (brilliant (genius, and) superb), confused (about, being, french)";
+
+ // Create HeaderTokenizer object
+ HeaderTokenizer ht = new HeaderTokenizer(value,
+ HeaderTokenizer.RFC822,
+ true);
+
+ HeaderTokenizer.Token token;
+
+ while ((token = ht.next()).getType() != HeaderTokenizer.Token.EOF) { // API
+ if (token.getType() == 0 || token.getValue() == null) {
+ fail(type(token.getType()) + "\t" + token.getValue());
+ }
+ }
+ }
+
+ public void testNext2() throws Exception {
+
+ // Create HeaderTokenizer object
+ HeaderTokenizer ht;
+ HeaderTokenizer.Token token;
+
+ for (TestCase tc : testCases) {
+ ht = new HeaderTokenizer(tc.test, HeaderTokenizer.MIME, true);
+ token = ht.next();
+ if (token.getType() != HeaderTokenizer.Token.ATOM || !token.getValue().equals("a")) {
+ System.out.println("\t" + type(token.getType()) + "\t" + token.getValue());
+ fail();
+
+ } else {
+ token = ht.next();
+ if (token.getType() != '=') {
+ System.out.println("\t" + type(token.getType()) + "\t" + token.getValue());
+ fail();
+ } else {
+ token = ht.next(tc.endOfAtom);
+ if (token.getType() != HeaderTokenizer.Token.QUOTEDSTRING
+ || !token.getValue().equals(tc.expected)) {
+ fail(type(token.getType()) + "\t" + token.getValue());
+ }
+ }
+ }
+ }
+ }
+
+ public void testNext3() throws Exception {
+
+ // Create HeaderTokenizer object
+ HeaderTokenizer ht;
+ HeaderTokenizer.Token token;
+
+ for (TestCase tc : testCasesEsc) {
+ ht = new HeaderTokenizer(tc.test, HeaderTokenizer.MIME, true);
+ token = ht.next();
+ if (token.getType() != HeaderTokenizer.Token.ATOM || !token.getValue().equals("a")) {
+ System.out.println("\t" + type(token.getType()) + "\t" + token.getValue());
+ fail();
+ } else {
+ token = ht.next();
+ if (token.getType() != '=') {
+ System.out.println("\t" + type(token.getType()) + "\t" + token.getValue());
+ fail();
+ } else {
+ token = ht.next(tc.endOfAtom, true);
+ if (token.getType() != HeaderTokenizer.Token.QUOTEDSTRING
+ || !token.getValue().equals(tc.expected)) {
+ fail(type(token.getType()) + "\t" + token.getValue());
+ }
+ }
+ }
+ }
+
+ }
+
+ private static String type(int t) {
+ if (t == HeaderTokenizer.Token.ATOM)
+ return "ATOM";
+ else if (t == HeaderTokenizer.Token.QUOTEDSTRING)
+ return "QUOTEDSTRING";
+ else if (t == HeaderTokenizer.Token.COMMENT)
+ return "COMMENT";
+ else if (t == HeaderTokenizer.Token.EOF)
+ return "EOF";
+ else if (t < 0)
+ return "UNKNOWN";
+ else
+ return "SPECIAL";
+ }
+
+ static class TestCase {
+
+ public TestCase(final char endOfAtom, final String test, String expected) {
+ this.endOfAtom = endOfAtom;
+ this.test = test;
+ this.expected = expected;
+ }
+
+ public char endOfAtom;
+ public String test;
+ public String expected;
+ };
+
}