Project: javamail
Repository: mercurial
Revision: 833
Author: shannon
Date: 2016-06-25 00:15:25 UTC
Link:
Log Message:
------------
Store finalizers should not talk to server - bug 7472
fix possible NPE if SASL is enabled on Android - bug 7512
kludge WriteTimeoutSocket to work properly on Android - bug 7513
fix javadoc error
MailHandler verify should load additional content handlers - Bug K7506
MailHandlerTest add content type of formatter test.
MailHandlerDemo correct javadoc example.
(From Jason)
Revisions:
----------
829
830
831
832
833
Modified Paths:
---------------
doc/release/CHANGES.txt
doc/release/COMPAT.txt
mail/src/main/java/com/sun/mail/imap/IMAPStore.java
mail/src/main/java/com/sun/mail/imap/package.html
mail/src/main/java/com/sun/mail/pop3/POP3Folder.java
mail/src/main/java/com/sun/mail/pop3/POP3Store.java
mail/src/main/java/com/sun/mail/pop3/Protocol.java
mail/src/main/java/com/sun/mail/pop3/package.html
mail/src/main/java/com/sun/mail/util/WriteTimeoutSocket.java
mail/src/test/java/com/sun/mail/test/ProtocolHandler.java
mail/src/test/java/com/sun/mail/util/WriteTimeoutSocketTest.java
mail/src/main/java/com/sun/mail/smtp/SMTPTransport.java
logging/src/main/java/MailHandlerDemo.java
mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
Diffs:
------
diff -r b141c179a836 -r 4d54159387fe doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Tue Jun 14 14:18:45 2016 -0700
+++ b/doc/release/CHANGES.txt Fri Jun 24 16:42:22 2016 -0700
@@ -31,6 +31,7 @@
K 7378 Deadlock in IMAPFolder.doProtocolCommand()
K 7471 InternetAddress.getLocalAddress should use
InetAddress.getCanonicalHostName
+K 7472 Store finalizers should not talk to server
CHANGES IN THE 1.5.5 RELEASE
diff -r b141c179a836 -r 4d54159387fe doc/release/COMPAT.txt
--- a/doc/release/COMPAT.txt Tue Jun 14 14:18:45 2016 -0700
+++ b/doc/release/COMPAT.txt Fri Jun 24 16:42:22 2016 -0700
@@ -16,6 +16,20 @@
-- JavaMail 1.5.6 --
+- finalizers close sockets abruptly
+
+ It's important for finalizers to close an open socket
+ connection to prevent file descriptor leaks. Previously the
+ finalizers for the IMAP and POP3 providers would try to close
+ the connection cleanly, which could result in a timeout waiting
+ for the server. They now close the connection without
+ performing any socket I/O, which may result in an unclean
+ shutdown when seen from the server. Applications should always
+ close Stores and Folders when done with them to avoid the need
+ for the finalizer to do this cleanup. The Session property
+ "mail.<protocol>.finalizecleanclose" can be set to "true" to
+ force the connection to be closed cleanly in the finalizer.
+
- InternetAddress.getLocalAddress uses canonical host name
The InternetAddress.getLocalAddress method now uses the
diff -r b141c179a836 -r 4d54159387fe mail/src/main/java/com/sun/mail/imap/IMAPStore.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Tue Jun 14 14:18:45 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Fri Jun 24 16:42:22 2016 -0700
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
@@ -225,6 +225,7 @@
private boolean peek = false;
private boolean closeFoldersOnStoreFailure = true;
private boolean enableCompress = false; // enable COMPRESS=DEFLATE
+ private boolean finalizeCleanClose = false;
/*
* This field is set in the Store's response handler if we see
@@ -598,6 +599,12 @@
if (enableCompress)
logger.config("enable COMPRESS");
+ // check if finalizeCleanClose is enabled
+ finalizeCleanClose = PropUtil.getBooleanSessionProperty(session,
+ "mail." + name + ".finalizecleanclose", false);
+ if (finalizeCleanClose)
+ logger.config("close connection cleanly in finalize");
+
s = session.getProperty("mail." + name + ".folder.class");
if (s != null) {
logger.log(Level.CONFIG, "IMAP: folder class: {0}", s);
@@ -1662,6 +1669,14 @@
}
protected void finalize() throws Throwable {
+ if (!finalizeCleanClose) {
+ // when finalizing, close connections abruptly
+ synchronized (connectionFailedLock) {
+ connectionFailed = true;
+ forceClose = true;
+ }
+ closeFoldersOnStoreFailure = true; // make sure folders get closed
+ }
try {
close();
} finally {
diff -r b141c179a836 -r 4d54159387fe mail/src/main/java/com/sun/mail/imap/package.html
--- a/mail/src/main/java/com/sun/mail/imap/package.html Tue Jun 14 14:18:45 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/package.html Fri Jun 24 16:42:22 2016 -0700
@@ -5,7 +5,7 @@
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 2 only ("GPL") or the Common Development
@@ -867,6 +867,20 @@
</TD>
</TR>
+<A NAME="mail.imap.finalizecleanclose"></A>
+<TR id="mail.imap.finalizecleanclose">
+<TD>mail.imap.finalizecleanclose</TD>
+<TD>boolean</TD>
+<TD>
+When the finalizer for IMAPStore is called,
+should the connection to the server be closed cleanly, as if the
+application called the close method?
+Or should the connection to the server be closed without sending
+any commands to the server?
+Defaults to false, the connection is not closed cleanly.
+</TD>
+</TR>
+
<A NAME="mail.imap.referralexception"></A>
<TR id="mail.imap.referralexception">
<TD>mail.imap.referralexception</TD>
diff -r b141c179a836 -r 4d54159387fe mail/src/main/java/com/sun/mail/pop3/POP3Folder.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Folder.java Tue Jun 14 14:18:45 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Folder.java Fri Jun 24 16:42:22 2016 -0700
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
@@ -75,6 +75,7 @@
private POP3Message[] message_cache;
private boolean doneUidl = false;
private volatile TempFile fileCache = null;
+ private boolean forceClose;
MailLogger logger; // package private, for POP3Message
@@ -250,10 +251,10 @@
* the "marked for deletion" flags. We can then explicitly
* delete messages as desired.
*/
- if (store.rsetBeforeQuit)
+ if (store.rsetBeforeQuit && !forceClose)
port.rset();
POP3Message m;
- if (expunge && mode == READ_WRITE) {
+ if (expunge && mode == READ_WRITE && !forceClose) {
// find all messages marked deleted and issue DELE commands
for (int i = 0; i < message_cache.length; i++) {
if ((m = message_cache[i]) != null) {
@@ -277,7 +278,10 @@
m.invalidate(true);
}
- port.quit();
+ if (forceClose)
+ port.close();
+ else
+ port.quit();
} catch (IOException ex) {
// do nothing
} finally {
@@ -545,11 +549,13 @@
* Close the folder when we're finalized.
*/
protected void finalize() throws Throwable {
+ forceClose = !store.finalizeCleanClose;
try {
if (opened)
close(false);
} finally {
super.finalize();
+ forceClose = false;
}
}
diff -r b141c179a836 -r 4d54159387fe mail/src/main/java/com/sun/mail/pop3/POP3Store.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Tue Jun 14 14:18:45 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Fri Jun 24 16:42:22 2016 -0700
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
@@ -95,6 +95,7 @@
volatile boolean useFileCache = false;
volatile File fileCacheDir = null;
volatile boolean keepMessageContent = false;
+ volatile boolean finalizeCleanClose = false;
public POP3Store(Session session, URLName url) {
this(session, url, "pop3", false);
@@ -136,6 +137,9 @@
// mail.pop3.starttls.required requires use of STLS command
requireStartTLS = getBoolProp("starttls.required");
+ // mail.pop3.finalizecleanclose requires clean close when finalizing
+ finalizeCleanClose = getBoolProp("finalizecleanclose");
+
String s = session.getProperty("mail." + name + ".message.class");
if (s != null) {
logger.log(Level.CONFIG, "message class: {0}", s);
@@ -341,9 +345,17 @@
}
public synchronized void close() throws MessagingException {
+ close(false);
+ }
+
+ synchronized void close(boolean force) throws MessagingException {
try {
- if (port != null)
- port.quit();
+ if (port != null) {
+ if (force)
+ port.close();
+ else
+ port.quit();
+ }
} catch (IOException ioex) {
} finally {
port = null;
@@ -410,7 +422,7 @@
protected void finalize() throws Throwable {
try {
if (port != null) // don't force a connection attempt
- close();
+ close(!finalizeCleanClose);
} finally {
super.finalize();
}
diff -r b141c179a836 -r 4d54159387fe mail/src/main/java/com/sun/mail/pop3/Protocol.java
--- a/mail/src/main/java/com/sun/mail/pop3/Protocol.java Tue Jun 14 14:18:45 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/Protocol.java Fri Jun 24 16:42:22 2016 -0700
@@ -346,18 +346,27 @@
Response r = simpleCommand("QUIT");
ok = r.ok;
} finally {
- try {
- socket.close();
- } finally {
- socket = null;
- input = null;
- output = null;
- }
+ close();
}
return ok;
}
/**
+ * Close the connection without sending any commands.
+ */
+ void close() {
+ try {
+ socket.close();
+ } catch (IOException ex) {
+ // ignore it
+ } finally {
+ socket = null;
+ input = null;
+ output = null;
+ }
+ }
+
+ /**
* Return the total number of messages and mailbox size,
* using the STAT command.
*/
diff -r b141c179a836 -r 4d54159387fe mail/src/main/java/com/sun/mail/pop3/package.html
--- a/mail/src/main/java/com/sun/mail/pop3/package.html Tue Jun 14 14:18:45 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/package.html Fri Jun 24 16:42:22 2016 -0700
@@ -5,7 +5,7 @@
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 2 only ("GPL") or the Common Development
@@ -606,6 +606,20 @@
</TD>
</TR>
+<A NAME="mail.pop3.finalizecleanclose"></A>
+<TR id="mail.pop3.finalizecleanclose">
+<TD>mail.pop3.finalizecleanclose</TD>
+<TD>boolean</TD>
+<TD>
+When the finalizer for POP3Store or POP3Folder is called,
+should the connection to the server be closed cleanly, as if the
+application called the close method?
+Or should the connection to the server be closed without sending
+any commands to the server?
+Defaults to false, the connection is not closed cleanly.
+</TD>
+</TR>
+
</TABLE>
<P>
In general, applications should not need to use the classes in this
diff -r 4d54159387fe -r ee2c77a43ffc doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Jun 24 16:42:22 2016 -0700
+++ b/doc/release/CHANGES.txt Fri Jun 24 16:43:55 2016 -0700
@@ -32,6 +32,7 @@
K 7471 InternetAddress.getLocalAddress should use
InetAddress.getCanonicalHostName
K 7472 Store finalizers should not talk to server
+K 7512 NullPointerException if SASL is enabled on Android
CHANGES IN THE 1.5.5 RELEASE
diff -r 4d54159387fe -r ee2c77a43ffc mail/src/main/java/com/sun/mail/imap/IMAPStore.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Fri Jun 24 16:42:22 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Fri Jun 24 16:43:55 2016 -0700
@@ -720,8 +720,9 @@
if (protocol != null)
protocol.disconnect();
protocol = null;
+ Response r = cex.getResponse();
throw new AuthenticationFailedException(
- cex.getResponse().getRest());
+ r != null ? r.getRest() : cex.getMessage());
} catch (ProtocolException pex) { // any other exception
// failure in login command, close connection to server
if (protocol != null)
diff -r ee2c77a43ffc -r ca92e4135bef doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Jun 24 16:43:55 2016 -0700
+++ b/doc/release/CHANGES.txt Fri Jun 24 16:54:11 2016 -0700
@@ -33,6 +33,7 @@
InetAddress.getCanonicalHostName
K 7472 Store finalizers should not talk to server
K 7512 NullPointerException if SASL is enabled on Android
+K 7513 write timeouts don't work with SSL on Android
CHANGES IN THE 1.5.5 RELEASE
diff -r ee2c77a43ffc -r ca92e4135bef mail/src/main/java/com/sun/mail/util/WriteTimeoutSocket.java
--- a/mail/src/main/java/com/sun/mail/util/WriteTimeoutSocket.java Fri Jun 24 16:43:55 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/util/WriteTimeoutSocket.java Fri Jun 24 16:54:11 2016 -0700
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright (c) 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
@@ -44,6 +44,7 @@
import java.net.*;
import java.util.concurrent.*;
import java.nio.channels.SocketChannel;
+import java.lang.reflect.*;
/**
* A special Socket that uses a ScheduledExecutorService to
@@ -118,6 +119,22 @@
}
@Override
+ public SocketAddress getRemoteSocketAddress() {
+ return socket.getRemoteSocketAddress();
+ }
+
+ @Override
+ public SocketAddress getLocalSocketAddress() {
+ return socket.getLocalSocketAddress();
+ }
+
+ @Override
+ public void setPerformancePreferences(int connectionTime, int latency,
+ int bandwidth) {
+ socket.setPerformancePreferences(connectionTime, latency, bandwidth);
+ }
+
+ @Override
public SocketChannel getChannel() {
return socket.getChannel();
}
@@ -296,6 +313,18 @@
public boolean isOutputShutdown() {
return socket.isOutputShutdown();
}
+
+ /**
+ * KLUDGE for Android, which has this illegal non-Java Compatible method.
+ */
+ public FileDescriptor getFileDescriptor$() {
+ try {
+ Method m = Socket.class.getDeclaredMethod("getFileDescriptor$");
+ return (FileDescriptor)m.invoke(socket);
+ } catch (Exception ex) {
+ return null;
+ }
+ }
}
diff -r ee2c77a43ffc -r ca92e4135bef mail/src/test/java/com/sun/mail/test/ProtocolHandler.java
--- a/mail/src/test/java/com/sun/mail/test/ProtocolHandler.java Fri Jun 24 16:43:55 2016 -0700
+++ b/mail/src/test/java/com/sun/mail/test/ProtocolHandler.java Fri Jun 24 16:54:11 2016 -0700
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright (c) 2009-2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
@@ -48,6 +48,7 @@
import java.net.SocketException;
import java.util.logging.Logger;
import java.util.logging.Level;
+import javax.net.ssl.SSLException;
/**
* Handle protocol connection.
@@ -113,6 +114,8 @@
//clientSocket.close();
} catch (SocketException sex) {
// ignore it, often get "connection reset" when client closes
+ } catch (SSLException sex) {
+ // ignore it, often occurs when testing SSL
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error", e);
} finally {
diff -r ee2c77a43ffc -r ca92e4135bef mail/src/test/java/com/sun/mail/util/WriteTimeoutSocketTest.java
--- a/mail/src/test/java/com/sun/mail/util/WriteTimeoutSocketTest.java Fri Jun 24 16:43:55 2016 -0700
+++ b/mail/src/test/java/com/sun/mail/util/WriteTimeoutSocketTest.java Fri Jun 24 16:54:11 2016 -0700
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright (c) 2009-2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2016 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
@@ -40,11 +40,15 @@
package com.sun.mail.util;
+import java.lang.reflect.*;
+
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Properties;
import java.util.List;
import java.util.ArrayList;
+import java.util.Set;
+import java.util.HashSet;
import javax.mail.*;
import javax.mail.internet.MimeMessage;
@@ -142,6 +146,40 @@
assertTrue(sf.getSocketWrapped() || sf.getSocketCreated());
}
+ /**
+ * Test that WriteTimeoutSocket overrides all methods from Socket.
+ * XXX - this is kind of hacky since it depends on Method.toString
+ */
+ @Test
+ public void testOverrides() throws Exception {
+ Set<String> socketMethods = new HashSet<String>();
+ Method[] m = java.net.Socket.class.getDeclaredMethods();
+ String className = java.net.Socket.class.getName() + ".";
+ for (int i = 0; i < m.length; i++) {
+ if (Modifier.isPublic(m[i].getModifiers()) &&
+ !Modifier.isStatic(m[i].getModifiers())) {
+ String name = m[i].toString().
+ replace("synchronized ", "").
+ replace(className, "");
+ socketMethods.add(name);
+ }
+ }
+ Set<String> wtsocketMethods = new HashSet<String>();
+ m = WriteTimeoutSocket.class.getDeclaredMethods();
+ className = WriteTimeoutSocket.class.getName() + ".";
+ for (int i = 0; i < m.length; i++) {
+ if (Modifier.isPublic(m[i].getModifiers())) {
+ String name = m[i].toString().
+ replace("synchronized ", "").
+ replace(className, "");
+ socketMethods.remove(name);
+ }
+ }
+ for (String s : socketMethods)
+ System.out.println("WriteTimeoutSocket did not override: " + s);
+ assertTrue(socketMethods.isEmpty());
+ }
+
private static String[] getAnonCipherSuitesArray() {
SSLSocketFactory sf = (SSLSocketFactory)SSLSocketFactory.getDefault();
List<String> anon = new ArrayList<String>();
diff -r ca92e4135bef -r 9031f1e5787a mail/src/main/java/com/sun/mail/smtp/SMTPTransport.java
--- a/mail/src/main/java/com/sun/mail/smtp/SMTPTransport.java Fri Jun 24 16:54:11 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/smtp/SMTPTransport.java Fri Jun 24 17:13:19 2016 -0700
@@ -652,7 +652,7 @@
* @param host the name of the host to connect to
* @param port the port to use (-1 means use default port)
* @param user the name of the user to login as
- * @param passwd the user's password
+ * @param password the user's password
* @return true if connection successful, false if authentication failed
* @exception MessagingException for non-authentication failures
*/
diff -r 9031f1e5787a -r 9b7804254f97 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Jun 24 17:13:19 2016 -0700
+++ b/doc/release/CHANGES.txt Fri Jun 24 17:15:25 2016 -0700
@@ -32,6 +32,7 @@
K 7471 InternetAddress.getLocalAddress should use
InetAddress.getCanonicalHostName
K 7472 Store finalizers should not talk to server
+K 7506 MailHandler verify should load additional content handlers
K 7512 NullPointerException if SASL is enabled on Android
K 7513 write timeouts don't work with SSL on Android
diff -r 9031f1e5787a -r 9b7804254f97 logging/src/main/java/MailHandlerDemo.java
--- a/logging/src/main/java/MailHandlerDemo.java Fri Jun 24 17:13:19 2016 -0700
+++ b/logging/src/main/java/MailHandlerDemo.java Fri Jun 24 17:15:25 2016 -0700
@@ -49,7 +49,7 @@
/**
* Demo for the different configurations for the MailHandler. If the logging
* properties file or class is not specified then this demo will apply some
- * default settings to store emails in the users temp dir.
+ * default settings to store emails in the user's temp directory.
*
* @author Jason Mehrens
*/
@@ -440,9 +440,8 @@
* com.sun.mail.util.logging.MailHandler.level=ALL
* java.util.logging.MemoryHandler.level=ALL
* java.util.logging.MemoryHandler.push=WARNING
- * com.sun.mail.util.logging.MailHandler.subject=Push on MessagingException demo
- * com.sun.mail.util.logging.MailHandler.pushLevel=ALL
- * com.sun.mail.util.logging.MailHandler.pushFilter=MailHandlerDemo$MessageErrorsFilter
+ * com.sun.mail.util.logging.MailHandler.subject=Push only demo
+ * com.sun.mail.util.logging.MailHandler.pushLevel=WARNING
* ##
* </code>
*/
@@ -658,4 +657,12 @@
}
return file;
}
+
+ /**
+ * No objects are allowed.
+ * @throws IllegalAccessException always.
+ */
+ private MailHandlerDemo() throws IllegalAccessException {
+ throw new IllegalAccessException();
+ }
}
diff -r 9031f1e5787a -r 9b7804254f97 mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
--- a/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Fri Jun 24 17:13:19 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Fri Jun 24 17:15:25 2016 -0700
@@ -384,16 +384,17 @@
* prepared to deal with unexpected null values since the
* WebappClassLoader.clearReferencesThreadLocals() and
* InnocuousThread.eraseThreadLocals() can remove thread local values.
- * The MUTEX has 4 states:
+ * The MUTEX has 5 states:
* 1. A null value meaning default state of not publishing.
* 2. MUTEX_PUBLISH on first entry of a push or publish.
* 3. The index of the first filter to accept a log record.
* 4. MUTEX_REPORT when cycle of records is detected.
+ * 5. MUTEXT_LINKAGE when a linkage error is reported.
*/
private static final ThreadLocal<Integer> MUTEX = new ThreadLocal<Integer>();
/**
* The marker object used to report a publishing state.
- * This must be less than the body filter index.
+ * This must be less than the body filter index (-1).
*/
private static final Integer MUTEX_PUBLISH = -2;
/**
@@ -1632,6 +1633,39 @@
return null; //text/plain
}
+ /**
+ * Determines the mimeType of a formatter by the class name. This method
+ * avoids calling getHead and getTail of content formatters during verify
+ * because they might trigger side effects or excessive work. The name
+ * formatters and subject are usually safe to call.
+ * Package-private for unit testing.
+ *
+ * @param f the formatter or null.
+ * @return return the mime type or text/plain.
+ * @since JavaMail 1.5.6
+ */
+ final String contentTypeOf(final Formatter f) {
+ if (f != null) {
+ for (Class<?> k = f.getClass(); k != Formatter.class;
+ k = k.getSuperclass()) {
+ String name = k.getName().toLowerCase(Locale.ENGLISH);
+ for (int idx = name.indexOf('$') + 1;
+ (idx = name.indexOf("ml", idx)) > -1; idx += 2) {
+ if (idx > 0) {
+ if (name.charAt(idx - 1) == 'x') {
+ return "application/xml";
+ }
+ if (idx > 1 && name.charAt(idx - 2) == 'h'
+ && name.charAt(idx - 1) == 't') {
+ return "text/html";
+ }
+ }
+ }
+ }
+ }
+ return "text/plain";
+ }
+
/**
* Determines if the given throwable is a no content exception. It is
* assumed Transport.sendMessage will call Message.writeTo so we need to
@@ -1677,12 +1711,14 @@
*/
@SuppressWarnings("UseSpecificCatch")
private void reportError(Message msg, Exception ex, int code) {
- try { //Use direct call so we do not prefix raw email.
- errorManager.error(toRawString(msg), ex, code);
- } catch (final RuntimeException re) {
- reportError(toMsgString(re), ex, code);
- } catch (final Exception e) {
- reportError(toMsgString(e), ex, code);
+ try {
+ try { //Use direct call so we do not prefix raw email.
+ errorManager.error(toRawString(msg), ex, code);
+ } catch (final RuntimeException re) {
+ reportError(toMsgString(re), ex, code);
+ } catch (final Exception e) {
+ reportError(toMsgString(e), ex, code);
+ }
} catch (final LinkageError GLASSFISH_21258) {
reportLinkageError(GLASSFISH_21258, code);
}
@@ -1798,7 +1834,7 @@
* Sets the capacity for this handler. This method is kept private
* because we would have to define a public policy for when the size is
* greater than the capacity.
- * I.E. do nothing, flush now, truncate now, push now and resize.
+ * E.G. do nothing, flush now, truncate now, push now and resize.
* @param newCapacity the max number of records.
* @throws SecurityException if a security manager exists and the
* caller does not have <tt>LoggingPermission("control")</tt>.
@@ -2998,9 +3034,19 @@
}
//Perform all of the copy actions first.
+ String[] atn;
synchronized (this) { //Create the subject.
appendSubject(abort, head(subjectFormatter));
appendSubject(abort, tail(subjectFormatter, ""));
+ atn = new String[attachmentNames.length];
+ for (int i = 0; i < atn.length; ++i) {
+ atn[i] = head(attachmentNames[i]);
+ if (atn[i].length() == 0) {
+ atn[i] = tail(attachmentNames[i], "");
+ } else {
+ atn[i] = atn[i].concat(tail(attachmentNames[i], ""));
+ }
+ }
}
setIncompleteCopy(abort); //Original body part is never added.
@@ -3151,13 +3197,29 @@
try { //Verify that the DataHandler can be loaded.
Object ccl = getAndSetContextClassLoader(MAILHANDLER_LOADER);
try {
- final MimeMultipart multipart = new MimeMultipart();
- final MimeBodyPart body = new MimeBodyPart();
- body.setDisposition(Part.INLINE);
+ MimeMultipart multipart = new MimeMultipart();
+ MimeBodyPart[] ambp = new MimeBodyPart[atn.length];
+ final MimeBodyPart body;
+ final String bodyContentType;
+ synchronized (this) {
+ bodyContentType = contentTypeOf(getFormatter());
+ body = createBodyPart();
+ for (int i = 0; i < atn.length; ++i) {
+ ambp[i] = createBodyPart(i);
+ ambp[i].setFileName(atn[i]);
+ //Convert names to mime type.
+ atn[i] = getContentType(atn[i]);
+ }
+ }
+
body.setDescription(verify);
- setAcceptLang(body);
- setContent(body, "", "text/plain");
+ setContent(body, "", bodyContentType);
multipart.addBodyPart(body);
+ for (int i = 0; i < ambp.length; ++i) {
+ ambp[i].setDescription(verify);
+ setContent(ambp[i], "", atn[i]);
+ }
+
abort.setContent(multipart);
abort.saveChanges();
abort.writeTo(new ByteArrayOutputStream(MIN_HEADER_SIZE));
@@ -3220,6 +3282,8 @@
* @param host the host or null.
* @return the address.
* @throws IOException if the host name is not valid.
+ * @throws SecurityException if security manager is present and doesn't
+ * allow access to check connect permission.
* @since JavaMail 1.5.0
*/
private static InetAddress verifyHost(String host) throws IOException {
diff -r 9031f1e5787a -r 9b7804254f97 mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Fri Jun 24 17:13:19 2016 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Fri Jun 24 17:15:25 2016 -0700
@@ -2482,6 +2482,53 @@
}
@Test
+ public void testContentTypeOfFormatter() {
+ MailHandler instance = new MailHandler(createInitProperties(""));
+ InternalErrorManager em = new InternalErrorManager();
+ instance.setErrorManager(em);
+
+ assertEquals("text/plain", instance.contentTypeOf(new SimpleFormatter()));
+ assertEquals("text/plain", instance.contentTypeOf(new SimpleFormatter(){}));
+
+ assertEquals("application/xml", instance.contentTypeOf(new XMLFormatter()));
+ assertEquals("application/xml", instance.contentTypeOf(new XMLFormatter(){}));
+
+ /**
+ * None of the Formatter methods that can generate content should be
+ * invoked during a verify as that could lead to poor startup times.
+ */
+ class UnsupportedHTML extends Formatter {
+
+ @Override
+ public String getHead(Handler h) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String format(LogRecord record) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getTail(Handler h) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ throw new UnsupportedOperationException();
+ }
+ }
+ assertEquals("text/html", instance.contentTypeOf(new UnsupportedHTML()));
+ assertEquals("text/html", instance.contentTypeOf(new UnsupportedHTML(){}));
+
+ instance.close();
+ for (Exception exception : em.exceptions) {
+ fail(exception.toString());
+ }
+ }
+
+ @Test
public void testGuessContentTypeReadlimit() throws Exception {
class LastMarkInputStream extends ByteArrayInputStream {
@@ -5627,7 +5674,7 @@
Properties props = createInitProperties(p);
props.put(p.concat(".subject"), p.concat(" test"));
props.put(p.concat(".errorManager"), InternalErrorManager.class.getName());
-
+ props.put(p.concat(".formatter"), XMLFormatter.class.getName());
read(manager, props);
props = createInitProperties("");
@@ -5656,7 +5703,7 @@
props.put("subject", "test");
props.put("mail.from", "badAddress");
props.put("verify", "local");
-
+
instance = new MailHandler(props);
try {
InternalErrorManager em = internalErrorManagerFrom(instance);