From c0dd5ad22711d1b27747a66a3774ffe83ff5757f Mon Sep 17 00:00:00 2001 From: fhanik Date: Fri, 4 Aug 2006 21:13:05 +0000 Subject: [PATCH] Added HTTPS support to the NIO connector. Works exactly like the Http11Protocol does, but uses JDK1.5 JSSE implementation. Rollback info if this breaks something else, it should all be backwards compatible revision:428882 Files: java/org/apache/coyote/http11/Http11NioProtocol.java java/org/apache/coyote/http11/Http11NioProcessor.java java/org/apache/coyote/http11/InternalNioInputBuffer.java java/org/apache/coyote/http11/InternalNioOutputBuffer.java java/org/apache/tomcat/util/net/SSLImplementation.java java/org/apache/tomcat/util/net/NioChannel.java java/org/apache/tomcat/util/net/jsse/JSSESupport.java java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java java/org/apache/tomcat/util/net/jsse/JSSEFactory.java java/org/apache/tomcat/util/net/SecureNioChannel.java java/org/apache/tomcat/util/net/NioEndpoint.java git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@428884 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/coyote/http11/Http11NioProcessor.java | 158 ++++---- .../apache/coyote/http11/Http11NioProtocol.java | 207 ++++------- .../coyote/http11/InternalNioInputBuffer.java | 38 +- .../coyote/http11/InternalNioOutputBuffer.java | 35 +- java/org/apache/tomcat/util/net/NioChannel.java | 140 +++++++ java/org/apache/tomcat/util/net/NioEndpoint.java | 400 ++++++++++---------- .../apache/tomcat/util/net/SSLImplementation.java | 2 + .../apache/tomcat/util/net/SecureNioChannel.java | 408 +++++++++++++++++++++ .../apache/tomcat/util/net/jsse/JSSEFactory.java | 6 + .../tomcat/util/net/jsse/JSSEImplementation.java | 7 + .../apache/tomcat/util/net/jsse/JSSESupport.java | 13 +- 11 files changed, 943 insertions(+), 471 deletions(-) create mode 100644 java/org/apache/tomcat/util/net/NioChannel.java create mode 100644 java/org/apache/tomcat/util/net/SecureNioChannel.java diff --git a/java/org/apache/coyote/http11/Http11NioProcessor.java b/java/org/apache/coyote/http11/Http11NioProcessor.java index f03587f44..61482b997 100644 --- a/java/org/apache/coyote/http11/Http11NioProcessor.java +++ b/java/org/apache/coyote/http11/Http11NioProcessor.java @@ -19,7 +19,7 @@ package org.apache.coyote.http11; import java.io.IOException; import java.io.InterruptedIOException; import java.net.InetAddress; -import java.nio.channels.SocketChannel; +import java.nio.channels.SelectionKey; import java.util.StringTokenizer; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -45,11 +45,12 @@ import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.FastHttpDateFormat; import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioEndpoint.Handler; import org.apache.tomcat.util.net.NioEndpoint.Handler.SocketState; +import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.res.StringManager; -import java.nio.channels.SelectionKey; /** @@ -73,6 +74,10 @@ public class Http11NioProcessor implements ActionHook { protected static StringManager sm = StringManager.getManager(Constants.Package); + /** + * SSL information. + */ + protected SSLSupport sslSupport; // ----------------------------------------------------------- Constructors @@ -99,7 +104,7 @@ public class Http11NioProcessor implements ActionHook { response.setOutputBuffer(outputBuffer); request.setResponse(response); - ssl = !"off".equalsIgnoreCase(endpoint.getSSLEngine()); + ssl = endpoint.getSecure(); initializeFilters(); @@ -217,7 +222,7 @@ public class Http11NioProcessor implements ActionHook { /** * Socket associated with the current connection. */ - protected SocketChannel socket = null; + protected NioChannel socket = null; /** @@ -747,7 +752,7 @@ public class Http11NioProcessor implements ActionHook { if (request.getAttribute("org.apache.tomcat.comet") == null) { comet = false; } - SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); + SelectionKey key = socket.getIOChannel().keyFor(endpoint.getPoller().getSelector()); if ( key != null ) { NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); if ( attach!=null ) { @@ -787,7 +792,7 @@ public class Http11NioProcessor implements ActionHook { * * @throws IOException error during an I/O operation */ - public SocketState process(SocketChannel socket) + public SocketState process(NioChannel socket) throws IOException { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); @@ -826,7 +831,7 @@ public class Http11NioProcessor implements ActionHook { // Parsing the request header try { if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { - socket.socket().setSoTimeout((int)soTimeout); + socket.getIOChannel().socket().setSoTimeout((int)soTimeout); inputBuffer.readTimeout = soTimeout; } if (!inputBuffer.parseRequestLine @@ -842,7 +847,7 @@ public class Http11NioProcessor implements ActionHook { request.setStartTime(System.currentTimeMillis()); keptAlive = true; if (!disableUploadTimeout) { - socket.socket().setSoTimeout((int)timeout); + socket.getIOChannel().socket().setSoTimeout((int)timeout); inputBuffer.readTimeout = soTimeout; } inputBuffer.parseHeaders(); @@ -892,7 +897,7 @@ public class Http11NioProcessor implements ActionHook { if (request.getAttribute("org.apache.tomcat.comet") != null) { comet = true; } - SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); + SelectionKey key = socket.getIOChannel().keyFor(endpoint.getPoller().getSelector()); if (key != null) { NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); if (attach != null) { @@ -1044,7 +1049,7 @@ public class Http11NioProcessor implements ActionHook { comet = false; cometClose = true; - SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); + SelectionKey key = socket.getIOChannel().keyFor(endpoint.getPoller().getSelector()); if ( key != null ) { NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); if ( attach!=null && attach.getComet()) { @@ -1078,7 +1083,7 @@ public class Http11NioProcessor implements ActionHook { // Get remote host address if ((remoteAddr == null) && (socket != null)) { - InetAddress inetAddr = socket.socket().getInetAddress(); + InetAddress inetAddr = socket.getIOChannel().socket().getInetAddress(); if (inetAddr != null) { remoteAddr = inetAddr.getHostAddress(); } @@ -1089,7 +1094,7 @@ public class Http11NioProcessor implements ActionHook { // Get local host name if ((localName == null) && (socket != null)) { - InetAddress inetAddr = socket.socket().getLocalAddress(); + InetAddress inetAddr = socket.getIOChannel().socket().getLocalAddress(); if (inetAddr != null) { localName = inetAddr.getHostName(); } @@ -1100,7 +1105,7 @@ public class Http11NioProcessor implements ActionHook { // Get remote host name if ((remoteHost == null) && (socket != null)) { - InetAddress inetAddr = socket.socket().getInetAddress(); + InetAddress inetAddr = socket.getIOChannel().socket().getInetAddress(); if (inetAddr != null) { remoteHost = inetAddr.getHostName(); } @@ -1117,102 +1122,71 @@ public class Http11NioProcessor implements ActionHook { } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { if (localAddr == null) - localAddr = socket.socket().getLocalAddress().getHostAddress(); + localAddr = socket.getIOChannel().socket().getLocalAddress().getHostAddress(); request.localAddr().setString(localAddr); } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) { if ((remotePort == -1 ) && (socket !=null)) { - remotePort = socket.socket().getPort(); + remotePort = socket.getIOChannel().socket().getPort(); } request.setRemotePort(remotePort); } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) { if ((localPort == -1 ) && (socket !=null)) { - localPort = socket.socket().getLocalPort(); + localPort = socket.getIOChannel().socket().getLocalPort(); } request.setLocalPort(localPort); } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { -// if (ssl && (socket != 0)) { -// try { -// // Cipher suite -// Object sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER); -// if (sslO != null) { -// request.setAttribute -// (NioEndpoint.CIPHER_SUITE_KEY, sslO); -// } -// // Client certificate chain if present -// int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); -// X509Certificate[] certs = null; -// if (certLength > 0) { -// certs = new X509Certificate[certLength]; -// for (int i = 0; i < certLength; i++) { -// byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); -// CertificateFactory cf = -// CertificateFactory.getInstance("X.509"); -// ByteArrayInputStream stream = new ByteArrayInputStream(data); -// certs[i] = (X509Certificate) cf.generateCertificate(stream); -// } -// } -// if (certs != null) { -// request.setAttribute -// (NioEndpoint.CERTIFICATE_KEY, certs); -// } -// // User key size -// sslO = new Integer(SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE)); -// if (sslO != null) { -// request.setAttribute -// (NioEndpoint.KEY_SIZE_KEY, sslO); -// } -// // SSL session ID -// sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_SESSION_ID); -// if (sslO != null) { -// request.setAttribute -// (NioEndpoint.SESSION_ID_KEY, sslO); -// } -// } catch (Exception e) { -// log.warn(sm.getString("http11processor.socket.ssl"), e); -// } -// } + try { + if (sslSupport != null) { + Object sslO = sslSupport.getCipherSuite(); + if (sslO != null) + request.setAttribute + (SSLSupport.CIPHER_SUITE_KEY, sslO); + sslO = sslSupport.getPeerCertificateChain(false); + if (sslO != null) + request.setAttribute + (SSLSupport.CERTIFICATE_KEY, sslO); + sslO = sslSupport.getKeySize(); + if (sslO != null) + request.setAttribute + (SSLSupport.KEY_SIZE_KEY, sslO); + sslO = sslSupport.getSessionId(); + if (sslO != null) + request.setAttribute + (SSLSupport.SESSION_ID_KEY, sslO); + } + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.ssl"), e); + } } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) { -// if (ssl && (socket != 0)) { -// // Consume and buffer the request body, so that it does not -// // interfere with the client's handshake messages -// InputFilter[] inputFilters = inputBuffer.getFilters(); -// ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) -// .setLimit(maxSavePostSize); -// inputBuffer.addActiveFilter -// (inputFilters[Constants.BUFFERED_FILTER]); -// try { -// // Renegociate certificates -// SSLSocket.renegotiate(socket); -// // Client certificate chain if present -// int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); -// X509Certificate[] certs = null; -// if (certLength > 0) { -// certs = new X509Certificate[certLength]; -// for (int i = 0; i < certLength; i++) { -// byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); -// CertificateFactory cf = -// CertificateFactory.getInstance("X.509"); -// ByteArrayInputStream stream = new ByteArrayInputStream(data); -// certs[i] = (X509Certificate) cf.generateCertificate(stream); -// } -// } -// if (certs != null) { -// request.setAttribute -// (NioEndpoint.CERTIFICATE_KEY, certs); -// } -// } catch (Exception e) { -// log.warn(sm.getString("http11processor.socket.ssl"), e); -// } -// } + if( sslSupport != null) { + /* + * Consume and buffer the request body, so that it does not + * interfere with the client's handshake messages + */ + InputFilter[] inputFilters = inputBuffer.getFilters(); + ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) + .setLimit(maxSavePostSize); + inputBuffer.addActiveFilter + (inputFilters[Constants.BUFFERED_FILTER]); + try { + Object sslO = sslSupport.getPeerCertificateChain(true); + if( sslO != null) { + request.setAttribute + (SSLSupport.CERTIFICATE_KEY, sslO); + } + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.ssl"), e); + } + } } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { ByteChunk body = (ByteChunk) param; @@ -1240,6 +1214,9 @@ public class Http11NioProcessor implements ActionHook { this.adapter = adapter; } + public void setSslSupport(SSLSupport sslSupport) { + this.sslSupport = sslSupport; + } /** * Get the associated adapter. @@ -1250,6 +1227,9 @@ public class Http11NioProcessor implements ActionHook { return adapter; } + public SSLSupport getSslSupport() { + return sslSupport; + } // ------------------------------------------------------ Protected Methods diff --git a/java/org/apache/coyote/http11/Http11NioProtocol.java b/java/org/apache/coyote/http11/Http11NioProtocol.java index 467849d52..e5792b8e9 100644 --- a/java/org/apache/coyote/http11/Http11NioProtocol.java +++ b/java/org/apache/coyote/http11/Http11NioProtocol.java @@ -18,7 +18,6 @@ package org.apache.coyote.http11; import java.net.InetAddress; import java.net.URLEncoder; -import java.nio.channels.SocketChannel; import java.util.Hashtable; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; @@ -37,6 +36,9 @@ import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioEndpoint.Handler; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.net.NioChannel; +import org.apache.tomcat.util.net.SSLImplementation; +import org.apache.tomcat.util.net.SecureNioChannel; /** @@ -50,6 +52,8 @@ import org.apache.tomcat.util.res.StringManager; */ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration { + protected SSLImplementation sslImplementation = null; + public Http11NioProtocol() { cHandler = new Http11ConnectionHandler( this ); setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); @@ -113,9 +117,13 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration public void init() throws Exception { ep.setName(getName()); ep.setHandler(cHandler); - + ep.setReadBufSize(getMaxHttpHeaderSize()); + ep.setWriteBufSize(getMaxHttpHeaderSize()); try { ep.init(); + + sslImplementation = SSLImplementation.getInstance("org.apache.tomcat.util.net.jsse.JSSEImplementation"); + } catch (Exception ex) { log.error(sm.getString("http11protocol.endpoint.initerror"), ex); throw ex; @@ -188,7 +196,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration // -------------------- Properties-------------------- protected NioEndpoint ep=new NioEndpoint(); - protected boolean secure; + protected boolean secure = false; protected Hashtable attributes = new Hashtable(); @@ -430,6 +438,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration } public void setSecure( boolean b ) { + ep.setSecure(b); secure=b; setAttribute("secure", "" + b); } @@ -489,96 +498,27 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration // -------------------- SSL related properties -------------------- - /** - * SSL engine. - */ - public String getSSLEngine() { return ep.getSSLEngine(); } - public void setSSLEngine(String SSLEngine) { ep.setSSLEngine(SSLEngine); } - - - /** - * SSL protocol. - */ - public String getSSLProtocol() { return ep.getSSLProtocol(); } - public void setSSLProtocol(String SSLProtocol) { ep.setSSLProtocol(SSLProtocol); } - - - /** - * SSL password (if a cert is encrypted, and no password has been provided, a callback - * will ask for a password). - */ - public String getSSLPassword() { return ep.getSSLPassword(); } - public void setSSLPassword(String SSLPassword) { ep.setSSLPassword(SSLPassword); } - - - /** - * SSL cipher suite. - */ - public String getSSLCipherSuite() { return ep.getSSLCipherSuite(); } - public void setSSLCipherSuite(String SSLCipherSuite) { ep.setSSLCipherSuite(SSLCipherSuite); } - - - /** - * SSL certificate file. - */ - public String getSSLCertificateFile() { return ep.getSSLCertificateFile(); } - public void setSSLCertificateFile(String SSLCertificateFile) { ep.setSSLCertificateFile(SSLCertificateFile); } - - - /** - * SSL certificate key file. - */ - public String getSSLCertificateKeyFile() { return ep.getSSLCertificateKeyFile(); } - public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ep.setSSLCertificateKeyFile(SSLCertificateKeyFile); } - - - /** - * SSL certificate chain file. - */ - public String getSSLCertificateChainFile() { return ep.getSSLCertificateChainFile(); } - public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ep.setSSLCertificateChainFile(SSLCertificateChainFile); } - - - /** - * SSL CA certificate path. - */ - public String getSSLCACertificatePath() { return ep.getSSLCACertificatePath(); } - public void setSSLCACertificatePath(String SSLCACertificatePath) { ep.setSSLCACertificatePath(SSLCACertificatePath); } - - - /** - * SSL CA certificate file. - */ - public String getSSLCACertificateFile() { return ep.getSSLCACertificateFile(); } - public void setSSLCACertificateFile(String SSLCACertificateFile) { ep.setSSLCACertificateFile(SSLCACertificateFile); } - - - /** - * SSL CA revocation path. - */ - public String getSSLCARevocationPath() { return ep.getSSLCARevocationPath(); } - public void setSSLCARevocationPath(String SSLCARevocationPath) { ep.setSSLCARevocationPath(SSLCARevocationPath); } - - - /** - * SSL CA revocation file. - */ - public String getSSLCARevocationFile() { return ep.getSSLCARevocationFile(); } - public void setSSLCARevocationFile(String SSLCARevocationFile) { ep.setSSLCARevocationFile(SSLCARevocationFile); } - - - /** - * SSL verify client. - */ - public String getSSLVerifyClient() { return ep.getSSLVerifyClient(); } - public void setSSLVerifyClient(String SSLVerifyClient) { ep.setSSLVerifyClient(SSLVerifyClient); } - - - /** - * SSL verify depth. - */ - public int getSSLVerifyDepth() { return ep.getSSLVerifyDepth(); } - public void setSSLVerifyDepth(int SSLVerifyDepth) { ep.setSSLVerifyDepth(SSLVerifyDepth); } + public String getKeystoreFile() { return ep.getKeystoreFile();} + public void setKeystoreFile(String s ) { ep.setKeystoreFile(s);} + + public String getAlgorithm() { return ep.getAlgorithm();} + public void setAlgorithm(String s ) { ep.setAlgorithm(s);} + + public boolean getClientAuth() { return ep.getClientAuth();} + public void setClientAuth(boolean b ) { ep.setClientAuth(b);} + + public String getKeystorePass() { return ep.getKeystorePass();} + public void setKeystorePass(String s ) { ep.setKeystorePass(s);} + + public String getKeystoreType() { return ep.getKeystoreType();} + public void setKeystoreType(String s ) { ep.setKeystoreType(s);} + + public String getSslProtocol() { return ep.getSslProtocol();} + public void setSslProtocol(String s) { ep.setSslProtocol(s);} + + public String getCiphers() { return ep.getCiphers();} + public void setCiphers(String s) { ep.setCiphers(s);} + // -------------------- Connection handler -------------------- @@ -590,8 +530,8 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration protected ThreadLocal localProcessor = new ThreadLocal(); - protected ConcurrentHashMap connections = - new ConcurrentHashMap(); + protected ConcurrentHashMap connections = + new ConcurrentHashMap(); protected java.util.Stack recycledProcessors = new java.util.Stack(); @@ -599,7 +539,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration this.proto = proto; } - public SocketState event(SocketChannel socket, boolean error) { + public SocketState event(NioChannel socket, boolean error) { Http11NioProcessor result = connections.get(socket); SocketState state = SocketState.CLOSED; @@ -638,7 +578,7 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration return state; } - public SocketState process(SocketChannel socket) { + public SocketState process(NioChannel socket) { Http11NioProcessor processor = null; try { processor = (Http11NioProcessor) localProcessor.get(); @@ -651,40 +591,23 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration } } if (processor == null) { - processor = - new Http11NioProcessor(proto.maxHttpHeaderSize, proto.ep); - processor.setAdapter(proto.adapter); - processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests); - processor.setTimeout(proto.timeout); - processor.setDisableUploadTimeout(proto.disableUploadTimeout); - processor.setCompression(proto.compression); - processor.setCompressionMinSize(proto.compressionMinSize); - processor.setNoCompressionUserAgents(proto.noCompressionUserAgents); - processor.setCompressableMimeTypes(proto.compressableMimeTypes); - processor.setRestrictedUserAgents(proto.restrictedUserAgents); - processor.setSocketBuffer(proto.socketBuffer); - processor.setMaxSavePostSize(proto.maxSavePostSize); - processor.setServer(proto.server); - localProcessor.set(processor); - if (proto.getDomain() != null) { - synchronized (this) { - try { - RequestInfo rp = processor.getRequest().getRequestProcessor(); - rp.setGlobalProcessor(global); - ObjectName rpName = new ObjectName - (proto.getDomain() + ":type=RequestProcessor,worker=" - + proto.getName() + ",name=HttpRequest" + count++); - Registry.getRegistry(null, null).registerComponent(rp, rpName, null); - } catch (Exception e) { - log.warn("Error registering request"); - } - } - } + processor = createProcessor(); } if (processor instanceof ActionHook) { ((ActionHook) processor).action(ActionCode.ACTION_START, null); } + + + if (proto.ep.getSecure() && (proto.sslImplementation != null)) { + if (socket instanceof SecureNioChannel) { + SecureNioChannel ch = (SecureNioChannel)socket; + processor.setSslSupport(proto.sslImplementation.getSSLSupport(ch.getSslEngine().getSession())); + }else processor.setSslSupport(null); + } else { + processor.setSslSupport(null); + } + SocketState state = processor.process(socket); if (state == SocketState.LONG) { @@ -720,6 +643,38 @@ public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration } return SocketState.CLOSED; } + + public Http11NioProcessor createProcessor() { + Http11NioProcessor processor = new Http11NioProcessor(proto.maxHttpHeaderSize, proto.ep); + processor.setAdapter(proto.adapter); + processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests); + processor.setTimeout(proto.timeout); + processor.setDisableUploadTimeout(proto.disableUploadTimeout); + processor.setCompression(proto.compression); + processor.setCompressionMinSize(proto.compressionMinSize); + processor.setNoCompressionUserAgents(proto.noCompressionUserAgents); + processor.setCompressableMimeTypes(proto.compressableMimeTypes); + processor.setRestrictedUserAgents(proto.restrictedUserAgents); + processor.setSocketBuffer(proto.socketBuffer); + processor.setMaxSavePostSize(proto.maxSavePostSize); + processor.setServer(proto.server); + localProcessor.set(processor); + if (proto.getDomain() != null) { + synchronized (this) { + try { + RequestInfo rp = processor.getRequest().getRequestProcessor(); + rp.setGlobalProcessor(global); + ObjectName rpName = new ObjectName + (proto.getDomain() + ":type=RequestProcessor,worker=" + + proto.getName() + ",name=HttpRequest" + count++); + Registry.getRegistry(null, null).registerComponent(rp, rpName, null); + } catch (Exception e) { + log.warn("Error registering request"); + } + } + } + return processor; + } } protected static org.apache.commons.logging.Log log diff --git a/java/org/apache/coyote/http11/InternalNioInputBuffer.java b/java/org/apache/coyote/http11/InternalNioInputBuffer.java index f34a3f188..247b128db 100644 --- a/java/org/apache/coyote/http11/InternalNioInputBuffer.java +++ b/java/org/apache/coyote/http11/InternalNioInputBuffer.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectionKey; -import java.nio.channels.SocketChannel; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; @@ -32,6 +31,7 @@ import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; import org.apache.tomcat.util.net.NioEndpoint.Poller; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.net.NioChannel; /** * Implementation of InputBuffer which provides HTTP request header parsing as @@ -59,11 +59,11 @@ public class InternalNioInputBuffer implements InputBuffer { headers = request.getMimeHeaders(); buf = new byte[headerBufferSize]; - if (headerBufferSize < (8 * 1024)) { - bbuf = ByteBuffer.allocateDirect(6 * 1500); - } else { - bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); - } +// if (headerBufferSize < (8 * 1024)) { +// bbuf = ByteBuffer.allocateDirect(6 * 1500); +// } else { +// bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); +// } inputStreamInputBuffer = new SocketInputBuffer(); @@ -145,16 +145,11 @@ public class InternalNioInputBuffer implements InputBuffer { protected int end; - /** - * Direct byte buffer used to perform actual reading. - */ - protected ByteBuffer bbuf; - /** * Underlying socket. */ - protected SocketChannel socket; + protected NioChannel socket; /** @@ -195,7 +190,7 @@ public class InternalNioInputBuffer implements InputBuffer { /** * Set the underlying socket. */ - public void setSocket(SocketChannel socket) { + public void setSocket(NioChannel socket) { this.socket = socket; } @@ -203,7 +198,7 @@ public class InternalNioInputBuffer implements InputBuffer { /** * Get the underlying socket input stream. */ - public SocketChannel getSocket() { + public NioChannel getSocket() { return socket; } @@ -548,13 +543,14 @@ public class InternalNioInputBuffer implements InputBuffer { long start = System.currentTimeMillis(); boolean timedOut = false; do { - bbuf.clear(); - nRead = socket.read(bbuf); + + socket.getBufHandler().getReadBuffer().clear(); + nRead = socket.read(socket.getBufHandler().getReadBuffer()); if (nRead > 0) { - bbuf.flip(); - bbuf.limit(nRead); + socket.getBufHandler().getReadBuffer().flip(); + socket.getBufHandler().getReadBuffer().limit(nRead); expand(nRead + pos); - bbuf.get(buf, pos, nRead); + socket.getBufHandler().getReadBuffer().get(buf, pos, nRead); lastValid = pos + nRead; return true; } else if (nRead == -1) { @@ -564,7 +560,7 @@ public class InternalNioInputBuffer implements InputBuffer { timedOut = (readTimeout != -1) && ((System.currentTimeMillis()-start)>this.readTimeout); if ( !timedOut && nRead == 0 ) try { - final SelectionKey key = socket.keyFor(poller.getSelector()); + final SelectionKey key = socket.getIOChannel().keyFor(poller.getSelector()); final KeyAttachment att = (KeyAttachment)key.attachment(); //to do, add in a check, we might have just timed out on the wait, //so there is no need to register us again. @@ -596,7 +592,7 @@ public class InternalNioInputBuffer implements InputBuffer { KeyAttachment ka = (KeyAttachment)key.attachment(); ka.setError(true); //set to collect this socket immediately } - socket.socket().close(); + socket.getIOChannel().socket().close(); socket.close(); att.setWakeUp(false); } catch (Exception ignore) {} diff --git a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java index 2b76a4c95..673bffe90 100644 --- a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java @@ -18,7 +18,6 @@ package org.apache.coyote.http11; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; import org.apache.coyote.ActionCode; import org.apache.coyote.OutputBuffer; @@ -32,6 +31,7 @@ import org.apache.tomcat.util.res.StringManager; import java.nio.channels.SelectionKey; import org.apache.tomcat.util.net.NioEndpoint; import java.nio.channels.Selector; +import org.apache.tomcat.util.net.NioChannel; /** * Output buffer. @@ -74,7 +74,7 @@ public class InternalNioOutputBuffer } else { bbufLimit = (headerBufferSize / 1500 + 1) * 1500; } - bbuf = ByteBuffer.allocateDirect(bbufLimit); + //bbuf = ByteBuffer.allocateDirect(bbufLimit); outputStreamOutputBuffer = new SocketOutputBuffer(); @@ -143,7 +143,7 @@ public class InternalNioOutputBuffer /** * Underlying socket. */ - protected SocketChannel socket; + protected NioChannel socket; /** @@ -171,11 +171,6 @@ public class InternalNioOutputBuffer protected int lastActiveFilter; - /** - * Direct byte buffer used for writing. - */ - protected ByteBuffer bbuf = null; - // ------------------------------------------------------------- Properties @@ -183,7 +178,7 @@ public class InternalNioOutputBuffer /** * Set the underlying socket. */ - public void setSocket(SocketChannel socket) { + public void setSocket(NioChannel socket) { this.socket = socket; } @@ -194,7 +189,7 @@ public class InternalNioOutputBuffer /** * Get the underlying socket input stream. */ - public SocketChannel getSocket() { + public NioChannel getSocket() { return socket; } /** @@ -316,7 +311,7 @@ public class InternalNioOutputBuffer // Recycle Request object response.recycle(); - bbuf.clear(); + socket.getBufHandler().getWriteBuffer().clear(); socket = null; pos = 0; @@ -405,7 +400,7 @@ public class InternalNioOutputBuffer while ( bytebuffer.hasRemaining() ) { int written = socket.write(bytebuffer); } - bbuf.clear(); + socket.getBufHandler().getWriteBuffer().clear(); this.total = 0; } @@ -571,10 +566,10 @@ public class InternalNioOutputBuffer int total = 0; private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException { - if (bbuf.capacity() <= (offset + length)) { + if (socket.getBufHandler().getWriteBuffer().capacity() <= (offset + length)) { flushBuffer(); } - bbuf.put(buf, offset, length); + socket.getBufHandler().getWriteBuffer().put(buf, offset, length); total += length; } @@ -715,15 +710,15 @@ public class InternalNioOutputBuffer throws IOException { //prevent timeout for async, - SelectionKey key = socket.keyFor(selector); + SelectionKey key = socket.getIOChannel().keyFor(selector); if (key != null) { NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); attach.access(); } //write to the socket, if there is anything to write - if (bbuf.position() > 0) { - writeToSocket(bbuf,true); + if (socket.getBufHandler().getWriteBuffer().position() > 0) { + writeToSocket(socket.getBufHandler().getWriteBuffer(),true); } } @@ -750,11 +745,11 @@ public class InternalNioOutputBuffer byte[] b = chunk.getBuffer(); while (len > 0) { int thisTime = len; - if (bbuf.position() == bbuf.capacity()) { + if (socket.getBufHandler().getWriteBuffer().position() == socket.getBufHandler().getWriteBuffer().capacity()) { flushBuffer(); } - if (thisTime > bbuf.capacity() - bbuf.position()) { - thisTime = bbuf.capacity() - bbuf.position(); + if (thisTime > socket.getBufHandler().getWriteBuffer().capacity() - socket.getBufHandler().getWriteBuffer().position()) { + thisTime = socket.getBufHandler().getWriteBuffer().capacity() - socket.getBufHandler().getWriteBuffer().position(); } addToBB(b,start,thisTime); len = len - thisTime; diff --git a/java/org/apache/tomcat/util/net/NioChannel.java b/java/org/apache/tomcat/util/net/NioChannel.java new file mode 100644 index 000000000..5360ffe7f --- /dev/null +++ b/java/org/apache/tomcat/util/net/NioChannel.java @@ -0,0 +1,140 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation + * + * Licensed 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.tomcat.util.net; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ByteChannel; +import java.nio.channels.SocketChannel; + +import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; +/** + * + * Base class for a SocketChannel wrapper used by the endpoint. + * This way, logic for a SSL socket channel remains the same as for + * a non SSL, making sure we don't need to code for any exception cases. + * + * @author Filip Hanik + * @version 1.0 + */ +public class NioChannel implements ByteChannel{ + + protected static ByteBuffer emptyBuf = ByteBuffer.allocate(0); + + protected SocketChannel sc = null; + + protected ApplicationBufferHandler bufHandler; + + public NioChannel(SocketChannel channel, ApplicationBufferHandler bufHandler) throws IOException { + this.sc = channel; + this.bufHandler = bufHandler; + } + + + /** + * Closes this channel. + * + * @throws IOException If an I/O error occurs + * @todo Implement this java.nio.channels.Channel method + */ + public void close() throws IOException { + sc.close(); + } + + public void close(boolean force) throws IOException { + close(); + } + /** + * Tells whether or not this channel is open. + * + * @return true if, and only if, this channel is open + * @todo Implement this java.nio.channels.Channel method + */ + public boolean isOpen() { + return sc.isOpen(); + } + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + * @param src The buffer from which bytes are to be retrieved + * @return The number of bytes written, possibly zero + * @throws IOException If some other I/O error occurs + * @todo Implement this java.nio.channels.WritableByteChannel method + */ + public int write(ByteBuffer src) throws IOException { + return sc.write(src); + } + + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + * @param dst The buffer into which bytes are to be transferred + * @return The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream + * @throws IOException If some other I/O error occurs + * @todo Implement this java.nio.channels.ReadableByteChannel method + */ + public int read(ByteBuffer dst) throws IOException { + return sc.read(dst); + } + + + /** + * getBufHandler + * + * @return ApplicationBufferHandler + * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method + */ + public ApplicationBufferHandler getBufHandler() { + return bufHandler; + } + + /** + * getIOChannel + * + * @return SocketChannel + * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method + */ + public SocketChannel getIOChannel() { + return sc; + } + + /** + * isClosing + * + * @return boolean + * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method + */ + public boolean isClosing() { + return false; + } + + /** + * isInitHandshakeComplete + * + * @return boolean + * @todo Implement this org.apache.tomcat.util.net.SecureNioChannel method + */ + public boolean isInitHandshakeComplete() { + return true; + } + + public int handshake(boolean read, boolean write) throws IOException { + return 0; + } + + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java index 3c15e8a4a..38894abd1 100644 --- a/java/org/apache/tomcat/util/net/NioEndpoint.java +++ b/java/org/apache/tomcat/util/net/NioEndpoint.java @@ -16,22 +16,29 @@ package org.apache.tomcat.util.net; +import java.io.FileInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.security.KeyStore; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import java.util.concurrent.Executor; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManagerFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.jni.SSL; +import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; import org.apache.tomcat.util.res.StringManager; /** @@ -128,12 +135,9 @@ public class NioEndpoint { protected int sequence = 0; - /** - * Root APR memory pool. - */ - protected long rootPool = 0; - - + protected int readBufSize = 8192; + protected int writeBufSize = 8192; + /** * Server socket "pointer". */ @@ -146,11 +150,7 @@ public class NioEndpoint { protected long serverSockPool = 0; - /** - * SSL context. - */ - protected long sslContext = 0; - + // ------------------------------------------------------------- Properties @@ -341,112 +341,51 @@ public class NioEndpoint { */ public int getMinSpareThreads() { return 0; } + // -------------------- SSL related properties -------------------- + protected String keystoreFile = System.getProperty("user.home")+"/.keystore"; + public String getKeystoreFile() { return keystoreFile;} + public void setKeystoreFile(String s ) { this.keystoreFile = s;} - /** - * SSL engine. - */ - protected String SSLEngine = "off"; - public String getSSLEngine() { return SSLEngine; } - public void setSSLEngine(String SSLEngine) { this.SSLEngine = SSLEngine; } - - - /** - * SSL protocols. - */ - protected String SSLProtocol = "all"; - public String getSSLProtocol() { return SSLProtocol; } - public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; } - - - /** - * SSL password (if a cert is encrypted, and no password has been provided, a callback - * will ask for a password). - */ - protected String SSLPassword = null; - public String getSSLPassword() { return SSLPassword; } - public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; } - - - /** - * SSL cipher suite. - */ - protected String SSLCipherSuite = "ALL"; - public String getSSLCipherSuite() { return SSLCipherSuite; } - public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; } - - - /** - * SSL certificate file. - */ - protected String SSLCertificateFile = null; - public String getSSLCertificateFile() { return SSLCertificateFile; } - public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; } - - - /** - * SSL certificate key file. - */ - protected String SSLCertificateKeyFile = null; - public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; } - public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; } - - - /** - * SSL certificate chain file. - */ - protected String SSLCertificateChainFile = null; - public String getSSLCertificateChainFile() { return SSLCertificateChainFile; } - public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; } - - - /** - * SSL CA certificate path. - */ - protected String SSLCACertificatePath = null; - public String getSSLCACertificatePath() { return SSLCACertificatePath; } - public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; } - - - /** - * SSL CA certificate file. - */ - protected String SSLCACertificateFile = null; - public String getSSLCACertificateFile() { return SSLCACertificateFile; } - public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; } - - - /** - * SSL CA revocation path. - */ - protected String SSLCARevocationPath = null; - public String getSSLCARevocationPath() { return SSLCARevocationPath; } - public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; } - - - /** - * SSL CA revocation file. - */ - protected String SSLCARevocationFile = null; - public String getSSLCARevocationFile() { return SSLCARevocationFile; } - public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; } - + protected String algorithm = "SunX509"; + public String getAlgorithm() { return algorithm;} + public void setAlgorithm(String s ) { this.algorithm = s;} - /** - * SSL verify client. - */ - protected String SSLVerifyClient = "none"; - public String getSSLVerifyClient() { return SSLVerifyClient; } - public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; } + protected boolean clientAuth = false; + public boolean getClientAuth() { return clientAuth;} + public void setClientAuth(boolean b ) { this.clientAuth = b;} + + protected String keystorePass = "changeit"; + public String getKeystorePass() { return keystorePass;} + public void setKeystorePass(String s ) { this.keystorePass = s;} + + protected String keystoreType = "JKS"; + public String getKeystoreType() { return keystoreType;} + public void setKeystoreType(String s ) { this.keystoreType = s;} + protected String sslProtocol = "TLS"; + public String getSslProtocol() { return sslProtocol;} + public void setSslProtocol(String s) { sslProtocol = s;} + + protected String ciphers = null; + public String getCiphers() { return ciphers;} + public void setCiphers(String s) { ciphers = s;} + + protected boolean secure = false; + public boolean getSecure() { return secure;} + public void setSecure(boolean b) { secure = b;} - /** - * SSL verify depth. - */ - protected int SSLVerifyDepth = 10; - public int getSSLVerifyDepth() { return SSLVerifyDepth; } - public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } + public void setWriteBufSize(int writeBufSize) { + this.writeBufSize = writeBufSize; + } + public void setReadBufSize(int readBufSize) { + this.readBufSize = readBufSize; + } + protected SSLContext sslContext = null; + public SSLContext getSSLContext() { return sslContext;} + public void setSSLContext(SSLContext c) { sslContext = c;} + // --------------------------------------------------------- Public Methods @@ -535,47 +474,24 @@ public class NioEndpoint { } // Initialize SSL if needed - if (!"off".equalsIgnoreCase(SSLEngine)) { + if (secure) { // Initialize SSL - // FIXME: one per VM call ? - if ("on".equalsIgnoreCase(SSLEngine)) { - //SSL.initialize(null); - } else { - //SSL.initialize(SSLEngine); - } - // SSL protocol - int value = SSL.SSL_PROTOCOL_ALL; - if ("SSLv2".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV2; - } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV3; - } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_TLSV1; - } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3; - } -// // Create SSL Context -// sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER); -// // List the ciphers that the client is permitted to negotiate -// SSLContext.setCipherSuite(sslContext, SSLCipherSuite); -// // Load Server key and certificate -// SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA); -// // Set certificate chain file -// SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false); -// // Support Client Certificates -// SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath); -// // Set revocation -// SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath); -// // Client certificate verification -// value = SSL.SSL_CVERIFY_NONE; -// if ("optional".equalsIgnoreCase(SSLVerifyClient)) { -// value = SSL.SSL_CVERIFY_OPTIONAL; -// } else if ("require".equalsIgnoreCase(SSLVerifyClient)) { -// value = SSL.SSL_CVERIFY_REQUIRE; -// } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) { -// value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA; -// } -// SSLContext.setVerify(sslContext, value, SSLVerifyDepth); + char[] passphrase = getKeystorePass().toCharArray(); + + KeyStore ks = KeyStore.getInstance(getKeystoreType()); + ks.load(new FileInputStream(getKeystoreFile()), passphrase); + KeyStore ts = KeyStore.getInstance(getKeystoreType()); + ts.load(new FileInputStream(getKeystoreFile()), passphrase); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(getAlgorithm()); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(getAlgorithm()); + tmf.init(ts); + + sslContext = SSLContext.getInstance(getSslProtocol()); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } initialized = true; @@ -671,7 +587,7 @@ public class NioEndpoint { serverSock.socket().close(); serverSock.close(); serverSock = null; - sslContext = 0; + sslContext = null; initialized = false; } @@ -686,6 +602,13 @@ public class NioEndpoint { return sequence++; } + public int getWriteBufSize() { + return writeBufSize; + } + + public int getReadBufSize() { + return readBufSize; + } /** * Unlock the server socket accept using a bugus connection. @@ -736,20 +659,24 @@ public class NioEndpoint { if (soTimeout > 0) socket.socket().setSoTimeout(soTimeout); - - // 2: SSL handshake + NioChannel channel = null; + // 2: SSL setup step = 2; - if (sslContext != 0) { -// SSLSocket.attach(sslContext, socket); -// if (SSLSocket.handshake(socket) != 0) { -// if (log.isDebugEnabled()) { -// log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError()); -// } -// return false; -// } + if (sslContext != null) { + SSLEngine engine = sslContext.createSSLEngine(); + engine.setNeedClientAuth(getClientAuth()); + engine.setUseClientMode(false); + int appbufsize = engine.getSession().getApplicationBufferSize(); + int bufsize = Math.max(Math.max(getReadBufSize(),getWriteBufSize()),appbufsize); + NioBufferHandler bufhandler = new NioBufferHandler(bufsize,bufsize); + channel = new SecureNioChannel(socket,engine,bufhandler); + + } else { + NioBufferHandler bufhandler = new NioBufferHandler(getReadBufSize(),getWriteBufSize()); + channel = new NioChannel(socket,bufhandler); } - getPoller().register(socket); + getPoller().register(channel); } catch (Throwable t) { if (log.isDebugEnabled()) { @@ -845,7 +772,7 @@ public class NioEndpoint { /** * Process given socket. */ - protected boolean processSocket(SocketChannel socket) { + protected boolean processSocket(NioChannel socket) { try { if (executor == null) { getWorkerThread().assign(socket); @@ -865,7 +792,7 @@ public class NioEndpoint { /** * Process given socket for an event. */ - protected boolean processSocket(SocketChannel socket, boolean error) { + protected boolean processSocket(NioChannel socket, boolean error) { try { if (executor == null) { getWorkerThread().assign(socket, error); @@ -996,8 +923,8 @@ public class NioEndpoint { * * @param socket to add to the poller */ - public void add(final SocketChannel socket) { - final SelectionKey key = socket.keyFor(selector); + public void add(final NioChannel socket) { + final SelectionKey key = socket.getIOChannel().keyFor(selector); KeyAttachment att = (KeyAttachment)key.attachment(); if ( att != null ) att.setWakeUp(false); Runnable r = new Runnable() { @@ -1010,7 +937,7 @@ public class NioEndpoint { KeyAttachment ka = (KeyAttachment)key.attachment(); ka.setError(true); //set to collect this socket immediately } - socket.socket().close(); + socket.getIOChannel().socket().close(); socket.close(); } catch ( Exception ignore ) {} } @@ -1036,13 +963,15 @@ public class NioEndpoint { return result; } - public void register(final SocketChannel socket) + public void register(final NioChannel socket) { - SelectionKey key = socket.keyFor(selector); + SelectionKey key = socket.getIOChannel().keyFor(selector); Runnable r = new Runnable() { public void run() { try { - socket.register(selector, SelectionKey.OP_READ, new KeyAttachment()); + KeyAttachment ka = new KeyAttachment(); + ka.setChannel(socket); + socket.getIOChannel().register(selector, SelectionKey.OP_READ, ka); } catch (Exception x) { log.error("", x); } @@ -1059,7 +988,7 @@ public class NioEndpoint { try { KeyAttachment ka = (KeyAttachment) key.attachment(); key.cancel(); - if (ka != null && ka.getComet()) processSocket( (SocketChannel) key.channel(), true); + if (ka != null && ka.getComet()) processSocket( ka.getChannel(), true); key.channel().close(); } catch (IOException e) { if ( log.isDebugEnabled() ) log.debug("",e); @@ -1115,9 +1044,8 @@ public class NioEndpoint { sk.attach(attachment); int readyOps = sk.readyOps(); sk.interestOps(sk.interestOps() & ~readyOps); - SocketChannel channel = (SocketChannel)sk.channel(); - boolean read = sk.isReadable(); - if (read) { + NioChannel channel = attachment.getChannel(); + if (sk.isReadable() || sk.isWritable() ) { if ( attachment.getWakeUp() ) { attachment.setWakeUp(false); synchronized (attachment.getMutex()) {attachment.getMutex().notifyAll();} @@ -1126,17 +1054,17 @@ public class NioEndpoint { } else { boolean close = (!processSocket(channel)); if ( close ) { - channel.socket().close(); + channel.getIOChannel().socket().close(); channel.close(); } } - } + } } else { //invalid key cancelledKey(sk); } } catch ( CancelledKeyException ckx ) { - if (attachment!=null && attachment.getComet()) processSocket( (SocketChannel) sk.channel(), true); + if (attachment!=null && attachment.getComet()) processSocket( attachment.getChannel(), true); try { sk.channel().close(); }catch ( Exception ignore){} @@ -1203,6 +1131,8 @@ public class NioEndpoint { public long getTimeout() {return this.timeout;} public boolean getError() { return error; } public void setError(boolean error) { this.error = error; } + public NioChannel getChannel() { return channel;} + public void setChannel(NioChannel channel) { this.channel = channel;} protected Object mutex = new Object(); protected boolean wakeUp = false; protected long lastAccess = System.currentTimeMillis(); @@ -1210,6 +1140,7 @@ public class NioEndpoint { protected boolean comet = false; protected long timeout = -1; protected boolean error = false; + protected NioChannel channel = null; } @@ -1226,7 +1157,7 @@ public class NioEndpoint { protected Thread thread = null; protected boolean available = false; - protected SocketChannel socket = null; + protected NioChannel socket = null; protected boolean event = false; protected boolean error = false; @@ -1240,7 +1171,7 @@ public class NioEndpoint { * * @param socket TCP socket to process */ - protected synchronized void assign(SocketChannel socket) { + protected synchronized void assign(NioChannel socket) { // Wait for the Processor to get the previous Socket while (available) { @@ -1260,7 +1191,7 @@ public class NioEndpoint { } - protected synchronized void assign(SocketChannel socket, boolean error) { + protected synchronized void assign(NioChannel socket, boolean error) { // Wait for the Processor to get the previous Socket while (available) { @@ -1283,7 +1214,7 @@ public class NioEndpoint { * Await a newly assigned Socket from our Connector, or null * if we are supposed to shut down. */ - protected synchronized SocketChannel await() { + protected synchronized NioChannel await() { // Wait for the Connector to provide a new Socket while (!available) { @@ -1294,7 +1225,7 @@ public class NioEndpoint { } // Notify the Connector that we have received this Socket - SocketChannel socket = this.socket; + NioChannel socket = this.socket; available = false; notifyAll(); @@ -1312,27 +1243,62 @@ public class NioEndpoint { // Process requests until we receive a shutdown signal while (running) { // Wait for the next socket to be assigned - SocketChannel socket = await(); + NioChannel socket = await(); if (socket == null) continue; - - // Process the request from this socket - if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) { - // Close socket and pool - try { - socket.socket().close(); - socket.close(); - }catch ( Exception x ) { - log.error("",x); - } - } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) { - // Close socket and pool - try { - socket.socket().close(); - socket.close(); - }catch ( Exception x ) { - log.error("",x); + SelectionKey key = socket.getIOChannel().keyFor(getPoller().getSelector()); + int handshake = -1; + try { + handshake = socket.handshake(key.isReadable(), key.isWritable()); + }catch ( IOException x ) { + handshake = -1; + log.error("Error during SSL handshake",x); + } + if ( handshake == 0 ) { + // Process the request from this socket + if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) { + // Close socket and pool + try { + socket.getIOChannel().socket().close(); + socket.close(); + }catch ( Exception x ) { + log.error("",x); + } + } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) { + // Close socket and pool + try { + socket.getIOChannel().socket().close(); + socket.close(); + }catch ( Exception x ) { + log.error("",x); + } } + } else if (handshake == -1 ) { + key.cancel(); + try {socket.close(true);}catch (IOException ignore){} + } else { + final SelectionKey fk = key; + final int intops = handshake; + //register for handshake ops + Runnable r = new Runnable() { + public void run() { + try { + fk.interestOps(intops); + } catch (CancelledKeyException ckx) { + try { + if ( fk != null && fk.attachment() != null ) { + KeyAttachment ka = (KeyAttachment)fk.attachment(); + ka.setError(true); //set to collect this socket immediately + try {ka.getChannel().getIOChannel().socket().close();}catch(Exception ignore){} + try {ka.getChannel().close();}catch(Exception ignore){} + ka.setWakeUp(false); + } + } catch (Exception ignore) {} + } + + } + }; + getPoller().addEvent(r); } //dereference socket to let GC do its job socket = null; @@ -1355,7 +1321,21 @@ public class NioEndpoint { } + // ------------------------------------------------ Application Buffer Handler + public class NioBufferHandler implements ApplicationBufferHandler { + protected ByteBuffer readbuf = null; + protected ByteBuffer writebuf = null; + + public NioBufferHandler(int readsize, int writesize) { + readbuf = ByteBuffer.allocateDirect(readsize); + writebuf = ByteBuffer.allocateDirect(writesize); + } + + public ByteBuffer expand(ByteBuffer buffer, int remaining) {return buffer;} + public ByteBuffer getReadBuffer() {return readbuf;} + public ByteBuffer getWriteBuffer() {return writebuf;} + } // ------------------------------------------------ Handler Inner Interface @@ -1369,8 +1349,8 @@ public class NioEndpoint { public enum SocketState { OPEN, CLOSED, LONG } - public SocketState process(SocketChannel socket); - public SocketState event(SocketChannel socket, boolean error); + public SocketState process(NioChannel socket); + public SocketState event(NioChannel socket, boolean error); } @@ -1439,9 +1419,9 @@ public class NioEndpoint { */ protected class SocketProcessor implements Runnable { - protected SocketChannel socket = null; + protected NioChannel socket = null; - public SocketProcessor(SocketChannel socket) { + public SocketProcessor(NioChannel socket) { this.socket = socket; } @@ -1451,7 +1431,7 @@ public class NioEndpoint { if (handler.process(socket) == Handler.SocketState.CLOSED) { // Close socket and pool try { - socket.socket().close(); + socket.getIOChannel().socket().close(); socket.close(); } catch ( Exception x ) { log.error("",x); @@ -1473,10 +1453,10 @@ public class NioEndpoint { */ protected class SocketEventProcessor implements Runnable { - protected SocketChannel socket = null; + protected NioChannel socket = null; protected boolean error = false; - public SocketEventProcessor(SocketChannel socket, boolean error) { + public SocketEventProcessor(NioChannel socket, boolean error) { this.socket = socket; this.error = error; } @@ -1487,7 +1467,7 @@ public class NioEndpoint { if (handler.event(socket, error) == Handler.SocketState.CLOSED) { // Close socket and pool try { - socket.socket().close(); + socket.getIOChannel().socket().close(); socket.close(); } catch ( Exception x ) { log.error("",x); diff --git a/java/org/apache/tomcat/util/net/SSLImplementation.java b/java/org/apache/tomcat/util/net/SSLImplementation.java index 859cbd98d..4d9169b37 100644 --- a/java/org/apache/tomcat/util/net/SSLImplementation.java +++ b/java/org/apache/tomcat/util/net/SSLImplementation.java @@ -17,6 +17,7 @@ package org.apache.tomcat.util.net; import java.net.Socket; +import javax.net.ssl.SSLSession; /* SSLImplementation: @@ -83,4 +84,5 @@ abstract public class SSLImplementation { abstract public String getImplementationName(); abstract public ServerSocketFactory getServerSocketFactory(); abstract public SSLSupport getSSLSupport(Socket sock); + abstract public SSLSupport getSSLSupport(SSLSession session); } diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java b/java/org/apache/tomcat/util/net/SecureNioChannel.java new file mode 100644 index 000000000..7b021d802 --- /dev/null +++ b/java/org/apache/tomcat/util/net/SecureNioChannel.java @@ -0,0 +1,408 @@ +package org.apache.tomcat.util.net; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; + +/** + * + * Implementation of a secure socket channel + * @author Filip Hanik + * @version 1.0 + */ + +public class SecureNioChannel extends NioChannel { + + protected ByteBuffer netInBuffer; + protected ByteBuffer netOutBuffer; + + protected SSLEngine sslEngine; + + protected boolean initHandshakeComplete = false; + protected HandshakeStatus initHandshakeStatus; //gets set by begin handshake + + protected boolean closed = false; + protected boolean closing = false; + + public SecureNioChannel(SocketChannel channel, SSLEngine engine, ApplicationBufferHandler bufHandler) throws IOException { + super(channel,bufHandler); + + this.sslEngine = engine; + + + int appBufSize = sslEngine.getSession().getApplicationBufferSize(); + int netBufSize = sslEngine.getSession().getPacketBufferSize(); + + //ensure that the application has a large enough read/write buffers + //by doing this, we should not encounter any buffer overflow errors + bufHandler.expand(bufHandler.getReadBuffer(), appBufSize); + bufHandler.expand(bufHandler.getWriteBuffer(), appBufSize); + //allocate network buffers - TODO, add in optional direct buffers + this.netInBuffer = ByteBuffer.allocate(netBufSize); + this.netOutBuffer = ByteBuffer.allocate(netBufSize); + this.netOutBuffer.position(0); + this.netOutBuffer.limit(0); + this.netInBuffer.position(0); + this.netInBuffer.limit(0); + + //initiate handshake + sslEngine.beginHandshake(); + initHandshakeStatus = sslEngine.getHandshakeStatus(); + } + +//=========================================================================================== +// NIO SSL METHODS +//=========================================================================================== + + /** + * Flushes the buffer to the network + * @param buf ByteBuffer + * @return boolean true if the buffer has been emptied out, false otherwise + * @throws IOException + */ + protected boolean flush(ByteBuffer buf) throws IOException { + int remaining = buf.remaining(); + if ( remaining > 0 ) { + int written = sc.write(buf); + return written >= remaining; + }else { + return true; + } + } + + /** + * Performs SSL handshake, non blocking, but performs NEED_TASK on the same thread.
+ * Hence, you should never call this method using your Acceptor thread, as you would slow down + * your system significantly.
+ * The return for this operation is 0 if the handshake is complete and a positive value if it is not complete. + * In the event of a positive value coming back, reregister the selection key for the return values interestOps. + * @param read boolean - true if the underlying channel is readable + * @param write boolean - true if the underlying channel is writable + * @return int - 0 if hand shake is complete, otherwise it returns a SelectionKey interestOps value + * @throws IOException + */ + public int handshake(boolean read, boolean write) throws IOException { + if ( initHandshakeComplete ) return 0; //we have done our initial handshake + + if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still have data to write + + SSLEngineResult handshake = null; + + while (!initHandshakeComplete) { + switch ( initHandshakeStatus ) { + case NOT_HANDSHAKING: { + //should never happen + throw new IOException("NOT_HANDSHAKING during handshake"); + } + case FINISHED: { + //we are complete if we have delivered the last package + initHandshakeComplete = !netOutBuffer.hasRemaining(); + //return 0 if we are complete, otherwise we still have data to write + return initHandshakeComplete?0:SelectionKey.OP_WRITE; + } + case NEED_WRAP: { + //perform the wrap function + handshake = handshakeWrap(write); + if ( handshake.getStatus() == Status.OK ){ + if (initHandshakeStatus == HandshakeStatus.NEED_TASK) + initHandshakeStatus = tasks(); + } else { + //wrap should always work with our buffers + throw new IOException("Unexpected status:" + handshake.getStatus() + " during handshake WRAP."); + } + if ( initHandshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) { + //should actually return OP_READ if we have NEED_UNWRAP + return SelectionKey.OP_WRITE; + } + //fall down to NEED_UNWRAP on the same call, will result in a + //BUFFER_UNDERFLOW if it needs data + } + case NEED_UNWRAP: { + //perform the unwrap function + handshake = handshakeUnwrap(read); + if ( handshake.getStatus() == Status.OK ) { + if (initHandshakeStatus == HandshakeStatus.NEED_TASK) + initHandshakeStatus = tasks(); + } else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){ + //read more data, reregister for OP_READ + return SelectionKey.OP_READ; + } else { + throw new IOException("Invalid handshake status:"+initHandshakeStatus+" during handshake UNWRAP."); + }//switch + break; + } + case NEED_TASK: { + initHandshakeStatus = tasks(); + break; + } + default: throw new IllegalStateException("Invalid handshake status:"+initHandshakeStatus); + }//switch + }//while + //return 0 if we are complete, otherwise reregister for any activity that + //would cause this method to be called again. + return initHandshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ); + } + + /** + * Executes all the tasks needed on the same thread. + * @return HandshakeStatus + */ + protected SSLEngineResult.HandshakeStatus tasks() { + Runnable r = null; + while ( (r = sslEngine.getDelegatedTask()) != null) { + r.run(); + } + return sslEngine.getHandshakeStatus(); + } + + /** + * Performs the WRAP function + * @param doWrite boolean + * @return SSLEngineResult + * @throws IOException + */ + protected SSLEngineResult handshakeWrap(boolean doWrite) throws IOException { + //this should never be called with a network buffer that contains data + //so we can clear it here. + netOutBuffer.clear(); + //perform the wrap + SSLEngineResult result = sslEngine.wrap(bufHandler.getWriteBuffer(), netOutBuffer); + //prepare the results to be written + netOutBuffer.flip(); + //set the status + initHandshakeStatus = result.getHandshakeStatus(); + //optimization, if we do have a writable channel, write it now + if ( doWrite ) flush(netOutBuffer); + return result; + } + + /** + * Perform handshake unwrap + * @param doread boolean + * @return SSLEngineResult + * @throws IOException + */ + protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException { + + if (netInBuffer.position() == netInBuffer.limit()) { + //clear the buffer if we have emptied it out on data + netInBuffer.clear(); + } + if ( doread ) { + //if we have data to read, read it + int read = sc.read(netInBuffer); + if (read == -1) throw new IOException("EOF encountered during handshake."); + } + SSLEngineResult result; + boolean cont = false; + //loop while we can perform pure SSLEngine data + do { + //prepare the buffer with the incoming data + netInBuffer.flip(); + //call unwrap + result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer()); + //compact the buffer, this is an optional method, wonder what would happen if we didn't + netInBuffer.compact(); + //read in the status + initHandshakeStatus = result.getHandshakeStatus(); + if ( result.getStatus() == SSLEngineResult.Status.OK && + result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) { + //execute tasks if we need to + initHandshakeStatus = tasks(); + } + //perform another unwrap? + cont = result.getStatus() == SSLEngineResult.Status.OK && + initHandshakeStatus == HandshakeStatus.NEED_UNWRAP; + }while ( cont ); + return result; + } + + /** + * Sends a SSL close message, will not physically close the connection here.
+ * To close the connection, you could do something like + *

+     *   close();
+     *   while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
+     *   if ( isOpen() ) close(true); //forces a close if you timed out
+     * 
+ * @throws IOException if an I/O error occurs + * @throws IOException if there is data on the outgoing network buffer and we are unable to flush it + * @todo Implement this java.io.Closeable method + */ + public void close() throws IOException { + if (closing) return; + closing = true; + sslEngine.closeOutbound(); + + if (!flush(netOutBuffer)) { + throw new IOException("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead"); + } + //prep the buffer for the close message + netOutBuffer.clear(); + //perform the close, since we called sslEngine.closeOutbound + SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer); + //we should be in a close state + if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) { + throw new IOException("Invalid close state, will not send network data."); + } + //prepare the buffer for writing + netOutBuffer.flip(); + //if there is data to be written + flush(netOutBuffer); + + //is the channel closed? + closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP)); + } + + /** + * Force a close, can throw an IOException + * @param force boolean + * @throws IOException + */ + public void close(boolean force) throws IOException { + try { + close(); + }finally { + closed = true; + sc.close(); + } + } + + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + * @param dst The buffer into which bytes are to be transferred + * @return The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream + * @throws IOException If some other I/O error occurs + * @throws IllegalArgumentException if the destination buffer is different than bufHandler.getReadBuffer() + * @todo Implement this java.nio.channels.ReadableByteChannel method + */ + public int read(ByteBuffer dst) throws IOException { + //if we want to take advantage of the expand function, make sure we only use the ApplicationBufferHandler's buffers + if ( dst != bufHandler.getReadBuffer() ) throw new IllegalArgumentException("You can only read using the application read buffer provided by the handler."); + //are we in the middle of closing or closed? + if ( closing || closed) return -1; + //did we finish our handshake? + if (!initHandshakeComplete) throw new IllegalStateException("Handshake incomplete, you must complete handshake before reading data."); + + //read from the network + int netread = sc.read(netInBuffer); + //did we reach EOF? if so send EOF up one layer. + if (netread == -1) return -1; + + //the data read + int read = 0; + //the SSL engine result + SSLEngineResult unwrap; + do { + //prepare the buffer + netInBuffer.flip(); + //unwrap the data + unwrap = sslEngine.unwrap(netInBuffer, dst); + //compact the buffer + netInBuffer.compact(); + + if ( unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW ) { + //we did receive some data, add it to our total + read += unwrap.bytesProduced(); + //perform any tasks if needed + if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks(); + //if we need more network data, then bail out for now. + if ( unwrap.getStatus() == Status.BUFFER_UNDERFLOW ) break; + }else { + //here we should trap BUFFER_OVERFLOW and call expand on the buffer + //for now, throw an exception, as we initialized the buffers + //in the constructor + throw new IOException("Unable to unwrap data, invalid status: " + unwrap.getStatus()); + } + } while ( (netInBuffer.position() != 0)); + return (read); + } + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + * @param src The buffer from which bytes are to be retrieved + * @return The number of bytes written, possibly zero + * @throws IOException If some other I/O error occurs + * @todo Implement this java.nio.channels.WritableByteChannel method + */ + public int write(ByteBuffer src) throws IOException { + //make sure we can handle expand, and that we only use on buffer + if ( src != bufHandler.getWriteBuffer() ) throw new IllegalArgumentException("You can only write using the application write buffer provided by the handler."); + //are we closing or closed? + if ( closing || closed) throw new IOException("Channel is in closing state."); + + //the number of bytes written + int written = 0; + + if (!flush(netOutBuffer)) { + //we haven't emptied out the buffer yet + return written; + } + + /* + * The data buffer is empty, we can reuse the entire buffer. + */ + netOutBuffer.clear(); + + SSLEngineResult result = sslEngine.wrap(src, netOutBuffer); + written = result.bytesConsumed(); + netOutBuffer.flip(); + + if (result.getStatus() == Status.OK) { + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks(); + } else { + throw new IOException("Unable to wrap data, invalid engine state: " +result.getStatus()); + } + + //force a flush + flush(netOutBuffer); + + return written; + } + + /** + * Callback interface to be able to expand buffers + * when buffer overflow exceptions happen + */ + public static interface ApplicationBufferHandler { + public ByteBuffer expand(ByteBuffer buffer, int remaining); + public ByteBuffer getReadBuffer(); + public ByteBuffer getWriteBuffer(); + } + + public ApplicationBufferHandler getBufHandler() { + return bufHandler; + } + + public boolean isInitHandshakeComplete() { + return initHandshakeComplete; + } + + public boolean isClosing() { + return closing; + } + + public SSLEngine getSslEngine() { + return sslEngine; + } + + public ByteBuffer getEmptyBuf() { + return emptyBuf; + } + + public void setBufHandler(ApplicationBufferHandler bufHandler) { + this.bufHandler = bufHandler; + } + + public SocketChannel getIOChannel() { + return sc; + } + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java b/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java index f648520b3..b3a81ea89 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java @@ -22,12 +22,14 @@ import javax.net.ssl.SSLSocket; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.ServerSocketFactory; +import javax.net.ssl.SSLSession; /** * Factory interface to construct components based on the JSSE version * in use. * * @author Bill Barker + * @author Filip Hanik */ public class JSSEFactory { @@ -45,5 +47,9 @@ public class JSSEFactory { public SSLSupport getSSLSupport(Socket socket) { return new JSSESupport((SSLSocket)socket); } + + public SSLSupport getSSLSupport(SSLSession session) { + return new JSSESupport(session); + } }; diff --git a/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java b/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java index d42162601..5b7d3b3ce 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java @@ -21,6 +21,7 @@ import java.net.Socket; import org.apache.tomcat.util.net.SSLImplementation; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.ServerSocketFactory; +import javax.net.ssl.SSLSession; /* JSSEImplementation: @@ -58,4 +59,10 @@ public class JSSEImplementation extends SSLImplementation SSLSupport ssls = factory.getSSLSupport(s); return ssls; } + + public SSLSupport getSSLSupport(SSLSession session) { + SSLSupport ssls = factory.getSSLSupport(session); + return ssls; + } + } diff --git a/java/org/apache/tomcat/util/net/jsse/JSSESupport.java b/java/org/apache/tomcat/util/net/jsse/JSSESupport.java index 3dfca7556..b61f170e0 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSESupport.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSESupport.java @@ -32,7 +32,7 @@ import javax.security.cert.X509Certificate; import org.apache.tomcat.util.net.SSLSupport; -/* JSSESupport +/** JSSESupport Concrete implementation class for JSSE Support classes. @@ -42,6 +42,7 @@ import org.apache.tomcat.util.net.SSLSupport; @author EKR @author Craig R. McClanahan + @author Filip Hanik Parts cribbed from JSSECertCompat Parts cribbed from CertificatesValve */ @@ -52,17 +53,22 @@ class JSSESupport implements SSLSupport { org.apache.commons.logging.LogFactory.getLog(JSSESupport.class); protected SSLSocket ssl; + protected SSLSession session; Listener listener = new Listener(); JSSESupport(SSLSocket sock){ ssl=sock; + session = sock.getSession(); sock.addHandshakeCompletedListener(listener); } + + JSSESupport(SSLSession session) { + this.session = session; + } public String getCipherSuite() throws IOException { // Look up the current SSLSession - SSLSession session = ssl.getSession(); if (session == null) return null; return session.getCipherSuite(); @@ -114,7 +120,6 @@ class JSSESupport implements SSLSupport { public Object[] getPeerCertificateChain(boolean force) throws IOException { // Look up the current SSLSession - SSLSession session = ssl.getSession(); if (session == null) return null; @@ -177,7 +182,6 @@ class JSSESupport implements SSLSupport { public Integer getKeySize() throws IOException { // Look up the current SSLSession - SSLSession session = ssl.getSession(); SSLSupport.CipherData c_aux[]=ciphers; if (session == null) return null; @@ -200,7 +204,6 @@ class JSSESupport implements SSLSupport { public String getSessionId() throws IOException { // Look up the current SSLSession - SSLSession session = ssl.getSession(); if (session == null) return null; // Expose ssl_session (getId) -- 2.11.0