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 no...@apache.org on 2010/06/29 16:27:07 UTC
svn commit: r958989 - in /james/server/trunk:
imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java
spring-deployment/src/main/config/james/imapserver.xml
Author: norman
Date: Tue Jun 29 14:27:07 2010
New Revision: 958989
URL: http://svn.apache.org/viewvc?rev=958989&view=rev
Log:
Complete STARTTLS support, now it works with real mailclients too (JAMES-926)
Modified:
james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java
james/server/trunk/spring-deployment/src/main/config/james/imapserver.xml
Modified: james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java?rev=958989&r1=958988&r2=958989&view=diff
==============================================================================
--- james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java (original)
+++ james/server/trunk/imapserver/src/main/java/org/apache/james/imapserver/netty/ImapStreamChannelUpstreamHandler.java Tue Jun 29 14:27:07 2010
@@ -18,6 +18,8 @@
****************************************************************/
package org.apache.james.imapserver.netty;
+import java.io.FilterOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
@@ -29,6 +31,7 @@ import org.apache.james.imap.api.ImapCon
import org.apache.james.imap.api.process.ImapSession;
import org.apache.james.imap.main.ImapRequestStreamHandler;
import org.apache.james.imap.main.ImapSessionImpl;
+import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
@@ -54,6 +57,7 @@ public class ImapStreamChannelUpstreamHa
private SSLEngine engine;
private final static String IMAP_SESSION = "IMAP_SESSION";
+ private final static String BUFFERED_OUT = "BUFFERED_OUT";
public ImapStreamChannelUpstreamHandler(final String hello, final ImapRequestStreamHandler handler, final Log logger, final long readTimeout) {
this(hello, handler, logger, readTimeout, null);
@@ -71,12 +75,17 @@ public class ImapStreamChannelUpstreamHa
@Override
protected void processStreamIo(final ChannelHandlerContext ctx, final InputStream in, final OutputStream out) {
final ImapSessionImpl imapSession = (ImapSessionImpl) getAttachment(ctx).get(IMAP_SESSION);
-
+ Channel channel = ctx.getChannel();
+
+ // Store the stream as attachment
+ OutputStream bufferedOut = new StartTLSOutputStream(out);
+ getAttachment(ctx).put(BUFFERED_OUT, bufferedOut);
+
// handle requests in a loop
- while (handler.handleRequest(in, out, imapSession));
+ while (channel.isConnected() && handler.handleRequest(in, bufferedOut, imapSession));
+
if (imapSession != null) imapSession.logout();
- Channel channel = ctx.getChannel();
logger.debug("Thread execution complete for session " + channel.getId());
channel.close();
@@ -92,11 +101,14 @@ public class ImapStreamChannelUpstreamHa
@Override
public boolean startTLS() {
if (supportStartTLS() == false) return false;
- ctx.getChannel().setReadable(false);
- SslHandler filter = new SslHandler(engine);
+
+ // enable buffering of the stream
+ ((StartTLSOutputStream)getAttachment(ctx).get(BUFFERED_OUT)).bufferTillCRLF();
+
+ SslHandler filter = new SslHandler(engine, true);
filter.getEngine().setUseClientMode(false);
ctx.getPipeline().addFirst("sslHandler", filter);
- ctx.getChannel().setReadable(true);
+
return true;
}
@@ -136,5 +148,63 @@ public class ImapStreamChannelUpstreamHa
super.exceptionCaught(ctx, e);
}
-
+ /**
+ * Because Netty {@link SslHandler} need to NOT encrypt the first response send to client this {@link FilterOutputStream} is needed. It
+ * buffer the data till the complete response was written to the stream (searching for the CRLF).
+ *
+ * Once this was done it just pass the data to the wrapped {@link OutputStream} without doing any more buffering
+ *
+ */
+ private final class StartTLSOutputStream extends FilterOutputStream {
+ private int lastChar;
+ private boolean bufferData = false;
+ private final ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
+
+ public StartTLSOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ /**
+ * Buffer the data till the next CLRF was found
+ */
+ public synchronized final void bufferTillCRLF() {
+ bufferData = true;
+ }
+
+ @Override
+ public synchronized void write(byte[] b, int off, int len) throws IOException {
+ if (bufferData) {
+ for (int i = off; i < len; i++) {
+ write(b[i]);
+ }
+ } else {
+ out.write(b, off, len);
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ @Override
+ public synchronized void write(int b) throws IOException {
+ if (bufferData) {
+ buffer.writeByte((byte)b);
+ // check for CLRF and if found write the data and disable buffering
+ if (b == '\n' && lastChar == '\r') {
+ byte[] line = new byte[buffer.capacity()];
+ buffer.getBytes(0, line);
+ out.write(line);
+ bufferData = false;
+ }
+ lastChar = b;
+
+ } else {
+ out.write(b);
+ }
+ }
+
+
+ }
}
Modified: james/server/trunk/spring-deployment/src/main/config/james/imapserver.xml
URL: http://svn.apache.org/viewvc/james/server/trunk/spring-deployment/src/main/config/james/imapserver.xml?rev=958989&r1=958988&r2=958989&view=diff
==============================================================================
--- james/server/trunk/spring-deployment/src/main/config/james/imapserver.xml (original)
+++ james/server/trunk/spring-deployment/src/main/config/james/imapserver.xml Tue Jun 29 14:27:07 2010
@@ -36,13 +36,13 @@
<!-- Set to true to use TLS for the Socket.
To use this you need to copy sunjce_provider.jar to /path/james/lib directory.
-->
- <tls socketTLS="false">
- <!-- To create a new keystore execute:
- keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
- -->
- <keystore>file://conf/keystore</keystore>
- <secret>yoursecret</secret>
- <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+ <tls socketTLS="false" startTLS="false">
+ <!-- To create a new keystore execute:
+ keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
+ -->
+ <keystore>file://conf/keystore</keystore>
+ <secret>yoursecret</secret>
+ <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
</tls>
<handler>
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org