You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/04/09 23:15:11 UTC

svn commit: r1672492 - in /tomcat/trunk/java/org/apache/tomcat/util/net: LocalStrings.properties SNIExtractor.java SecureNioChannel.java

Author: markt
Date: Thu Apr  9 21:15:11 2015
New Revision: 1672492

URL: http://svn.apache.org/r1672492
Log:
SNI refactoring for NIO.
Peek at the data but currently parsing the data is stubbed to report no hostname found.

Added:
    tomcat/trunk/java/org/apache/tomcat/util/net/SNIExtractor.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties
    tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties?rev=1672492&r1=1672491&r2=1672492&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties Thu Apr  9 21:15:11 2015
@@ -94,6 +94,8 @@ channel.nio.ssl.wrapFail=Unable to wrap
 channel.nio.ssl.incompleteHandshake=Handshake incomplete, you must complete handshake before reading data.
 channel.nio.ssl.closing=Channel is in closing state.
 channel.nio.ssl.invalidBuffer=You can only read using the application read buffer provided by the handler.
+channel.nio.ssl.expandNetInBuffer=Expanding network input buffer to [{0}] bytes
+channel.nio.ssl.expandNetOutBuffer=Expanding network input buffer to [{0}] bytes
 
 socket.closed=The socket associated with this connection has been closed.
 

Added: tomcat/trunk/java/org/apache/tomcat/util/net/SNIExtractor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SNIExtractor.java?rev=1672492&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SNIExtractor.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SNIExtractor.java Thu Apr  9 21:15:11 2015
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.tomcat.util.net;
+
+import java.nio.ByteBuffer;
+
+public class SNIExtractor {
+
+    private final SNIResult result = SNIResult.NOT_PRESENT;
+    private final String sniValue = null;
+
+    public SNIExtractor(ByteBuffer netInBuffer) {
+        // TODO: Detect use of http on a secure connection and provide a simple
+        //       error page.
+
+        int pos = netInBuffer.position();
+        try {
+            // TODO Parse the data
+
+        } finally {
+            // Whatever happens, return the buffer to its original state
+            netInBuffer.limit(netInBuffer.capacity());
+            netInBuffer.position(pos);
+        }
+    }
+
+    public SNIResult getResult() {
+        return result;
+    }
+
+    public String getSNIValue() {
+        if (result == SNIResult.FOUND) {
+            return sniValue;
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public static enum SNIResult {
+        FOUND,
+        NOT_PRESENT,
+        UNDERFLOW,
+        ERROR
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/util/net/SNIExtractor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1672492&r1=1672491&r2=1672492&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Thu Apr  9 21:15:11 2015
@@ -28,16 +28,23 @@ import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLEngineResult;
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 import javax.net.ssl.SSLEngineResult.Status;
-import javax.net.ssl.SSLException;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
 
 /**
- *
  * Implementation of a secure socket channel
- * @version 1.0
  */
-
 public class SecureNioChannel extends NioChannel  {
 
+    private static final Log log = LogFactory.getLog(SecureNioChannel.class);
+    private static final StringManager sm = StringManager.getManager(SecureNioChannel.class);
+
+    // Value determined by observation of what the SSL Engine requested in
+    // various scenarios
+    private static final int DEFAULT_NET_BUFFER_SIZE = 16921;
+
     protected ByteBuffer netInBuffer;
     protected ByteBuffer netOutBuffer;
 
@@ -211,50 +218,50 @@ public class SecureNioChannel extends Ni
      * present and, if it is, what host name has been requested. Based on the
      * provided host name, configure the SSLEngine for this connection.
      */
-    private int processSNI() throws SSLException {
-        // TODO The peek at the available data to determine the host requested
-        //      via SNI (if any) goes here.
-
+    private int processSNI() throws IOException {
         SocketProperties sp = endpoint.getSocketProperties();
-        sslEngine = endpoint.createSSLEngine();
-
-        // Ensure the application buffers (which have to be created earlier) are
-        // big enough.
-        bufHandler.expand(sslEngine.getSession().getApplicationBufferSize());
 
-        // Create/expand network buffers.
-        // In/Out are always created in a pair with identical settings so only
-        // need to test one to determine what needs to be done for both.
-        int netBufSize = sslEngine.getSession().getPacketBufferSize();
+        // Create the network input buffer as data needs to be read into this
+        // to be able to peek at it.
         if (netInBuffer == null) {
             if (sp.getDirectSslBuffer()) {
-                netInBuffer = ByteBuffer.allocateDirect(netBufSize);
-                netOutBuffer = ByteBuffer.allocateDirect(netBufSize);
+                netInBuffer = ByteBuffer.allocateDirect(DEFAULT_NET_BUFFER_SIZE);
             } else {
-                netInBuffer = ByteBuffer.allocate(netBufSize);
-                netOutBuffer = ByteBuffer.allocate(netBufSize);
+                netInBuffer = ByteBuffer.allocate(DEFAULT_NET_BUFFER_SIZE);
             }
-        } else if (netInBuffer.capacity() < netBufSize) {
-            // Need to expand the buffers, making sure no data is lost.
-            ByteBuffer newInBuffer;
-            ByteBuffer newOutBuffer;
-            if (sp.getDirectSslBuffer()) {
-                newInBuffer = ByteBuffer.allocateDirect(netBufSize);
-                newOutBuffer = ByteBuffer.allocateDirect(netBufSize);
-            } else {
-                newInBuffer = ByteBuffer.allocate(netBufSize);
-                newOutBuffer = ByteBuffer.allocate(netBufSize);
-            }
-            newInBuffer.put(netInBuffer);
-            newOutBuffer.put(netOutBuffer);
-            netInBuffer = newInBuffer;
-            netOutBuffer = newOutBuffer;
-        } else {
-            // Existing buffers are big enough. Nothing to do here.
         }
+
+        sc.read(netInBuffer);
+        SNIExtractor extractor = new SNIExtractor(netInBuffer);
+
+        String hostName = null;
+        switch (extractor.getResult()) {
+        case FOUND:
+            hostName = extractor.getSNIValue();
+            break;
+        case ERROR:
+            // NO-OP Let the handshake continue and deal with whatever was wrong
+            break;
+        case NOT_PRESENT:
+            // NO-OP
+            break;
+        case UNDERFLOW:
+            return SelectionKey.OP_READ;
+        }
+
+        System.out.println("SNI hostname was [" + hostName + "]");
+
+        // TODO: Extract the correct configuration for the requested host name
+        //       and set up the SSLEngine accordingly.
+
+        sslEngine = endpoint.createSSLEngine();
+
+        // Ensure the application buffers (which have to be created earlier) are
+        // big enough.
+        bufHandler.expand(sslEngine.getSession().getApplicationBufferSize());
+        expandNetBuffers(sslEngine.getSession().getPacketBufferSize(), sp.getDirectSslBuffer());
+
         // Set limit and position to expected values
-        netInBuffer.position(0);
-        netInBuffer.limit(0);
         netOutBuffer.position(0);
         netOutBuffer.limit(0);
 
@@ -266,6 +273,48 @@ public class SecureNioChannel extends Ni
     }
 
 
+    private void expandNetBuffers(int newSize, boolean direct) {
+
+        // The input buffer will always have been created by the time this
+        // method is called.
+        if (netInBuffer.capacity() < newSize) {
+            // Info as we may need to increase DEFAULT_NET_BUFFER_SIZE
+            log.info(sm.getString("channel.nio.ssl.expandNetInBuffer", Integer.toString(newSize)));
+            ByteBuffer newInBuffer;
+            if (direct) {
+                newInBuffer = ByteBuffer.allocateDirect(newSize);
+            } else {
+                newInBuffer = ByteBuffer.allocate(newSize);
+            }
+            // Need to expand the buffers, making sure no data is lost.
+            netInBuffer.flip();
+            newInBuffer.put(netInBuffer);
+            netInBuffer = newInBuffer;
+        }
+
+        if (netOutBuffer == null) {
+            if (direct) {
+                netOutBuffer = ByteBuffer.allocateDirect(newSize);
+            } else {
+                netOutBuffer = ByteBuffer.allocate(newSize);
+            }
+        } else if (netOutBuffer.capacity() < newSize) {
+            // Info as we may need to increase DEFAULT_NET_BUFFER_SIZE
+            log.info(sm.getString("channel.nio.ssl.expandNetOutBuffer", Integer.toString(newSize)));
+            // Need to expand the buffers, making sure no data is lost.
+            ByteBuffer newOutBuffer;
+            if (direct) {
+                newOutBuffer = ByteBuffer.allocateDirect(newSize);
+            } else {
+                newOutBuffer = ByteBuffer.allocate(newSize);
+            }
+            netOutBuffer.flip();
+            newOutBuffer.put(netOutBuffer);
+            netOutBuffer = newOutBuffer;
+        }
+    }
+
+
     /**
      * Force a blocking handshake to take place for this key.
      * This requires that both network and application buffers have been emptied out prior to this call taking place, or a



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