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/01/29 21:37:05 UTC
svn commit: r1655847 - in /tomcat/trunk/java/org/apache: coyote/ coyote/ajp/
coyote/http11/ coyote/http11/upgrade/ tomcat/util/net/
Author: markt
Date: Thu Jan 29 20:37:04 2015
New Revision: 1655847
URL: http://svn.apache.org/r1655847
Log:
Refactor obtaining the SSL attributes.
Add an AprSSLSupport wrapper which allows APR to be aligned with NIO/NIO2 and then pulled up to the AbstractHttp11Processor
Added:
tomcat/trunk/java/org/apache/tomcat/util/net/AprSSLSupport.java (with props)
Modified:
tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java
tomcat/trunk/java/org/apache/coyote/Processor.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java
Modified: tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java Thu Jan 29 20:37:04 2015
@@ -42,6 +42,7 @@ public abstract class AbstractProcessor<
protected final Request request;
protected final Response response;
protected SocketWrapperBase<S> socketWrapper = null;
+ private String clientCertProvider = null;
/**
* Error state for the request/response currently being processed.
@@ -137,6 +138,16 @@ public abstract class AbstractProcessor<
}
+ public String getClientCertProvider() {
+ return clientCertProvider;
+ }
+
+
+ public void setClientCertProvider(String s) {
+ this.clientCertProvider = s;
+ }
+
+
/**
* Set the socket wrapper being used.
*/
Modified: tomcat/trunk/java/org/apache/coyote/Processor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/Processor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/Processor.java Thu Jan 29 20:37:04 2015
@@ -55,6 +55,20 @@ public interface Processor<S> {
*/
void recycle();
+ /**
+ * When client certificate information is presented in a form other than
+ * instances of {@link java.security.cert.X509Certificate} it needs to be
+ * converted before it can be used and this property controls which JSSE
+ * provider is used to perform the conversion. For example it is used with
+ * the AJP connectors, the HTTP APR connector and with the
+ * {@link org.apache.catalina.valves.SSLValve}. If not specified, the
+ * default provider will be used.
+ *
+ * @return The name of the JSSE provider to use for certificate
+ * transformation if required
+ */
+ String getClientCertProvider();
+
void setSslSupport(SSLSupport sslSupport);
/**
@@ -62,4 +76,6 @@ public interface Processor<S> {
* @return leftover bytes
*/
ByteBuffer getLeftoverInput();
+
+
}
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java Thu Jan 29 20:37:04 2015
@@ -313,19 +313,6 @@ public class AjpProcessor<S> extends Abs
}
- /**
- * When client certificate information is presented in a form other than
- * instances of {@link java.security.cert.X509Certificate} it needs to be
- * converted before it can be used and this property controls which JSSE
- * provider is used to perform the conversion. For example it is used with
- * the AJP connectors, the HTTP APR connector and with the
- * {@link org.apache.catalina.valves.SSLValve}. If not specified, the
- * default provider will be used.
- */
- private String clientCertProvider = null;
- public String getClientCertProvider() { return clientCertProvider; }
- public void setClientCertProvider(String s) { this.clientCertProvider = s; }
-
// --------------------------------------------------------- Public Methods
@@ -415,6 +402,7 @@ public class AjpProcessor<S> extends Abs
// Fill the elements.
try {
CertificateFactory cf;
+ String clientCertProvider = getClientCertProvider();
if (clientCertProvider == null) {
cf = CertificateFactory.getInstance("X.509");
} else {
Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java Thu Jan 29 20:37:04 2015
@@ -53,6 +53,7 @@ import org.apache.tomcat.util.log.UserDa
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.DispatchType;
+import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SendfileDataBase;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapperBase;
@@ -229,6 +230,12 @@ public abstract class AbstractHttp11Proc
protected SendfileDataBase sendfileData = null;
+ /**
+ * SSL information.
+ */
+ protected SSLSupport sslSupport;
+
+
public AbstractHttp11Processor(int maxHttpHeaderSize, AbstractEndpoint<S> endpoint,
int maxTrailerSize, int maxExtensionSize, int maxSwallowSize) {
@@ -691,6 +698,15 @@ public abstract class AbstractHttp11Proc
/**
+ * Set the SSL information for this HTTP connection.
+ */
+ @Override
+ public void setSslSupport(SSLSupport sslSupport) {
+ this.sslSupport = sslSupport;
+ }
+
+
+ /**
* Send an action to the connector.
*
* @param actionCode Type of the action
@@ -934,6 +950,36 @@ public abstract class AbstractHttp11Proc
}
break;
}
+ case REQ_SSL_ATTRIBUTE: {
+ 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);
+ }
+ request.setAttribute(SSLSupport.SESSION_MGR, sslSupport);
+ }
+ } catch (Exception e) {
+ getLog().warn(sm.getString("http11processor.socket.ssl"), e);
+ }
+ break;
+ }
default: {
actionInternal(actionCode, param);
break;
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java Thu Jan 29 20:37:04 2015
@@ -55,30 +55,6 @@ public class Http11AprProcessor extends
}
- // ----------------------------------------------------- Instance Variables
-
- /**
- * When client certificate information is presented in a form other than
- * instances of {@link java.security.cert.X509Certificate} it needs to be
- * converted before it can be used and this property controls which JSSE
- * provider is used to perform the conversion. For example it is used with
- * the AJP connectors, the HTTP APR connector and with the
- * {@link org.apache.catalina.valves.SSLValve}. If not specified, the
- * default provider will be used.
- */
- protected String clientCertProvider = null;
- public String getClientCertProvider() { return clientCertProvider; }
- public void setClientCertProvider(String s) { this.clientCertProvider = s; }
-
-
- // --------------------------------------------------------- Public Methods
-
- @Override
- public void setSslSupport(SSLSupport sslSupport) {
- // NOOP for APR
- }
-
-
// ----------------------------------------------------- ActionHook Methods
/**
@@ -94,55 +70,6 @@ public class Http11AprProcessor extends
long socketRef = socketWrapper.getSocket().longValue();
switch (actionCode) {
- case REQ_SSL_ATTRIBUTE: {
- if (endpoint.isSSLEnabled() && (socketRef != 0)) {
- try {
- // Cipher suite
- Object sslO = SSLSocket.getInfoS(socketRef, SSL.SSL_INFO_CIPHER);
- if (sslO != null) {
- request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, sslO);
- }
- // Get client certificate and the certificate chain if present
- // certLength == -1 indicates an error
- int certLength = SSLSocket.getInfoI(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN);
- byte[] clientCert = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT);
- X509Certificate[] certs = null;
- if (clientCert != null && certLength > -1) {
- certs = new X509Certificate[certLength + 1];
- CertificateFactory cf;
- if (clientCertProvider == null) {
- cf = CertificateFactory.getInstance("X.509");
- } else {
- cf = CertificateFactory.getInstance("X.509",
- clientCertProvider);
- }
- certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert));
- for (int i = 0; i < certLength; i++) {
- byte[] data = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
- certs[i+1] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data));
- }
- }
- if (certs != null) {
- request.setAttribute(SSLSupport.CERTIFICATE_KEY, certs);
- }
- // User key size
- sslO = Integer.valueOf(SSLSocket.getInfoI(socketRef,
- SSL.SSL_INFO_CIPHER_USEKEYSIZE));
- request.setAttribute(SSLSupport.KEY_SIZE_KEY, sslO);
-
- // SSL session ID
- sslO = SSLSocket.getInfoS(socketRef, SSL.SSL_INFO_SESSION_ID);
- if (sslO != null) {
- request.setAttribute(SSLSupport.SESSION_ID_KEY, sslO);
- }
- //TODO provide a hook to enable the SSL session to be
- // invalidated. Set AprEndpoint.SESSION_MGR req attr
- } catch (Exception e) {
- log.warn(sm.getString("http11processor.socket.ssl"), e);
- }
- }
- break;
- }
case REQ_SSL_CERTIFICATE: {
if (endpoint.isSSLEnabled() && (socketRef != 0)) {
// Consume and buffer the request body, so that it does not
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProtocol.java Thu Jan 29 20:37:04 2015
@@ -28,6 +28,7 @@ import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.AprEndpoint;
import org.apache.tomcat.util.net.AprEndpoint.Poller;
+import org.apache.tomcat.util.net.AprSSLSupport;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapperBase;
@@ -264,9 +265,14 @@ public class Http11AprProtocol extends A
}
@Override
- protected void initSsl(SocketWrapperBase<Long> socket,
- Processor<Long> processor) {
- // NOOP for APR
+ protected void initSsl(SocketWrapperBase<Long> socket, Processor<Long> processor) {
+ if (proto.isSSLEnabled()) {
+ AprSSLSupport sslSupport =
+ new AprSSLSupport(socket, processor.getClientCertProvider());
+ processor.setSslSupport(sslSupport);
+ } else {
+ processor.setSslSupport(null);
+ }
}
@Override
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java Thu Jan 29 20:37:04 2015
@@ -45,12 +45,6 @@ public class Http11Nio2Processor extends
}
- /**
- * SSL information.
- */
- protected SSLSupport sslSupport;
-
-
// ----------------------------------------------------------- Constructors
public Http11Nio2Processor(int maxHttpHeaderSize, AbstractEndpoint<Nio2Channel> endpoint,
@@ -62,15 +56,6 @@ public class Http11Nio2Processor extends
// --------------------------------------------------------- Public Methods
- /**
- * Set the SSL information for this HTTP connection.
- */
- @Override
- public void setSslSupport(SSLSupport sslSupport) {
- this.sslSupport = sslSupport;
- }
-
-
@Override
public SocketState asyncDispatch(SocketStatus status) {
SocketState state = super.asyncDispatch(status);
@@ -97,36 +82,6 @@ public class Http11Nio2Processor extends
public void actionInternal(ActionCode actionCode, Object param) {
switch (actionCode) {
- case REQ_SSL_ATTRIBUTE: {
- 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);
- }
- request.setAttribute(SSLSupport.SESSION_MGR, sslSupport);
- }
- } catch (Exception e) {
- log.warn(sm.getString("http11processor.socket.ssl"), e);
- }
- break;
- }
case REQ_SSL_CERTIFICATE: {
if (sslSupport != null && socketWrapper.getSocket() != null) {
/*
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Thu Jan 29 20:37:04 2015
@@ -45,12 +45,6 @@ public class Http11NioProcessor extends
}
- /**
- * SSL information.
- */
- protected SSLSupport sslSupport;
-
-
// ----------------------------------------------------------- Constructors
public Http11NioProcessor(int maxHttpHeaderSize, AbstractEndpoint<NioChannel> endpoint,
@@ -60,17 +54,6 @@ public class Http11NioProcessor extends
}
- // --------------------------------------------------------- Public Methods
-
- /**
- * Set the SSL information for this HTTP connection.
- */
- @Override
- public void setSslSupport(SSLSupport sslSupport) {
- this.sslSupport = sslSupport;
- }
-
-
// ----------------------------------------------------- ActionHook Methods
/**
@@ -84,36 +67,6 @@ public class Http11NioProcessor extends
public void actionInternal(ActionCode actionCode, Object param) {
switch (actionCode) {
- case REQ_SSL_ATTRIBUTE: {
- 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);
- }
- request.setAttribute(SSLSupport.SESSION_MGR, sslSupport);
- }
- } catch (Exception e) {
- log.warn(sm.getString("http11processor.socket.ssl"), e);
- }
- break;
- }
case REQ_SSL_CERTIFICATE: {
if (sslSupport != null) {
/*
Modified: tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java?rev=1655847&r1=1655846&r2=1655847&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java Thu Jan 29 20:37:04 2015
@@ -176,6 +176,12 @@ public class UpgradeProcessor<S> impleme
@Override
+ public String getClientCertProvider() {
+ return null;
+ }
+
+
+ @Override
public final void setSslSupport(SSLSupport sslSupport) {
// NOOP
}
Added: tomcat/trunk/java/org/apache/tomcat/util/net/AprSSLSupport.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AprSSLSupport.java?rev=1655847&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/AprSSLSupport.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/AprSSLSupport.java Thu Jan 29 20:37:04 2015
@@ -0,0 +1,120 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import org.apache.tomcat.jni.SSL;
+import org.apache.tomcat.jni.SSLSocket;
+
+/**
+ * Implementation of SSLSupport for APR.
+ * <p>
+ * TODO: Add a mechanism (or figure out how to use what we already have) to
+ * invalidate the session.
+ */
+public class AprSSLSupport implements SSLSupport {
+
+ private final SocketWrapperBase<Long> socketWrapper;
+ private final String clientCertProvider;
+
+
+ public AprSSLSupport(SocketWrapperBase<Long> socketWrapper, String clientCertProvider) {
+ this.socketWrapper = socketWrapper;
+ this.clientCertProvider = clientCertProvider;
+ }
+
+
+ @Override
+ public String getCipherSuite() throws IOException {
+ long socketRef = socketWrapper.getSocket().longValue();
+ if (socketRef == 0) {
+ return null;
+ }
+ try {
+ return SSLSocket.getInfoS(socketRef, SSL.SSL_INFO_CIPHER);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+
+ @Override
+ public X509Certificate[] getPeerCertificateChain(boolean force) throws IOException {
+ long socketRef = socketWrapper.getSocket().longValue();
+ if (socketRef == 0) {
+ return null;
+ }
+
+ try {
+ // certLength == -1 indicates an error
+ int certLength = SSLSocket.getInfoI(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN);
+ byte[] clientCert = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT);
+ X509Certificate[] certs = null;
+ if (clientCert != null && certLength > -1) {
+ certs = new X509Certificate[certLength + 1];
+ CertificateFactory cf;
+ if (clientCertProvider == null) {
+ cf = CertificateFactory.getInstance("X.509");
+ } else {
+ cf = CertificateFactory.getInstance("X.509", clientCertProvider);
+ }
+ certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert));
+ for (int i = 0; i < certLength; i++) {
+ byte[] data = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
+ certs[i+1] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data));
+ }
+ }
+ return certs;
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+
+ @Override
+ public Integer getKeySize() throws IOException {
+ long socketRef = socketWrapper.getSocket().longValue();
+ if (socketRef == 0) {
+ return null;
+ }
+
+ try {
+ return Integer.valueOf(SSLSocket.getInfoI(socketRef, SSL.SSL_INFO_CIPHER_USEKEYSIZE));
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+
+ @Override
+ public String getSessionId() throws IOException {
+ long socketRef = socketWrapper.getSocket().longValue();
+ if (socketRef == 0) {
+ return null;
+ }
+
+ try {
+ return SSLSocket.getInfoS(socketRef, SSL.SSL_INFO_SESSION_ID);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+}
Propchange: tomcat/trunk/java/org/apache/tomcat/util/net/AprSSLSupport.java
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org