[tomcat8] 01/05: Imported Upstream version 8.0.22

Emmanuel Bourg ebourg-guest at moszumanska.debian.org
Wed May 6 10:47:01 UTC 2015


This is an automated email from the git hooks/post-receive script.

ebourg-guest pushed a commit to annotated tag debian/8.0.22-1
in repository tomcat8.

commit 6c92e2a86993f0d44e4dd911fbb3a5b984a7feae
Author: Emmanuel Bourg <ebourg at apache.org>
Date:   Wed May 6 09:51:45 2015 +0200

    Imported Upstream version 8.0.22
---
 RELEASE-NOTES                                      |    1 -
 bin/catalina.sh                                    |    2 +
 build.properties.default                           |   10 +-
 build.xml                                          |   54 +-
 conf/catalina.properties                           |    2 +-
 .../catalina/authenticator/SingleSignOn.java       |    2 +-
 java/org/apache/catalina/connector/Response.java   |   62 +-
 .../apache/catalina/core/LocalStrings.properties   |    7 +
 java/org/apache/catalina/core/StandardContext.java |   17 +-
 .../catalina/filters/LocalStrings.properties       |    1 +
 .../apache/catalina/filters/RemoteIpFilter.java    |   58 +-
 .../catalina/ha/session/ClusterManagerBase.java    |   14 +
 .../apache/catalina/ha/session/DeltaRequest.java   |    4 +-
 .../apache/catalina/ha/session/DeltaSession.java   |   18 +-
 .../catalina/ha/session/mbeans-descriptors.xml     |   14 +-
 java/org/apache/catalina/startup/HostConfig.java   |  100 +-
 .../tribes/tipis/AbstractReplicatedMap.java        |   13 +-
 java/org/apache/catalina/util/Introspection.java   |    8 +-
 .../catalina/valves/AbstractAccessLogValve.java    |   81 +-
 .../apache/catalina/valves/LocalStrings.properties |    1 +
 .../catalina/valves/rewrite/RewriteValve.java      |   23 -
 .../catalina/valves/rewrite/Substitution.java      |    9 +-
 java/org/apache/catalina/webresources/Cache.java   |    4 +-
 .../catalina/webresources/JarWarResource.java      |    2 +-
 .../apache/catalina/webresources/StandardRoot.java |    2 +-
 .../catalina/webresources/WarURLStreamHandler.java |    6 +-
 java/org/apache/coyote/AbstractProcessor.java      |   11 +-
 java/org/apache/coyote/ajp/AjpNio2Protocol.java    |    6 -
 java/org/apache/coyote/ajp/AjpNioProtocol.java     |    6 -
 .../coyote/http11/AbstractHttp11Protocol.java      |   13 +-
 .../apache/coyote/http11/Http11AprProtocol.java    |   31 -
 .../apache/coyote/http11/Http11Nio2Protocol.java   |   27 -
 .../apache/coyote/http11/Http11NioProtocol.java    |   28 -
 java/org/apache/coyote/http11/Http11Protocol.java  |   20 -
 .../coyote/http11/InternalNio2OutputBuffer.java    |   14 +
 .../apache/coyote/http11/LocalStrings.properties   |    2 +
 java/org/apache/coyote/http11/NpnHandler.java      |   58 -
 java/org/apache/coyote/spdy/SpdyAprNpnHandler.java |  112 --
 java/org/apache/coyote/spdy/SpdyProcessor.java     |  648 ----------
 java/org/apache/coyote/spdy/SpdyProxyProtocol.java |  142 --
 java/org/apache/el/Messages.properties             |    2 +
 java/org/apache/el/parser/AstValue.java            |   32 +-
 java/org/apache/jasper/JspCompilationContext.java  |    5 +
 .../apache/jasper/servlet/JspServletWrapper.java   |    7 +
 java/org/apache/tomcat/jni/Library.java            |   10 +-
 java/org/apache/tomcat/jni/Poll.java               |   17 -
 java/org/apache/tomcat/jni/SSLExt.java             |  159 ---
 java/org/apache/tomcat/jni/socket/AprSocket.java   |  922 -------------
 .../apache/tomcat/jni/socket/AprSocketContext.java | 1352 --------------------
 java/org/apache/tomcat/jni/socket/HostInfo.java    |   84 --
 java/org/apache/tomcat/spdy/CompressDeflater6.java |  178 ---
 java/org/apache/tomcat/spdy/NetSupportOpenSSL.java |  208 ---
 java/org/apache/tomcat/spdy/NetSupportSocket.java  |  171 ---
 java/org/apache/tomcat/spdy/SpdyConnection.java    |  681 ----------
 java/org/apache/tomcat/spdy/SpdyContext.java       |  216 ----
 java/org/apache/tomcat/spdy/SpdyFrame.java         |  354 -----
 java/org/apache/tomcat/spdy/SpdyStream.java        |  308 -----
 java/org/apache/tomcat/util/digester/Digester.java |    6 -
 java/org/apache/tomcat/util/net/Nio2Endpoint.java  |   10 +-
 java/org/apache/tomcat/util/net/NioEndpoint.java   |   10 +-
 .../apache/tomcat/util/net/SecureNio2Channel.java  |  105 +-
 java/org/apache/tomcat/util/scan/JarFactory.java   |    2 +-
 .../tomcat/websocket/LocalStrings.properties       |    2 +-
 .../apache/tomcat/websocket/PerMessageDeflate.java |   54 +-
 java/org/apache/tomcat/websocket/Util.java         |    4 +
 .../org/apache/tomcat/websocket/WsFrameClient.java |   11 +
 .../tomcat/websocket/WsWebSocketContainer.java     |   13 +-
 .../server/WsRemoteEndpointImplServer.java         |    3 +-
 res/checkstyle/org-import-control.xml              |    5 -
 res/maven/mvn-pub.xml                              |    5 +-
 res/maven/mvn.properties.default                   |    2 +-
 .../{tomcat-spdy.pom => tomcat-storeconfig.pom}    |   20 +-
 .../apache/catalina/connector/TesterResponse.java  |   31 +
 .../apache/catalina/core/TestStandardContext.java  |    4 +-
 .../catalina/filters/TestRemoteIpFilter.java       |  150 ++-
 ...TestWebappClassLoaderThreadLocalMemoryLeak.java |   17 +
 .../startup/TestHostConfigAutomaticDeployment.java |   32 +-
 .../catalina/valves/rewrite/TestRewriteValve.java  |   14 +
 .../valves/rewrite/TesterRewriteMapA.java}         |   27 +-
 .../webresources/TestWarURLConnection.java         |    2 +-
 ...onnection.java => TestWarURLStreamHandler.java} |    4 +-
 ...ava => TestWarURLStreamHandlerIntegration.java} |   35 +-
 test/org/apache/el/TestMethodExpressionImpl.java   |   49 +
 test/org/apache/el/TesterBeanB.java                |   15 +
 .../tomcat/websocket/TestWebSocketFrameClient.java |   51 +
 .../apache/tomcat/websocket/TesterEchoServer.java  |   18 +
 webapps/docs/changelog.xml                         |  226 +++-
 webapps/docs/class-loader-howto.xml                |    1 -
 webapps/docs/config/ajp.xml                        |    4 +-
 webapps/docs/config/cluster-manager.xml            |    7 +
 webapps/docs/config/cluster.xml                    |    6 +-
 webapps/docs/config/http.xml                       |   12 +-
 webapps/docs/config/valve.xml                      |   20 +-
 webapps/docs/security-howto.xml                    |   12 +-
 94 files changed, 1195 insertions(+), 6133 deletions(-)

diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 40052c3..e53ee9d 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -83,7 +83,6 @@ for use by web applications (by placing them in "lib"):
 * tomcat-dbcp.jar (package renamed database connection pool based on Commons DBCP)
 * tomcat-jdbc.jar (Tomcat's database connection pooling solution)
 * tomcat-jni.jar (Interface to the native component of the APR/native connector)
-* tomcat-spdy.jar (SPDY implementation)
 * tomcat-util.jar (Various utilities)
 * tomcat-websocket.jar (WebSocket 1.1 implementation)
 * websocket-api.jar (WebSocket 1.1 API)
diff --git a/bin/catalina.sh b/bin/catalina.sh
index 18c70a3..1d473e5 100755
--- a/bin/catalina.sh
+++ b/bin/catalina.sh
@@ -349,6 +349,8 @@ elif [ "$1" = "start" ] ; then
           ps -p $PID >/dev/null 2>&1
           if [ $? -eq 0 ] ; then
             echo "Tomcat appears to still be running with PID $PID. Start aborted."
+            echo "If the following process is not a Tomcat process, remove the PID file and try again:"
+            ps -f -p $PID
             exit 1
           else
             echo "Removing/clearing stale PID file."
diff --git a/build.properties.default b/build.properties.default
index ea07c8b..3854957 100644
--- a/build.properties.default
+++ b/build.properties.default
@@ -25,7 +25,7 @@
 # ----- Version Control Flags -----
 version.major=8
 version.minor=0
-version.build=21
+version.build=22
 version.patch=0
 version.suffix=
 
@@ -145,12 +145,6 @@ jdt.jar=${jdt.home}/ecj-${jdt.version}.jar
 jdt.loc.1=http://archive.eclipse.org/eclipse/downloads/drops4/${jdt.release}/ecj-${jdt.version}.jar
 jdt.loc.2=http://download.eclipse.org/eclipse/downloads/drops4/${jdt.release}/ecj-${jdt.version}.jar
 
-# ---- NPN support
-npn.version=8.1.2.v20120308
-npn.home=${base.path}/npn-${npn.version}
-npn.jar=${npn.home}/npn-${npn.version}.jar
-npn.loc=http://repo1.maven.org/maven2/org/eclipse/jetty/npn/npn-api/${npn.version}/npn-api-${npn.version}.jar
-
 # ----- Tomcat native library -----
 tomcat-native.version=1.1.33
 tomcat-native.home=${base.path}/tomcat-native-${tomcat-native.version}
@@ -214,7 +208,7 @@ objenesis.loc=https://objenesis.googlecode.com/files/objenesis-${objenesis.versi
 objenesis.jar=${objenesis.home}/objenesis-${objenesis.version}.jar
 
 # ----- Checkstyle, version 6.0 or later -----
-checkstyle.version=6.4.1
+checkstyle.version=6.5
 checkstyle.home=${base.path}/checkstyle-${checkstyle.version}
 checkstyle.loc=${base-sf.loc}/checkstyle/checkstyle/${checkstyle.version}/checkstyle-${checkstyle.version}-all.jar
 checkstyle.jar=${checkstyle.home}/checkstyle-${checkstyle.version}-all.jar
diff --git a/build.xml b/build.xml
index e626e8a..ff8b5d7 100644
--- a/build.xml
+++ b/build.xml
@@ -100,7 +100,6 @@
   <property name="tomcat-coyote.jar" value="${tomcat.build}/lib/tomcat-coyote.jar"/>
   <property name="tomcat-dbcp.jar" value="${tomcat.build}/lib/tomcat-dbcp.jar"/>
   <property name="tomcat-jni.jar" value="${tomcat.build}/lib/tomcat-jni.jar"/>
-  <property name="tomcat-spdy.jar" value="${tomcat.build}/lib/tomcat-spdy.jar"/>
   <property name="tomcat-api.jar" value="${tomcat.build}/lib/tomcat-api.jar"/>
   <property name="tomcat-util.jar" value="${tomcat.build}/lib/tomcat-util.jar"/>
   <property name="tomcat-util-scan.jar" value="${tomcat.build}/lib/tomcat-util-scan.jar"/>
@@ -124,7 +123,6 @@
   <property name="catalina-ant-src.jar" value="${tomcat.src.jars}/catalina-ant-src.jar"/>
   <property name="catalina-storeconfig-src.jar" value="${tomcat.src.jars}/catalina-storeconfig-src.jar"/>
   <property name="tomcat-jni-src.jar" value="${tomcat.src.jars}/tomcat-jni-src.jar"/>
-  <property name="tomcat-spdy-src.jar" value="${tomcat.src.jars}/tomcat-spdy-src.jar"/>
   <property name="tomcat-coyote-src.jar" value="${tomcat.src.jars}/tomcat-coyote-src.jar"/>
   <property name="tomcat-dbcp-src.jar" value="${tomcat.src.jars}/tomcat-dbcp-src.jar"/>
   <property name="tomcat-api-src.jar" value="${tomcat.src.jars}/tomcat-api-src.jar"/>
@@ -194,12 +192,9 @@
   <defaultexcludes remove="**/.gitignore" />
   <!--<defaultexcludes echo="true" />-->
 
-  <available file="${npn.jar}" property="npn.exists" />
-
   <!-- Classpaths -->
   <path id="compile.classpath">
     <pathelement location="${jdt.jar}"/>
-    <pathelement location="${npn.jar}"/>
   </path>
 
   <path id="tomcat.classpath">
@@ -347,7 +342,6 @@
     <exclude name="org/apache/tomcat/buildutil" />
     <exclude name="org/apache/tomcat/dbcp" />
     <exclude name="org/apache/tomcat/jni" />
-    <exclude name="org/apache/tomcat/spdy" />
     <exclude name="org/apache/tomcat/util" />
     <exclude name="org/apache/tomcat/websocket" />
   </patternset>
@@ -412,8 +406,6 @@
 
   <patternset id="files.tomcat-coyote">
     <include name="org/apache/coyote/**" />
-    <!-- Included in tomcat-spdy -->
-    <exclude name="org/apache/coyote/spdy/**" />
     <!-- Remaining tomcat-util packages -->
     <include name="org/apache/tomcat/util/bcel/**" />
     <include name="org/apache/tomcat/util/collections/**" />
@@ -423,11 +415,6 @@
     <include name="org/apache/tomcat/util/net/**" />
   </patternset>
 
-  <patternset id="files.tomcat-spdy">
-    <include name="org/apache/coyote/spdy/**" />
-    <include name="org/apache/tomcat/spdy/**" />
-  </patternset>
-
   <patternset id="files.jasper">
     <include name="org/apache/jasper/**" />
   </patternset>
@@ -662,9 +649,6 @@
       -->
       <classpath refid="compile.classpath" />
         <exclude name="org/apache/naming/factory/webservices/**" />
-        <exclude name="org/apache/tomcat/spdy/NetSupportJava7*" unless="npn.exists"/>
-        <exclude name="org/apache/coyote/spdy/*Nio*" unless="npn.exists"/>
-        <exclude name="org/apache/coyote/spdy/SpdyNpnHandler*" unless="npn.exists"/>
     </javac>
     <!-- Copy static resource files -->
     <copy todir="${tomcat.classes}" encoding="ISO-8859-1">
@@ -796,10 +780,6 @@
       filesDir="${tomcat.classes}"
       filesId="files.tomcat-coyote" />
 
-    <jarIt jarfile="${tomcat-spdy.jar}"
-      filesDir="${tomcat.classes}"
-      filesId="files.tomcat-spdy" />
-
     <jarIt jarfile="${tomcat-jni.jar}"
       filesDir="${tomcat.classes}"
       filesId="files.tomcat-jni" />
@@ -2124,9 +2104,27 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
     </copy>
   </target>
 
+  <target name="-installer-pre-init">
+    <property environment="env" />
+    <condition property="wine.ok">
+      <or>
+        <os family="windows" />
+        <available file="wine" filepath="${env.PATH}" />
+        <isset property="skip.installer"/>
+      </or>
+    </condition>
+  </target>
+
+  <target name="-installer-init" depends="-installer-pre-init" unless="${wine.ok}">
+    <fail message="The executable wine was not found on the current path.
+Wine is required to build the Windows installer when running a release build on
+a non-Windows platform. To skip building the Windows installer, set the
+skip.installer property in build.properties" />
+  </target>
+
   <target name="-installer-prep"
       description="Prepares file structure required to build installer"
-      unless="skip.installer" depends="dist-static">
+      unless="skip.installer" depends="dist-static,-installer-init">
     <copy todir="${tomcat.dist}">
       <fileset dir="res">
         <include name="INSTALLLICENSE" />
@@ -2683,11 +2681,6 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
       notice="${tomcat.manifests}/tomcat-coyote.jar.notice"
       license="${tomcat.manifests}/tomcat-coyote.license" />
 
-    <!-- SPDY -->
-    <jarIt jarfile="${tomcat-spdy-src.jar}"
-      filesDir="java"
-      filesId="files.tomcat-spdy" />
-
     <!-- JNI -->
     <jarIt jarfile="${tomcat-jni-src.jar}"
       filesDir="java"
@@ -2775,15 +2768,6 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
 
   </target>
 
-  <target name="download-npn"
-          description="Download optional NPN" >
-    <antcall target="downloadfile">
-     <param name="sourcefile" value="${npn.loc}"/>
-     <param name="destfile" value="${npn.jar}"/>
-     <param name="destdir" value="${npn.home}"/>
-    </antcall>
-  </target>
-
   <target name="download-test-compile"
           description="Download additional components for the tests" >
 
diff --git a/conf/catalina.properties b/conf/catalina.properties
index 2e3d4d9..ff4a09d 100644
--- a/conf/catalina.properties
+++ b/conf/catalina.properties
@@ -112,7 +112,7 @@ catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-storeconfig.jar,\
 catalina-tribes.jar,\
 jasper.jar,jasper-el.jar,ecj-*.jar,\
 tomcat-api.jar,tomcat-util.jar,tomcat-util-scan.jar,tomcat-coyote.jar,\
-tomcat-dbcp.jar,tomcat-jni.jar,tomcat-spdy.jar,tomcat-websocket.jar,\
+tomcat-dbcp.jar,tomcat-jni.jar,tomcat-websocket.jar,\
 tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,\
 tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,\
 tomcat-jdbc.jar,\
diff --git a/java/org/apache/catalina/authenticator/SingleSignOn.java b/java/org/apache/catalina/authenticator/SingleSignOn.java
index e9459d8..481e1ed 100644
--- a/java/org/apache/catalina/authenticator/SingleSignOn.java
+++ b/java/org/apache/catalina/authenticator/SingleSignOn.java
@@ -59,7 +59,7 @@ import org.apache.tomcat.util.res.StringManager;
  */
 public class SingleSignOn extends ValveBase {
 
-    private static final StringManager sm = StringManager.getManager(SingleSignOn.class.getName());
+    private static final StringManager sm = StringManager.getManager(Constants.Package);
 
     /* The engine at the top of the container hierarchy in which this SSO Valve
      * has been placed. It is used to get back to a session object from a
diff --git a/java/org/apache/catalina/connector/Response.java b/java/org/apache/catalina/connector/Response.java
index fdd59e2..759f125 100644
--- a/java/org/apache/catalina/connector/Response.java
+++ b/java/org/apache/catalina/connector/Response.java
@@ -321,7 +321,7 @@ public class Response
                 // Ignore - the client has probably closed the connection
             }
         }
-        return coyoteResponse.getBytesWritten(flush);
+        return getCoyoteResponse().getBytesWritten(flush);
     }
 
     /**
@@ -458,7 +458,7 @@ public class Response
      * Return the content length that was set or calculated for this Response.
      */
     public int getContentLength() {
-        return coyoteResponse.getContentLength();
+        return getCoyoteResponse().getContentLength();
     }
 
 
@@ -468,7 +468,7 @@ public class Response
      */
     @Override
     public String getContentType() {
-        return coyoteResponse.getContentType();
+        return getCoyoteResponse().getContentType();
     }
 
 
@@ -525,7 +525,7 @@ public class Response
      */
     @Override
     public String getCharacterEncoding() {
-        return (coyoteResponse.getCharacterEncoding());
+        return (getCoyoteResponse().getCharacterEncoding());
     }
 
 
@@ -559,7 +559,7 @@ public class Response
      */
     @Override
     public Locale getLocale() {
-        return (coyoteResponse.getLocale());
+        return (getCoyoteResponse().getLocale());
     }
 
 
@@ -609,7 +609,7 @@ public class Response
      */
     @Override
     public boolean isCommitted() {
-        return coyoteResponse.isCommitted();
+        return getCoyoteResponse().isCommitted();
     }
 
 
@@ -626,7 +626,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.reset();
+        getCoyoteResponse().reset();
         outputBuffer.reset();
         usingOutputStream = false;
         usingWriter = false;
@@ -723,7 +723,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.setContentLength(length);
+        getCoyoteResponse().setContentLength(length);
 
     }
 
@@ -746,7 +746,7 @@ public class Response
         }
 
         if (type == null) {
-            coyoteResponse.setContentType(null);
+            getCoyoteResponse().setContentType(null);
             return;
         }
 
@@ -754,16 +754,16 @@ public class Response
         if (m == null) {
             // Invalid - Assume no charset and just pass through whatever
             // the user provided.
-            coyoteResponse.setContentTypeNoCharset(type);
+            getCoyoteResponse().setContentTypeNoCharset(type);
             return;
         }
 
-        coyoteResponse.setContentTypeNoCharset(m[0]);
+        getCoyoteResponse().setContentTypeNoCharset(m[0]);
 
         if (m[1] != null) {
             // Ignore charset if getWriter() has already been called
             if (!usingWriter) {
-                coyoteResponse.setCharacterEncoding(m[1]);
+                getCoyoteResponse().setCharacterEncoding(m[1]);
                 isCharacterEncodingSet = true;
             }
         }
@@ -795,7 +795,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.setCharacterEncoding(charset);
+        getCoyoteResponse().setCharacterEncoding(charset);
         isCharacterEncodingSet = true;
     }
 
@@ -818,7 +818,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.setLocale(locale);
+        getCoyoteResponse().setLocale(locale);
 
         // Ignore any call made after the getWriter has been invoked.
         // The default should be used
@@ -832,7 +832,7 @@ public class Response
 
         String charset = getContext().getCharset(locale);
         if (charset != null) {
-            coyoteResponse.setCharacterEncoding(charset);
+            getCoyoteResponse().setCharacterEncoding(charset);
         }
     }
 
@@ -842,14 +842,14 @@ public class Response
 
     @Override
     public String getHeader(String name) {
-        return coyoteResponse.getMimeHeaders().getHeader(name);
+        return getCoyoteResponse().getMimeHeaders().getHeader(name);
     }
 
 
     @Override
     public Collection<String> getHeaderNames() {
 
-        MimeHeaders headers = coyoteResponse.getMimeHeaders();
+        MimeHeaders headers = getCoyoteResponse().getMimeHeaders();
         int n = headers.size();
         List<String> result = new ArrayList<>(n);
         for (int i = 0; i < n; i++) {
@@ -864,7 +864,7 @@ public class Response
     public Collection<String> getHeaders(String name) {
 
         Enumeration<String> enumeration =
-            coyoteResponse.getMimeHeaders().values(name);
+                getCoyoteResponse().getMimeHeaders().values(name);
         Vector<String> result = new Vector<>();
         while (enumeration.hasMoreElements()) {
             result.addElement(enumeration.nextElement());
@@ -878,13 +878,13 @@ public class Response
      * for this Response.
      */
     public String getMessage() {
-        return coyoteResponse.getMessage();
+        return getCoyoteResponse().getMessage();
     }
 
 
     @Override
     public int getStatus() {
-        return coyoteResponse.getStatus();
+        return getCoyoteResponse().getStatus();
     }
 
 
@@ -928,7 +928,7 @@ public class Response
         final String startsWith = name + "=";
         String header = generateCookieString(cookie);
         boolean set = false;
-        MimeHeaders headers = coyoteResponse.getMimeHeaders();
+        MimeHeaders headers = getCoyoteResponse().getMimeHeaders();
         int n = headers.size();
         for (int i = 0; i < n; i++) {
             if (headers.getName(i).toString().equals(headername)) {
@@ -1027,7 +1027,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.addHeader(name, value, charset);
+        getCoyoteResponse().addHeader(name, value, charset);
     }
 
 
@@ -1089,15 +1089,15 @@ public class Response
         if(cc=='C' || cc=='c') {
             if(name.equalsIgnoreCase("Content-Type")) {
                 // Will return null if this has not been set
-                return (coyoteResponse.getContentType() != null);
+                return (getCoyoteResponse().getContentType() != null);
             }
             if(name.equalsIgnoreCase("Content-Length")) {
                 // -1 means not known and is not sent to client
-                return (coyoteResponse.getContentLengthLong() != -1);
+                return (getCoyoteResponse().getContentLengthLong() != -1);
             }
         }
 
-        return coyoteResponse.containsHeader(name);
+        return getCoyoteResponse().containsHeader(name);
     }
 
 
@@ -1200,7 +1200,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.action(ActionCode.ACK, null);
+        getCoyoteResponse().action(ActionCode.ACK, null);
     }
 
 
@@ -1245,8 +1245,8 @@ public class Response
 
         setError();
 
-        coyoteResponse.setStatus(status);
-        coyoteResponse.setMessage(message);
+        getCoyoteResponse().setStatus(status);
+        getCoyoteResponse().setMessage(message);
 
         // Clear any data content that has been buffered
         resetBuffer();
@@ -1369,7 +1369,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.setHeader(name, value);
+        getCoyoteResponse().setHeader(name, value);
     }
 
 
@@ -1434,8 +1434,8 @@ public class Response
             return;
         }
 
-        coyoteResponse.setStatus(status);
-        coyoteResponse.setMessage(message);
+        getCoyoteResponse().setStatus(status);
+        getCoyoteResponse().setMessage(message);
 
     }
 
diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties
index a4b93ee..214a11b 100644
--- a/java/org/apache/catalina/core/LocalStrings.properties
+++ b/java/org/apache/catalina/core/LocalStrings.properties
@@ -108,16 +108,20 @@ standardContext.backgroundProcess.loader=Exception processing loader {0} backgro
 standardContext.backgroundProcess.manager=Exception processing manager {0} background process
 standardContext.backgroundProcess.resources=Exception processing resources {0} background process
 standardContext.cluster.noManager=No manager found. Checking if cluster manager should be used. Cluster configured: [{0}], Application distributable: [{1}]
+standardContext.configurationFail=One or more components marked the context as not correctly configured
 standardContext.duplicateListener=The listener "{0}" is already configured for this context. The duplicate definition has been ignored.
 standardContext.errorPage.error=Error page location {0} must start with a ''/''
 standardContext.errorPage.required=ErrorPage cannot be null
 standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4
+standardContext.extensionValidationError=Error while attempting to validate required application extensions
+standardContext.filterFail=One or more Filters failed to start. Full details will be found in the appropriate container log file
 standardContext.filterMap.either=Filter mapping must specify either a <url-pattern> or a <servlet-name>
 standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0}
 standardContext.filterMap.pattern=Invalid <url-pattern> {0} in filter mapping
 standardContext.filterStart=Exception starting filter {0}
 standardContext.requestListener.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0}
 standardContext.isUnavailable=This application is not currently available
+standardContext.listenerFail=One or more listeners failed to start. Full details will be found in the appropriate container log file
 standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0}
 standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0}
 standardContext.loadOnStartup.loadException=Servlet [{1}] in web application [{0}] threw load() exception
@@ -127,6 +131,7 @@ standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/'
 standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4
 standardContext.loginConfig.required=LoginConfig cannot be null
 standardContext.manager=Configured a manager of class [{0}]
+standardContext.managerFail=The session manager failed to start
 standardContext.namingResource.init.fail=Failed to init new naming resources
 standardContext.namingResource.destroy.fail=Failed to destroy old naming resources
 standardContext.noResourceJar=Resource JARs are not supported. The JAR found at [{0}] will not be used to provide static content for context with name [{1}]
@@ -141,10 +146,12 @@ standardContext.predestroy.duplicate=Duplicate pre destroy method definition for
 standardContext.predestroy.required=Both fully qualified class name and method name are required
 standardContext.reloadingCompleted=Reloading Context with name [{0}] is completed
 standardContext.reloadingStarted=Reloading Context with name [{0}] has started
+standardContext.resourcesInit=Error initializing static Resources
 standardContext.resourcesStart=Error starting static Resources
 standardContext.sciFail=Error during ServletContainerInitializer processing
 standardContext.securityConstraint.mixHttpMethod=It is not permitted to mix <http-method> and <http-method-omission> in the same web resource collection
 standardContext.securityConstraint.pattern=Invalid <url-pattern> {0} in security constraint
+standardContext.servletFail=One or more Servlets failed to load on startup. Full details will be found in the appropriate container log file
 standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0}
 standardContext.servletMap.pattern=Invalid <url-pattern> {0} in servlet mapping
 standardContext.startFailed=Context [{0}] startup failed due to previous errors
diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java
index 9a21f8e..c240037 100644
--- a/java/org/apache/catalina/core/StandardContext.java
+++ b/java/org/apache/catalina/core/StandardContext.java
@@ -4414,7 +4414,8 @@ public class StandardContext extends ContainerBase
                 String canonicalPath = resource.getCanonicalPath();
                 if (canonicalPath == null) {
                     return null;
-                } else if (resource.isDirectory() && !canonicalPath.endsWith(File.separator)) {
+                } else if ((resource.isDirectory() && !canonicalPath.endsWith(File.separator) ||
+                        !resource.exists()) && path.endsWith("/")) {
                     return canonicalPath + File.separatorChar;
                 } else {
                     return canonicalPath;
@@ -4966,7 +4967,7 @@ public class StandardContext extends ContainerBase
             try {
                 setResources(new StandardRoot(this));
             } catch (IllegalArgumentException e) {
-                log.error("Error initializing resources: " + e.getMessage());
+                log.error(sm.getString("standardContext.resourcesInit"), e);
                 ok = false;
             }
         }
@@ -4992,7 +4993,7 @@ public class StandardContext extends ContainerBase
             dependencyCheck = ExtensionValidator.validateApplication
                 (getResources(), this);
         } catch (IOException ioe) {
-            log.error("Error in dependencyCheck", ioe);
+            log.error(sm.getString("standardContext.extensionValidationError"), ioe);
             dependencyCheck = false;
         }
 
@@ -5115,7 +5116,7 @@ public class StandardContext extends ContainerBase
             }
 
             if (!getConfigured()) {
-                log.error( "Error getConfigured");
+                log.error(sm.getString("standardContext.configurationFail"));
                 ok = false;
             }
 
@@ -5164,7 +5165,7 @@ public class StandardContext extends ContainerBase
             // Configure and call application event listeners
             if (ok) {
                 if (!listenerStart()) {
-                    log.error( "Error listenerStart");
+                    log.error(sm.getString("standardContext.listenerFail"));
                     ok = false;
                 }
             }
@@ -5183,14 +5184,14 @@ public class StandardContext extends ContainerBase
                     ((Lifecycle) manager).start();
                 }
             } catch(Exception e) {
-                log.error("Error manager.start()", e);
+                log.error(sm.getString("standardContext.managerFail"), e);
                 ok = false;
             }
 
             // Configure and call application filters
             if (ok) {
                 if (!filterStart()) {
-                    log.error("Error filterStart");
+                    log.error(sm.getString("standardContext.filterFail"));
                     ok = false;
                 }
             }
@@ -5198,7 +5199,7 @@ public class StandardContext extends ContainerBase
             // Load and initialize all "load on startup" servlets
             if (ok) {
                 if (!loadOnStartup(findChildren())){
-                    log.error("Error loadOnStartup");
+                    log.error(sm.getString("standardContext.servletFail"));
                     ok = false;
                 }
             }
diff --git a/java/org/apache/catalina/filters/LocalStrings.properties b/java/org/apache/catalina/filters/LocalStrings.properties
index 66116e4..9c94cc6 100644
--- a/java/org/apache/catalina/filters/LocalStrings.properties
+++ b/java/org/apache/catalina/filters/LocalStrings.properties
@@ -40,3 +40,4 @@ expiresFilter.filterInitialized=Filter initialized with configuration {0}
 expiresFilter.expirationHeaderAlreadyDefined=Request "{0}" with response status "{1}" content-type "{2}", expiration header already defined
 expiresFilter.skippedStatusCode=Request "{0}" with response status "{1}" content-type "{1}", skip expiration header generation for given status
 
+remoteIpFilter.invalidLocation=Failed to modify the rewrite location [{0}] to use scheme [{1}] and port [{2}]
\ No newline at end of file
diff --git a/java/org/apache/catalina/filters/RemoteIpFilter.java b/java/org/apache/catalina/filters/RemoteIpFilter.java
index db63789..1304c12 100644
--- a/java/org/apache/catalina/filters/RemoteIpFilter.java
+++ b/java/org/apache/catalina/filters/RemoteIpFilter.java
@@ -17,6 +17,8 @@
 package org.apache.catalina.filters;
 
 import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
@@ -40,11 +42,13 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
 
 import org.apache.catalina.AccessLog;
 import org.apache.catalina.Globals;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
 
 /**
  * <p>
@@ -617,6 +621,49 @@ public class RemoteIpFilter implements Filter {
         }
     }
 
+    public static class XForwardedResponse extends HttpServletResponseWrapper {
+
+        private final String scheme;
+        private final int port;
+
+        public XForwardedResponse(HttpServletResponse response, String scheme, int port) {
+            super(response);
+            this.scheme = scheme;
+            if ("http".equals(scheme) && port == 80 || "https".equals(scheme) && port == 443) {
+                this.port = -1;
+            } else {
+                this.port = port;
+            }
+        }
+
+        @Override
+        public void sendRedirect(String location) throws IOException {
+            /*
+             * This isn't particularly pretty but, given that:
+             * a) there is no setRequest() method on ServletResponse (even if
+             *    there were the response could still access this information
+             *    via some internal structure for speed); and
+             * b) that this is meant to work on any Servlet container;
+             * this was the cleanest way I could come up with for doing this.
+             */
+            super.sendRedirect(location);
+            String redirect = getHeader("location");
+            URI newRedirectURI;
+            try {
+                URI redirectURI = new URI(redirect);
+                newRedirectURI = new URI(scheme, redirectURI.getUserInfo(),
+                        redirectURI.getHost(), port, redirectURI.getPath(),
+                        redirectURI.getQuery(), redirectURI.getFragment());
+            } catch (URISyntaxException e) {
+                log.warn(sm.getString("remoteIpFilter.invalidLocation",
+                        location, scheme, Integer.toString(port)));
+                return;
+            }
+            reset();
+            super.sendRedirect(newRedirectURI.toString());
+        }
+    }
+
     /**
      * {@link Pattern} for a comma delimited string that support whitespace characters
      */
@@ -632,6 +679,7 @@ public class RemoteIpFilter implements Filter {
      * Logger
      */
     private static final Log log = LogFactory.getLog(RemoteIpFilter.class);
+    private static final StringManager sm = StringManager.getManager(Constants.Package);
 
     protected static final String PROTOCOL_HEADER_PARAMETER = "protocolHeader";
 
@@ -810,6 +858,14 @@ public class RemoteIpFilter implements Filter {
                 }
             }
 
+            HttpServletResponse xResponse;
+            if (xRequest.getScheme() != request.getScheme() ||
+                    xRequest.getServerPort() != request.getServerPort()) {
+                xResponse = new XForwardedResponse(response, xRequest.getScheme(), xRequest.getServerPort());
+            } else {
+                xResponse = response;
+            }
+
             if (log.isDebugEnabled()) {
                 log.debug("Incoming request " + request.getRequestURI() + " with originalRemoteAddr '" + request.getRemoteAddr()
                         + "', originalRemoteHost='" + request.getRemoteHost() + "', originalSecure='" + request.isSecure()
@@ -832,7 +888,7 @@ public class RemoteIpFilter implements Filter {
                 request.setAttribute(AccessLog.SERVER_PORT_ATTRIBUTE,
                         Integer.valueOf(xRequest.getServerPort()));
             }
-            chain.doFilter(xRequest, response);
+            chain.doFilter(xRequest, xResponse);
         } else {
             if (log.isDebugEnabled()) {
                 log.debug("Skip RemoteIpFilter for request " + request.getRequestURI() + " with originalRemoteAddr '"
diff --git a/java/org/apache/catalina/ha/session/ClusterManagerBase.java b/java/org/apache/catalina/ha/session/ClusterManagerBase.java
index bdfd7e9..5831981 100644
--- a/java/org/apache/catalina/ha/session/ClusterManagerBase.java
+++ b/java/org/apache/catalina/ha/session/ClusterManagerBase.java
@@ -67,6 +67,11 @@ public abstract class ClusterManagerBase extends ManagerBase implements ClusterM
      */
     private volatile ReplicationValve replicationValve = null ;
 
+    /**
+     * send all actions of session attributes.
+     */
+    private boolean recordAllActions = false;
+
     /*
      * @see org.apache.catalina.ha.ClusterManager#getCluster()
      */
@@ -120,6 +125,14 @@ public abstract class ClusterManagerBase extends ManagerBase implements ClusterM
         }
     }
 
+    public boolean isRecordAllActions() {
+        return recordAllActions;
+    }
+
+    public void setRecordAllActions(boolean recordAllActions) {
+        this.recordAllActions = recordAllActions;
+    }
+
     /**
      * Check whether the given session attribute should be distributed
      *
@@ -210,6 +223,7 @@ public abstract class ClusterManagerBase extends ManagerBase implements ClusterM
              // Ignore
             }
         }
+        copy.setRecordAllActions(isRecordAllActions());
     }
 
     /**
diff --git a/java/org/apache/catalina/ha/session/DeltaRequest.java b/java/org/apache/catalina/ha/session/DeltaRequest.java
index 1ccd999..786311a 100644
--- a/java/org/apache/catalina/ha/session/DeltaRequest.java
+++ b/java/org/apache/catalina/ha/session/DeltaRequest.java
@@ -204,9 +204,9 @@ public class DeltaRequest implements Externalizable {
                 case TYPE_LISTENER:
                     SessionListener listener = (SessionListener) info.getValue();
                     if (info.getAction() == ACTION_SET) {
-                        session.addSessionListener(listener);
+                        session.addSessionListener(listener,false);
                     } else {
-                        session.removeSessionListener(listener);
+                        session.removeSessionListener(listener,false);
                     }
                     break;
                 default :
diff --git a/java/org/apache/catalina/ha/session/DeltaSession.java b/java/org/apache/catalina/ha/session/DeltaSession.java
index 0b29b0e..ee3de8c 100644
--- a/java/org/apache/catalina/ha/session/DeltaSession.java
+++ b/java/org/apache/catalina/ha/session/DeltaSession.java
@@ -134,7 +134,7 @@ public class DeltaSession extends StandardSession implements Externalizable,Clus
         lock();
         try {
             return getDeltaRequest().serialize();
-        } finally{
+        } finally {
             unlock();
         }
     }
@@ -502,10 +502,14 @@ public class DeltaSession extends StandardSession implements Externalizable,Clus
 
     @Override
     public void addSessionListener(SessionListener listener) {
+        addSessionListener(listener, true);
+    }
+
+    public void addSessionListener(SessionListener listener, boolean addDeltaRequest) {
         lock();
         try {
             super.addSessionListener(listener);
-            if (deltaRequest != null && listener instanceof ReplicatedSessionListener) {
+            if (addDeltaRequest && deltaRequest != null && listener instanceof ReplicatedSessionListener) {
                 deltaRequest.addSessionListener(listener);
             }
         } finally {
@@ -515,10 +519,14 @@ public class DeltaSession extends StandardSession implements Externalizable,Clus
 
     @Override
     public void removeSessionListener(SessionListener listener) {
+        removeSessionListener(listener, true);
+    }
+
+    public void removeSessionListener(SessionListener listener, boolean addDeltaRequest) {
         lock();
         try {
             super.removeSessionListener(listener);
-            if (deltaRequest != null && listener instanceof ReplicatedSessionListener) {
+            if (addDeltaRequest && deltaRequest != null && listener instanceof ReplicatedSessionListener) {
                 deltaRequest.removeSessionListener(listener);
             }
         } finally {
@@ -584,7 +592,9 @@ public class DeltaSession extends StandardSession implements Externalizable,Clus
         lock();
         try {
             if (deltaRequest == null) {
-                deltaRequest = new DeltaRequest(getIdInternal(), false);
+                boolean recordAllActions = manager instanceof ClusterManagerBase &&
+                        ((ClusterManagerBase)manager).isRecordAllActions();
+                deltaRequest = new DeltaRequest(getIdInternal(), recordAllActions);
             } else {
                 deltaRequest.reset();
                 deltaRequest.setSessionId(getIdInternal());
diff --git a/java/org/apache/catalina/ha/session/mbeans-descriptors.xml b/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
index 76a689e..e1b1ecd 100644
--- a/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
@@ -309,6 +309,11 @@
       is="true"
       description="All session messages before state transfer message creation are dropped."
       type="boolean"/>
+    <attribute
+      name="recordAllActions"
+      is="true"
+      description="Flag whether send all actions for session across Tomcat cluster nodes."
+      type="boolean"/>
     <operation
       name="expireSession"
       description="Expired the given session"
@@ -474,10 +479,6 @@
       description="Send session attribute change events on backup nodes"
       type="boolean"/>
     <attribute
-      name="pathname"
-      description="Path name of the disk file in which active sessions"
-      type="java.lang.String"/>
-    <attribute
       name="processExpiresFrequency"
       description="The frequency of the manager checks (expiration and passivation)"
       type="int"/>
@@ -530,6 +531,11 @@
       name="secureRandomProvider"
       description="The secure random number generator provider name"
       type="java.lang.String"/>
+    <attribute
+      name="recordAllActions"
+      is="true"
+      description="Flag whether send all actions for session across Tomcat cluster nodes."
+      type="boolean"/>
     <operation
       name="expireSession"
       description="Expired the given session"
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 15a8d5b..bcadb31 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -77,9 +77,14 @@ public class HostConfig
 
     private static final Log log = LogFactory.getLog( HostConfig.class );
 
-    // ----------------------------------------------------- Instance Variables
+    /**
+     * The resolution, in milliseconds, of file modification times.
+     */
+    protected static final long FILE_MODIFICATION_RESOLUTION_MS = 1000;
 
 
+    // ----------------------------------------------------- Instance Variables
+
     /**
      * The Java class name of the Context implementation we should use.
      */
@@ -1226,6 +1231,9 @@ public class HostConfig
     protected synchronized void checkResources(DeployedApplication app) {
         String[] resources =
             app.redeployResources.keySet().toArray(new String[0]);
+        // Offset the current time by the resolution of File.lastModified()
+        long currentTimeWithResolutionOffset =
+                System.currentTimeMillis() - FILE_MODIFICATION_RESOLUTION_MS;
         for (int i = 0; i < resources.length; i++) {
             File resource = new File(resources[i]);
             if (log.isDebugEnabled())
@@ -1234,7 +1242,12 @@ public class HostConfig
             long lastModified =
                     app.redeployResources.get(resources[i]).longValue();
             if (resource.exists() || lastModified == 0) {
-                if (resource.lastModified() > lastModified) {
+                // File.lastModified() has a resolution of 1s (1000ms). The last
+                // modified time has to be more than 1000ms ago to ensure that
+                // modifications that take place in the same second are not
+                // missed. See Bug 57765.
+                if (resource.lastModified() != lastModified && (!host.getAutoDeploy() ||
+                        resource.lastModified() < currentTimeWithResolutionOffset)) {
                     if (resource.isDirectory()) {
                         // No action required for modified directory
                         app.redeployResources.put(resources[i],
@@ -1255,12 +1268,10 @@ public class HostConfig
                                 docBaseFile = new File(host.getAppBaseFile(),
                                         docBase);
                             }
-                            ExpandWar.delete(docBaseFile);
-                            // Reset the docBase to trigger re-expansion of the
-                            // WAR
-                            context.setDocBase(resource.getAbsolutePath());
+                            reload(app, docBaseFile, resource.getAbsolutePath());
+                        } else {
+                            reload(app, null, null);
                         }
-                        reload(app);
                         // Update times
                         app.redeployResources.put(resources[i],
                                 Long.valueOf(resource.lastModified()));
@@ -1312,10 +1323,17 @@ public class HostConfig
                 log.debug("Checking context[" + app.name + "] reload resource " + resource);
             }
             long lastModified = app.reloadResources.get(resources[i]).longValue();
-            if (resource.lastModified() != lastModified || update) {
+            // File.lastModified() has a resolution of 1s (1000ms). The last
+            // modified time has to be more than 1000ms ago to ensure that
+            // modifications that take place in the same second are not
+            // missed. See Bug 57765.
+            if ((resource.lastModified() != lastModified &&
+                    (!host.getAutoDeploy() ||
+                            resource.lastModified() < currentTimeWithResolutionOffset)) ||
+                    update) {
                 if (!update) {
                     // Reload application
-                    reload(app);
+                    reload(app, null, null);
                     update = true;
                 }
                 // Update times. More than one file may have been updated. We
@@ -1328,16 +1346,28 @@ public class HostConfig
     }
 
 
-    private void reload(DeployedApplication app) {
+    /*
+     * Note: If either of fileToRemove and newDocBase are null, both will be
+     *       ignored.
+     */
+    private void reload(DeployedApplication app, File fileToRemove, String newDocBase) {
         if(log.isInfoEnabled())
             log.info(sm.getString("hostConfig.reload", app.name));
         Context context = (Context) host.findChild(app.name);
         if (context.getState().isAvailable()) {
+            if (fileToRemove != null && newDocBase != null) {
+                context.addLifecycleListener(
+                        new ExpandedDirectoryRemovalListener(fileToRemove, newDocBase));
+            }
             // Reload catches and logs exceptions
             context.reload();
         } else {
             // If the context was not started (for example an error
             // in web.xml) we'll still get to try to start
+            if (fileToRemove != null && newDocBase != null) {
+                ExpandWar.delete(fileToRemove);
+                context.setDocBase(newDocBase);
+            }
             try {
                 context.start();
             } catch (Exception e) {
@@ -1756,4 +1786,54 @@ public class HostConfig
             config.deployDirectory(cn, dir);
         }
     }
+
+
+    /*
+     * The purpose of this class is to provide a way for HostConfig to get
+     * a Context to delete an expanded WAR after the Context stops. This is to
+     * resolve this issue described in Bug 57772. The alternative solutions
+     * require either duplicating a lot of the Context.reload() code in
+     * HostConfig or adding a new reload(boolean) method to Context that allows
+     * the caller to optionally delete any expanded WAR.
+     *
+     * The LifecycleListener approach offers greater flexibility and enables the
+     * behaviour to be changed / extended / removed in future without changing
+     * the Context API.
+     */
+    private static class ExpandedDirectoryRemovalListener implements LifecycleListener {
+
+        private final File toDelete;
+        private final String newDocBase;
+
+        /**
+         * Create a listener that will ensure that any expanded WAR is removed
+         * and the docBase set to the specified WAR.
+         *
+         * @param toDelete The file (a directory representing an expanded WAR)
+         *                 to be deleted
+         * @param newDocBase The new docBase for the Context
+         */
+        public ExpandedDirectoryRemovalListener(File toDelete, String newDocBase) {
+            this.toDelete = toDelete;
+            this.newDocBase = newDocBase;
+        }
+
+        @Override
+        public void lifecycleEvent(LifecycleEvent event) {
+            if (event.getType() == Lifecycle.AFTER_STOP_EVENT) {
+                // The context has stopped.
+                Context context = (Context) event.getLifecycle();
+
+                // Remove the old expanded WAR.
+                ExpandWar.delete(toDelete);
+
+                // Reset the docBase to trigger re-expansion of the WAR.
+                context.setDocBase(newDocBase);
+
+                // Remove this listener from the Context else it will run every
+                // time the Context is stopped.
+                context.removeLifecycleListener(this);
+            }
+        }
+    }
 }
diff --git a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
index 7a1e6ea..7bbfe4a 100644
--- a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
@@ -671,8 +671,17 @@ public abstract class AbstractReplicatedMap<K,V>
                             diff.unlock();
                         }
                     } else {
-                        if ( mapmsg.getValue()!=null ) entry.setValue((V) mapmsg.getValue());
-                        ((ReplicatedMapEntry)entry.getValue()).setOwner(getMapOwner());
+                        if ( mapmsg.getValue()!=null ) {
+                            if (mapmsg.getValue() instanceof ReplicatedMapEntry) {
+                                ReplicatedMapEntry re = (ReplicatedMapEntry)mapmsg.getValue();
+                                re.setOwner(getMapOwner());
+                                entry.setValue((V) re);
+                            } else {
+                                entry.setValue((V) mapmsg.getValue());
+                            }
+                        } else {
+                            ((ReplicatedMapEntry)entry.getValue()).setOwner(getMapOwner());
+                        }
                     } //end if
                 } else if  (mapmsg.getValue() instanceof ReplicatedMapEntry) {
                     ReplicatedMapEntry re = (ReplicatedMapEntry)mapmsg.getValue();
diff --git a/java/org/apache/catalina/util/Introspection.java b/java/org/apache/catalina/util/Introspection.java
index 4167c28..0e5a1db 100644
--- a/java/org/apache/catalina/util/Introspection.java
+++ b/java/org/apache/catalina/util/Introspection.java
@@ -142,14 +142,14 @@ public class Introspection {
         try {
             clazz = cl.loadClass(className);
         } catch (ClassNotFoundException e) {
-            log.debug(sm.getString("introspection.classLoadFailed"), e);
+            log.debug(sm.getString("introspection.classLoadFailed", className), e);
         } catch (NoClassDefFoundError e) {
-            log.debug(sm.getString("introspection.classLoadFailed"), e);
+            log.debug(sm.getString("introspection.classLoadFailed", className), e);
         } catch (ClassFormatError e) {
-            log.debug(sm.getString("introspection.classLoadFailed"), e);
+            log.debug(sm.getString("introspection.classLoadFailed", className), e);
         } catch (Throwable t) {
             ExceptionUtils.handleThrowable(t);
-            log.debug(sm.getString("introspection.classLoadFailed"), t);
+            log.debug(sm.getString("introspection.classLoadFailed", className), t);
         }
         return clazz;
     }
diff --git a/java/org/apache/catalina/valves/AbstractAccessLogValve.java b/java/org/apache/catalina/valves/AbstractAccessLogValve.java
index 05ff098..87faf6c 100644
--- a/java/org/apache/catalina/valves/AbstractAccessLogValve.java
+++ b/java/org/apache/catalina/valves/AbstractAccessLogValve.java
@@ -135,6 +135,20 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access
 
     private static final Log log = LogFactory.getLog(AbstractAccessLogValve.class);
 
+    /**
+     * The list of our time format types.
+     */
+    private static enum FormatType {
+        CLF, SEC, MSEC, MSEC_FRAC, SDF
+    }
+
+    /**
+     * The list of our port types.
+     */
+    private static enum PortType {
+        LOCAL, REMOTE
+    }
+
     //------------------------------------------------------ Constructor
     public AbstractAccessLogValve() {
         super(true);
@@ -394,13 +408,6 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access
     };
 
     /**
-     * The list of our format types.
-     */
-    private static enum FormatType {
-        CLF, SEC, MSEC, MSEC_FRAC, SDF
-    }
-
-    /**
      * Are we doing conditional logging. default null.
      * It is the value of <code>conditionUnless</code> property.
      */
@@ -1091,13 +1098,41 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access
     }
 
     /**
-     * write local port on which this request was received - %p
+     * write local or remote port for request connection - %p and %{xxx}p
      */
-    protected class LocalPortElement implements AccessLogElement {
+    protected class PortElement implements AccessLogElement {
+
+        /**
+         * Type of port to log
+         */
+        private static final String localPort = "local";
+        private static final String remotePort = "remote";
+
+        private final PortType portType;
+
+        public PortElement() {
+            portType = PortType.LOCAL;
+        }
+
+        public PortElement(String type) {
+            switch (type) {
+            case remotePort:
+                portType = PortType.REMOTE;
+                break;
+            case localPort:
+                portType = PortType.LOCAL;
+                break;
+            default:
+                log.error(sm.getString("accessLogValve.invalidPortType", type));
+                portType = PortType.LOCAL;
+                break;
+            }
+        }
+
         @Override
         public void addElement(CharArrayWriter buf, Date date, Request request,
                 Response response, long time) {
-            if (requestAttributesEnabled) {
+            if (requestAttributesEnabled && portType == PortType.LOCAL) {
                 Object port = request.getAttribute(SERVER_PORT_ATTRIBUTE);
                 if (port == null) {
                     buf.append(Integer.toString(request.getServerPort()));
@@ -1105,7 +1140,11 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access
                     buf.append(port.toString());
                 }
             } else {
-                buf.append(Integer.toString(request.getServerPort()));
+                if (portType == PortType.LOCAL) {
+                    buf.append(Integer.toString(request.getServerPort()));
+                } else {
+                    buf.append(Integer.toString(request.getRemotePort()));
+                }
             }
         }
     }
@@ -1488,22 +1527,24 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access
     }
 
     /**
-     * create an AccessLogElement implementation which needs header string
+     * create an AccessLogElement implementation which needs an element name
      */
-    protected AccessLogElement createAccessLogElement(String header, char pattern) {
+    protected AccessLogElement createAccessLogElement(String name, char pattern) {
         switch (pattern) {
         case 'i':
-            return new HeaderElement(header);
+            return new HeaderElement(name);
         case 'c':
-            return new CookieElement(header);
+            return new CookieElement(name);
         case 'o':
-            return new ResponseHeaderElement(header);
+            return new ResponseHeaderElement(name);
+        case 'p':
+            return new PortElement(name);
         case 'r':
-            return new RequestAttributeElement(header);
+            return new RequestAttributeElement(name);
         case 's':
-            return new SessionAttributeElement(header);
+            return new SessionAttributeElement(name);
         case 't':
-            return new DateAndTimeElement(header);
+            return new DateAndTimeElement(name);
         default:
             return new StringElement("???");
         }
@@ -1535,7 +1576,7 @@ public abstract class AbstractAccessLogValve extends ValveBase implements Access
         case 'm':
             return new MethodElement();
         case 'p':
-            return new LocalPortElement();
+            return new PortElement();
         case 'q':
             return new QueryElement();
         case 'r':
diff --git a/java/org/apache/catalina/valves/LocalStrings.properties b/java/org/apache/catalina/valves/LocalStrings.properties
index c11240d..ba32d83 100644
--- a/java/org/apache/catalina/valves/LocalStrings.properties
+++ b/java/org/apache/catalina/valves/LocalStrings.properties
@@ -26,6 +26,7 @@ accessLogValve.renameFail=Failed to rename access log from [{0}] to [{1}]
 accessLogValve.alreadyExists=Failed to rename access log from [{0}] to [{1}], file already exists.
 accessLogValve.invalidLocale=Failed to set locale to [{0}]
 accessLogValve.unsupportedEncoding=Failed to set encoding to [{0}], will use the system default character set.
+accessLogValve.invalidPortType=Invalid port type [{0}], using server (local) port
 
 # Error report valve
 errorReportValve.errorReport=Error report
diff --git a/java/org/apache/catalina/valves/rewrite/RewriteValve.java b/java/org/apache/catalina/valves/rewrite/RewriteValve.java
index 5b15f35..773cb75 100644
--- a/java/org/apache/catalina/valves/rewrite/RewriteValve.java
+++ b/java/org/apache/catalina/valves/rewrite/RewriteValve.java
@@ -40,12 +40,10 @@ import org.apache.catalina.Engine;
 import org.apache.catalina.Host;
 import org.apache.catalina.Lifecycle;
 import org.apache.catalina.LifecycleException;
-import org.apache.catalina.LifecycleListener;
 import org.apache.catalina.Pipeline;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.connector.Response;
-import org.apache.catalina.util.LifecycleSupport;
 import org.apache.catalina.util.URLEncoder;
 import org.apache.catalina.valves.ValveBase;
 import org.apache.tomcat.util.buf.CharChunk;
@@ -56,12 +54,6 @@ import org.apache.tomcat.util.net.URL;
 public class RewriteValve extends ValveBase {
 
     /**
-     * The lifecycle event support for this component.
-     */
-    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
-
-
-    /**
      * The rewrite rules that the valve will use.
      */
     protected RewriteRule[] rules = null;
@@ -107,21 +99,6 @@ public class RewriteValve extends ValveBase {
     }
 
     @Override
-    public void addLifecycleListener(LifecycleListener listener) {
-        lifecycle.addLifecycleListener(listener);
-    }
-
-    @Override
-    public LifecycleListener[] findLifecycleListeners() {
-        return lifecycle.findLifecycleListeners();
-    }
-
-    @Override
-    public void removeLifecycleListener(LifecycleListener listener) {
-        lifecycle.removeLifecycleListener(listener);
-    }
-
-    @Override
     protected synchronized void startInternal() throws LifecycleException {
 
         super.startInternal();
diff --git a/java/org/apache/catalina/valves/rewrite/Substitution.java b/java/org/apache/catalina/valves/rewrite/Substitution.java
index cb7d235..0f84792 100644
--- a/java/org/apache/catalina/valves/rewrite/Substitution.java
+++ b/java/org/apache/catalina/valves/rewrite/Substitution.java
@@ -30,8 +30,7 @@ public class Substitution {
         public String value;
 
         @Override
-        public String evaluate
-            (Matcher rule, Matcher cond, Resolver resolver) {
+        public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
             return value;
         }
 
@@ -89,9 +88,10 @@ public class Substitution {
         public RewriteMap map = null;
         public String key;
         public String defaultValue = null;
+        public int n;
         @Override
         public String evaluate(Matcher rule, Matcher cond, Resolver resolver) {
-            String result = map.lookup(key);
+            String result = map.lookup(rule.group(n));
             if (result == null) {
                 result = defaultValue;
             }
@@ -162,6 +162,9 @@ public class Substitution {
                     } else {
                         newElement.key = sub.substring(colon + 1, close);
                     }
+                    if (newElement.key.startsWith("$")) {
+                        newElement.n = Integer.parseInt(newElement.key.substring(1));
+                    }
                     pos = close + 1;
                     elements.add(newElement);
                 }
diff --git a/java/org/apache/catalina/webresources/Cache.java b/java/org/apache/catalina/webresources/Cache.java
index c4ca629..eb255d2 100644
--- a/java/org/apache/catalina/webresources/Cache.java
+++ b/java/org/apache/catalina/webresources/Cache.java
@@ -59,12 +59,12 @@ public class Cache {
 
     protected WebResource getResource(String path, boolean useClassLoaderResources) {
 
-        lookupCount.incrementAndGet();
-
         if (noCache(path)) {
             return root.getResourceInternal(path, useClassLoaderResources);
         }
 
+        lookupCount.incrementAndGet();
+
         CachedResource cacheEntry = resourceCache.get(path);
 
         if (cacheEntry != null && !cacheEntry.validateResource(useClassLoaderResources)) {
diff --git a/java/org/apache/catalina/webresources/JarWarResource.java b/java/org/apache/catalina/webresources/JarWarResource.java
index d6cb1a2..0e8c979 100644
--- a/java/org/apache/catalina/webresources/JarWarResource.java
+++ b/java/org/apache/catalina/webresources/JarWarResource.java
@@ -37,7 +37,7 @@ public class JarWarResource extends AbstractArchiveResource {
 
     public JarWarResource(AbstractArchiveResourceSet archiveResourceSet, String webAppPath,
             String baseUrl, JarEntry jarEntry, String archivePath) {
-        super(archiveResourceSet, webAppPath, "jar:war:" + baseUrl + "^/" + archivePath,
+        super(archiveResourceSet, webAppPath, "jar:war:" + baseUrl + "*/" + archivePath,
                 jarEntry, "jar:" + baseUrl + "!/" + archivePath);
         this.archivePath = archivePath;
     }
diff --git a/java/org/apache/catalina/webresources/StandardRoot.java b/java/org/apache/catalina/webresources/StandardRoot.java
index 4e10735..13d38df 100644
--- a/java/org/apache/catalina/webresources/StandardRoot.java
+++ b/java/org/apache/catalina/webresources/StandardRoot.java
@@ -61,7 +61,7 @@ import org.apache.tomcat.util.res.StringManager;
  */
 public class StandardRoot extends LifecycleMBeanBase implements WebResourceRoot {
 
-    private static final Log log = LogFactory.getLog(Cache.class);
+    private static final Log log = LogFactory.getLog(StandardRoot.class);
     protected static final StringManager sm =
             StringManager.getManager(Constants.Package);
 
diff --git a/java/org/apache/catalina/webresources/WarURLStreamHandler.java b/java/org/apache/catalina/webresources/WarURLStreamHandler.java
index 3f012a0..09e118f 100644
--- a/java/org/apache/catalina/webresources/WarURLStreamHandler.java
+++ b/java/org/apache/catalina/webresources/WarURLStreamHandler.java
@@ -30,7 +30,11 @@ public class WarURLStreamHandler extends URLStreamHandler {
 
         // Only the path needs to be changed
         String path = "jar:" + spec.substring(4);
-        path = path.replaceFirst("\\^/", "!/");
+        if (path.contains("*/")) {
+            path = path.replaceFirst("\\*/", "!/");
+        } else {
+            path = path.replaceFirst("\\^/", "!/");
+        }
 
         setURL(u, u.getProtocol(), "", -1, null, null,
                 path, null, null);
diff --git a/java/org/apache/coyote/AbstractProcessor.java b/java/org/apache/coyote/AbstractProcessor.java
index 762cc5f..b65c940 100644
--- a/java/org/apache/coyote/AbstractProcessor.java
+++ b/java/org/apache/coyote/AbstractProcessor.java
@@ -77,11 +77,12 @@ public abstract class AbstractProcessor<S> implements ActionHook, Processor<S> {
     protected void setErrorState(ErrorState errorState, Throwable t) {
         boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed();
         this.errorState = this.errorState.getMostSevere(errorState);
-        if (blockIo && !ContainerThreadMarker.isContainerThread()) {
-            // The error occurred on a non-container thread which means not all
-            // of the necessary clean-up will have been completed. Dispatch to
-            // a container thread to do the clean-up. Need to do it this way to
-            // ensure that all the necessary clean-up is performed.
+        if (blockIo && !ContainerThreadMarker.isContainerThread() && isAsync()) {
+            // The error occurred on a non-container thread during async
+            // processing which means not all of the necessary clean-up will
+            // have been completed. Dispatch to a container thread to do the
+            // clean-up. Need to do it this way to ensure that all the necessary
+            // clean-up is performed.
             if (response.getStatus() < 400) {
                 response.setStatus(500);
             }
diff --git a/java/org/apache/coyote/ajp/AjpNio2Protocol.java b/java/org/apache/coyote/ajp/AjpNio2Protocol.java
index df72013..76e3a7f 100644
--- a/java/org/apache/coyote/ajp/AjpNio2Protocol.java
+++ b/java/org/apache/coyote/ajp/AjpNio2Protocol.java
@@ -16,8 +16,6 @@
  */
 package org.apache.coyote.ajp;
 
-import javax.net.ssl.SSLEngine;
-
 import org.apache.coyote.AbstractProtocol;
 import org.apache.coyote.Processor;
 import org.apache.juli.logging.Log;
@@ -150,10 +148,6 @@ public class AjpNio2Protocol extends AbstractAjpProtocol<Nio2Channel> {
         }
 
         @Override
-        public void onCreateSSLEngine(SSLEngine engine) {
-        }
-
-        @Override
         public void closeAll() {
             for (Nio2Channel channel : connections.keySet()) {
                 ((Nio2Endpoint) proto.endpoint).closeSocket(channel.getSocket(), SocketStatus.STOP);
diff --git a/java/org/apache/coyote/ajp/AjpNioProtocol.java b/java/org/apache/coyote/ajp/AjpNioProtocol.java
index 35a239a..522e76c 100644
--- a/java/org/apache/coyote/ajp/AjpNioProtocol.java
+++ b/java/org/apache/coyote/ajp/AjpNioProtocol.java
@@ -19,8 +19,6 @@ package org.apache.coyote.ajp;
 import java.nio.channels.SocketChannel;
 import java.util.Iterator;
 
-import javax.net.ssl.SSLEngine;
-
 import org.apache.coyote.AbstractProtocol;
 import org.apache.coyote.Processor;
 import org.apache.juli.logging.Log;
@@ -177,9 +175,5 @@ public class AjpNioProtocol extends AbstractAjpProtocol<NioChannel> {
             register(processor);
             return processor;
         }
-
-        @Override
-        public void onCreateSSLEngine(SSLEngine engine) {
-        }
     }
 }
diff --git a/java/org/apache/coyote/http11/AbstractHttp11Protocol.java b/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
index 2144ce6..d735e81 100644
--- a/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
@@ -100,7 +100,7 @@ public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> {
     }
 
 
-    private String compressableMimeTypes = "text/html,text/xml,text/plain";
+    private String compressableMimeTypes = "text/html,text/xml,text/plain,text/css";
     public String getCompressableMimeType() { return compressableMimeTypes; }
     public void setCompressableMimeType(String valueS) {
         compressableMimeTypes = valueS;
@@ -270,17 +270,6 @@ public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> {
         endpoint.setMaxKeepAliveRequests(mkar);
     }
 
-    protected NpnHandler<S> npnHandler;
-    @SuppressWarnings("unchecked")
-    public void setNpnHandler(String impl) {
-        try {
-            Class<?> c = Class.forName(impl);
-            npnHandler = (NpnHandler<S>) c.newInstance();
-        } catch (Exception ex) {
-            getLog().warn("Failed to init light protocol " + impl, ex);
-        }
-    }
-
 
     // ------------------------------------------------------------- Common code
 
diff --git a/java/org/apache/coyote/http11/Http11AprProtocol.java b/java/org/apache/coyote/http11/Http11AprProtocol.java
index b9f463c..b8948c6 100644
--- a/java/org/apache/coyote/http11/Http11AprProtocol.java
+++ b/java/org/apache/coyote/http11/Http11AprProtocol.java
@@ -211,15 +211,6 @@ public class Http11AprProtocol extends AbstractHttp11Protocol<Long> {
     }
 
 
-    @Override
-    public void start() throws Exception {
-        super.start();
-        if (npnHandler != null) {
-            long sslCtx = ((AprEndpoint) endpoint).getJniSslContext();
-            npnHandler.init(endpoint, sslCtx, getAdapter());
-        }
-    }
-
     // --------------------  Connection handler --------------------
 
     protected static class Http11ConnectionHandler
@@ -262,28 +253,6 @@ public class Http11AprProtocol extends AbstractHttp11Protocol<Long> {
         }
 
         @Override
-        public SocketState process(SocketWrapper<Long> socket,
-                SocketStatus status) {
-            if (proto.npnHandler != null) {
-                Processor<Long> processor = null;
-                if (status == SocketStatus.OPEN_READ) {
-                    processor = connections.get(socket.getSocket());
-
-                }
-                if (processor == null) {
-                    // if not null - this is a former comet request, handled by http11
-                    SocketState socketState = proto.npnHandler.process(socket, status);
-                    // handled by npn protocol.
-                    if (socketState == SocketState.CLOSED ||
-                            socketState == SocketState.LONG) {
-                        return socketState;
-                    }
-                }
-            }
-            return super.process(socket, status);
-        }
-
-        @Override
         protected void initSsl(SocketWrapper<Long> socket,
                 Processor<Long> processor) {
             // NOOP for APR
diff --git a/java/org/apache/coyote/http11/Http11Nio2Protocol.java b/java/org/apache/coyote/http11/Http11Nio2Protocol.java
index 50a685b..3947cca 100644
--- a/java/org/apache/coyote/http11/Http11Nio2Protocol.java
+++ b/java/org/apache/coyote/http11/Http11Nio2Protocol.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadPendingException;
 
-import javax.net.ssl.SSLEngine;
 import javax.servlet.http.HttpUpgradeHandler;
 
 import org.apache.coyote.AbstractProtocol;
@@ -71,13 +70,6 @@ public class Http11Nio2Protocol extends AbstractHttp11JsseProtocol<Nio2Channel>
         return ((Nio2Endpoint)endpoint);
     }
 
-    @Override
-    public void start() throws Exception {
-        super.start();
-        if (npnHandler != null) {
-            npnHandler.init(getEndpoint(), 0, getAdapter());
-        }
-    }
 
     // -------------------- Properties--------------------
 
@@ -165,18 +157,6 @@ public class Http11Nio2Protocol extends AbstractHttp11JsseProtocol<Nio2Channel>
             }
         }
 
-        @Override
-        public SocketState process(SocketWrapper<Nio2Channel> socket,
-                SocketStatus status) {
-            if (proto.npnHandler != null) {
-                SocketState ss = proto.npnHandler.process(socket, status);
-                if (ss != SocketState.OPEN) {
-                    return ss;
-                }
-            }
-            return super.process(socket, status);
-        }
-
 
         /**
          * Expected to be used by the handler once the processor is no longer
@@ -266,13 +246,6 @@ public class Http11Nio2Protocol extends AbstractHttp11JsseProtocol<Nio2Channel>
         }
 
         @Override
-        public void onCreateSSLEngine(SSLEngine engine) {
-            if (proto.npnHandler != null) {
-                proto.npnHandler.onCreateEngine(engine);
-            }
-        }
-
-        @Override
         public void closeAll() {
             for (Nio2Channel channel : connections.keySet()) {
                 ((Nio2Endpoint) proto.endpoint).closeSocket(channel.getSocket(), SocketStatus.STOP);
diff --git a/java/org/apache/coyote/http11/Http11NioProtocol.java b/java/org/apache/coyote/http11/Http11NioProtocol.java
index e0284f5..28a69d4 100644
--- a/java/org/apache/coyote/http11/Http11NioProtocol.java
+++ b/java/org/apache/coyote/http11/Http11NioProtocol.java
@@ -21,7 +21,6 @@ import java.nio.ByteBuffer;
 import java.nio.channels.SocketChannel;
 import java.util.Iterator;
 
-import javax.net.ssl.SSLEngine;
 import javax.servlet.http.HttpUpgradeHandler;
 
 import org.apache.coyote.AbstractProtocol;
@@ -35,7 +34,6 @@ import org.apache.tomcat.util.net.NioEndpoint;
 import org.apache.tomcat.util.net.NioEndpoint.Handler;
 import org.apache.tomcat.util.net.SSLImplementation;
 import org.apache.tomcat.util.net.SecureNioChannel;
-import org.apache.tomcat.util.net.SocketStatus;
 import org.apache.tomcat.util.net.SocketWrapper;
 
 
@@ -76,13 +74,6 @@ public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
         return ((NioEndpoint)endpoint);
     }
 
-    @Override
-    public void start() throws Exception {
-        super.start();
-        if (npnHandler != null) {
-            npnHandler.init(getEndpoint(), 0, getAdapter());
-        }
-    }
 
     // -------------------- Properties--------------------
 
@@ -211,18 +202,6 @@ public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
             }
         }
 
-        @Override
-        public SocketState process(SocketWrapper<NioChannel> socket,
-                SocketStatus status) {
-            if (proto.npnHandler != null) {
-                SocketState ss = proto.npnHandler.process(socket, status);
-                if (ss != SocketState.OPEN) {
-                    return ss;
-                }
-            }
-            return super.process(socket, status);
-        }
-
 
         /**
          * Expected to be used by the handler once the processor is no longer
@@ -297,12 +276,5 @@ public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
                     proto.getEndpoint().getSelectorPool(),
                     proto.getUpgradeAsyncWriteBufferSize());
         }
-
-        @Override
-        public void onCreateSSLEngine(SSLEngine engine) {
-            if (proto.npnHandler != null) {
-                proto.npnHandler.onCreateEngine(engine);
-            }
-        }
     }
 }
diff --git a/java/org/apache/coyote/http11/Http11Protocol.java b/java/org/apache/coyote/http11/Http11Protocol.java
index 823f39a..3576f53 100644
--- a/java/org/apache/coyote/http11/Http11Protocol.java
+++ b/java/org/apache/coyote/http11/Http11Protocol.java
@@ -30,7 +30,6 @@ import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.JIoEndpoint;
 import org.apache.tomcat.util.net.JIoEndpoint.Handler;
 import org.apache.tomcat.util.net.SSLImplementation;
-import org.apache.tomcat.util.net.SocketStatus;
 import org.apache.tomcat.util.net.SocketWrapper;
 
 
@@ -93,13 +92,6 @@ public class Http11Protocol extends AbstractHttp11JsseProtocol<Socket> {
         }
     }
 
-    @Override
-    public void start() throws Exception {
-        super.start();
-        if (npnHandler != null) {
-            npnHandler.init(endpoint, 0, getAdapter());
-        }
-    }
 
     // ----------------------------------------------------- JMX related methods
 
@@ -135,18 +127,6 @@ public class Http11Protocol extends AbstractHttp11JsseProtocol<Socket> {
             return proto.sslImplementation;
         }
 
-        @Override
-        public SocketState process(SocketWrapper<Socket> socket,
-                SocketStatus status) {
-            if (proto.npnHandler != null) {
-                SocketState ss = proto.npnHandler.process(socket, status);
-                if (ss != SocketState.OPEN) {
-                    return ss;
-                }
-            }
-            return super.process(socket, status);
-        }
-
         /**
          * Expected to be used by the handler once the processor is no longer
          * required.
diff --git a/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java b/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java
index 2aade80..95a125b 100644
--- a/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java
+++ b/java/org/apache/coyote/http11/InternalNio2OutputBuffer.java
@@ -32,6 +32,8 @@ import javax.servlet.RequestDispatcher;
 
 import org.apache.coyote.OutputBuffer;
 import org.apache.coyote.Response;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.Nio2Channel;
@@ -44,6 +46,8 @@ import org.apache.tomcat.util.net.SocketWrapper;
  */
 public class InternalNio2OutputBuffer extends AbstractOutputBuffer<Nio2Channel> {
 
+    private static final Log log = LogFactory.getLog(InternalNio2OutputBuffer.class);
+
     // ----------------------------------------------------------- Constructors
 
     /**
@@ -151,6 +155,11 @@ public class InternalNio2OutputBuffer extends AbstractOutputBuffer<Nio2Channel>
 
             @Override
             public void failed(Throwable exc, ByteBuffer attachment) {
+                if (socket == null) {
+                    log.warn(sm.getString("iob.nio2.nullSocket"), exc);
+                    // Can't do anything else with a null socket
+                    return;
+                }
                 socket.setError(true);
                 if (exc instanceof IOException) {
                     e = (IOException) exc;
@@ -202,6 +211,11 @@ public class InternalNio2OutputBuffer extends AbstractOutputBuffer<Nio2Channel>
 
             @Override
             public void failed(Throwable exc, ByteBuffer[] attachment) {
+                if (socket == null) {
+                    log.debug(sm.getString("iob.nio2.nullSocket"), exc);
+                    // Can't do anything else with a null socket
+                    return;
+                }
                 socket.setError(true);
                 if (exc instanceof IOException) {
                     e = (IOException) exc;
diff --git a/java/org/apache/coyote/http11/LocalStrings.properties b/java/org/apache/coyote/http11/LocalStrings.properties
index e55ce1a..6a1120c 100644
--- a/java/org/apache/coyote/http11/LocalStrings.properties
+++ b/java/org/apache/coyote/http11/LocalStrings.properties
@@ -42,3 +42,5 @@ iob.failedwrite=Failed write
 iob.failedwrite.ack=Failed to send HTTP 100 continue response
 iob.illegalreset=The response may not be reset once it has been committed
 iob.responseheadertoolarge.error=An attempt was made to write more data to the response headers than there was room available in the buffer. Increase maxHttpHeaderSize on the connector or write less data into the response headers.
+
+iob.nio2.nullSocket=Socket was null while trying to process exception. See Bug 57749
\ No newline at end of file
diff --git a/java/org/apache/coyote/http11/NpnHandler.java b/java/org/apache/coyote/http11/NpnHandler.java
deleted file mode 100644
index 5c00299..0000000
--- a/java/org/apache/coyote/http11/NpnHandler.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  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.coyote.http11;
-
-import org.apache.coyote.Adapter;
-import org.apache.tomcat.util.net.AbstractEndpoint;
-import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
-import org.apache.tomcat.util.net.SocketStatus;
-import org.apache.tomcat.util.net.SocketWrapper;
-
-/**
- * Interface specific for protocols that negotiate at NPN level, like
- * SPDY. This is only available for APR, will replace the HTTP framing.
- */
-public interface NpnHandler<S> {
-
-    /**
-     * Check if the socket has negotiated the right NPN and process it.
-     *
-     * @param socket
-     * @param status
-     * @return OPEN if the socket doesn't have the right npn.
-     *    CLOSE if processing is done. LONG to request read polling.
-     */
-    SocketState process(SocketWrapper<S> socket, SocketStatus status);
-
-    /**
-     * Initialize the npn handler.
-     *
-     * @param ep
-     * @param sslContext
-     * @param adapter
-     */
-    public void init(final AbstractEndpoint<S> ep, long sslContext, Adapter adapter);
-
-    /**
-     * Called when a SSLSocket or SSLEngine are first used, to initialize
-     * NPN extension.
-     *
-     * @param socket SSLEngine or SSLSocket
-     */
-    void onCreateEngine(Object socket);
-}
\ No newline at end of file
diff --git a/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java b/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java
deleted file mode 100644
index 8507617..0000000
--- a/java/org/apache/coyote/spdy/SpdyAprNpnHandler.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- *  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.coyote.spdy;
-
-import java.io.IOException;
-
-import org.apache.coyote.Adapter;
-import org.apache.coyote.http11.NpnHandler;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.jni.SSLExt;
-import org.apache.tomcat.spdy.NetSupportOpenSSL;
-import org.apache.tomcat.spdy.SpdyConnection;
-import org.apache.tomcat.spdy.SpdyContext;
-import org.apache.tomcat.spdy.SpdyContext.SpdyHandler;
-import org.apache.tomcat.spdy.SpdyStream;
-import org.apache.tomcat.util.net.AbstractEndpoint;
-import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
-import org.apache.tomcat.util.net.AprEndpoint;
-import org.apache.tomcat.util.net.SocketStatus;
-import org.apache.tomcat.util.net.SocketWrapper;
-
-/**
- * Plugin for APR connector providing SPDY support via NPN negotiation.
- *
- * Example:
- * <Connector port="9443"
- *            npnHandler="org.apache.coyote.spdy.SpdyAprNpnHandler"
- *            protocol="HTTP/1.1"
- *            SSLEnabled="true"
- *            maxThreads="150"
- *            scheme="https"
- *            secure="true"
- *            sslProtocol="TLS"
- *            SSLCertificateFile="conf/localhost-cert.pem"
- *            SSLCertificateKeyFile="conf/localhost-key.pem"/>
- *
- * This requires APR library ( libtcnative-1 ) to be present and compiled
- * with a recent openssl or a openssl patched with npn support.
- *
- * Because we need to auto-detect SPDY and fallback to HTTP ( based on SSL next
- * proto ) this is implemented in tomcat a special way:
- * Http11AprProtocol will delegate to Spdy.process if spdy is
- * negotiated by TLS.
- *
- */
-public class SpdyAprNpnHandler implements NpnHandler<Long> {
-
-    private static final Log log = LogFactory.getLog(AprEndpoint.class);
-
-    private SpdyContext spdyContext;
-
-    @Override
-    public void init(final AbstractEndpoint<Long> ep, long sslContext,
-            final Adapter adapter) {
-        spdyContext = new SpdyContext();
-        if (sslContext == 0) {
-            // Apr endpoint without SSL - proxy mode.
-            spdyContext.setTlsCompression(false, false);
-            return;
-        }
-        if (0 != SSLExt.setNPN(sslContext, SpdyContext.SPDY_NPN_OUT)) {
-            log.warn("SPDY/NPN not supported");
-        }
-        spdyContext.setNetSupport(new NetSupportOpenSSL());
-        spdyContext.setExecutor(ep.getExecutor());
-        spdyContext.setHandler(new SpdyHandler() {
-            @Override
-            public void onStream(SpdyConnection con, SpdyStream ch)
-                    throws IOException {
-                SpdyProcessor<Long> sp = new SpdyProcessor<>(con, ep);
-                sp.setAdapter(adapter);
-                sp.onSynStream(ch);
-            }
-        });
-    }
-
-    @Override
-    public SocketState process(SocketWrapper<Long> socketWrapper,
-            SocketStatus status) {
-
-        long socket = socketWrapper.getSocket().longValue();
-
-        if (! spdyContext.getNetSupport().isSpdy(socketWrapper.getSocket())) {
-            return SocketState.OPEN;
-        }
-
-        ((NetSupportOpenSSL) spdyContext.getNetSupport()).onAcceptLong(socket);
-
-        // No need to keep tomcat thread busy - but socket will be handled by apr socket context.
-        return SocketState.LONG;
-    }
-
-
-    @Override
-    public void onCreateEngine(Object socket) {
-    }
-}
diff --git a/java/org/apache/coyote/spdy/SpdyProcessor.java b/java/org/apache/coyote/spdy/SpdyProcessor.java
deleted file mode 100644
index 618e41e..0000000
--- a/java/org/apache/coyote/spdy/SpdyProcessor.java
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- *  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.coyote.spdy;
-
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.servlet.http.HttpUpgradeHandler;
-
-import org.apache.coyote.AbstractProcessor;
-import org.apache.coyote.ActionCode;
-import org.apache.coyote.AsyncContextCallback;
-import org.apache.coyote.ErrorState;
-import org.apache.coyote.InputBuffer;
-import org.apache.coyote.OutputBuffer;
-import org.apache.coyote.Request;
-import org.apache.coyote.RequestInfo;
-import org.apache.coyote.Response;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.spdy.SpdyConnection;
-import org.apache.tomcat.spdy.SpdyContext;
-import org.apache.tomcat.spdy.SpdyFrame;
-import org.apache.tomcat.spdy.SpdyStream;
-import org.apache.tomcat.util.ExceptionUtils;
-import org.apache.tomcat.util.buf.Ascii;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.HttpMessages;
-import org.apache.tomcat.util.http.MimeHeaders;
-import org.apache.tomcat.util.net.AbstractEndpoint;
-import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
-import org.apache.tomcat.util.net.SSLSupport;
-import org.apache.tomcat.util.net.SocketStatus;
-import org.apache.tomcat.util.net.SocketWrapper;
-
-/**
- * A spdy stream ( multiplexed over a spdy tcp connection ) processed by a
- * tomcat servlet.
- *
- * Based on the AJP processor.
- */
-public class SpdyProcessor<S> extends AbstractProcessor<S> implements Runnable {
-
-    private static final Log log = LogFactory.getLog(SpdyProcessor.class);
-
-    // TODO: handle input
-    // TODO: recycle
-    // TODO: swallow input ( recycle only after input close )
-    // TODO: find a way to inject an OutputBuffer, or interecept close() -
-    // so we can send FIN in the last data packet.
-
-    private final SpdyConnection spdy;
-
-    // Associated spdy stream
-    private SpdyStream spdyStream;
-
-    private final ByteChunk keyBuffer = new ByteChunk();
-
-    private boolean finished;
-
-    private SpdyFrame inFrame = null;
-
-    private boolean outClosed = false;
-
-    private boolean outCommit = false;
-
-    public SpdyProcessor(SpdyConnection spdy, AbstractEndpoint<S> endpoint) {
-        super(endpoint);
-
-        this.spdy = spdy;
-        request.setInputBuffer(new LiteInputBuffer());
-        response.setOutputBuffer(new LiteOutputBuffer());
-
-    }
-
-    class LiteInputBuffer implements InputBuffer {
-        @Override
-        public int doRead(ByteChunk bchunk, Request request) throws IOException {
-            if (inFrame == null) {
-                // blocking
-                inFrame = spdyStream.getDataFrame(endpoint.getSoTimeout());
-            }
-            if (inFrame == null) {
-                return -1; // timeout
-            }
-            if (inFrame.remaining() == 0 && inFrame.isHalfClose()) {
-                return -1;
-            }
-
-            int rd = Math.min(inFrame.remaining(), bchunk.getBytes().length);
-            System.arraycopy(inFrame.data, inFrame.off, bchunk.getBytes(),
-                    bchunk.getStart(), rd);
-            inFrame.advance(rd);
-            if (inFrame.remaining() == 0) {
-                if (!inFrame.isHalfClose()) {
-                    inFrame = null;
-                }
-            }
-            bchunk.setEnd(bchunk.getEnd() + rd);
-            return rd;
-        }
-    }
-
-    final class LiteOutputBuffer implements OutputBuffer {
-        long byteCount;
-
-        @Override
-        public int doWrite(org.apache.tomcat.util.buf.ByteChunk chunk,
-                Response response) throws IOException {
-            if (!response.isCommitted()) {
-
-                // Send the connector a request for commit. The connector should
-                // then validate the headers, send them (using sendHeader) and
-                // set the filters accordingly.
-                response.action(ActionCode.COMMIT, null);
-
-            }
-            spdyStream.sendDataFrame(chunk.getBuffer(), chunk.getStart(),
-                    chunk.getLength(), false);
-            byteCount += chunk.getLength();
-            return chunk.getLength();
-        }
-
-        @Override
-        public long getBytesWritten() {
-            return byteCount;
-        }
-    }
-
-    void onRequest() {
-        Executor exec = spdy.getSpdyContext().getExecutor();
-        exec.execute(this);
-    }
-
-    /**
-     * Execute the request.
-     */
-    @Override
-    public void run() {
-        RequestInfo rp = request.getRequestProcessor();
-        try {
-            rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
-            getAdapter().service(request, response);
-        } catch (InterruptedIOException e) {
-            setErrorState(ErrorState.CLOSE_NOW, e);
-        } catch (Throwable t) {
-            ExceptionUtils.handleThrowable(t);
-            // log.error(sm.getString("ajpprocessor.request.process"), t);
-            // 500 - Internal Server Error
-            // TODO Log this properly
-            t.printStackTrace();
-            response.setStatus(500);
-            getAdapter().log(request, response, 0);
-            setErrorState(ErrorState.CLOSE_NOW, t);
-        }
-
-        // TODO: async, etc ( detached mode - use a special light protocol)
-
-        // Finish the response if not done yet
-        if (!finished) {
-            try {
-                finish();
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                setErrorState(ErrorState.CLOSE_NOW, t);
-            }
-        }
-
-        if (getErrorState().isError()) {
-            response.setStatus(500);
-        }
-
-        request.updateCounters();
-        rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
-        // TODO: recycle
-    }
-
-    private void finish() {
-        if (!response.isCommitted()) {
-            response.action(ActionCode.COMMIT, response);
-        }
-
-        if (finished)
-            return;
-
-        finished = true;
-
-        response.action(ActionCode.CLOSE, null);
-    }
-
-    private static final byte[] EMPTY = new byte[0];
-
-    // Processor implementation
-
-    private void maybeCommit() {
-        if (outCommit) {
-            return;
-        }
-        if (!response.isCommitted()) {
-            // Validate and write response headers
-            sendSynReply();
-        }
-    }
-
-    @Override
-    public void action(ActionCode actionCode, Object param) {
-        // if (SpdyContext.debug) {
-        // System.err.println(actionCode);
-        // }
-
-        // TODO: async
-
-        switch (actionCode) {
-        case COMMIT: {
-            maybeCommit();
-            break;
-        }
-        case CLIENT_FLUSH: {
-            maybeCommit();
-
-            // try {
-            // flush(true);
-            // } catch (IOException e) {
-            // // Set error flag
-            // error = true;
-            // }
-            break;
-        }
-        case IS_ERROR: {
-            ((AtomicBoolean) param).set(getErrorState().isError());
-            break;
-        }
-        case DISABLE_SWALLOW_INPUT: {
-            // TODO: Do not swallow request input but
-            // make sure we are closing the connection
-            setErrorState(ErrorState.CLOSE_CLEAN, null);
-            break;
-        }
-        case CLOSE: {
-            if (outClosed) {
-                return;
-            }
-            outClosed = true;
-            // Close
-            // End the processing of the current request, and stop any further
-            // transactions with the client
-            maybeCommit();
-
-            spdyStream.sendDataFrame(EMPTY, 0, 0, true);
-            break;
-        }
-        case REQ_SSL_ATTRIBUTE: {
-            // if (!certificates.isNull()) {
-            // ByteChunk certData = certificates.getByteChunk();
-            // X509Certificate jsseCerts[] = null;
-            // ByteArrayInputStream bais =
-            // new ByteArrayInputStream(certData.getBytes(),
-            // certData.getStart(),
-            // certData.getLength());
-            // // Fill the elements.
-            // try {
-            // CertificateFactory cf;
-            // if (clientCertProvider == null) {
-            // cf = CertificateFactory.getInstance("X.509");
-            // } else {
-            // cf = CertificateFactory.getInstance("X.509",
-            // clientCertProvider);
-            // }
-            // while(bais.available() > 0) {
-            // X509Certificate cert = (X509Certificate)
-            // cf.generateCertificate(bais);
-            // if(jsseCerts == null) {
-            // jsseCerts = new X509Certificate[1];
-            // jsseCerts[0] = cert;
-            // } else {
-            // X509Certificate [] temp = new
-            // X509Certificate[jsseCerts.length+1];
-            // System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length);
-            // temp[jsseCerts.length] = cert;
-            // jsseCerts = temp;
-            // }
-            // }
-            // } catch (java.security.cert.CertificateException e) {
-            // getLog().error(sm.getString("ajpprocessor.certs.fail"), e);
-            // return;
-            // } catch (NoSuchProviderException e) {
-            // getLog().error(sm.getString("ajpprocessor.certs.fail"), e);
-            // return;
-            // }
-            // request.setAttribute(SSLSupport.CERTIFICATE_KEY, jsseCerts);
-            // }
-            break;
-        }
-        case REQ_HOST_ATTRIBUTE: {
-            // Get remote host name using a DNS resolution
-            if (request.remoteHost().isNull()) {
-                try {
-                    request.remoteHost().setString(
-                            InetAddress.getByName(
-                                    request.remoteAddr().toString())
-                                    .getHostName());
-                } catch (IOException iex) {
-                    // Ignore
-                }
-            }
-            break;
-        }
-        case REQ_LOCALPORT_ATTRIBUTE: {
-            String configured = (String) endpoint.getAttribute("proxyPort");
-            int localPort = 0;
-            if (configured != null) {
-                localPort = Integer.parseInt(configured);
-            } else {
-                localPort = endpoint.getPort();
-            }
-            request.setLocalPort(localPort);
-            break;
-        }
-        case REQ_LOCAL_ADDR_ATTRIBUTE: {
-            InetAddress localAddress = endpoint.getAddress();
-            String localIp = localAddress == null ? null : localAddress
-                    .getHostAddress();
-            if (localIp == null) {
-                localIp = (String) endpoint.getAttribute("proxyIP");
-            }
-            if (localIp == null) {
-                localIp = "127.0.0.1";
-            }
-            request.localAddr().setString(localIp);
-            break;
-        }
-        case REQ_HOST_ADDR_ATTRIBUTE: {
-            InetAddress localAddress = endpoint.getAddress();
-            String localH = localAddress == null ? null : localAddress
-                    .getCanonicalHostName();
-            if (localH == null) {
-                localH = (String) endpoint.getAttribute("proxyName");
-            }
-            if (localH == null) {
-                localH = "localhost";
-            }
-
-            request.localAddr().setString(localH);
-            break;
-        }
-        case REQ_SET_BODY_REPLAY: {
-            // // Set the given bytes as the content
-            // ByteChunk bc = (ByteChunk) param;
-            // int length = bc.getLength();
-            // bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length);
-            // request.setContentLength(length);
-            // first = false;
-            // empty = false;
-            // replay = true;
-            break;
-        }
-        case ASYNC_START: {
-            asyncStateMachine.asyncStart((AsyncContextCallback) param);
-            break;
-        }
-        case ASYNC_DISPATCHED: {
-            asyncStateMachine.asyncDispatched();
-            break;
-        }
-        case ASYNC_TIMEOUT: {
-            AtomicBoolean result = (AtomicBoolean) param;
-            result.set(asyncStateMachine.asyncTimeout());
-            break;
-        }
-        case ASYNC_RUN: {
-            asyncStateMachine.asyncRun((Runnable) param);
-            break;
-        }
-        case ASYNC_ERROR: {
-            asyncStateMachine.asyncError();
-            break;
-        }
-        case ASYNC_IS_STARTED: {
-            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncStarted());
-            break;
-        }
-        case ASYNC_IS_DISPATCHING: {
-            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncDispatching());
-            break;
-        }
-        case ASYNC_IS_ASYNC: {
-            ((AtomicBoolean) param).set(asyncStateMachine.isAsync());
-            break;
-        }
-        case ASYNC_IS_TIMINGOUT: {
-            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut());
-            break;
-        }
-        case ASYNC_IS_ERROR: {
-            ((AtomicBoolean) param).set(asyncStateMachine.isAsyncError());
-            break;
-        }
-        case CLOSE_NOW: {
-            setErrorState(ErrorState.CLOSE_NOW, null);
-            break;
-        }
-        default: {
-            // TODO:
-            // actionInternal(actionCode, param);
-            break;
-        }
-        }
-    }
-
-
-    /**
-     * When committing the response, we have to validate the set of headers, as
-     * well as setup the response filters.
-     */
-    protected void sendSynReply() {
-
-        response.setCommitted(true);
-
-        // Special headers
-        MimeHeaders headers = response.getMimeHeaders();
-        String contentType = response.getContentType();
-        if (contentType != null) {
-            headers.setValue("Content-Type").setString(contentType);
-        }
-        String contentLanguage = response.getContentLanguage();
-        if (contentLanguage != null) {
-            headers.setValue("Content-Language").setString(contentLanguage);
-        }
-        long contentLength = response.getContentLengthLong();
-        if (contentLength >= 0) {
-            headers.setValue("Content-Length").setLong(contentLength);
-        }
-
-        sendResponseHead();
-    }
-
-    private void sendResponseHead() {
-        SpdyFrame rframe = spdy.getFrame(SpdyConnection.TYPE_SYN_REPLY);
-        rframe.associated = 0;
-
-        MimeHeaders headers = response.getMimeHeaders();
-        for (int i = 0; i < headers.size(); i++) {
-            MessageBytes mb = headers.getName(i);
-            mb.toBytes();
-            ByteChunk bc = mb.getByteChunk();
-            byte[] bb = bc.getBuffer();
-            for (int j = bc.getStart(); j < bc.getEnd(); j++) {
-                bb[j] = (byte) Ascii.toLower(bb[j]);
-            }
-            // TODO: filter headers: Connection, Keep-Alive, Proxy-Connection,
-            rframe.headerName(bc.getBuffer(), bc.getStart(), bc.getLength());
-            mb = headers.getValue(i);
-            mb.toBytes();
-            bc = mb.getByteChunk();
-            rframe.headerValue(bc.getBuffer(), bc.getStart(), bc.getLength());
-        }
-        if (response.getStatus() == 0) {
-            rframe.addHeader(SpdyFrame.STATUS, SpdyFrame.OK200);
-        } else {
-            // HTTP header contents
-            String message = null;
-            if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER
-                    && HttpMessages.isSafeInHttpHeader(response.getMessage())) {
-                message = response.getMessage();
-            }
-            if (message == null) {
-                message = HttpMessages.getInstance(
-                        response.getLocale()).getMessage(response.getStatus());
-            }
-            if (message == null) {
-                // mod_jk + httpd 2.x fails with a null status message - bug
-                // 45026
-                message = Integer.toString(response.getStatus());
-            }
-            // TODO: optimize
-            String status = response.getStatus() + " " + message;
-            byte[] statusB = status.getBytes();
-            rframe.headerName(SpdyFrame.STATUS, 0, SpdyFrame.STATUS.length);
-            rframe.headerValue(statusB, 0, statusB.length);
-        }
-        rframe.addHeader(SpdyFrame.VERSION, SpdyFrame.HTTP11);
-
-        rframe.streamId = spdyStream.reqFrame.streamId;
-        spdy.send(rframe, spdyStream);
-        // we can't reuse the frame - it'll be queued, the coyote processor
-        // may be reused as well.
-        outCommit = true;
-    }
-
-    @Override
-    public boolean isComet() {
-        return false;
-    }
-
-    @Override
-    public SocketState process(SocketWrapper<S> socket)
-            throws IOException {
-        throw new IOException("Unimplemented");
-    }
-
-    @Override
-    public SocketState event(SocketStatus status) throws IOException {
-        System.err.println("EVENT: " + status);
-        return null;
-    }
-
-    @Override
-    public SocketState asyncDispatch(SocketStatus status) {
-        System.err.println("ASYNC DISPATCH: " + status);
-        return null;
-    }
-
-    @Override
-    public boolean isUpgrade() {
-        return false;
-    }
-
-    @Override
-    public ByteBuffer getLeftoverInput() {
-        return null;
-    }
-
-    @Override
-    public SocketState upgradeDispatch(SocketStatus status) throws IOException {
-        return null;
-    }
-
-    @Override
-    protected void registerForEvent(boolean read, boolean write) {
-        // NO-OP
-    }
-
-    public void onSynStream(SpdyStream str) throws IOException {
-        this.spdyStream = str;
-        SpdyFrame frame = str.reqFrame;
-        // We need to make a copy - the frame buffer will be reused.
-        // We use the 'wrap' methods of MimeHeaders - which should be
-        // lighter on mem in some cases.
-        RequestInfo rp = request.getRequestProcessor();
-        rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
-
-        // Request received.
-        MimeHeaders mimeHeaders = request.getMimeHeaders();
-
-        // Set this every time in case limit has been changed via JMX
-        mimeHeaders.setLimit(endpoint.getMaxHeaderCount());
-
-        for (int i = 0; i < frame.nvCount; i++) {
-            int nameLen = frame.read16();
-            if (nameLen > frame.remaining()) {
-                throw new IOException("Name too long");
-            }
-
-            keyBuffer.setBytes(frame.data, frame.off, nameLen);
-            if (keyBuffer.equals("method")) {
-                frame.advance(nameLen);
-                int valueLen = frame.read16();
-                if (valueLen > frame.remaining()) {
-                    throw new IOException("Name too long");
-                }
-                request.method().setBytes(frame.data, frame.off, valueLen);
-                frame.advance(valueLen);
-            } else if (keyBuffer.equals("url")) {
-                frame.advance(nameLen);
-                int valueLen = frame.read16();
-                if (valueLen > frame.remaining()) {
-                    throw new IOException("Name too long");
-                }
-
-                int questionPos = -1;
-                int end = frame.off + valueLen;
-                for(int k = frame.off; k < end; k ++) {
-                    if (frame.data[k] == '?') {
-                        questionPos = k;
-                        break;
-                    }
-                }
-
-                if (questionPos >= 0) {
-                    request.queryString().setBytes(frame.data, questionPos + 1, end - questionPos - 1);
-                    request.requestURI().setBytes(frame.data, frame.off, questionPos - frame.off);
-                } else {
-                    request.requestURI().setBytes(frame.data, frame.off, valueLen);
-                }
-                if (SpdyContext.debug) {
-                    System.err.println("URL= " + request.requestURI());
-                }
-                frame.advance(valueLen);
-            } else if (keyBuffer.equals("version")) {
-                frame.advance(nameLen);
-                int valueLen = frame.read16();
-                if (valueLen > frame.remaining()) {
-                    throw new IOException("Name too long");
-                }
-                frame.advance(valueLen);
-            } else {
-                MessageBytes value = mimeHeaders.addValue(frame.data,
-                        frame.off, nameLen);
-                frame.advance(nameLen);
-                int valueLen = frame.read16();
-                if (valueLen > frame.remaining()) {
-                    throw new IOException("Name too long");
-                }
-                value.setBytes(frame.data, frame.off, valueLen);
-                frame.advance(valueLen);
-            }
-        }
-
-        onRequest();
-    }
-
-    @Override
-    public void recycle(boolean socketClosing) {
-    }
-
-    @Override
-    public void setSslSupport(SSLSupport sslSupport) {
-    }
-
-    @Override
-    public HttpUpgradeHandler getHttpUpgradeHandler() {
-        return null;
-    }
-
-    @Override
-    protected Log getLog() {
-        return log;
-    }
-}
diff --git a/java/org/apache/coyote/spdy/SpdyProxyProtocol.java b/java/org/apache/coyote/spdy/SpdyProxyProtocol.java
deleted file mode 100644
index 07a1442..0000000
--- a/java/org/apache/coyote/spdy/SpdyProxyProtocol.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- *  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.coyote.spdy;
-
-import java.io.IOException;
-import java.net.Socket;
-
-import org.apache.coyote.AbstractProtocol;
-import org.apache.coyote.ajp.Constants;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.spdy.NetSupportSocket;
-import org.apache.tomcat.spdy.SpdyConnection;
-import org.apache.tomcat.spdy.SpdyContext;
-import org.apache.tomcat.spdy.SpdyContext.SpdyHandler;
-import org.apache.tomcat.spdy.SpdyStream;
-import org.apache.tomcat.util.net.AbstractEndpoint.Handler;
-import org.apache.tomcat.util.net.JIoEndpoint;
-import org.apache.tomcat.util.net.SSLImplementation;
-import org.apache.tomcat.util.net.SocketStatus;
-import org.apache.tomcat.util.net.SocketWrapper;
-
-/**
- * SPDY in 'proxy' mode - no SSL and no header compression.
- * This doesn't require JNI libraries, SSL/compression are off-loaded to
- * a reverse proxy ( apache, etc ).
- *
- * To configure:
- * <Connector port="8011" protocol="org.apache.coyote.spdy.SpdyProxyProtocol"/>
- *
- * To test, use
- *   chrome  --use-spdy=no-compress,no-ssl [--enable-websocket-over-spdy]
- *
- * TODO: Remote information (client ip, certs, etc ) will be sent in X- headers.
- * TODO: if spdy->spdy proxy, info about original spdy stream for pushes.
- *
- */
-public class SpdyProxyProtocol extends AbstractProtocol<Socket> {
-    private static final Log log = LogFactory.getLog(SpdyProxyProtocol.class);
-
-    private final JIoEndpoint.Handler cHandler = new TomcatJioHandler();
-    private SpdyContext spdyContext;
-
-    private boolean compress = false;
-
-    public SpdyProxyProtocol() {
-        endpoint = new JIoEndpoint();
-        ((JIoEndpoint) endpoint).setHandler(cHandler);
-        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
-        setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
-        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
-    }
-
-    @Override
-    protected Log getLog() {
-        return log;
-    }
-
-    @Override
-    protected String getNamePrefix() {
-        return "spdy2-jio";
-    }
-
-    @Override
-    protected String getProtocolName() {
-        return "spdy2";
-    }
-
-    @Override
-    protected Handler getHandler() {
-        return cHandler;
-    }
-
-    @Override
-    public void start() throws Exception {
-        super.start();
-        spdyContext = new SpdyContext();
-        spdyContext.setTlsCompression(false, compress);
-        spdyContext.setHandler(new SpdyHandler() {
-            @Override
-            public void onStream(SpdyConnection con, SpdyStream ch) throws IOException {
-                SpdyProcessor<Socket> sp = new SpdyProcessor<>(con, endpoint);
-                sp.setAdapter(getAdapter());
-                sp.onSynStream(ch);
-            }
-        });
-        spdyContext.setNetSupport(new NetSupportSocket());
-        spdyContext.setExecutor(endpoint.getExecutor());
-    }
-
-    public boolean isCompress() {
-        return compress;
-    }
-
-    public void setCompress(boolean compress) {
-        this.compress = compress;
-    }
-
-    public class TomcatJioHandler implements JIoEndpoint.Handler {
-
-        @Override
-        public Object getGlobal() {
-            return null;
-        }
-
-        @Override
-        public void recycle() {
-        }
-
-        @Override
-        public SocketState process(SocketWrapper<Socket> socket,
-                SocketStatus status) {
-
-            spdyContext.getNetSupport().onAccept(socket.getSocket());
-            return SocketState.CLOSED;
-        }
-
-        @Override
-        public SSLImplementation getSslImplementation() {
-            return null;
-        }
-
-        @Override
-        public void beforeHandshake(SocketWrapper<Socket> socket) {
-        }
-
-    }
-}
diff --git a/java/org/apache/el/Messages.properties b/java/org/apache/el/Messages.properties
index 9aed846..f3d8708 100644
--- a/java/org/apache/el/Messages.properties
+++ b/java/org/apache/el/Messages.properties
@@ -21,6 +21,8 @@ error.unreachable.base=Target Unreachable, identifier ''{0}'' resolved to null
 error.unreachable.property=Target Unreachable, ''{0}'' returned null
 error.resolver.unhandled=ELResolver did not handle type: {0} with property of ''{1}''
 error.resolver.unhandled.null=ELResolver cannot handle a null base Object with identifier ''{0}''
+error.invoke.wrongParams=The method [{0}] was called with [{1}] parameter(s) when it expected [{2}]
+error.invoke.tooFewParams=The method [{0}] was called with [{1}] parameter(s) when it expected at least [{2}]
 
 # ValueExpressionLiteral
 error.value.literal.write=ValueExpression is a literal and not writable: {0}
diff --git a/java/org/apache/el/parser/AstValue.java b/java/org/apache/el/parser/AstValue.java
index 0f6e01c..06e10c3 100644
--- a/java/org/apache/el/parser/AstValue.java
+++ b/java/org/apache/el/parser/AstValue.java
@@ -41,6 +41,8 @@ import org.apache.el.util.ReflectionUtil;
  */
 public final class AstValue extends SimpleNode {
 
+    private static final Object[] EMPTY_ARRAY = new Object[0];
+
     protected static class Target {
         protected Object base;
 
@@ -237,7 +239,7 @@ public final class AstValue extends SimpleNode {
         }
         m = ReflectionUtil.getMethod(ctx, t.base, t.property, types, values);
 
-        // Handle varArgs and any co-ercion required
+        // Handle varArgs and any coercion required
         values = convertArgs(ctx, values, m);
 
         Object result = null;
@@ -263,11 +265,37 @@ public final class AstValue extends SimpleNode {
     private Object[] convertArgs(EvaluationContext ctx, Object[] src, Method m) {
         Class<?>[] types = m.getParameterTypes();
         if (types.length == 0) {
-            return new Object[0];
+            // Treated as if parameters have been provided so src is ignored
+            return EMPTY_ARRAY;
         }
 
         int paramCount = types.length;
 
+        if (m.isVarArgs() && paramCount > 1 && (src == null || paramCount > src.length) ||
+                !m.isVarArgs() && (paramCount > 0 && src == null ||
+                        src != null && src.length != paramCount)) {
+            String srcCount = null;
+            if (src != null) {
+                srcCount = Integer.toString(src.length);
+            }
+            String msg;
+            if (m.isVarArgs()) {
+                msg = MessageFactory.get("error.invoke.tooFewParams",
+                        m.getName(), srcCount, Integer.toString(paramCount));
+            } else {
+                msg = MessageFactory.get("error.invoke.wrongParams",
+                        m.getName(), srcCount, Integer.toString(paramCount));
+            }
+            throw new IllegalArgumentException(msg);
+        }
+
+        if (src == null) {
+            // Must be a varargs method with a single parameter.
+            // Use a new array every time since the called code could modify the
+            // contents of the array
+            return new Object[1];
+        }
+
         Object[] dest = new Object[paramCount];
 
         for (int i = 0; i < paramCount - 1; i++) {
diff --git a/java/org/apache/jasper/JspCompilationContext.java b/java/org/apache/jasper/JspCompilationContext.java
index 5153c37..5a03723 100644
--- a/java/org/apache/jasper/JspCompilationContext.java
+++ b/java/org/apache/jasper/JspCompilationContext.java
@@ -182,6 +182,11 @@ public class JspCompilationContext {
         return jspLoader;
     }
 
+    public void clearJspLoader() {
+        jspLoader = null;
+    }
+
+
     /** ---------- Input/Output  ---------- */
 
     /**
diff --git a/java/org/apache/jasper/servlet/JspServletWrapper.java b/java/org/apache/jasper/servlet/JspServletWrapper.java
index b970776..939376d 100644
--- a/java/org/apache/jasper/servlet/JspServletWrapper.java
+++ b/java/org/apache/jasper/servlet/JspServletWrapper.java
@@ -219,6 +219,13 @@ public class JspServletWrapper {
                 if (this.servletClassLastModifiedTime < lastModified) {
                     this.servletClassLastModifiedTime = lastModified;
                     reload = true;
+                    // Really need to unload the old class but can't do that. Do
+                    // the next best thing which is throw away the JspLoader so
+                    // a new loader will be created which will load the new
+                    // class.
+                    // TODO Are there inefficiencies between reload and the
+                    //      isOutDated() check?
+                    ctxt.clearJspLoader();
                 }
             }
         }
diff --git a/java/org/apache/tomcat/jni/Library.java b/java/org/apache/tomcat/jni/Library.java
index c1e717e..77094aa 100644
--- a/java/org/apache/tomcat/jni/Library.java
+++ b/java/org/apache/tomcat/jni/Library.java
@@ -32,7 +32,7 @@ public final class Library {
      */
     private static Library _instance = null;
 
-    private Library() throws Exception {
+    private Library() throws Throwable {
         boolean loaded = false;
         String path = System.getProperty("java.library.path");
         String [] paths = path.split(File.pathSeparator);
@@ -41,7 +41,11 @@ public final class Library {
             try {
                 System.loadLibrary(NAMES[i]);
                 loaded = true;
-            } catch (ThreadDeath | VirtualMachineError t) {
+            } catch (ThreadDeath t) {
+                throw t;
+            } catch (VirtualMachineError t) {
+                // Don't use a Java 7 multiple exception catch so we can keep
+                // the JNI code identical between Tomcat 6/7/8
                 throw t;
             } catch (Throwable t) {
                 String name = System.mapLibraryName(NAMES[i]);
@@ -164,7 +168,7 @@ public final class Library {
      * @param libraryName the name of the library to load
      */
     public static boolean initialize(String libraryName)
-        throws Exception
+        throws Throwable
     {
         if (_instance == null) {
             if (libraryName == null)
diff --git a/java/org/apache/tomcat/jni/Poll.java b/java/org/apache/tomcat/jni/Poll.java
index 3d23945..0fc8308 100644
--- a/java/org/apache/tomcat/jni/Poll.java
+++ b/java/org/apache/tomcat/jni/Poll.java
@@ -163,21 +163,4 @@ public class Poll {
      *         or negative APR error code.
      */
     public static native int pollset(long pollset, long [] descriptors);
-
-    /**
-     * Make poll() return.
-     *
-     * @param   pollset
-     * @return  Negative APR error code
-     */
-    public static native int interrupt(long pollset);
-
-    /**
-     * Check if interrupt() is allowed.
-     *
-     * @param pollset
-     * @return  <code>true</code> if {@link #interrupt(long)} is allowed, else
-     *          <code>false</code>
-     */
-    public static native boolean wakeable(long pollset);
 }
diff --git a/java/org/apache/tomcat/jni/SSLExt.java b/java/org/apache/tomcat/jni/SSLExt.java
deleted file mode 100644
index e794de0..0000000
--- a/java/org/apache/tomcat/jni/SSLExt.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- *  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.jni;
-
-/**
- * Support TLS extensions and extra methods.
- *
- * The methods are separated to make it easier for java code to
- * support existing native library - it can check if this class can
- * be loaded in order to use the exensions.
- *
- * @author Costin Manolache
- */
-public final class SSLExt {
-
-
-    /**
-     * Set advertised NPN protocol.
-     * This is only available for recent or patched openssl.
-     *
-     * Example: "\x06spdy/2"
-     *
-     * Works with TLS1, doesn't with SSL2/SSL3
-     *
-     * Servers sends list in ServerHelo, client selects it and
-     * sends it back after ChangeChipher
-     *
-     * Not supported in 1.0.0, seems to be in 1.0.1 and after
-     */
-    public static native int setNPN(long tcctx, byte[] proto, int len);
-
-    /**
-     * Get other side's advertised protocols.
-     * Only works after handshake.
-     */
-    public static native int getNPN(long tcsock, byte[] proto);
-
-    /**
-     * Enabling dump/debugging on the socket. Both raw and decrypted
-     * packets will be logged.
-     */
-    public static native int debug(long tcsock);
-
-    /**
-     * Server: Extract the session data associated with the socket.
-     * Must be saved, keyed by session ID.
-     */
-    public static native byte[] getSessionData(long tcsock);
-
-    /**
-     * Server: Set the session data for a socket.
-     */
-    public static native int setSessionData(long tcsock, byte[] data, int len);
-
-
-    /**
-     * Client: get the ticket received from server, if tickets are supported.
-     */
-    public static native int getTicket(long tcsock, byte[] resBuf);
-
-    /**
-     * Client: set the previously received ticket.
-     */
-    public static native int setTicket(long tcsock, byte[] data, int len);
-
-    /**
-     * Set the key used by server to generate tickets.
-     * Key must be 48 bytes.
-     */
-    public static native int setTicketKeys(long ctx, byte[] data, int len);
-
-    /**
-     * For client side calls. Data should be a \0 terminated string
-     */
-    public static native int setSNI(long tcsock, byte[] data, int len);
-
-    /**
-     * Return the last openssl error
-     */
-    public static native String sslErrReasonErrorString();
-
-    public static native long sslCtxSetMode(long ctx, long mode);
-
-    /* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
-     * when just a single record has been written): */
-    public static final int SSL_MODE_ENABLE_PARTIAL_WRITE = 0x1;
-
-    /* Make it possible to retry SSL_write() with changed buffer location
-     * (buffer contents must stay the same!); this is not the default to avoid
-     * the misconception that non-blocking SSL_write() behaves like
-     * non-blocking write(): */
-    public static final int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = 0x2;
-
-    /* Don't attempt to automatically build certificate chain */
-    static final int SSL_MODE_NO_AUTO_CHAIN = 0x8;
-
-    /* Save RAM by releasing read and write buffers when they're empty. (SSL3 and
-     * TLS only.)  "Released" buffers are put onto a free-list in the context
-     * or just freed (depending on the context's setting for freelist_max_len). */
-    public static final int SSL_MODE_RELEASE_BUFFERS = 0x10;
-
-    // 1.1
-    //static final int SSL_MODE_HANDSHAKE_CUTTHROUGH = ..;
-
-    /**
-     * SSL_set_mode
-     */
-    public static native long sslSetMode(long tcsock, long mode);
-
-    public static int setNPN(long sslContext, byte[] spdyNPN) {
-        try {
-            return SSLExt.setNPN(sslContext, spdyNPN, spdyNPN.length);
-        } catch (Throwable t) {
-            t.printStackTrace();
-            return -1;
-        }
-    }
-
-    /**
-     * Higher level method, checking if the specified protocol has been
-     * negotiated.
-     */
-    public static boolean checkNPN(long tcsocket, byte[] expected) {
-        byte[] npn = new byte[expected.length + 1];
-        int npnLen = 0;
-        try {
-            npnLen = SSLExt.getNPN(tcsocket, npn);
-            if (npnLen != expected.length) {
-                return false;
-            }
-        } catch (Throwable t) {
-            // ignore
-            return false;
-        }
-        for (int i = 0; i < expected.length; i++) {
-            if (expected[i] != npn[i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-
-
-}
diff --git a/java/org/apache/tomcat/jni/socket/AprSocket.java b/java/org/apache/tomcat/jni/socket/AprSocket.java
deleted file mode 100644
index 1800bab..0000000
--- a/java/org/apache/tomcat/jni/socket/AprSocket.java
+++ /dev/null
@@ -1,922 +0,0 @@
-/*
- *  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.jni.socket;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.apache.tomcat.jni.Address;
-import org.apache.tomcat.jni.Error;
-import org.apache.tomcat.jni.Poll;
-import org.apache.tomcat.jni.SSL;
-import org.apache.tomcat.jni.SSLExt;
-import org.apache.tomcat.jni.SSLSocket;
-import org.apache.tomcat.jni.Sockaddr;
-import org.apache.tomcat.jni.Socket;
-import org.apache.tomcat.jni.Status;
-import org.apache.tomcat.jni.socket.AprSocketContext.AprPoller;
-import org.apache.tomcat.jni.socket.AprSocketContext.BlockingPollHandler;
-
-/**
- * Native socket, using JNI + APR + openssl.
- *
- * The socket is non-blocking - you can register either a blocking or non
- * blocking callback.
- *
- * There is no explicit method to register/unregister poll interest -
- * it is done automatically, when read/write methods return 0.
- *
- * To keep the socket polling you must read all the available data, until
- * read() returns 0. If you want to pause - don't read all input. To resume -
- * read again until it returns 0.
- *
- * Same for write - when write() returns 0 the socket is registered for
- * write interest.
- *
- * You can also use the blocking read/write methods.
- */
-public class AprSocket implements Runnable {
-
-    private static final Logger log =
-            Logger.getLogger("org.apache.tomcat.jni.socket.AprSocket");
-
-    private static final byte[][] NO_CERTS = new byte[0][];
-
-    static final int CONNECTING = 0x1;
-    static final int CONNECTED = 0x2;
-
-    // Current ( real ) poll status
-    static final int POLLIN_ACTIVE = 0x4;
-    static final int POLLOUT_ACTIVE = 0x8;
-
-    static final int POLL = 0x10;
-
-    static final int SSL_ATTACHED = 0x40;
-
-    // Requested poll status. Set by read/write when needed.
-    // Cleared when polled
-    static final int POLLIN = 0x80;
-    static final int POLLOUT = 0x100;
-
-    static final int ACCEPTED = 0x200;
-    static final int ERROR = 0x400;
-    static final int CLOSED = 0x800;
-
-    static final int READING = 0x1000;
-    static final int WRITING = 0x2000;
-
-    // Not null
-    private final AprSocketContext context;
-
-    // only one - to save per/socket memory - context has similar callbacks.
-    BlockingPollHandler handler;
-
-    // Set while it's associated with a poller - it'll stay associated after
-    // connect until close. Destroy will happen in the poller.
-    // POLL bit indicates if the socket is actually polling.
-    AprPoller poller;
-
-    // Bit field indicating the status and socket should only be accessed with
-    // socketLock protection
-    private int status;
-
-    long socket;
-
-    //long to = 10000;
-
-    // Persistent info about the peer ( SSL, etc )
-    private HostInfo hostInfo;
-
-    AprSocket(AprSocketContext context) {
-        this.context = context;
-    }
-
-    public void recycle() {
-        status = 0;
-        hostInfo = null;
-        handler = null;
-        socket = 0;
-        poller = null;
-    }
-
-    @Override
-    public String toString() {
-        return (context.isServer() ? "AprSrv-" : "AprCli-") +
-                Long.toHexString(socket) + " " + Integer.toHexString(status);
-    }
-
-    public void setHandler(BlockingPollHandler l) {
-        handler = l;
-    }
-
-    private void setNonBlocking() {
-        if (socket != 0 && context.running) {
-            Socket.optSet(socket, Socket.APR_SO_NONBLOCK, 1);
-            Socket.timeoutSet(socket, 0);
-        }
-    }
-
-    /**
-     * Check if the socket is currently registered with a poller.
-     */
-    public boolean isPolling() {
-        synchronized (this) {
-            return (status & POLL) != 0;
-        }
-    }
-
-    public BlockingPollHandler getHandler() {
-        return handler;
-    }
-
-    public AprSocketContext getContext() {
-        return context;
-    }
-
-    AprSocket setHost(HostInfo hi) {
-        hostInfo = hi;
-        return this;
-    }
-
-    /**
-     */
-    public void connect() throws IOException {
-        if (isBlocking()) {
-            // will call handleConnected() at the end.
-            context.connectBlocking(this);
-        } else {
-            synchronized(this) {
-                if ((status & CONNECTING) != 0) {
-                    return;
-                }
-                status |= CONNECTING;
-            }
-            context.connectExecutor.execute(this);
-        }
-    }
-
-
-    // after connection is done, called from a thread pool ( not IO thread )
-    // may block for handshake.
-    void afterConnect() throws IOException {
-        if (hostInfo.secure) {
-            blockingStartTLS();
-        }
-
-        setNonBlocking(); // call again, to set the bits ( connect was blocking )
-
-        setStatus(CONNECTED);
-        clearStatus(CONNECTING);
-
-        notifyConnected(false);
-    }
-
-    public HostInfo getHost() {
-        return hostInfo;
-    }
-
-    /**
-     * Write as much data as possible to the socket.
-     *
-     * @param data
-     * @param off
-     * @param len
-     * @return  For both blocking and non-blocking, returns the number of bytes
-     *          written. If no data can be written (e.g. if the buffers are
-     *          full) 0 will be returned.
-     * @throws IOException
-     */
-    public int write(byte[] data, int off, int len, long to) throws IOException {
-        long max = System.currentTimeMillis() + to;
-
-        while (true) {
-            int rc = writeInternal(data, off, len);
-            if (rc < 0) {
-                throw new IOException("Write error " + rc);
-            } else if (rc == 0) {
-                // need poll out - do we need to update polling ?
-                context.findPollerAndAdd(this);
-            } else {
-                return rc;
-            }
-
-            try {
-                long waitTime = max - System.currentTimeMillis();
-                if (waitTime <= 0) {
-                    return 0;
-                }
-                wait(waitTime);
-            } catch (InterruptedException e) {
-                return 0;
-            }
-        }
-    }
-
-    public int write(byte[] data, int off, int len) throws IOException {
-        // In SSL mode, read/write can't be called at the same time.
-        int rc = writeInternal(data, off, len);
-        if (rc < 0) {
-            throw new IOException("Write error " + rc);
-        } else if (rc == 0) {
-            // need poll out - do we need to update polling ?
-            synchronized (this) {
-                context.findPollerAndAdd(this);
-            }
-        }
-        return rc;
-    }
-
-    private int writeInternal(byte[] data, int off, int len) throws IOException {
-        int rt = 0;
-        int sent = 0;
-        synchronized(this) {
-            if ((status & CLOSED) != 0
-                    || socket == 0
-                    || !context.running) {
-                throw new IOException("Closed");
-            }
-            if ((status & WRITING) != 0) {
-                throw new IOException("Write from 2 threads not allowed");
-            }
-            status |= WRITING;
-
-            while (len > 0) {
-                sent = Socket.send(socket, data, off, len);
-                if (sent <= 0) {
-                    break;
-                }
-                off += sent;
-                len -= sent;
-            }
-
-            status &= ~WRITING;
-        }
-
-        if (context.rawDataHandler != null) {
-            context.rawData(this, false, data, off, sent, len, false);
-        }
-
-        if (sent <= 0) {
-            if (sent == -Status.TIMEUP || sent == -Status.EAGAIN || sent == 0) {
-                setStatus(POLLOUT);
-                updatePolling();
-                return rt;
-            }
-            log.warning("apr.send(): Failed to send, closing " + sent);
-            reset();
-            throw new IOException("Error sending " + sent + " " + Error.strerror(-sent));
-        } else {
-            off += sent;
-            len -= sent;
-            rt += sent;
-            return sent;
-        }
-    }
-
-    public int read(byte[] data, int off, int len, long to) throws IOException {
-            int rd = readNB(data, off, len);
-            if (rd == 0) {
-                synchronized(this) {
-                    try {
-                        wait(to);
-                    } catch (InterruptedException e) {
-                        return 0;
-                    }
-                }
-                rd = readNB(data, off, len);
-            }
-            return processReadResult(data, off, len, rd);
-    }
-
-    public int read(byte[] data, int off, int len) throws IOException {
-        return readNB(data, off, len);
-    }
-
-    private int processReadResult(byte[] data, int off, int len, int read)
-            throws IOException {
-        if (context.rawDataHandler != null) {
-            context.rawData(this, true, data, off, read, len, false);
-        }
-
-        if (read > 0) {
-            return read;
-        }
-
-        if (read == 0 || read == -Status.TIMEUP || read == -Status.ETIMEDOUT
-                || read == -Status.EAGAIN) {
-            read = 0;
-            setStatus(POLLIN);
-            updatePolling();
-            return 0;
-        }
-
-        if (read == -Status.APR_EOF || read == -1) {
-            close();
-            return -1;
-        }
-        // abrupt close
-        reset();
-        throw new IOException("apr.read(): " + read + " " + Error.strerror(-read));
-    }
-
-    public int readNB(byte[] data, int off, int len) throws IOException {
-        int read;
-        synchronized(this) {
-            if ((status & CLOSED) != 0
-                    || socket == 0
-                    || !context.running) {
-                return -1;
-            }
-            if ((status & READING) != 0) {
-                throw new IOException("Read from 2 threads not allowed");
-            }
-            status |= READING;
-
-            read = Socket.recv(socket, data, off, len);
-            status &= ~READING;
-        }
-        return processReadResult(data, off, len, read);
-    }
-
-    /*
-      No support for shutdownOutput: SSL is quite tricky.
-      Use close() instead - no read/write will be allowed after.
-
-     */
-
-    public void close() {
-        synchronized (this) {
-            if ((status & CLOSED) != 0 || socket == 0) {
-                return;
-            }
-            status |= CLOSED;
-            status &= ~POLLIN;
-            status &= ~POLLOUT;
-        }
-        if (context.rawDataHandler != null) {
-            context.rawDataHandler.rawData(this, false, null, 0, 0, 0, true);
-        }
-        Socket.close(socket);
-        if (poller == null) {
-            maybeDestroy();
-        } else  {
-            try {
-                poller.requestUpdate(this);
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    void maybeDestroy() {
-        synchronized(this) {
-            if (socket == 0 ||
-                    (status & CONNECTING) != 0 || !context.running) {
-                // closed or operation in progress
-                // if context stopped, pool will be destroyed and close
-                // all sockets automatically.
-                return;
-            }
-            if ((status & CLOSED) == 0) {
-                return; // not closed
-            }
-            if ((status & (WRITING | READING)) != 0) {
-                return; // not closed
-            }
-
-            if (context.rawDataHandler != null) {
-                context.rawDataHandler.rawData(this, false, null, -1, -1, -1, true);
-            }
-            if (log.isLoggable(Level.FINE)) {
-                log.info("closing: context.open=" + context.open.get() + " " + this);
-            }
-
-            context.open.decrementAndGet();
-
-            if (socket != 0 && (status & CLOSED) == 0) {
-                Socket.close(socket);
-                status |= CLOSED;
-            }
-
-            if (handler != null) {
-                if (isBlocking()) {
-                    context.getExecutor().execute(this);
-                } else {
-                    handler.closed(this);
-                }
-            }
-
-            context.destroySocket(this);
-        }
-    }
-
-
-
-    /**
-     * Close input and output, potentially sending RST, than close the socket.
-     *
-     * The proper way to close when gracefully done is by calling writeEnd() and
-     * reading all remaining input until -1 (EOF) is received.
-     *
-     * If EOF is received, the proper way to close is send whatever is remaining and
-     * call writeEnd();
-     */
-    public void reset() {
-        setStatus(ERROR);
-        close();
-    }
-
-
-    /**
-     */
-    public boolean isClosed() {
-        synchronized(this) {
-            if ((status & CLOSED) != 0 || socket == 0 || !context.running) {
-                return true;
-            }
-            return false;
-        }
-    }
-
-    public long getIOTimeout() throws IOException {
-        if (socket != 0 && context.running) {
-            try {
-                return Socket.timeoutGet(socket) / 1000;
-            } catch (Exception e) {
-                throw new IOException(e);
-            }
-        } else {
-            throw new IOException("Socket is closed");
-        }
-    }
-
-    // Cert is in DER format
-    // Called after handshake
-    public byte[][] getPeerCert(boolean check) throws IOException {
-        getHost();
-        if (hostInfo.certs != null && hostInfo.certs != NO_CERTS && !check) {
-            return hostInfo.certs;
-        }
-        if (!checkBitAndSocket(SSL_ATTACHED)) {
-            return NO_CERTS;
-        }
-        try {
-            int certLength = SSLSocket.getInfoI(socket,
-                    SSL.SSL_INFO_CLIENT_CERT_CHAIN);
-            // TODO: if resumed, old certs are good.
-            // If not - warn if certs changed, remember first cert, etc.
-            if (certLength <= 0) {
-                // Can also happen on session resume - keep the old
-                if (hostInfo.certs == null) {
-                    hostInfo.certs = NO_CERTS;
-                }
-                return hostInfo.certs;
-            }
-            hostInfo.certs = new byte[certLength + 1][];
-
-            hostInfo.certs[0] = SSLSocket.getInfoB(socket,
-                    SSL.SSL_INFO_CLIENT_CERT);
-            for (int i = 0; i < certLength; i++) {
-                hostInfo.certs[i + 1] = SSLSocket.getInfoB(socket,
-                        SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
-            }
-            return hostInfo.certs;
-        } catch (Exception e) {
-            throw new IOException(e);
-        }
-    }
-
-    public X509Certificate[] getPeerX509Cert() throws IOException {
-        byte[][] certs = getPeerCert(false);
-        X509Certificate[] xcerts = new X509Certificate[certs.length];
-        if (certs.length == 0) {
-            return xcerts;
-        }
-        try {
-            CertificateFactory cf = CertificateFactory.getInstance("X.509");
-            for (int i = 0; i < certs.length; i++) {
-                if (certs[i] != null) {
-                    ByteArrayInputStream bis = new ByteArrayInputStream(
-                            certs[i]);
-                    xcerts[i] = (X509Certificate) cf.generateCertificate(bis);
-                    bis.close();
-                }
-            }
-        } catch (CertificateException ex) {
-            throw new IOException(ex);
-        }
-        return xcerts;
-    }
-
-    public String getCipherSuite() throws IOException {
-        if (checkBitAndSocket(SSL_ATTACHED)) {
-            return null;
-        }
-        try {
-            return SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER);
-        } catch (Exception e) {
-            throw new IOException(e);
-        }
-    }
-
-    public int getKeySize() throws IOException {
-        if (checkBitAndSocket(SSL_ATTACHED)) {
-            return -1;
-        }
-        try {
-            return SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE);
-        } catch (Exception e) {
-            throw new IOException(e);
-        }
-    }
-
-    public int getRemotePort() throws IOException {
-        if (socket != 0 && context.running) {
-            try {
-                long sa = Address.get(Socket.APR_REMOTE, socket);
-                Sockaddr addr = Address.getInfo(sa);
-                return addr.port;
-            } catch (Exception ex) {
-                throw new IOException(ex);
-            }
-        }
-        throw new IOException("Socket closed");
-    }
-
-    public String getRemoteAddress() throws IOException {
-        if (socket != 0 && context.running) {
-            try {
-                long sa = Address.get(Socket.APR_REMOTE, socket);
-                return Address.getip(sa);
-            } catch (Exception ex) {
-                throw new IOException(ex);
-            }
-        }
-        throw new IOException("Socket closed");
-    }
-
-    public String getRemoteHostname() throws IOException {
-        if (socket != 0 && context.running) {
-            try {
-                long sa = Address.get(Socket.APR_REMOTE, socket);
-                String remoteHost = Address.getnameinfo(sa, 0);
-                if (remoteHost == null) {
-                    remoteHost = Address.getip(sa);
-                }
-                return remoteHost;
-            } catch (Exception ex) {
-                throw new IOException(ex);
-            }
-        }
-        throw new IOException("Socket closed");
-    }
-
-    public int getLocalPort() throws IOException {
-        if (socket != 0 && context.running) {
-            try {
-                long sa = Address.get(Socket.APR_LOCAL, socket);
-                Sockaddr addr = Address.getInfo(sa);
-                return addr.port;
-            } catch (Exception ex) {
-                throw new IOException(ex);
-            }
-        }
-        throw new IOException("Socket closed");
-    }
-
-    public String getLocalAddress() throws IOException {
-        if (socket != 0 && context.running) {
-            try {
-                long sa = Address.get(Socket.APR_LOCAL, socket);
-                return Address.getip(sa);
-            } catch (Exception ex) {
-                throw new IOException(ex);
-            }
-        }
-        throw new IOException("Socket closed");
-    }
-
-    public String getLocalHostname() throws IOException {
-        if (socket != 0 && context.running) {
-            try {
-                long sa = Address.get(Socket.APR_LOCAL, socket);
-                return Address.getnameinfo(sa, 0);
-            } catch (Exception ex) {
-                throw new IOException(ex);
-            }
-        }
-        throw new IOException("Socket closed");
-    }
-
-    public boolean isBlocking() {
-        return ! (handler instanceof AprSocketContext.NonBlockingPollHandler);
-    }
-
-    public boolean isError() {
-        return checkPreConnect(ERROR);
-    }
-
-    void notifyError(Throwable err, boolean needsThread) {
-        if (handler instanceof AprSocketContext.NonBlockingPollHandler) {
-            if (err != null) {
-                ((AprSocketContext.NonBlockingPollHandler) handler).error(this, err);
-            }
-        } else {
-            // poller destroyed, etc
-            if (needsThread) {
-                context.getExecutor().execute(this);
-            } else {
-                try {
-                    notifyIO();
-                } catch (IOException e) {
-                    log.log(Level.SEVERE, this + " error ", e);
-                }
-            }
-        }
-    }
-
-    // Called after connect and from poller.
-    void notifyIO() throws IOException {
-        long t0 = System.currentTimeMillis();
-        try {
-            if (handler != null) {
-                handler.process(this, true, false, false);
-            }
-        } catch (Throwable t) {
-            throw new IOException(t);
-        } finally {
-            long t1 = System.currentTimeMillis();
-            t1 -= t0;
-            if (t1 > context.maxHandlerTime.get()) {
-                context.maxHandlerTime.set(t1);
-            }
-            context.totalHandlerTime.addAndGet(t1);
-            context.handlerCount.incrementAndGet();
-        }
-    }
-
-    private void notifyConnected(boolean server) throws IOException {
-        // Will set the handler on the channel for accepted
-        context.onSocket(this);
-
-        if (handler instanceof AprSocketContext.NonBlockingPollHandler) {
-            ((AprSocketContext.NonBlockingPollHandler) handler).connected(this);
-
-            ((AprSocketContext.NonBlockingPollHandler) handler).process(this, true, true, false);
-            // Now register for polling - unless process() set suspendRead and
-            // doesn't need out notifications
-            updatePolling();
-        } else {
-            if (server) {
-                // client will block in connect().
-                // Server: call process();
-                notifyIO();
-            }
-        }
-    }
-
-    private void updatePolling() throws IOException {
-        synchronized (this) {
-            if ((status & CLOSED) != 0) {
-                maybeDestroy();
-                return;
-            }
-        }
-        context.findPollerAndAdd(this);
-    }
-
-    @Override
-    public void run() {
-        if (!context.running) {
-            return;
-        }
-        if (checkPreConnect(CLOSED)) {
-            if (handler != null) {
-                handler.closed(this);
-            }
-            return;
-        }
-        if (!checkPreConnect(CONNECTED)) {
-            if (checkBitAndSocket(ACCEPTED)) {
-                try {
-                    context.open.incrementAndGet();
-
-                    if (log.isLoggable(Level.FINE)) {
-                        log.info("Accept: " + context.open.get() + " " + this + " " +
-                                getRemotePort());
-                    }
-                    if (context.tcpNoDelay) {
-                        Socket.optSet(socket, Socket.APR_TCP_NODELAY, 1);
-                    }
-
-                    setStatus(CONNECTED);
-                    if (context.sslMode) {
-                        Socket.timeoutSet(socket,
-                                context.connectTimeout * 1000L);
-                        blockingStartTLS();
-                    }
-                    setNonBlocking(); // call again, to set the bits ( connect was blocking )
-
-                    notifyConnected(true);
-                    return;
-                } catch (Throwable t) {
-                    t.printStackTrace(); // no error handler yet
-                    reset();
-                    notifyError(t, false);
-                    return;
-                }
-            }
-            if (checkPreConnect(CONNECTING)) {
-                // Non-blocking connect - will call 'afterConnection' at the end.
-                try {
-                    context.connectBlocking(this);
-                } catch (IOException t) {
-                    reset(); // also sets status ERROR
-                    if (handler instanceof AprSocketContext.NonBlockingPollHandler) {
-                        ((AprSocketContext.NonBlockingPollHandler) handler).process(this, false, false, true);
-                    }
-                    notifyError(t, false);
-                }
-            }
-        } else {
-            if (handler != null) {
-                try {
-                    notifyIO();
-                } catch (Throwable e) {
-                    log.log(Level.SEVERE, this + " error ", e);
-                    reset();
-                    // no notifyIO - just did it.
-                }
-            }
-        }
-    }
-
-    /**
-     * This is a blocking call ! ( can be made non-blocking, but too complex )
-     *
-     * Will be called automatically after connect() or accept if 'secure' is
-     * true.
-     *
-     * Can be called manually to upgrade the channel
-     * @throws IOException
-     */
-    public void blockingStartTLS() throws IOException {
-        synchronized(this) {
-            if (socket == 0 || !context.running) {
-                return;
-            }
-            if ((status & SSL_ATTACHED) != 0) {
-                return;
-            }
-            status |= SSL_ATTACHED;
-        }
-
-        try {
-            if (log.isLoggable(Level.FINE)) {
-                log.info(this + " StartSSL");
-            }
-
-            AprSocketContext aprCon = context;
-            SSLSocket.attach(aprCon.getSslCtx(), socket);
-
-            if (context.debugSSL) {
-                SSLExt.debug(socket);
-            }
-            if (!getContext().isServer()) {
-                if (context.USE_TICKETS && hostInfo.ticketLen > 0) {
-                    SSLExt.setTicket(socket, hostInfo.ticket,
-                            hostInfo.ticketLen);
-                } else if (hostInfo.sessDer != null) {
-                    SSLExt.setSessionData(socket, hostInfo.sessDer,
-                            hostInfo.sessDer.length);
-                }
-            }
-            SSLExt.sslSetMode(socket, SSLExt.SSL_MODE_ENABLE_PARTIAL_WRITE |
-                    SSLExt.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
-            int rc = SSLSocket.handshake(socket);
-
-            // At this point we have the session ID, remote certs, etc
-            // we can lookup host info
-            if (hostInfo == null) {
-                hostInfo = new HostInfo();
-            }
-
-            if (rc != Status.APR_SUCCESS) {
-                throw new IOException(this + " Handshake failed " + rc + " "
-                        + Error.strerror(rc) + " SSLL "
-                        + SSL.getLastError());
-            } else { // SUCCESS
-                handshakeDone();
-            }
-        } catch (IOException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new IOException(e);
-        }
-    }
-
-    private void handshakeDone() throws IOException {
-        getHost();
-        if (socket == 0 || !context.running) {
-            throw new IOException("Socket closed");
-        }
-        if (context.USE_TICKETS && ! context.isServer()) {
-            if (hostInfo.ticket == null) {
-                hostInfo.ticket = new byte[2048];
-            }
-            int ticketLen = SSLExt.getTicket(socket, hostInfo.ticket);
-            if (ticketLen > 0) {
-                hostInfo.ticketLen = ticketLen;
-                if (log.isLoggable(Level.FINE)) {
-                    log.info("Received ticket: " + ticketLen);
-                }
-            }
-        }
-
-        // TODO: if the ticket, session id or session changed - callback to
-        // save the session again
-        try {
-            hostInfo.sessDer = SSLExt.getSessionData(socket);
-            getPeerCert(true);
-            hostInfo.sessionId = SSLSocket.getInfoS(socket,
-                    SSL.SSL_INFO_SESSION_ID);
-        } catch (Exception e) {
-            throw new IOException(e);
-        }
-
-        hostInfo.npn = new byte[32];
-        hostInfo.npnLen = SSLExt.getNPN(socket, hostInfo.npn);
-
-        // If custom verification is used - should check the certificates
-        if (context.tlsCertVerifier != null) {
-            context.tlsCertVerifier.handshakeDone(this);
-        }
-    }
-
-    int requestedPolling() {
-        synchronized(this) {
-            if (socket == 0 || ((status & CLOSED) != 0)) {
-                return 0;
-            }
-            // Implicit:
-            //Poll.APR_POLLNVAL | Poll.APR_POLLHUP | Poll.APR_POLLERR |
-            int res = 0;
-            if ((status & POLLIN) != 0) {
-                res = Poll.APR_POLLIN;
-            }
-            if ((status & POLLOUT) != 0) {
-                res |= Poll.APR_POLLOUT;
-            }
-            return res;
-        }
-    }
-
-    boolean checkBitAndSocket(int bit) {
-        synchronized (this) {
-            return ((status & bit) != 0 && socket != 0 &&
-                    (status & CLOSED) == 0 && context.running);
-        }
-    }
-
-    boolean checkPreConnect(int bit) {
-        synchronized (this) {
-            return ((status & bit) != 0);
-        }
-    }
-
-    void clearStatus(int bit) {
-        synchronized (this) {
-            status &= ~bit;
-        }
-    }
-
-    boolean setStatus(int bit) {
-        synchronized (this) {
-            int old = status & bit;
-            status |= bit;
-            return old != 0;
-        }
-    }
-
-
-}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/jni/socket/AprSocketContext.java b/java/org/apache/tomcat/jni/socket/AprSocketContext.java
deleted file mode 100644
index 03036c9..0000000
--- a/java/org/apache/tomcat/jni/socket/AprSocketContext.java
+++ /dev/null
@@ -1,1352 +0,0 @@
-/*
- *  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.jni.socket;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.RejectedExecutionHandler;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.apache.tomcat.jni.Address;
-import org.apache.tomcat.jni.Error;
-import org.apache.tomcat.jni.Library;
-import org.apache.tomcat.jni.OS;
-import org.apache.tomcat.jni.Poll;
-import org.apache.tomcat.jni.Pool;
-import org.apache.tomcat.jni.SSL;
-import org.apache.tomcat.jni.SSLContext;
-import org.apache.tomcat.jni.SSLExt;
-import org.apache.tomcat.jni.Socket;
-import org.apache.tomcat.jni.Status;
-
-public class AprSocketContext {
-    /**
-     * Called when a chunk of data is sent or received. This is very low
-     * level, used mostly for debugging or stats.
-     */
-    public static interface RawDataHandler {
-        public void rawData(AprSocket ch, boolean input, byte[] data, int pos,
-                int len, int requested, boolean closed);
-    }
-
-    /**
-     * Called in SSL mode after the handshake is completed.
-     *
-     * @see AprSocketContext#customVerification(TlsCertVerifier)
-     */
-    public static interface TlsCertVerifier {
-        public void handshakeDone(AprSocket ch);
-    }
-
-    /**
-     * Delegates loading of persistent info about a host - public certs,
-     * tickets, config, persistent info etc.
-     */
-    public static interface HostInfoLoader {
-        public HostInfo getHostInfo(String name, int port, boolean ssl);
-    }
-
-    private static final Logger log = Logger.getLogger("AprSocketCtx");
-
-    // If interrupt() or thread-safe poll update are not supported - the
-    // poll updates will happen after the poll() timeout.
-    // The poll timeout with interrupt/thread safe updates can be much higher/
-    private static final int FALLBACK_POLL_TIME = 2000;
-
-    // It seems to send the ticket, get server helo / ChangeCipherSpec, but than
-    // SSL3_GET_RECORD:decryption failed or bad record mac in s3_pkt.c:480:
-    // Either bug in openssl, or some combination of ciphers - needs more debugging.
-    // ( this can save a roundtrip and CPU on TLS handshake )
-    boolean USE_TICKETS = false;
-
-    private final AprSocket END = new AprSocket(this);
-
-    private static final AtomicInteger contextNumber = new AtomicInteger();
-    private int contextId;
-
-    private final AtomicInteger threadNumber = new AtomicInteger();
-
-    /**
-     * For now - single acceptor thread per connector.
-     */
-    private AcceptorThread acceptor;
-    private AcceptorDispatchThread acceptorDispatch;
-
-    // APR/JNI is thread safe
-    private boolean threadSafe = true;
-
-    /**
-     * Pollers.
-     */
-    private final List<AprPoller> pollers = new ArrayList<>();
-
-    // Set on all accepted or connected sockets.
-    // TODO: add the other properties
-    boolean tcpNoDelay = true;
-
-    protected boolean running = true;
-
-    protected boolean sslMode;
-
-    // onSocket() will be called in accept thread.
-    // If false: use executor ( but that may choke the acceptor thread )
-    private boolean nonBlockingAccept = false;
-
-    private final BlockingQueue<AprSocket> acceptedQueue =
-            new LinkedBlockingQueue<>();
-
-    /**
-     * Root APR memory pool.
-     */
-    private long rootPool = 0;
-
-    /**
-     * SSL context.
-     */
-    private volatile long sslCtx = 0;
-
-    TlsCertVerifier tlsCertVerifier;
-
-    //
-    final int connectTimeout =  20000;
-    final int defaultTimeout = 100000;
-    // TODO: Use this
-    final int keepAliveTimeout = 20000;
-
-    final AtomicInteger open = new AtomicInteger();
-
-    /**
-     * Poll interval, in microseconds. If the platform doesn't support
-     * poll interrupt - it'll take this time to stop the poller.
-     *
-     */
-    private int pollTime = 5 * 1000000;
-
-    private HostInfoLoader hostInfoLoader;
-
-    final RawDataHandler rawDataHandler = null;
-
-    // TODO: do we need this here ?
-    private final Map<String, HostInfo> hosts = new HashMap<>();
-
-    private String certFile;
-    private String keyFile;
-
-    private byte[] spdyNPN;
-
-    private byte[] ticketKey;
-
-    // For resolving DNS ( i.e. connect ), callbacks
-    private ExecutorService threadPool;
-
-    // Separate executor for connect/handshakes
-    final ExecutorService connectExecutor;
-
-    final boolean debugSSL = false;
-    private boolean debugPoll = false;
-
-    private boolean deferAccept = false;
-
-    private int backlog = 100;
-
-    private boolean useSendfile;
-
-    private int sslProtocol = SSL.SSL_PROTOCOL_TLSV1 | SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
-
-    /**
-     * Max time spent in a callback ( will be longer for blocking )
-     */
-    final AtomicLong maxHandlerTime = new AtomicLong();
-    final AtomicLong totalHandlerTime = new AtomicLong();
-    final AtomicLong handlerCount = new AtomicLong();
-
-    /**
-     * Total connections handled ( accepted or connected ).
-     */
-    private final AtomicInteger connectionsCount = new AtomicInteger();
-
-
-    public AprSocketContext() {
-        connectExecutor =new ThreadPoolExecutor(0, 64, 5, TimeUnit.SECONDS,
-                new LinkedBlockingQueue<Runnable>(), new RejectedExecutionHandler() {
-                    @Override
-                    public void rejectedExecution(Runnable r,
-                            java.util.concurrent.ThreadPoolExecutor executor) {
-                        AprSocket s = (AprSocket) r;
-                        log.severe("Rejecting " + s);
-                        s.reset();
-                    }
-                });
-        contextId = contextNumber.incrementAndGet();
-    }
-
-    /**
-     * Poller thread count.
-     */
-    private int pollerThreadCount = 4;
-    public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; }
-    public int getPollerThreadCount() { return pollerThreadCount; }
-
-    // to test the limits - default should be lower
-    private int maxConnections = 64 * 1024;
-    public void setMaxconnections(int maxCon) {
-        this.maxConnections = maxCon;
-    }
-
-    public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; }
-    public int getBacklog() { return backlog; }
-
-    /**
-     * Defer accept.
-     */
-    public void setDeferAccept(boolean deferAccept) { this.deferAccept = deferAccept; }
-    public boolean getDeferAccept() { return deferAccept; }
-
-    /**
-     * For client:
-     *   - ClientHello will include the npn extension ( the ID == 0x3374)
-     *   - if ServerHello includes a list of protocols - select one
-     *   - send it after ChangeCipherSpec and before Finish
-     *
-     *  For server:
-     *   - if ClientHello includes the npn extension
-     *    -- will send this string as list of supported protocols in ServerHello
-     *   - read the selection before Finish.
-     * @param npn
-     */
-    public void setNpn(String npn) {
-        byte[] data = npn.getBytes();
-        byte[] npnB = new byte[data.length + 2];
-
-        System.arraycopy(data, 0, npnB, 1, data.length);
-        npnB[0] = (byte) data.length;
-        npnB[npnB.length - 1] = 0;
-        spdyNPN = npnB;
-
-    }
-
-    public void setNpn(byte[] data) {
-        spdyNPN = data;
-    }
-
-    public void setHostLoader(HostInfoLoader handler) {
-        this.hostInfoLoader = handler;
-    }
-
-    public boolean isServer() {
-        return acceptor != null;
-    }
-
-    protected Executor getExecutor() {
-        if (threadPool == null) {
-            threadPool = Executors.newCachedThreadPool(new ThreadFactory( ) {
-                @Override
-                public Thread newThread(Runnable r) {
-                    Thread t = new Thread(r, "AprThread-" + contextId + "-" +
-                            threadNumber.incrementAndGet());
-                    t.setDaemon(true);
-                    return t;
-                }
-            });
-        }
-        return threadPool;
-    }
-
-    /**
-     * All accepted/connected sockets will start handshake automatically.
-     */
-    public AprSocketContext setTls() {
-        this.sslMode = true;
-        return this;
-    }
-
-    public void setTcpNoDelay(boolean b) {
-        tcpNoDelay = b;
-    }
-
-    public void setSslProtocol(String protocol) {
-        protocol = protocol.trim();
-        if ("SSLv2".equalsIgnoreCase(protocol)) {
-            sslProtocol = SSL.SSL_PROTOCOL_SSLV2;
-        } else if ("SSLv3".equalsIgnoreCase(protocol)) {
-            sslProtocol = SSL.SSL_PROTOCOL_SSLV3;
-        } else if ("TLSv1".equalsIgnoreCase(protocol)) {
-            sslProtocol = SSL.SSL_PROTOCOL_TLSV1;
-        } else if ("TLSv1.1".equalsIgnoreCase(protocol)) {
-            sslProtocol = SSL.SSL_PROTOCOL_TLSV1_1;
-        } else if ("TLSv1.2".equalsIgnoreCase(protocol)) {
-            sslProtocol = SSL.SSL_PROTOCOL_TLSV1_2;
-        } else if ("all".equalsIgnoreCase(protocol)) {
-            sslProtocol = SSL.SSL_PROTOCOL_ALL;
-        }
-    }
-
-    public void setTicketKey(byte[] key48Bytes) {
-        if(key48Bytes.length != 48) {
-            throw new RuntimeException("Key must be 48 bytes");
-        }
-        this.ticketKey = key48Bytes;
-    }
-
-    public void customVerification(TlsCertVerifier verifier) {
-        tlsCertVerifier = verifier;
-    }
-
-    // TODO: should have a separate method for switching to tls later.
-    /**
-     * Set certificate, will also enable TLS mode.
-     */
-    public AprSocketContext setKeys(String certPemFile, String keyDerFile) {
-        this.sslMode = true;
-        setTls();
-        certFile = certPemFile;
-        keyFile = keyDerFile;
-        return this;
-    }
-
-    /**
-     * SSL cipher suite.
-     */
-    private String SSLCipherSuite = "ALL";
-    public String getSSLCipherSuite() { return SSLCipherSuite; }
-    public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; }
-
-    /**
-     * Override or use hostInfoLoader to implement persistent/memcache storage.
-     */
-    public HostInfo getHostInfo(String host, int port, boolean ssl) {
-        if (hostInfoLoader != null) {
-            return hostInfoLoader.getHostInfo(host, port, ssl);
-        }
-        // Use local cache
-        String key = host + ":" + port;
-        HostInfo pi = hosts.get(key);
-        if (pi != null) {
-            return pi;
-        }
-        pi = new HostInfo(host, port, ssl);
-        hosts.put(key, pi);
-        return pi;
-    }
-
-    protected void rawData(AprSocket ch, boolean inp, byte[] data, int pos,
-            int len, int requested, boolean closed) {
-        if (rawDataHandler != null) {
-            rawDataHandler.rawData(ch, inp, data, pos, len, requested, closed);
-        }
-    }
-
-    public void listen(final int port) throws IOException {
-        if (acceptor != null) {
-            throw new IOException("Already accepting on " + acceptor.port);
-        }
-        if (sslMode && certFile == null) {
-            throw new IOException("Missing certificates for server");
-        }
-        if (sslMode || !nonBlockingAccept) {
-            acceptorDispatch = new AcceptorDispatchThread();
-            acceptorDispatch.setName("AprAcceptorDispatch-" + port);
-            acceptorDispatch.start();
-        }
-
-        acceptor = new AcceptorThread(port);
-        acceptor.prepare();
-        acceptor.setName("AprAcceptor-" + port);
-        acceptor.start();
-
-
-    }
-
-    /**
-     * Get a socket for connectiong to host:port.
-     */
-    public AprSocket socket(String host, int port, boolean ssl) {
-        HostInfo hi = getHostInfo(host, port, ssl);
-        return socket(hi);
-    }
-
-    public AprSocket socket(HostInfo hi) {
-        AprSocket sock = newSocket(this);
-        sock.setHost(hi);
-        return sock;
-    }
-
-    public AprSocket socket(long socket) {
-        AprSocket sock = newSocket(this);
-        // Tomcat doesn't set this
-        SSLExt.sslSetMode(socket, SSLExt.SSL_MODE_ENABLE_PARTIAL_WRITE |
-                SSLExt.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-        sock.setStatus(AprSocket.ACCEPTED);
-        sock.socket = socket;
-        return sock;
-    }
-
-
-    void destroySocket(AprSocket socket) {
-        // TODO: does it need to be done in io thread ?
-        synchronized (socket) {
-            if (socket.socket != 0) {
-                long s = socket.socket;
-                socket.socket = 0;
-                log.info("DESTROY: " + Long.toHexString(s));
-                Socket.destroy(s);
-            }
-        }
-    }
-
-    protected void connectBlocking(AprSocket apr) throws IOException {
-        try {
-            if (!running) {
-                throw new IOException("Stopped");
-            }
-            HostInfo hi = apr.getHost();
-
-            long clientSockP;
-            synchronized (pollers) {
-                long socketpool = Pool.create(getRootPool());
-
-                int family = Socket.APR_INET;
-
-                clientSockP = Socket.create(family,
-                        Socket.SOCK_STREAM,
-                        Socket.APR_PROTO_TCP, socketpool); // or rootPool ?
-            }
-            Socket.timeoutSet(clientSockP, connectTimeout * 1000);
-            if (OS.IS_UNIX) {
-                Socket.optSet(clientSockP, Socket.APR_SO_REUSEADDR, 1);
-            }
-
-            Socket.optSet(clientSockP, Socket.APR_SO_KEEPALIVE, 1);
-
-            // Blocking
-            // TODO: use socket pool
-            // TODO: cache it ( and TTL ) in hi
-            long inetAddress = Address.info(hi.host, Socket.APR_INET,
-                  hi.port, 0, rootPool);
-            // this may take a long time - stop/destroy must wait
-            // at least connect timeout
-            int rc = Socket.connect(clientSockP, inetAddress);
-
-            if (rc != 0) {
-                synchronized (pollers) {
-                    Socket.close(clientSockP);
-                    Socket.destroy(clientSockP);
-                }
-                /////Pool.destroy(socketpool);
-                throw new IOException("Socket.connect(): " + rc + " " + Error.strerror(rc) + " " + connectTimeout);
-            }
-            if (!running) {
-                throw new IOException("Stopped");
-            }
-
-            connectionsCount.incrementAndGet();
-            if (tcpNoDelay) {
-                Socket.optSet(clientSockP, Socket.APR_TCP_NODELAY, 1);
-            }
-
-            Socket.timeoutSet(clientSockP, defaultTimeout * 1000);
-
-            apr.socket = clientSockP;
-
-            apr.afterConnect();
-        } catch (IOException e) {
-            apr.reset();
-            throw e;
-        } catch (Throwable e) {
-            apr.reset();
-            e.printStackTrace();
-            throw new IOException(e);
-        }
-    }
-
-    AprSocket newSocket(AprSocketContext context) {
-        return new AprSocket(context);
-    }
-
-    /**
-     * To clean the pools - we could track if all channels are
-     * closed, but this seems simpler and safer.
-     */
-    @Override
-    protected void finalize() throws Throwable {
-        if (rootPool != 0) {
-            log.warning(this + " GC without stop()");
-            try {
-                stop();
-            } catch (Exception e) {
-                //TODO Auto-generated catch block
-                e.printStackTrace();
-            }
-        }
-        super.finalize();
-    }
-
-
-    public void stop() {
-        synchronized (pollers) {
-            if (!running) {
-                return;
-            }
-            running = false;
-        }
-
-        if (rootPool != 0) {
-            if (acceptor != null) {
-                try {
-                    acceptor.unblock();
-                    acceptor.join();
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }
-            if (acceptorDispatch != null) {
-                acceptedQueue.add(END);
-                try {
-                    acceptorDispatch.join();
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }
-            if (threadPool != null) {
-                threadPool.shutdownNow();
-            }
-
-            log.info("Stopping pollers " + contextId);
-
-            while (true) {
-                AprPoller a;
-                synchronized (pollers) {
-                    if (pollers.size() == 0) {
-                        break;
-                    }
-                    a = pollers.remove(0);
-                }
-                a.interruptPoll();
-                try {
-                    a.join();
-                    log.info("Poller " + a.id + " done ");
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
-
-    // Called when the last poller has been destroyed.
-    void destroy() {
-        synchronized (pollers) {
-            if (pollers.size() != 0) {
-                return;
-            }
-
-            if (rootPool == 0) {
-                return;
-            }
-            log.info("Destroy root pool " + rootPool);
-            //Pool.destroy(rootPool);
-            //rootPool = 0;
-        }
-    }
-
-    private static IOException noApr;
-    static {
-
-        try {
-            Library.initialize(null);
-            SSL.initialize(null);
-        } catch (Exception e) {
-            noApr = new IOException("APR not present", e);
-        }
-
-    }
-
-    private long getRootPool() throws IOException {
-        if (rootPool == 0) {
-            if (noApr != null) {
-                throw noApr;
-            }
-            // Create the root APR memory pool
-            rootPool = Pool.create(0);
-
-            // Adjust poller sizes
-            if ((OS.IS_WIN32 || OS.IS_WIN64) && (maxConnections > 1024)) {
-                // The maximum per poller to get reasonable performance is 1024
-                pollerThreadCount = maxConnections / 1024;
-                // Adjust poller size so that it won't reach the limit
-                maxConnections = maxConnections - (maxConnections % 1024);
-            }
-        }
-        return rootPool;
-    }
-
-    long getSslCtx() throws Exception {
-        if (sslCtx == 0) {
-            synchronized (AprSocketContext.class) {
-                if (sslCtx == 0) {
-                    boolean serverMode = acceptor != null;
-                    sslCtx = SSLContext.make(getRootPool(),
-                            sslProtocol,
-                            serverMode ? SSL.SSL_MODE_SERVER : SSL.SSL_MODE_CLIENT);
-
-
-                    // SSL.SSL_OP_NO_SSLv3
-                    int opts = SSL.SSL_OP_NO_SSLv2 |
-                        SSL.SSL_OP_SINGLE_DH_USE;
-
-                    if (!USE_TICKETS || serverMode && ticketKey == null) {
-                        opts |= SSL.SSL_OP_NO_TICKET;
-                    }
-
-                    SSLContext.setOptions(sslCtx, opts);
-                    // Set revocation
-                    //        SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath);
-
-                    // Client certificate verification - maybe make it option
-                    try {
-                        SSLContext.setCipherSuite(sslCtx, SSLCipherSuite);
-
-
-                        if (serverMode) {
-                            if (ticketKey != null) {
-                                //SSLExt.setTicketKeys(sslCtx, ticketKey, ticketKey.length);
-                            }
-                            if (certFile != null) {
-                                boolean rc = SSLContext.setCertificate(sslCtx,
-                                        certFile,
-                                        keyFile, null, SSL.SSL_AIDX_DSA);
-                                if (!rc) {
-                                    throw new IOException("Can't set keys");
-                                }
-                            }
-                            SSLContext.setVerify(sslCtx, SSL.SSL_CVERIFY_NONE, 10);
-
-                            if (spdyNPN != null) {
-                                SSLExt.setNPN(sslCtx, spdyNPN, spdyNPN.length);
-                            }
-                        } else {
-                            if (tlsCertVerifier != null) {
-                                // NONE ?
-                                SSLContext.setVerify(sslCtx,
-                                        SSL.SSL_CVERIFY_NONE, 10);
-                            } else {
-                                SSLContext.setCACertificate(sslCtx,
-                                        "/etc/ssl/certs/ca-certificates.crt",
-                                        "/etc/ssl/certs");
-                                SSLContext.setVerify(sslCtx,
-                                        SSL.SSL_CVERIFY_REQUIRE, 10);
-                            }
-
-                            if (spdyNPN != null) {
-                                SSLExt.setNPN(sslCtx, spdyNPN, spdyNPN.length);
-                            }
-                        }
-                    } catch (IOException e) {
-                        throw e;
-                    } catch (Exception e) {
-                        throw new IOException(e);
-                    }
-                }
-            // TODO: try release buffers
-            }
-        }
-        return sslCtx;
-    }
-
-    void findPollerAndAdd(AprSocket ch) throws IOException {
-        if (ch.poller != null) {
-            ch.poller.requestUpdate(ch);
-            return;
-        }
-        assignPoller(ch);
-    }
-
-    void assignPoller(AprSocket ch) throws IOException {
-        AprPoller target = null;
-        synchronized (pollers) {
-            // Make sure we have min number of pollers
-            int needPollers = pollerThreadCount - pollers.size();
-            if (needPollers > 0) {
-                for (int i = needPollers; i > 0; i--) {
-                    pollers.add(allocatePoller());
-                }
-            }
-            int max = 0;
-            for (AprPoller poller: pollers) {
-                int rem = poller.remaining();
-                if (rem > max) {
-                    target = poller;
-                    max = rem;
-                }
-            }
-        }
-        if (target != null && target.add(ch)) {
-            return;
-        }
-
-        // can't be added - add a new poller
-        synchronized (pollers) {
-            AprPoller poller = allocatePoller();
-            poller.add(ch);
-            pollers.add(poller);
-        }
-    }
-
-    /**
-     * Called on each accepted socket (for servers) or after connection (client)
-     * after handshake.
-     */
-    protected void onSocket(@SuppressWarnings("unused") AprSocket s) {
-        // Defaults to NO-OP. Parameter is used by sub-classes.
-    }
-
-    private class AcceptorThread extends Thread {
-        private final int port;
-        private long serverSockPool = 0;
-        private long serverSock = 0;
-
-        private long inetAddress;
-
-        AcceptorThread(int port) {
-            this.port = port;
-            setDaemon(true);
-        }
-
-        void prepare() throws IOException {
-            try {
-                // Create the pool for the server socket
-                serverSockPool = Pool.create(getRootPool());
-
-                int family = Socket.APR_INET;
-                inetAddress =
-                        Address.info(null, family, port, 0, serverSockPool);
-
-                // Create the APR server socket
-                serverSock = Socket.create(family,
-                        Socket.SOCK_STREAM,
-                        Socket.APR_PROTO_TCP, serverSockPool);
-
-                if (OS.IS_UNIX) {
-                    Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
-                }
-                // Deal with the firewalls that tend to drop the inactive sockets
-                Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1);
-                // Bind the server socket
-                int ret = Socket.bind(serverSock, inetAddress);
-                if (ret != 0) {
-                    throw new IOException("Socket.bind " + ret + " " +
-                            Error.strerror(ret) + " port=" + port);
-                }
-                // Start listening on the server socket
-                ret = Socket.listen(serverSock, backlog );
-                if (ret != 0) {
-                    throw new IOException("endpoint.init.listen"
-                            + ret + " " + Error.strerror(ret));
-                }
-                if (OS.IS_WIN32 || OS.IS_WIN64) {
-                    // On Windows set the reuseaddr flag after the bind/listen
-                    Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
-                }
-
-                // Sendfile usage on systems which don't support it cause major problems
-                if (useSendfile && !Library.APR_HAS_SENDFILE) {
-                    useSendfile = false;
-                }
-
-                // Delay accepting of new connections until data is available
-                // Only Linux kernels 2.4 + have that implemented
-                // on other platforms this call is noop and will return APR_ENOTIMPL.
-                if (deferAccept) {
-                    if (Socket.optSet(serverSock, Socket.APR_TCP_DEFER_ACCEPT, 1) == Status.APR_ENOTIMPL) {
-                        deferAccept = false;
-                    }
-                }
-            } catch (Throwable t) {
-                throw new IOException(t);
-            }
-        }
-
-        void unblock() {
-            try (java.net.Socket sock = new java.net.Socket()) {
-                // Easiest ( maybe safest ) way to interrupt accept
-                // we could have it in non-blocking mode, etc
-                sock.connect(new InetSocketAddress("127.0.0.1", port));
-            } catch (Exception ex) {
-                // ignore - the acceptor may have shut down by itself.
-            }
-        }
-
-        @Override
-        public void run() {
-            while (running) {
-                try {
-                    // each socket has a pool.
-                    final AprSocket ch = newSocket(AprSocketContext.this);
-                    ch.setStatus(AprSocket.ACCEPTED);
-
-                    ch.socket = Socket.accept(serverSock);
-                    if (!running) {
-                        break;
-                    }
-                    connectionsCount.incrementAndGet();
-                    if (connectionsCount.get() % 1000 == 0) {
-                        System.err.println("Accepted: " + connectionsCount.get());
-                    }
-
-                    if (nonBlockingAccept && !sslMode) {
-                        ch.setStatus(AprSocket.CONNECTED);
-                        // TODO: SSL really needs a thread.
-                        onSocket(ch);
-                    } else {
-                        acceptedQueue.add(ch);
-                    }
-                } catch (Throwable e) {
-                    e.printStackTrace();
-                }
-            }
-            Socket.close(serverSock);
-        }
-    }
-
-    private class AcceptorDispatchThread extends Thread {
-
-        AcceptorDispatchThread() {
-            setDaemon(true);
-        }
-
-        @Override
-        public void run() {
-            while(running) {
-                try {
-                    AprSocket ch = acceptedQueue.take();
-                    if (ch == END) {
-                        return;
-                    }
-                    connectExecutor.execute(ch);
-                } catch (InterruptedException e) {
-                }
-            }
-        }
-    }
-
-    /**
-     * Create the poller. With some versions of APR, the maximum poller size will
-     * be 62 (recompiling APR is necessary to remove this limitation).
-     * @throws IOException
-     */
-    AprPoller allocatePoller() throws IOException {
-        long pool = Pool.create(getRootPool());
-        int size = maxConnections / pollerThreadCount;
-
-        long serverPollset = allocatePoller(size, pool);
-
-        if (serverPollset == 0 && size > 1024) {
-            log.severe("Falling back to 1024-sized poll, won't scale");
-            size = 1024;
-            serverPollset = allocatePoller(size, pool);
-        }
-        if (serverPollset == 0) {
-            log.severe("Falling back to 62-sized poll, won't scale");
-            size = 62;
-            serverPollset = allocatePoller(size, pool);
-        }
-
-        AprPoller res = new AprPoller();
-        res.pool = pool;
-        res.serverPollset = serverPollset;
-        res.desc = new long[size * 2];
-        res.size = size;
-        res.id = contextId++;
-        res.setDaemon(true);
-        res.setName("AprPoller-" + res.id);
-        res.start();
-        if (debugPoll && !sizeLogged) {
-            sizeLogged = true;
-            log.info("Poller size " + (res.desc.length / 2));
-        }
-        return res;
-    }
-
-    // Removed the 'thread safe' updates for now, to simplify the code
-    // last test shows a small improvement, can switch later.
-    private static boolean sizeLogged = false;
-
-    protected long allocatePoller(int size, long pool) {
-        int flag = threadSafe ? Poll.APR_POLLSET_THREADSAFE: 0;
-        for (int i = 0; i < 2; i++) {
-            try {
-                //  timeout must be -1 - or ttl will take effect, strange results.
-                return Poll.create(size, pool, flag, -1);
-            } catch (Error e) {
-                e.printStackTrace();
-                if (Status.APR_STATUS_IS_EINVAL(e.getError())) {
-                    log.info(" endpoint.poll.limitedpollsize " + size);
-                    return 0;
-                } else if (Status.APR_STATUS_IS_ENOTIMPL(e.getError())) {
-                    // thread safe not supported
-                    log.severe("THREAD SAFE NOT SUPPORTED" + e);
-                    threadSafe = false;
-                    // try again without the flags
-                    continue;
-                } else {
-                    log.severe("endpoint.poll.initfail" + e);
-                    return 0;
-                }
-            }
-        }
-        log.severe("Unexpected ENOTIMPL with flag==0");
-        return 0;
-    }
-
-    class AprPoller extends Thread {
-
-        private int id;
-        private int size;
-        private long serverPollset = 0;
-        private long pool = 0;
-        private long[] desc;
-
-        private long lastPoll;
-        private long lastPollTime;
-        private final AtomicBoolean inPoll = new AtomicBoolean(false);
-
-        // Should be replaced with socket data.
-        // used only to lookup by socket
-        private final Map<Long, AprSocket> channels = new HashMap<>();
-
-        // Active + pending, must be < desc.length / 2
-        // The channel will also have poller=this when active or pending
-        // How many sockets have poller == this
-        private final AtomicInteger keepAliveCount = new AtomicInteger();
-        // Tracks desc, how many sockets are actively polled
-        private final AtomicInteger polledCount = new AtomicInteger();
-
-        private final AtomicInteger pollCount = new AtomicInteger();
-
-        private final List<AprSocket> updates = new ArrayList<>();
-
-        @Override
-        public void run() {
-            if (!running) {
-                return;
-            }
-            if (debugPoll) {
-                log.info("Starting poller " + id + " " + (isServer() ? "SRV ": "CLI "));
-            }
-            long t0 = System.currentTimeMillis();
-            while (running) {
-                try {
-                    updates();
-
-                    // Pool for the specified interval. Remove signaled sockets
-                    synchronized (this) {
-                        inPoll.set(true);
-                    }
-                    // if updates are added after updates and poll - interrupt will have still
-                    // work
-
-                    int rv = Poll.poll(serverPollset, pollTime, desc, true);
-                    synchronized (this) {
-                        inPoll.set(false);
-                        if (!running) {
-                            break;
-                        }
-                    }
-
-                    pollCount.incrementAndGet();
-                    lastPoll = System.currentTimeMillis();
-                    lastPollTime = lastPoll - t0;
-
-                    if (rv > 0) {
-                        if (debugPoll) {
-                            log.info(" Poll() id=" + id + " rv=" + rv + " keepAliveCount=" + keepAliveCount +
-                                    " polled = " + polledCount.get()
-                                    + " time=" + lastPollTime);
-                        }
-                        polledCount.addAndGet(-rv);
-                        for (int pollIdx = 0; pollIdx < rv; pollIdx++) {
-                            long sock = desc[pollIdx * 2 + 1];
-                            AprSocket ch;
-                            boolean blocking = false;
-
-                            synchronized (channels) {
-                                ch = channels.get(Long.valueOf(sock));
-                                if (ch != null) {
-                                    blocking = ch.isBlocking();
-                                } else {
-                                    log.severe("Polled socket not found !!!!!" + Long.toHexString(sock));
-                                    // TODO: destroy/close the raw socket
-                                    continue;
-                                }
-                            }
-                            // was removed from polling
-                            ch.clearStatus(AprSocket.POLL);
-
-                            // We just removed it ( see last param to poll()).
-                            // Check for failed sockets and hand this socket off to a worker
-                            long mask = desc[pollIdx * 2];
-
-                            boolean err = ((mask & Poll.APR_POLLERR) == Poll.APR_POLLERR);
-                            boolean nval = ((mask & Poll.APR_POLLNVAL) != 0);
-                            if (err || nval) {
-                                System.err.println("ERR " + err + " NVAL " + nval);
-                            }
-
-                            boolean out = (mask & Poll.APR_POLLOUT) == Poll.APR_POLLOUT;
-                            boolean in = (mask & Poll.APR_POLLIN) == Poll.APR_POLLIN;
-                            if (debugPoll) {
-                                log.info(" Poll channel: " + Long.toHexString(mask) +
-                                        (out ? " OUT" :"") +
-                                        (in ? " IN": "") +
-                                        (err ? " ERR" : "") +
-                                        " Ch: " + ch);
-                            }
-
-                            // will be set again in process(), if all read/write is done
-                            ch.clearStatus(AprSocket.POLLOUT);
-                            ch.clearStatus(AprSocket.POLLIN);
-
-                            // try to send if needed
-                            if (blocking) {
-                                synchronized (ch) {
-                                    ch.notifyAll();
-                                }
-                                getExecutor().execute(ch);
-                            } else {
-                                ((AprSocketContext.NonBlockingPollHandler) ch.handler).process(ch, in, out, false);
-
-                                // Update polling for the channel (in IO thread, safe)
-                                updateIOThread(ch);
-                            }
-                        }
-                    } else if (rv < 0) {
-                        int errn = -rv;
-                        if (errn == Status.TIMEUP) {
-                            // to or interrupt
-//                            if (debugPoll) {
-//                                log.info(" Poll() timeup" + " keepAliveCount=" + keepAliveCount +
-//                                        " polled = " + polledCount.get()
-//                                        + " time=" + lastPollTime);
-//                            }
-                        } else if (errn == Status.EINTR) {
-                            // interrupt - no need to log
-                        } else {
-                            if (debugPoll) {
-                                log.info(" Poll() rv=" + rv + " keepAliveCount=" + keepAliveCount +
-                                        " polled = " + polledCount.get()
-                                        + " time=" + lastPollTime);
-                            }
-                            /* Any non timeup or interrupted error is critical */
-                            if (errn >  Status.APR_OS_START_USERERR) {
-                                errn -=  Status.APR_OS_START_USERERR;
-                            }
-                            log.severe("endpoint.poll.fail " + errn + " " + Error.strerror(errn));
-                            // Handle poll critical failure
-                            synchronized (this) {
-                                destroyPoller(); // will close all sockets
-                            }
-                            continue;
-                        }
-                    }
-                    // TODO: timeouts
-                } catch (Throwable t) {
-                    log.log(Level.SEVERE, "endpoint.poll.error", t);
-                }
-
-            }
-            if (!running) {
-                destroyPoller();
-            }
-        }
-
-        /**
-                 * Destroy the poller.
-                 */
-        protected void destroyPoller() {
-            synchronized (pollers) {
-                pollers.remove(this);
-            }
-            log.info("Poller stopped after cnt=" +
-                    pollCount.get() +
-                    " sockets=" + channels.size() +
-                    " lastPoll=" + lastPoll);
-
-            // Close all sockets
-            synchronized (this)  {
-                if (serverPollset == 0) {
-                    return;
-                }
-
-//                for (AprSocket ch: channels.values()) {
-//                    ch.poller = null;
-//                    ch.reset();
-//                }
-                keepAliveCount.set(0);
-                log.warning("Destroy pollset");
-                //serverPollset = 0;
-            }
-            Pool.destroy(pool);
-            pool = 0;
-            synchronized (pollers) {
-                // Now we can destroy the root pool
-                if (pollers.size() == 0 && !running) {
-                    log.info("Destroy server context");
-//                    AprSocketContext.this.destroy();
-                }
-            }
-        }
-
-        /**
-         * Called only in poller thread, only used if not thread safe
-         * @throws IOException
-         */
-        protected void updates() throws IOException {
-            synchronized (this) {
-                for (AprSocket up: updates) {
-                    updateIOThread(up);
-                }
-                updates.clear();
-            }
-        }
-
-        void interruptPoll() {
-            try {
-                int rc = Status.APR_SUCCESS;
-                synchronized (this) {
-                    if (serverPollset != 0) {
-                        rc = Poll.interrupt(serverPollset);
-                    } else {
-                        log.severe("Interrupt with closed pollset");
-                    }
-                }
-                if (rc != Status.APR_SUCCESS) {
-                    log.severe("Failed interrupt and not thread safe");
-                }
-            } catch (Throwable t) {
-                t.printStackTrace();
-                if (pollTime > FALLBACK_POLL_TIME) {
-                    pollTime = FALLBACK_POLL_TIME;
-                }
-            }
-        }
-
-
-        int remaining() {
-            synchronized (channels) {
-                return (desc.length - channels.size() * 2);
-            }
-        }
-
-
-
-        /**
-         * Called from any thread, return true if we could add it
-         * to pending.
-         */
-        boolean add(AprSocket ch) throws IOException {
-            synchronized (this) {
-                if (!running) {
-                    return false;
-                }
-                if (keepAliveCount.get() >= size) {
-                    return false;
-                }
-                keepAliveCount.incrementAndGet();
-                ch.poller = this;
-            }
-
-            requestUpdate(ch);
-
-            return true;
-        }
-
-        /**
-         * May be called outside of IOThread.
-         */
-        protected void requestUpdate(AprSocket ch) throws IOException {
-            synchronized (this) {
-                if (!running) {
-                    return;
-                }
-            }
-            if (isPollerThread()) {
-                updateIOThread(ch);
-            } else {
-                synchronized (this) {
-                    if (!updates.contains(ch)) {
-                        updates.add(ch);
-                    }
-                    interruptPoll();
-                }
-                if (debugPoll) {
-                    log.info("Poll: requestUpdate " + id + " " + ch);
-                }
-            }
-        }
-
-        private void updateIOThread(AprSocket ch) throws IOException {
-            if (!running || ch.socket == 0) {
-                return;
-            }
-            // called from IO thread, either in 'updates' or after
-            // poll.
-            //synchronized (ch)
-            boolean polling = ch.checkPreConnect(AprSocket.POLL);
-
-            int requested = ch.requestedPolling();
-            if (requested == 0) {
-                if (polling) {
-                    removeSafe(ch);
-                }
-                if (ch.isClosed()) {
-                    synchronized (channels) {
-                        ch.poller = null;
-                        channels.remove(Long.valueOf(ch.socket));
-                    }
-                    keepAliveCount.decrementAndGet();
-                    ch.reset();
-                }
-            } else {
-                if (polling) {
-                    removeSafe(ch);
-                }
-                // will close if error
-                pollAdd(ch, requested);
-            }
-            if (debugPoll) {
-                log.info("Poll: updated=" + id + " " + ch);
-            }
-        }
-
-        /**
-         * Called only from IO thread
-         */
-        private void pollAdd(AprSocket up, int req) throws IOException {
-            boolean failed = false;
-            int rv;
-            synchronized (channels) {
-                if (up.isClosed()) {
-                    return;
-                }
-                rv = Poll.add(serverPollset, up.socket, req);
-                if (rv != Status.APR_SUCCESS) {
-                    up.poller = null;
-                    keepAliveCount.decrementAndGet();
-                    failed = true;
-                } else {
-                    polledCount.incrementAndGet();
-                    channels.put(Long.valueOf(up.socket), up);
-                    up.setStatus(AprSocket.POLL);
-                }
-            }
-            if (failed) {
-                up.reset();
-                throw new IOException("poll add error " +  rv + " " + up + " " + Error.strerror(rv));
-            }
-        }
-
-        /**
-         * Called only from IO thread. Remove from Poll and channels,
-         * set POLL bit to false.
-         */
-        private void removeSafe(AprSocket up) {
-            int rv = Status.APR_EGENERAL;
-            if (running && serverPollset != 0 && up.socket != 0
-                    && !up.isClosed()) {
-                rv = Poll.remove(serverPollset, up.socket);
-            }
-            up.clearStatus(AprSocket.POLL);
-
-            if (rv != Status.APR_SUCCESS) {
-                log.severe("poll remove error " +  Error.strerror(rv) + " " + up);
-            } else {
-                polledCount.decrementAndGet();
-            }
-        }
-
-
-        public boolean isPollerThread() {
-            return Thread.currentThread() == this;
-        }
-
-    }
-
-    /**
-     * Callback for poll events, will be invoked in a thread pool.
-     *
-     */
-    public static interface BlockingPollHandler {
-
-        /**
-         * Called when the socket has been polled for in, out or closed.
-         *
-         *
-         */
-        public void process(AprSocket ch, boolean in, boolean out, boolean close);
-
-
-        /**
-         *  Called just before the socket is destroyed
-         */
-        public void closed(AprSocket ch);
-    }
-
-    /**
-     *  Additional callbacks for non-blocking.
-     *  This can be much faster - but it's harder to code, should be used only
-     *  for low-level protocol implementation, proxies, etc.
-     *
-     *  The model is restricted in many ways to avoid complexity and bugs:
-     *
-     *  - read can only happen in the IO thread associated with the poller
-     *  - user doesn't control poll interest - it is set automatically based
-     *  on read/write results
-     *  - it is only possible to suspend read, for TCP flow control - also
-     *  only from the IO thread. Resume can happen from any thread.
-     *  - it is also possible to call write() from any thread
-     */
-    public static interface NonBlockingPollHandler extends BlockingPollHandler {
-
-        /**
-         * Called after connection is established, in a thread pool.
-         * Process will be called next.
-         */
-        public void connected(AprSocket ch);
-
-        /**
-         * Before close, if an exception happens.
-         */
-        public void error(AprSocket ch, Throwable t);
-    }
-
-}
diff --git a/java/org/apache/tomcat/jni/socket/HostInfo.java b/java/org/apache/tomcat/jni/socket/HostInfo.java
deleted file mode 100644
index 4262910..0000000
--- a/java/org/apache/tomcat/jni/socket/HostInfo.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  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.jni.socket;
-
-import java.io.Serializable;
-
-/**
- * Information about the remote host. Persisting this in memcache or similar
- * storage can improve performance on future TLS connections by skipping roundtrips
- * and reducing CPU use in handshake.
- *
- * This class is used in both server and client mode.
- *
- * AprSocketContextLitener.getPeer(name) can be used to read from an external storage.
- *
- * TODO: also save the SPDY persistent settings here.
- * TODO: fix tickets, don't seem to work anymore.
- */
-public class HostInfo implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    public String host;
-
-    public int port;
-
-    public boolean secure;
-
-    /**
-     * Raw cert data (x.509 format).
-     * This is retrieved when a full handshake happens - if session reuse or tickets
-     * are used you'll not receive the certs again.
-     */
-    public byte[][] certs;
-
-    public byte[] ticket;
-    public int ticketLen;
-
-    public String sessionId;
-
-    /**
-     * DER-encoded session data.
-     */
-    public byte[] sessDer;
-
-    /**
-     * Negotiated NPN.
-     */
-    byte[] npn;
-    int npnLen;
-
-    public HostInfo() {
-    }
-
-    public HostInfo(String host, int port, boolean secure) {
-        this.host = host;
-        this.port = port;
-        this.secure = secure;
-    }
-
-    public String getNpn() {
-        return new String(npn, 0, npnLen);
-    }
-
-    public void setNpn(String npn) {
-        if (npn == null) {
-            npnLen = 0;
-        }
-    }
-}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/spdy/CompressDeflater6.java b/java/org/apache/tomcat/spdy/CompressDeflater6.java
deleted file mode 100644
index 5eb272e..0000000
--- a/java/org/apache/tomcat/spdy/CompressDeflater6.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *  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.spdy;
-
-import java.io.IOException;
-import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-
-import org.apache.tomcat.spdy.SpdyConnection.CompressSupport;
-
-/**
- * Java6 Deflater with the workaround from tomcat http filters.
- */
-class CompressDeflater6 implements CompressSupport {
-    public static final long DICT_ID = 3751956914L;
-
-    // Make sure to use the latest from net/spdy/spdy_framer.cc, not from spec
-    private static final String SPDY_DICT_S =
-              "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
-            + "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
-            + "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
-            + "-agent10010120020120220320420520630030130230330430530630740040140240340440"
-            + "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
-            + "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
-            + "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
-            + "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
-            + "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
-            + "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
-            + "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
-            + "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
-            + ".1statusversionurl ";
-
-    private static final byte[] SPDY_DICT = SPDY_DICT_S.getBytes();
-    // C code uses this - not in the spec
-    static {
-        SPDY_DICT[SPDY_DICT.length - 1] = (byte) 0;
-    }
-
-    private Deflater zipOut;
-    private Inflater zipIn;
-
-    private byte[] decompressBuffer;
-    private int decMax;
-
-    private byte[] compressBuffer;
-
-    public CompressDeflater6() {
-    }
-
-    public static CompressDeflater6 get() {
-        // TODO: code to plug in v7-specific. It is marginally faster.
-        return new CompressDeflater6();
-    }
-
-    public void recycle() {
-        // TODO
-    }
-
-    public void init() {
-        if (zipOut != null) {
-            return;
-        }
-        try {
-            // false is important - otherwise 'bad method'
-            zipOut = new Deflater(Deflater.DEFAULT_COMPRESSION, false);
-            zipOut.setDictionary(SPDY_DICT);
-            zipIn = new Inflater();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    @Override
-    public synchronized void compress(SpdyFrame frame, int start)
-            throws IOException {
-        init();
-
-        if (compressBuffer == null) {
-            compressBuffer = new byte[frame.data.length];
-        }
-
-        // last byte for flush ?
-        zipOut.setInput(frame.data, start, frame.endData - start - 1);
-        int coff = start;
-        zipOut.setLevel(Deflater.DEFAULT_COMPRESSION);
-        while (true) {
-            int rd = zipOut.deflate(compressBuffer, coff, compressBuffer.length - coff);
-            if (rd == 0) {
-                // needsInput needs to be called - we're done with this frame ?
-                zipOut.setInput(frame.data, frame.endData - 1, 1);
-                zipOut.setLevel(Deflater.BEST_SPEED);
-                while (true) {
-                    rd = zipOut.deflate(compressBuffer, coff, compressBuffer.length - coff);
-                    coff += rd;
-                    if (rd == 0) {
-                        break;
-                    }
-                    byte[] b = new byte[compressBuffer.length * 2];
-                    System.arraycopy(compressBuffer, 0, b, 0, coff);
-                    compressBuffer = b;
-                }
-                zipOut.setLevel(Deflater.DEFAULT_COMPRESSION);
-                break;
-            }
-            coff += rd;
-        }
-
-        byte[] tmp = frame.data;
-        frame.data = compressBuffer;
-        compressBuffer = tmp;
-        frame.endData = coff;
-    }
-
-    @Override
-    public synchronized void decompress(SpdyFrame frame, int start)
-            throws IOException {
-        // stream id ( 4 ) + unused ( 2 )
-        // nvCount is compressed in impl - spec is different
-        init();
-
-
-        if (decompressBuffer == null) {
-            decompressBuffer = new byte[frame.data.length];
-        }
-
-        // will read from dec buffer to frame.data
-        decMax = frame.endData;
-
-        int off = start;
-
-        zipIn.setInput(frame.data, start, decMax - start);
-
-        while (true) {
-            int rd;
-            try {
-                rd = zipIn.inflate(decompressBuffer, off, decompressBuffer.length - off);
-                if (rd == 0 && zipIn.needsDictionary()) {
-                    zipIn.setDictionary(SPDY_DICT);
-                    continue;
-                }
-            } catch (DataFormatException e) {
-                throw new IOException(e);
-            }
-            if (rd == 0) {
-                break;
-            }
-            if (rd == -1) {
-                break;
-            }
-            off += rd;
-            byte[] b = new byte[decompressBuffer.length * 2];
-            System.arraycopy(decompressBuffer, 0, b, 0, off);
-            decompressBuffer = b;
-
-        }
-        byte[] tmpBuf = decompressBuffer;
-        decompressBuffer = frame.data;
-        frame.data = tmpBuf;
-
-        frame.off = start;
-        frame.endData = off;
-    }
-}
diff --git a/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java b/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java
deleted file mode 100644
index 55de2f8..0000000
--- a/java/org/apache/tomcat/spdy/NetSupportOpenSSL.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- *  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.spdy;
-
-import java.io.IOException;
-
-import org.apache.tomcat.jni.SSLExt;
-import org.apache.tomcat.jni.Status;
-import org.apache.tomcat.jni.socket.AprSocket;
-import org.apache.tomcat.jni.socket.AprSocketContext;
-import org.apache.tomcat.jni.socket.AprSocketContext.NonBlockingPollHandler;
-import org.apache.tomcat.jni.socket.AprSocketContext.TlsCertVerifier;
-
-
-public class NetSupportOpenSSL extends SpdyContext.NetSupport {
-
-    private AprSocketContext con;
-
-    public NetSupportOpenSSL() {
-        con = new AprSocketContext();
-        //if (insecureCerts) {
-        con.customVerification(new TlsCertVerifier() {
-            @Override
-            public void handshakeDone(AprSocket ch) {
-            }
-        });
-        //}
-        con.setNpn("spdy/2");
-    }
-
-    @Override
-    public boolean isSpdy(Object socketW) {
-        byte[] proto = new byte[32];
-        int len = SSLExt.getNPN(((Long) socketW).longValue(), proto);
-        return len == 6; // todo: check spdy/2
-    }
-
-    @Override
-    public SpdyConnection getConnection(String host, int port) throws IOException {
-        SpdyConnectionAprSocket spdy = new SpdyConnectionAprSocket(ctx);
-
-        AprSocket ch = con.socket(host, port, ctx.tls);
-
-        spdy.setSocket(ch);
-
-        ch.connect();
-
-        ch.setHandler(new SpdySocketHandler(spdy));
-
-        // need to consume the input to receive more read events
-        int rc = spdy.processInput();
-        if (rc == SpdyConnection.CLOSE) {
-            ch.close();
-            throw new IOException("Error connecting");
-        }
-
-        return spdy;
-    }
-
-    @Override
-    public void onAccept(Object socket) {
-        onAcceptLong(((Long) socket).longValue());
-    }
-
-    public void onAcceptLong(long socket) {
-        SpdyConnectionAprSocket spdy = new SpdyConnectionAprSocket(ctx);
-        AprSocket s = con.socket(socket);
-        spdy.setSocket(s);
-
-        SpdySocketHandler handler = new SpdySocketHandler(spdy);
-        s.setHandler(handler);
-        handler.process(s, true, true, false);
-    }
-
-    public AprSocketContext getAprContext() {
-        return con;
-    }
-
-
-    @Override
-    public void listen(final int port, String cert, String key) throws IOException {
-        con = new AprSocketContext() {
-            @Override
-            protected void onSocket(AprSocket s) {
-                SpdyConnectionAprSocket spdy = new SpdyConnectionAprSocket(ctx);
-                spdy.setSocket(s);
-
-                SpdySocketHandler handler = new SpdySocketHandler(spdy);
-                s.setHandler(handler);
-            }
-        };
-
-        con.setNpn(SpdyContext.SPDY_NPN_OUT);
-        con.setKeys(cert, key);
-
-        con.listen(port);
-    }
-
-    @Override
-    public void stop() throws IOException {
-        con.stop();
-    }
-
-    // NB
-    private static class SpdySocketHandler implements NonBlockingPollHandler {
-        private final SpdyConnection con;
-
-        SpdySocketHandler(SpdyConnection con) {
-            this.con = con;
-        }
-
-        @Override
-        public void closed(AprSocket ch) {
-            // not used ( polling not implemented yet )
-        }
-
-        @Override
-        public void process(AprSocket ch, boolean in, boolean out, boolean close) {
-            try {
-                int rc = con.processInput();
-                if (rc == SpdyConnection.CLOSE) {
-                    ch.close();
-                }
-                con.drain();
-            } catch (IOException e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
-                ch.reset();
-            }
-        }
-
-        @Override
-        public void connected(AprSocket ch) {
-        }
-
-        @Override
-        public void error(AprSocket ch, Throwable t) {
-        }
-
-    }
-
-    private static class SpdyConnectionAprSocket extends SpdyConnection {
-        private AprSocket socket;
-
-        public SpdyConnectionAprSocket(SpdyContext spdyContext) {
-            super(spdyContext);
-        }
-
-        public void setSocket(AprSocket ch) {
-            this.socket = ch;
-        }
-
-        @Override
-        public void close() throws IOException {
-            socket.close();
-        }
-
-        @Override
-        public int write(byte[] data, int off, int len) throws IOException {
-            if (socket == null) {
-                return -1;
-            }
-            int sent = socket.write(data, off, len);
-            if (sent < 0) {
-                return -1;
-            }
-            return sent;
-        }
-
-        /**
-         * @throws IOException
-         */
-        @Override
-        public int read(byte[] data, int off, int len) throws IOException {
-            if (socket == null) {
-                return -1;
-            }
-            int rd = socket.read(data, off, len);
-            // org.apache.tomcat.jni.Socket.recv(socket, data, off, len);
-            if (rd == -Status.APR_EOF) {
-                return -1;
-            }
-            if (rd == -Status.TIMEUP || rd == -Status.EINTR || rd == -Status.EAGAIN) {
-                rd = 0;
-            }
-            if (rd < 0) {
-                return -1;
-            }
-            return rd;
-        }
-    }
-
-
-}
diff --git a/java/org/apache/tomcat/spdy/NetSupportSocket.java b/java/org/apache/tomcat/spdy/NetSupportSocket.java
deleted file mode 100644
index 71e9fdf..0000000
--- a/java/org/apache/tomcat/spdy/NetSupportSocket.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- *  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.spdy;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketTimeoutException;
-import java.security.NoSuchAlgorithmException;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-
-
-public class NetSupportSocket extends SpdyContext.NetSupport {
-
-    @Override
-    public boolean isSpdy(Object socketW) {
-        return false;
-    }
-
-    @Override
-    public SpdyConnection getConnection(String host, int port) throws IOException {
-        try {
-            Socket sock = getSocket(host, port);
-
-            sock.getInputStream();
-            SpdyConnectionSocket con = new SpdyConnectionSocket(ctx, sock);
-
-            ctx.getExecutor().execute(con.inputThread);
-            return con;
-        } catch (IOException ex) {
-            ex.printStackTrace();
-            throw ex;
-        }
-
-    }
-
-
-    protected Socket getSocket(String host, int port) throws IOException {
-        try {
-            if (ctx.tls) {
-                SSLContext sslCtx = SSLContext.getDefault();
-                SSLSocket socket = (SSLSocket) sslCtx.getSocketFactory().createSocket(host, port);
-                //socket.setEnabledProtocols(new String[] {"TLS1"});
-                socket.startHandshake();
-                return socket;
-            } else {
-                return new Socket(host, port);
-            }
-        } catch (NoSuchAlgorithmException e) {
-            throw new IOException(e);
-        }
-
-    }
-
-    private boolean running = true;
-    private ServerSocket serverSocket;
-
-    @Override
-    public void stop() throws IOException {
-        running = false;
-        serverSocket.close();
-    }
-
-    @Override
-    public void onAccept(Object socket) {
-        SpdyConnectionSocket ch = new SpdyConnectionSocket(ctx, (Socket) socket);
-        ch.onBlockingSocket();
-    }
-
-
-    @Override
-    public void listen(final int port, String cert, String key) throws IOException {
-        ctx.getExecutor().execute(new Runnable() {
-            @Override
-            public void run() {
-                accept(port);
-            }
-        });
-    }
-
-    private void accept(int port) {
-        try {
-            serverSocket = new ServerSocket(port);
-            while (running) {
-                final Socket socket = serverSocket.accept();
-                ctx.getExecutor().execute(new Runnable() {
-                    @Override
-                    public void run() {
-                        onAccept(socket);
-                        try {
-                            socket.close();
-                        } catch (IOException e) {
-                            e.printStackTrace();
-                        }
-                    }
-                });
-            }
-        } catch (IOException ex) {
-            if (running) {
-                ex.printStackTrace();
-            }
-            running = false;
-        }
-    }
-
-
-    private static class SpdyConnectionSocket extends SpdyConnection {
-        private Socket socket;
-
-
-        Runnable inputThread = new Runnable() {
-            @Override
-            public void run() {
-                onBlockingSocket();
-                try {
-                    inClosed = true;
-                    socket.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        };
-
-        public SpdyConnectionSocket(SpdyContext spdyContext) {
-            super(spdyContext);
-        }
-
-        public SpdyConnectionSocket(SpdyContext spdyContext, Socket socket) {
-            super(spdyContext);
-            this.socket = socket;
-        }
-
-        @Override
-        public void close() throws IOException {
-            socket.close();
-        }
-
-        @Override
-        public synchronized int write(byte[] data, int off, int len) throws IOException {
-            socket.getOutputStream().write(data, off, len);
-            return len;
-        }
-
-        @Override
-        public int read(byte[] data, int off, int len) throws IOException {
-            try {
-                return socket.getInputStream().read(data, off, len);
-            } catch (SocketTimeoutException ex) {
-                return 0;
-            }
-        }
-    }
-
-}
-
diff --git a/java/org/apache/tomcat/spdy/SpdyConnection.java b/java/org/apache/tomcat/spdy/SpdyConnection.java
deleted file mode 100644
index 75d237e..0000000
--- a/java/org/apache/tomcat/spdy/SpdyConnection.java
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- *  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.spdy;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Main class implementing SPDY protocol. Works with both blocking and
- * non-blocking sockets. To simplify integration in various endpoints there is
- * no 'socket' layer/abstraction, but read/write abstract methods.
- *
- * Because SPDY is multiplexing, a blocking socket needs a second thread to
- * handle writes ( the read thread may be blocked while a servlet is writing ).
- * The intended use of SPDY with blocking sockets is for frontend(load-balancer)
- * to tomcat, where each tomcat will have a few spdy connections.
- *
- */
-public abstract class SpdyConnection { // implements Runnable {
-
-    // TODO: this can be pooled, to avoid allocation on idle connections
-    // TODO: override socket timeout
-
-    private volatile SpdyFrame inFrame;
-
-    private CompressSupport compressSupport;
-
-    // Fields stored for each spdy connection
-    private final Map<Integer, SpdyStream> channels = new HashMap<>();
-
-    // --------------
-    private static final Logger log = Logger.getLogger(SpdyConnection.class
-            .getName());
-
-    public static final int TYPE_SYN_STREAM = 1;
-
-    public static final int TYPE_SYN_REPLY = 2;
-
-    public static final int TYPE_RST_STREAM = 3;
-
-    public static final int TYPE_SETTINGS = 4;
-
-    public static final int TYPE_PING = 6;
-
-    public static final int TYPE_GOAWAY = 7;
-
-    public static final int TYPE_HEADERS = 8;
-
-    public static final int TYPE_WINDOW = 8;
-
-    public static String[] TYPES = { "SYN_STREAM", "SYN_REPLY", "RST_STREAM",
-            "SETTINGS", "5", "PING", "GOAWAY", "HEADERS", "WINDOW_UPDATE" };
-
-    static final int FLAG_HALF_CLOSE = 1;
-
-    private static final String[] RST_ERRORS = {
-            // This is a generic error, and should only be used if a more
-            // specific error is not available.
-            "PROTOCOL_ERROR", "INVALID_STREAM",
-            // This is returned when a frame is received for a stream which is
-            // not
-            // active.
-            "REFUSED_STREAM",
-            // Indicates that the stream was refused before any processing has
-            // been
-            // done on the stream.
-            "UNSUPPORTED_VERSION",
-            // 4 Indicates that the recipient of a stream does not support the
-            // SPDY version requested.
-            "CANCEL",
-            // 5 Used by the creator of a stream to indicate that the stream is
-            // no longer needed.
-            "FLOW_CONTROL_ERROR",
-            // 6 The endpoint detected that its peer violated the flow control
-            // protocol.
-            "STREAM_IN_USE",
-            // 7 The endpoint received a SYN_REPLY for a stream already open.
-            "STREAM_ALREADY_CLOSED"
-    // 8 The endpoint received a data or SYN_REPLY frame for a stream which
-    // is half closed.
-    };
-
-    // protected SpdyFrame currentOutFrame = new SpdyFrame();
-
-    protected final SpdyContext spdyContext;
-
-    protected boolean inClosed;
-
-    private int lastChannel;
-
-    private int outStreamId = 1;
-
-    // TODO: finer handling of priorities
-    private final LinkedList<SpdyFrame> prioriyQueue = new LinkedList<>();
-
-    private final LinkedList<SpdyFrame> outQueue = new LinkedList<>();
-
-    // --------------
-
-    public static final int LONG = 1;
-
-    public static final int CLOSE = -1;
-
-    private SpdyFrame nextFrame;
-
-    /**
-     * Handles the out queue for blocking sockets.
-     */
-    private SpdyFrame out;
-
-    private int goAway = Integer.MAX_VALUE;
-
-    public SpdyConnection(SpdyContext spdyContext) {
-        this.spdyContext = spdyContext;
-        if (spdyContext.compression) {
-            setCompressSupport(CompressDeflater6.get());
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "SpdyCon open=" + channels.size() + " " + lastChannel;
-    }
-
-    public void dump(PrintWriter out) {
-        out.println("SpdyConnection open=" + channels.size() +
-                " outQ:" + outQueue.size());
-        for (SpdyStream str: channels.values()) {
-            str.dump(out);
-        }
-
-        out.println();
-
-    }
-
-    /**
-     * Write.
-     */
-    public abstract int write(byte[] data, int off, int len) throws IOException;
-
-    /**
-     * Like read, but may return 0 if no data is available and the channel
-     * supports polling.
-     */
-    public abstract int read(byte[] data, int off, int len) throws IOException;
-
-    public abstract void close() throws IOException;
-
-    public void setCompressSupport(CompressSupport cs) {
-        compressSupport = cs;
-    }
-
-    public SpdyFrame getFrame(int type) {
-        SpdyFrame frame = getSpdyContext().getFrame();
-        frame.c = true;
-        frame.type = type;
-        return frame;
-    }
-
-    public SpdyFrame getDataFrame() {
-        SpdyFrame frame = getSpdyContext().getFrame();
-        return frame;
-    }
-
-    /*
-     * Output requirements: - common case: sendFrame called from a thread ( like
-     * servlets ), wants to be blocked anyways
-     *
-     * - but also need to support 'non-blocking' mode ( ping )
-     *
-     * - we need to queue frames when write would block, so we can prioritize.
-     *
-     * - for fully non-blocking write: there will be a drain callback.
-     */
-
-    public void drain() {
-        synchronized (nbDrain) {
-            _drain();
-        }
-    }
-
-    /**
-     * Non blocking if the socket is not blocking.
-     */
-    private boolean _drain() {
-        while (true) {
-            synchronized (outQueue) {
-                if (out == null) {
-                    out = prioriyQueue.poll();
-                    if (out == null) {
-                        out = outQueue.poll();
-                    }
-                    if (out == null) {
-                        return false;
-                    }
-                    if (goAway < out.streamId) {
-                        // TODO
-                    }
-                    try {
-                        if (!out.c) {
-                            // late: IDs are assigned as we send ( priorities may affect
-                            // the transmission order )
-                            if (out.stream != null) {
-                                out.streamId = out.stream.getRequest().streamId;
-                            }
-                        } else if (out.type == TYPE_SYN_STREAM) {
-                            out.fixNV(18);
-                            if (compressSupport != null) {
-                                compressSupport.compress(out, 18);
-                            }
-                        } else if (out.type == TYPE_SYN_REPLY
-                                || out.type == TYPE_HEADERS) {
-                            out.fixNV(14);
-                            if (compressSupport != null) {
-                                compressSupport.compress(out, 14);
-                            }
-                        }
-                    } catch (IOException ex) {
-                        abort("Compress error");
-                        return false;
-                    }
-                    if (out.type == TYPE_SYN_STREAM) {
-                        out.streamId = outStreamId;
-                        outStreamId += 2;
-                        synchronized(channels) {
-                            channels.put(Integer.valueOf(out.streamId),
-                                    out.stream);
-                        }
-                    }
-
-                    out.serializeHead();
-
-                }
-                if (out.endData == out.off) {
-                    out = null;
-                    continue;
-                }
-            }
-
-            if (SpdyContext.debug) {
-                trace("> " + out);
-            }
-
-            try {
-                int toWrite = out.endData - out.off;
-                int wr;
-                while (toWrite > 0) {
-                    wr = write(out.data, out.off, toWrite);
-                    if (wr < 0) {
-                        return false;
-                    }
-                    if (wr == 0) {
-                        return true; // non blocking or to
-                    }
-                    if (wr <= toWrite) {
-                        out.off += wr;
-                        toWrite -= wr;
-                    }
-                }
-
-                synchronized (channels) {
-                    if (out.stream != null) {
-                        if (out.isHalfClose()) {
-                            out.stream.finSent = true;
-                        }
-                        if (out.stream.finRcvd && out.stream.finSent) {
-                            channels.remove(Integer.valueOf(out.streamId));
-                        }
-                    }
-                }
-                out = null;
-            } catch (IOException e) {
-                // connection closed - abort all streams
-                e.printStackTrace();
-                onClose();
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Send as much as possible without blocking.
-     *
-     * With a nb transport it should call drain directly.
-     */
-    public void nonBlockingSend(SpdyFrame oframe, SpdyStream proc) {
-        queueFrame(oframe, proc, oframe.pri == 0 ? outQueue : prioriyQueue);
-        getSpdyContext().getExecutor().execute(nbDrain);
-    }
-
-    private final Runnable nbDrain = new Runnable() {
-        @Override
-        public void run() {
-            drain();
-        }
-    };
-
-    /**
-     * Add the frame to the queue and send until the queue is empty.
-     *
-     */
-    public void send(SpdyFrame oframe, SpdyStream proc) {
-        queueFrame(oframe, proc, oframe.pri == 0 ? outQueue : prioriyQueue);
-        drain();
-    }
-
-    private void queueFrame(SpdyFrame oframe, SpdyStream proc,
-            LinkedList<SpdyFrame> queue) {
-
-        oframe.endData = oframe.off;
-        oframe.off = 0;
-        // We can't assing a stream ID until it is sent - priorities
-        // we can't compress either - it's stateful.
-        oframe.stream = proc;
-
-        // all sync for adding/removing is on outQueue
-        synchronized (outQueue) {
-            queue.add(oframe);
-        }
-    }
-
-    public void onClose() {
-        // TODO: abort
-    }
-
-    private void trace(String s) {
-        System.err.println(s);
-    }
-
-    public SpdyFrame inFrame() {
-        return inFrame;
-    }
-
-    /**
-     * Process a SPDY connection using a blocking socket.
-     */
-    public int onBlockingSocket() {
-        try {
-            if (SpdyContext.debug) {
-                trace("< onConnection() " + lastChannel);
-            }
-            int rc = processInput();
-
-            if (SpdyContext.debug) {
-                trace("< onConnection() " + rc + " " + lastChannel);
-            }
-            return rc;
-        } catch (Throwable t) {
-            t.printStackTrace();
-            trace("< onData-ERROR() " + lastChannel);
-            abort("Error processing socket" + t);
-            return CLOSE;
-        }
-    }
-
-    /**
-     * Non-blocking method, read as much as possible and return.
-     */
-    public int processInput() throws IOException {
-        while (true) {
-            if (inFrame == null) {
-                inFrame = getSpdyContext().getFrame();
-            }
-
-            if (inFrame.data == null) {
-                inFrame.data = new byte[16 * 1024];
-            }
-            // we might already have data from previous frame
-            if (inFrame.endReadData < 8 || // we don't have the header
-                    inFrame.endReadData < inFrame.endData) {
-
-                int rd = read(inFrame.data, inFrame.endReadData,
-                        inFrame.data.length - inFrame.endReadData);
-                if (rd == -1) {
-                    if (channels.size() == 0) {
-                        return CLOSE;
-                    } else {
-                        abort("Closed");
-                    }
-                } else if (rd < 0) {
-                    abort("Closed - read error");
-                    return CLOSE;
-                } else if (rd == 0) {
-                    return LONG;
-                    // Non-blocking channel - will resume reading at off
-                }
-                inFrame.endReadData += rd;
-            }
-            if (inFrame.endReadData < 8) {
-                continue; // keep reading
-            }
-            if (inFrame.endData == 0) {
-                inFrame.parse();
-                if (inFrame.version != 2) {
-                    abort("Wrong version");
-                    return CLOSE;
-                }
-
-                // MAX_FRAME_SIZE
-                if (inFrame.endData < 0 || inFrame.endData > 32000) {
-                    abort("Framing error, size = " + inFrame.endData);
-                    return CLOSE;
-                }
-
-                // TODO: if data, split it in 2 frames
-                // grow the buffer if needed.
-                if (inFrame.data.length < inFrame.endData) {
-                    byte[] tmp = new byte[inFrame.endData];
-                    System.arraycopy(inFrame.data, 0, tmp, 0, inFrame.endReadData);
-                    inFrame.data = tmp;
-                }
-            }
-
-            if (inFrame.endReadData < inFrame.endData) {
-                continue; // keep reading to fill current frame
-            }
-            // else: we have at least the current frame
-            int extra = inFrame.endReadData - inFrame.endData;
-            if (extra > 0) {
-                // and a bit more - to keep things simple for now we
-                // copy them to next frame, at least we saved reads.
-                // it is possible to avoid copy - but later.
-                nextFrame = getSpdyContext().getFrame();
-                nextFrame.makeSpace(extra);
-                System.arraycopy(inFrame.data, inFrame.endData,
-                        nextFrame.data, 0, extra);
-                nextFrame.endReadData = extra;
-                inFrame.endReadData = inFrame.endData;
-            }
-
-            // decompress
-            if (inFrame.type == TYPE_SYN_STREAM) {
-                inFrame.streamId = inFrame.readInt(); // 4
-                lastChannel = inFrame.streamId;
-                inFrame.associated = inFrame.readInt(); // 8
-                inFrame.pri = inFrame.read16(); // 10 pri and unused
-                if (compressSupport != null) {
-                    compressSupport.decompress(inFrame, 18);
-                }
-                inFrame.nvCount = inFrame.read16();
-
-            } else if (inFrame.type == TYPE_SYN_REPLY
-                    || inFrame.type == TYPE_HEADERS) {
-                inFrame.streamId = inFrame.readInt(); // 4
-                inFrame.read16();
-                if (compressSupport != null) {
-                    compressSupport.decompress(inFrame, 14);
-                }
-                inFrame.nvCount = inFrame.read16();
-            }
-
-            if (SpdyContext.debug) {
-                trace("< " + inFrame);
-            }
-
-            try {
-                int state = handleFrame();
-                if (state == CLOSE) {
-                    return state;
-                }
-            } catch (Throwable t) {
-                abort("Error handling frame");
-                t.printStackTrace();
-                return CLOSE;
-            }
-
-            if (inFrame != null) {
-                inFrame.recyle();
-                if (nextFrame != null) {
-                    inFrame = nextFrame;
-                    nextFrame = null;
-                }
-            } else {
-                inFrame = nextFrame;
-                nextFrame = null;
-                if (inFrame == null) {
-                    inFrame = getSpdyContext().getFrame();
-                }
-            }
-        }
-    }
-
-    // Framing error or shutdown- close all streams.
-    public void abort(String msg) {
-        System.err.println(msg);
-        inClosed = true;
-
-        List<Integer> ch = new ArrayList<>(channels.keySet());
-        for (Integer i: ch) {
-            SpdyStream stream = channels.remove(i);
-            if (stream != null) {
-                stream.onReset();
-            }
-        }
-    }
-
-    public void abort(String msg, int last) {
-        System.err.println(msg);
-        inClosed = true;
-
-        List<Integer> ch = new ArrayList<>(channels.keySet());
-        for (Integer i: ch) {
-            if (i.intValue() > last) {
-                SpdyStream stream = channels.remove(i);
-                if (stream != null) {
-                    stream.onReset();
-                }
-            }
-        }
-    }
-
-    /**
-     * Process a SPDY connection. Called in the input thread, should not
-     * block.
-     *
-     * @throws IOException
-     */
-    protected int handleFrame() throws IOException {
-        if (inFrame.c) {
-            switch (inFrame.type) {
-            case TYPE_SETTINGS: {
-                int cnt = inFrame.readInt();
-                for (int i = 0; i < cnt; i++) {
-                    inFrame.readByte();
-                    inFrame.read24();
-                    inFrame.readInt();
-                }
-                // TODO: save/interpret settings
-                break;
-            }
-            case TYPE_GOAWAY: {
-                int lastStream = inFrame.readInt();
-                log.info("GOAWAY last=" + lastStream);
-
-                // Server will shut down - but will keep processing the current requests,
-                // up to lastStream. If we sent any new ones - they need to be canceled.
-                abort("GO_AWAY", lastStream);
-                goAway  = lastStream;
-                return CLOSE;
-            }
-            case TYPE_RST_STREAM: {
-                inFrame.streamId = inFrame.read32();
-                int errCode = inFrame.read32();
-                if (SpdyContext.debug) {
-                    trace("> RST "
-                            + inFrame.streamId
-                            + " "
-                            + ((errCode < RST_ERRORS.length) ? RST_ERRORS[errCode]
-                                    : Integer.valueOf(errCode)));
-                }
-                SpdyStream sch;
-                synchronized(channels) {
-                        sch = channels.remove(
-                                Integer.valueOf(inFrame.streamId));
-                }
-                // if RST stream is for a closed channel - we can ignore.
-                if (sch != null) {
-                    sch.onReset();
-                }
-
-                inFrame = null;
-                break;
-            }
-            case TYPE_SYN_STREAM: {
-
-                SpdyStream ch = getSpdyContext().getStream(this);
-
-                synchronized (channels) {
-                    channels.put(Integer.valueOf(inFrame.streamId), ch);
-                }
-
-                try {
-                    ch.onCtlFrame(inFrame);
-                    inFrame = null;
-                } catch (Throwable t) {
-                    log.log(Level.SEVERE, "Error parsing head SYN_STREAM", t);
-                    abort("Error reading headers " + t);
-                    return CLOSE;
-                }
-                spdyContext.onStream(this, ch);
-                break;
-            }
-            case TYPE_SYN_REPLY: {
-                SpdyStream sch;
-                synchronized(channels) {
-                    sch = channels.get(Integer.valueOf(inFrame.streamId));
-                }
-                if (sch == null) {
-                    abort("Missing channel");
-                    return CLOSE;
-                }
-                try {
-                    sch.onCtlFrame(inFrame);
-                    inFrame = null;
-                } catch (Throwable t) {
-                    log.info("Error parsing head SYN_STREAM" + t);
-                    abort("Error reading headers " + t);
-                    return CLOSE;
-                }
-                break;
-            }
-            case TYPE_PING: {
-
-                SpdyFrame oframe = getSpdyContext().getFrame();
-                oframe.type = TYPE_PING;
-                oframe.c = true;
-
-                oframe.append32(inFrame.read32());
-                oframe.pri = 0x80;
-
-                send(oframe, null);
-                break;
-            }
-            }
-        } else {
-            // Data frame
-            SpdyStream sch;
-            synchronized (channels) {
-                sch = channels.get(Integer.valueOf(inFrame.streamId));
-            }
-            if (sch == null) {
-                abort("Missing channel");
-                return CLOSE;
-            }
-            sch.onDataFrame(inFrame);
-            synchronized (channels) {
-                if (sch.finRcvd && sch.finSent) {
-                    channels.remove(Integer.valueOf(inFrame.streamId));
-                }
-            }
-            inFrame = null;
-        }
-        return LONG;
-    }
-
-    public SpdyContext getSpdyContext() {
-        return spdyContext;
-    }
-
-    public SpdyStream get(String host, String url) {
-        SpdyStream sch = new SpdyStream(this);
-        sch.getRequest().addHeader("host", host);
-        sch.getRequest().addHeader("url", url);
-
-        sch.send();
-
-        return sch;
-    }
-
-    /**
-     * Abstract compression support. When using spdy on intranet ( between load
-     * balancer and tomcat) there is no need for the compression overhead. There
-     * are also multiple possible implementations.
-     */
-    static interface CompressSupport {
-        public void compress(SpdyFrame frame, int start) throws IOException;
-
-        public void decompress(SpdyFrame frame, int start) throws IOException;
-    }
-}
diff --git a/java/org/apache/tomcat/spdy/SpdyContext.java b/java/org/apache/tomcat/spdy/SpdyContext.java
deleted file mode 100644
index 37c59d9..0000000
--- a/java/org/apache/tomcat/spdy/SpdyContext.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- *  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.spdy;
-
-import java.io.IOException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-/**
- * Will implement polling/reuse of heavy objects, allow additional
- * configuration.
- *
- * The abstract methods allow integration with different libraries (
- * compression, request handling )
- *
- * In 'external' mode it must be used with APR library and compression.
- *
- * In 'intranet' mode - it is supposed to be used behind a load balancer that
- * handles SSL and compression. Test with: --user-data-dir=/tmp/test
- * --use-spdy=no-compress,no-ssl
- */
-public final class SpdyContext {
-
-    public static final byte[] SPDY_NPN;
-
-    public static final byte[] SPDY_NPN_OUT;
-    static {
-        SPDY_NPN = "spdy/2".getBytes();
-        SPDY_NPN_OUT = new byte[SPDY_NPN.length + 2];
-        System.arraycopy(SPDY_NPN, 0, SPDY_NPN_OUT, 1, SPDY_NPN.length);
-        SPDY_NPN_OUT[0] = (byte) SPDY_NPN.length;
-    }
-
-    private Executor executor;
-
-    private int defaultFrameSize = 8192;
-
-    public static final boolean debug = false;
-
-    protected boolean tls = true;
-    protected boolean compression = true;
-
-    private NetSupport netSupport;
-
-
-    public abstract static class NetSupport {
-        protected SpdyContext ctx;
-
-        public void setSpdyContext(SpdyContext ctx) {
-            this.ctx = ctx;
-        }
-
-        public abstract SpdyConnection getConnection(String host, int port)
-                throws IOException;
-
-        public abstract boolean isSpdy(Object socketW);
-
-        public abstract void onAccept(Object socket);
-
-        public abstract void listen(int port, String cert, String key)
-                throws IOException;
-
-        public abstract void stop() throws IOException;
-    }
-
-    public SpdyContext() {
-    }
-
-    public void setTlsCompression(boolean tls, boolean compress) {
-        this.tls = tls;
-        this.compression = compress;
-    }
-
-    /**
-     * Get a frame - frames are heavy buffers, may be reused.
-     */
-    public SpdyFrame getFrame() {
-        return new SpdyFrame(defaultFrameSize);
-    }
-
-    /**
-     * Set the max frame size.
-     *
-     * Larger data packets will be split in multiple frames.
-     *
-     * ( the code is currently accepting larger control frames - it's not
-     * clear if we should just reject them, many servers limit header size -
-     * the http connector also has a 8k limit - getMaxHttpHeaderSize )
-     */
-    public void setFrameSize(int frameSize) {
-        defaultFrameSize = frameSize;
-    }
-
-    /**
-     * Override for server side to return a custom stream.
-     */
-    public SpdyStream getStream(SpdyConnection framer) {
-        SpdyStream spdyStream = new SpdyStream(framer);
-        return spdyStream;
-    }
-
-    public void setExecutor(Executor executor) {
-        this.executor = executor;
-    }
-
-    public void setNetSupport(NetSupport netSupport) {
-        this.netSupport = netSupport;
-        netSupport.setSpdyContext(this);
-    }
-
-    public NetSupport getNetSupport() {
-        if (netSupport == null) {
-            try {
-                Class<?> c0 = Class.forName("org.apache.tomcat.spdy.NetSupportOpenSSL");
-                netSupport = (NetSupport) c0.newInstance();
-                netSupport.setSpdyContext(this);
-                return netSupport;
-            } catch (Throwable t) {
-                // ignore, openssl not supported
-            }
-            try {
-                Class<?> c1 = Class.forName("org.apache.tomcat.spdy.NetSupportJava7");
-                netSupport = (NetSupport) c1.newInstance();
-                netSupport.setSpdyContext(this);
-                return netSupport;
-            } catch (Throwable t) {
-                // ignore, npn not supported
-            }
-            // non-ssl mode must be set explicitly
-            throw new RuntimeException("SSL NextProtoclNegotiation no supported.");
-        }
-
-        return netSupport;
-    }
-
-
-    /**
-     * SPDY is a multiplexed protocol - the SpdyProcessors will be executed on
-     * this executor.
-     *
-     * If the context returns null - we'll assume the SpdyProcessors are fully
-     * non blocking, and will execute them in the spdy thread.
-     */
-    public Executor getExecutor() {
-        if (executor == null) {
-            executor = Executors.newCachedThreadPool();
-        }
-        return executor;
-    }
-
-    SpdyHandler handler;
-
-    public SpdyHandler getHandler() {
-        return handler;
-    }
-
-    public void setHandler(SpdyHandler handler) {
-        this.handler = handler;
-    }
-
-    public static interface SpdyHandler {
-        public void onStream(SpdyConnection spdyCon, SpdyStream ch) throws IOException;
-
-    }
-
-    /**
-     * A handler implementing this interface will be called in the 'io' thread - the
-     * thread reading the multiplexed stream, and in the case of non-blocking
-     * transports also handling polling the socket.
-     *
-     */
-    public static interface NonBlockingSpdyHandler extends SpdyHandler {
-    }
-
-
-    /**
-     * Client mode: return a connection for host/port.
-     * @throws IOException
-     */
-    public SpdyConnection getConnection(String host, int port) throws IOException {
-        return netSupport.getConnection(host, port);
-    }
-
-    public final void listen(final int port, String cert, String key) throws IOException {
-        netSupport.listen(port, cert, key);
-    }
-
-    /**
-     * Close all pending connections and free resources.
-     */
-    public final void stop() throws IOException {
-        netSupport.stop();
-    }
-
-    public void onStream(SpdyConnection spdyConnection, SpdyStream ch) throws IOException {
-        if (handler instanceof NonBlockingSpdyHandler) {
-            handler.onStream(spdyConnection, ch);
-        } else {
-            getExecutor().execute(ch);
-        }
-    }
-}
diff --git a/java/org/apache/tomcat/spdy/SpdyFrame.java b/java/org/apache/tomcat/spdy/SpdyFrame.java
deleted file mode 100644
index 35378c2..0000000
--- a/java/org/apache/tomcat/spdy/SpdyFrame.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- *  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.spdy;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-
-public class SpdyFrame {
-    public static final byte[] STATUS = "status".getBytes();
-
-    public static final byte[] VERSION = "version".getBytes();
-
-    public static final byte[] HTTP11 = "HTTP/1.1".getBytes();
-
-    public static final byte[] OK200 = "200 OK".getBytes();
-
-
-    // This is a bit more complicated, to avoid multiple reads/writes.
-    // We'll read as much as possible - possible past frame end. This may
-    // cost an extra copy - or even more complexity for dealing with slices
-    // if we want to save the copy.
-    public byte[] data;
-
-    public int off = 8; // used when reading - current offset
-
-    int endReadData; // how much has been read ( may be more or less than a frame )
-
-    // On write it is incremented.
-
-    /**
-     *  end of data in the buffer.
-     */
-    public int endData;
-
-    // Processed data from the frame
-    boolean c; // for control
-
-    int version;
-
-    int flags;
-
-    public int type;
-
-    // For control frames
-    public int streamId;
-
-    public int pri;
-
-    public int associated;
-
-    public int nvCount;
-
-    public SpdyStream stream;
-
-    public SpdyFrame(int size) {
-        data = new byte[size];
-    }
-
-    public int getDataSize() {
-        return endData - 8;
-    }
-
-    public void recyle() {
-        type = 0;
-        c = false;
-        endReadData = 0;
-        off = 8;
-        streamId = 0;
-        nvCount = 0;
-        endData = 0;
-    }
-
-    @Override
-    public String toString() {
-        if (c) {
-            if (type == 6) {
-                return "C PING " + read32(data, 0);
-            }
-            return "C" + " S=" + streamId + (flags != 0 ? " F=" + flags : "")
-                    + (version != 2 ? "  v" + version : "") + " t=" + type
-                    + " L=" + endData + "/" + off;
-        } else {
-            return "D" + " S=" + streamId + (flags != 0 ? " F=" + flags : "")
-                    + " L=" + endData + "/" + off;
-        }
-    }
-
-    public int serializeHead() {
-        if (c) {
-            data[0] = (byte) 0x80;
-            data[1] = 2;
-            data[2] = 0;
-            data[3] = (byte) type;
-            data[4] = (byte) flags;
-            append24(data, 5, endData - 8);
-            if (type == SpdyConnection.TYPE_SYN_STREAM) {
-                // nvcount is added before
-                append32(data, 8, streamId);
-                append32(data, 12, associated);
-                data[16] = 0; // TODO: priority
-                data[17] = 0;
-                return 18;
-            } else if (type == SpdyConnection.TYPE_SYN_REPLY) {
-                append32(data, 8, streamId);
-                data[12] = 0;
-                data[13] = 0;
-                return 14;
-            } else if (type == SpdyConnection.TYPE_HEADERS) {
-                append32(data, 8, streamId);
-                data[12] = 0;
-                data[13] = 0;
-                return 14;
-            }
-        } else {
-            append32(data, 0, streamId);
-            data[4] = (byte) flags;
-            append24(data, 5, endData - 8);
-        }
-        return 8;
-    }
-
-    public boolean parse() {
-        endData = 0;
-        streamId = 0;
-        nvCount = 0;
-
-        int b0 = data[0] & 0xFF;
-        if (b0 < 128) {
-            // data frame
-            c = false;
-            streamId = read32(data, 0);
-            version = 2;
-        } else {
-            c = true;
-            b0 -= 128;
-            version = ((b0 << 8) | data[1] & 0xFF);
-            if (version > 2) {
-                return false;
-            }
-            b0 = data[2] & 0xFF;
-            type = ((b0 << 8) | (data[3] & 0xFF));
-        }
-
-        flags = data[4] & 0xFF;
-        for (int i = 5; i < 8; i++) {
-            b0 = data[i] & 0xFF;
-            endData = endData << 8 | b0;
-        }
-
-        // size will represent the end of the data ( header is held in same
-        // buffer)
-        endData += 8;
-
-        return true;
-    }
-
-    public boolean isHalfClose() {
-        return (flags & SpdyConnection.FLAG_HALF_CLOSE) != 0;
-    }
-
-    public void halfClose() {
-        flags = SpdyConnection.FLAG_HALF_CLOSE;
-    }
-
-    public boolean closed() {
-        return (flags & SpdyConnection.FLAG_HALF_CLOSE) != 0;
-    }
-
-    static void append24(byte[] buff, int off, int v) {
-        buff[off++] = (byte) ((v & 0xFF0000) >> 16);
-        buff[off++] = (byte) ((v & 0xFF00) >> 8);
-        buff[off++] = (byte) ((v & 0xFF));
-    }
-
-    static void append32(byte[] buff, int off, int v) {
-        buff[off++] = (byte) ((v & 0xFF000000) >> 24);
-        buff[off++] = (byte) ((v & 0xFF0000) >> 16);
-        buff[off++] = (byte) ((v & 0xFF00) >> 8);
-        buff[off++] = (byte) ((v & 0xFF));
-    }
-
-    public void append32(int v) {
-        makeSpace(4);
-        data[off++] = (byte) ((v & 0xFF000000) >> 24);
-        data[off++] = (byte) ((v & 0xFF0000) >> 16);
-        data[off++] = (byte) ((v & 0xFF00) >> 8);
-        data[off++] = (byte) ((v & 0xFF));
-    }
-
-    public void append16(int v) {
-        makeSpace(2);
-        data[off++] = (byte) ((v & 0xFF00) >> 8);
-        data[off++] = (byte) ((v & 0xFF));
-    }
-
-    void fixNV(int nvPos) {
-        data[nvPos++] = (byte) ((nvCount & 0xFF00) >> 8);
-        data[nvPos] = (byte) ((nvCount & 0xFF));
-    }
-
-    public void append(byte[] buf, int soff, int len) {
-        makeSpace(len + off);
-        System.arraycopy(buf, soff, data, off, len);
-        off += len;
-    }
-
-    public void headerValue(byte[] buf, int soff, int len) {
-        makeSpace(len + 4);
-        append16(len);
-        System.arraycopy(buf, soff, data, off, len);
-        off += len;
-    }
-
-    public void headerName(byte[] buf, int soff, int len) {
-        // if it's the first header, leave space for extra params and NV count.
-        // they'll be filled in by send.
-        if (off == 8) {
-            if (type == SpdyConnection.TYPE_SYN_REPLY) {
-                off = 16;
-            } else if (type == SpdyConnection.TYPE_SYN_STREAM) {
-                off = 20;
-            } else if (type != SpdyConnection.TYPE_HEADERS) {
-                off = 16;
-            } else {
-                throw new RuntimeException("Wrong frame type");
-            }
-        }
-        nvCount++;
-        headerValue(buf, soff, len);
-    }
-
-    public void addHeader(String name, String value) {
-        byte[] nameB = name.getBytes();
-        headerName(nameB, 0, nameB.length);
-        nameB = value.getBytes();
-        headerValue(nameB, 0, nameB.length);
-    }
-
-    public void addHeader(byte[] nameB, String value) {
-        headerName(nameB, 0, nameB.length);
-        nameB = value.getBytes();
-        headerValue(nameB, 0, nameB.length);
-    }
-
-    public void addHeader(byte[] nameB, byte[] valueB) {
-        headerName(nameB, 0, nameB.length);
-        headerValue(valueB, 0, valueB.length);
-    }
-
-    public void getHeaders(Map<String, String> resHeaders) {
-        for (int i = 0; i < nvCount; i++) {
-            int len = read16();
-            String n = new String(data, off, len, StandardCharsets.UTF_8);
-            advance(len);
-            len = read16();
-            String v = new String(data, off, len, StandardCharsets.UTF_8);
-            advance(len);
-            resHeaders.put(n, v);
-        }
-    }
-
-
-    // TODO: instead of that, use byte[][]
-    void makeSpace(int len) {
-        if (len < 256) {
-            len = 256;
-        }
-        if (data == null) {
-            data = new byte[len];
-            return;
-        }
-        int newEnd = off + len;
-
-        if (data.length < newEnd) {
-            byte[] tmp = new byte[newEnd];
-            System.err.println("cp " + off + " " + data.length + " " + len
-                    + " " + tmp.length);
-            System.arraycopy(data, 0, tmp, 0, off);
-            data = tmp;
-        }
-
-    }
-
-    public int read16() {
-        int res = data[off++] & 0xFF;
-        return res << 8 | (data[off++] & 0xFF);
-    }
-
-    int readInt() {
-        int res = 0;
-        for (int i = 0; i < 4; i++) {
-            int b0 = data[off++] & 0xFF;
-            res = res << 8 | b0;
-        }
-        return res;
-    }
-
-    int read24() {
-        int res = 0;
-        for (int i = 0; i < 3; i++) {
-            int b0 = data[off++] & 0xFF;
-            res = res << 8 | b0;
-        }
-        return res;
-    }
-
-    int read32(byte[] data, int off) {
-        int res = 0;
-        for (int i = 0; i < 4; i++) {
-            int b0 = data[off++] & 0xFF;
-            res = res << 8 | b0;
-        }
-        return res;
-    }
-
-    int read32() {
-        int res = 0;
-        for (int i = 0; i < 4; i++) {
-            int b0 = data[off++] & 0xFF;
-            res = res << 8 | b0;
-        }
-        return res;
-    }
-
-    public int readByte() {
-        return data[off++] & 0xFF;
-    }
-
-    public int remaining() {
-        return endData - off;
-    }
-
-    public void advance(int cnt) {
-        off += cnt;
-    }
-
-    public boolean isData() {
-        return !c;
-    }
-}
diff --git a/java/org/apache/tomcat/spdy/SpdyStream.java b/java/org/apache/tomcat/spdy/SpdyStream.java
deleted file mode 100644
index 60d643f..0000000
--- a/java/org/apache/tomcat/spdy/SpdyStream.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- *  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.spdy;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * One SPDY stream.
- *
- * Created by SpdyContext.getProcessor(framer).
- *
- * The methods are called in a IO thread when the framer received a frame for
- * this stream.
- *
- * They should not block.
- *
- * The frame must be either consumed or popInFrame must be called, after the
- * call is done the frame will be reused.
- */
-public class SpdyStream implements Runnable {
-    private final SpdyConnection spdy;
-
-    public SpdyFrame reqFrame;
-
-    public SpdyFrame resFrame;
-
-    /**
-     * For blocking support.
-     */
-    private final BlockingQueue<SpdyFrame> inData = new LinkedBlockingQueue<>();
-
-    protected boolean finSent;
-
-    protected boolean finRcvd;
-
-    /**
-     *  Dummy data frame to insert on reset / go away
-     */
-    private static final SpdyFrame END_FRAME;
-
-    static {
-        END_FRAME = new SpdyFrame(16);
-        END_FRAME.endData = 0;
-        END_FRAME.off = 0;
-        END_FRAME.c = false;
-        END_FRAME.flags =SpdyConnection.FLAG_HALF_CLOSE;
-    }
-
-    public SpdyStream(SpdyConnection spdy) {
-        this.spdy = spdy;
-    }
-
-    public void dump(PrintWriter out) {
-        if (reqFrame != null) {
-            out.println("Req: " + reqFrame);
-        }
-        if (resFrame != null) {
-            out.println("Res: " + resFrame);
-        }
-        out.println("In: " + inData.size() + (finRcvd ? " FIN":""));
-    }
-
-    /**
-     * Non-blocking, called when a data frame is received.
-     */
-    public void onDataFrame(SpdyFrame inFrame) {
-        synchronized(this) {
-            inData.add(inFrame);
-            if (inFrame.closed()) {
-                finRcvd = true;
-            }
-        }
-    }
-
-    /**
-     * Non-blocking - handles a syn stream package. The processor must consume
-     * frame.data or set it to null.
-     *
-     * The base method is for client implementation - servers need to override
-     * and process the frame as a request.
-     */
-    public void onCtlFrame(SpdyFrame frame) {
-        // TODO: handle RST
-        if (frame.type == SpdyConnection.TYPE_SYN_STREAM) {
-            reqFrame = frame;
-        } else if (frame.type == SpdyConnection.TYPE_SYN_REPLY) {
-            resFrame = frame;
-        }
-        synchronized (this) {
-            inData.add(frame);
-            if (frame.isHalfClose()) {
-                finRcvd = true;
-            }
-        }
-    }
-
-    /**
-     * Called on GOAWAY or reset.
-     */
-    public void onReset() {
-        finRcvd = true;
-        finSent = true;
-
-        // To unblock
-        inData.add(END_FRAME);
-    }
-
-    /**
-     * True if the channel both received and sent FIN frames.
-     *
-     * This is tracked by the processor, to avoid extra storage in framer.
-     */
-    public boolean isFinished() {
-        return finSent && finRcvd;
-    }
-
-    /**
-     * Waits and return the next data frame, null on timeout.
-     */
-    public SpdyFrame getDataFrame(long to) throws IOException {
-        while (true) {
-            SpdyFrame res = getFrame(to);
-            if (res == null || res.isData()) {
-                return res;
-            }
-            if (res.type == SpdyConnection.TYPE_RST_STREAM) {
-                throw new IOException("Reset");
-            }
-        }
-    }
-
-    /**
-     * Waits and return the next frame.
-     *
-     * First frame will be the control frame
-     */
-    public SpdyFrame getFrame(long to) {
-        SpdyFrame in;
-        try {
-            synchronized (this) {
-                if (inData.size() == 0 && finRcvd) {
-                    return END_FRAME;
-                }
-            }
-            in = inData.poll(to, TimeUnit.MILLISECONDS);
-            return in;
-        } catch (InterruptedException e) {
-            return null;
-        }
-    }
-
-    public void getHeaders(Map<String, String> resHeaders) {
-        SpdyFrame f = resFrame;
-        int nvCount = f.nvCount;
-        for (int i = 0; i < nvCount; i++) {
-            int len = f.read16();
-            String n = new String(f.data, f.off, len, StandardCharsets.UTF_8);
-            f.advance(len);
-            len = f.read16();
-            String v = new String(f.data, f.off, len, StandardCharsets.UTF_8);
-            f.advance(len);
-            resHeaders.put(n, v);
-        }
-    }
-
-    public SpdyFrame getRequest() {
-        if (reqFrame == null) {
-            reqFrame = spdy.getFrame(SpdyConnection.TYPE_SYN_STREAM);
-        }
-        return reqFrame;
-    }
-
-    public SpdyFrame getResponse() {
-        if (resFrame == null) {
-            resFrame = spdy.getFrame(SpdyConnection.TYPE_SYN_REPLY);
-            resFrame.streamId = reqFrame.streamId;
-        }
-        return resFrame;
-    }
-
-    public synchronized void sendDataFrame(byte[] data, int start,
-            int length, boolean close) {
-
-        SpdyFrame oframe = spdy.getDataFrame();
-
-        // Options:
-        // 1. wrap the byte[] data, use a separate header[], wait frame sent
-        // -> 2 socket writes
-        // 2. copy the data to frame byte[] -> non-blocking queue
-        // 3. copy the data, blocking drain -> like 1, trade one copy to
-        // avoid
-        // 1 tcp packet. That's the current choice, seems closer to rest of
-        // tomcat
-
-        if (close)
-            oframe.halfClose();
-
-        oframe.append(data, start, length);
-        spdy.send(oframe, this);
-    }
-
-    public void send() {
-        send("http", "GET");
-    }
-
-    public void send(String host, String url, String scheme, String method) {
-        getRequest().addHeader("host", host);
-        getRequest().addHeader("url", url);
-
-        send(scheme, method);
-    }
-
-    public void send(String scheme, String method) {
-        getRequest();
-        if ("GET".equalsIgnoreCase(method)) {
-            // TODO: add the others
-            reqFrame.halfClose();
-        }
-        getRequest().addHeader("scheme", scheme);
-        getRequest().addHeader("method", method);
-        getRequest().addHeader("version", "HTTP/1.1");
-        if (reqFrame.isHalfClose()) {
-            finSent = true;
-        }
-        spdy.send(reqFrame, this);
-    }
-
-    @Override
-    public void run() {
-        try {
-            spdy.spdyContext.handler.onStream(spdy, this);
-        } catch (IOException e) {
-            e.printStackTrace();
-            // TODO: send rst, error processing the stream.
-        }
-    }
-
-
-    public InputStream getInputStream() {
-        return new SpdyInputStream();
-    }
-
-    private class SpdyInputStream extends InputStream {
-        private SpdyFrame current = null;
-        private long to = 10000; // TODO
-
-        private void fill() {
-            if (current == null || current.off == current.endData) {
-                current = getFrame(to);
-            }
-        }
-
-        @Override
-        public int read() throws IOException {
-            fill();
-            if (current == null) {
-                return -1;
-            }
-            return current.readByte();
-        }
-
-        @Override
-        public int read(byte b[], int off, int len) throws IOException {
-            fill();
-            if (current == null) {
-                return -1;
-            }
-            // don't wait for next frame
-            int rd = Math.min(len, current.endData - current.off);
-            System.arraycopy(current.data, current.off, b, off, rd);
-            current.off += rd;
-            return rd;
-        }
-
-        @Override
-        public int available() throws IOException {
-            return 0;
-        }
-        @Override
-        public void close() throws IOException {
-            // send RST if not closed
-        }
-
-
-
-    }
-}
diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java
index 37e0182..e298312 100644
--- a/java/org/apache/tomcat/util/digester/Digester.java
+++ b/java/org/apache/tomcat/util/digester/Digester.java
@@ -943,9 +943,6 @@ public class Digester extends DefaultHandler2 {
 
         // Recover the body text from the surrounding element
         bodyText = bodyTexts.pop();
-        if (debug) {
-            log.debug("  Popping body text '" + bodyText.toString() + "'");
-        }
 
         // Fire "end" events for all relevant rules in reverse order
         if (rules != null) {
@@ -1148,9 +1145,6 @@ public class Digester extends DefaultHandler2 {
 
         // Save the body text accumulated for our surrounding element
         bodyTexts.push(bodyText);
-        if (debug) {
-            log.debug("  Pushing body text '" + bodyText.toString() + "'");
-        }
         bodyText = new StringBuilder();
 
         // the actual element name is either in localName or qName, depending
diff --git a/java/org/apache/tomcat/util/net/Nio2Endpoint.java b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
index e3e2435..79d397c 100644
--- a/java/org/apache/tomcat/util/net/Nio2Endpoint.java
+++ b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
@@ -30,6 +30,7 @@ import java.nio.channels.ClosedChannelException;
 import java.nio.channels.CompletionHandler;
 import java.nio.channels.FileChannel;
 import java.nio.file.StandardOpenOption;
+import java.util.Locale;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.RejectedExecutionException;
@@ -319,7 +320,12 @@ public class Nio2Endpoint extends AbstractEndpoint<Nio2Channel> {
         KeyManager[] result = new KeyManager[managers.length];
         for (int i=0; i<result.length; i++) {
             if (managers[i] instanceof X509KeyManager && getKeyAlias()!=null) {
-                result[i] = new NioX509KeyManager((X509KeyManager)managers[i],getKeyAlias());
+                String keyAlias = getKeyAlias();
+                // JKS keystores always convert the alias name to lower case
+                if ("jks".equalsIgnoreCase(getKeystoreType())) {
+                    keyAlias = keyAlias.toLowerCase(Locale.ENGLISH);
+                }
+                result[i] = new NioX509KeyManager((X509KeyManager) managers[i], keyAlias);
             } else {
                 result[i] = managers[i];
             }
@@ -552,7 +558,6 @@ public class Nio2Endpoint extends AbstractEndpoint<Nio2Channel> {
         engine.setEnabledProtocols(enabledProtocols);
 
         configureUseServerCipherSuitesOrder(engine);
-        handler.onCreateSSLEngine(engine);
 
         return engine;
     }
@@ -809,7 +814,6 @@ public class Nio2Endpoint extends AbstractEndpoint<Nio2Channel> {
         public void release(SocketWrapper<Nio2Channel> socket);
         public void closeAll();
         public SSLImplementation getSslImplementation();
-        public void onCreateSSLEngine(SSLEngine engine);
     }
 
     /**
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index d9395ea..ab2ee91 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -33,6 +33,7 @@ import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.WritableByteChannel;
 import java.util.Iterator;
+import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -376,7 +377,12 @@ public class NioEndpoint extends AbstractEndpoint<NioChannel> {
         KeyManager[] result = new KeyManager[managers.length];
         for (int i=0; i<result.length; i++) {
             if (managers[i] instanceof X509KeyManager && getKeyAlias()!=null) {
-                result[i] = new NioX509KeyManager((X509KeyManager)managers[i],getKeyAlias());
+                String keyAlias = getKeyAlias();
+                // JKS keystores always convert the alias name to lower case
+                if ("jks".equalsIgnoreCase(getKeystoreType())) {
+                    keyAlias = keyAlias.toLowerCase(Locale.ENGLISH);
+                }
+                result[i] = new NioX509KeyManager((X509KeyManager) managers[i], keyAlias);
             } else {
                 result[i] = managers[i];
             }
@@ -580,7 +586,6 @@ public class NioEndpoint extends AbstractEndpoint<NioChannel> {
         engine.setEnabledProtocols(enabledProtocols);
 
         configureUseServerCipherSuitesOrder(engine);
-        handler.onCreateSSLEngine(engine);
 
         return engine;
     }
@@ -1433,7 +1438,6 @@ public class NioEndpoint extends AbstractEndpoint<NioChannel> {
         public void release(SocketWrapper<NioChannel> socket);
         public void release(SocketChannel socket);
         public SSLImplementation getSslImplementation();
-        public void onCreateSSLEngine(SSLEngine engine);
     }
 
 
diff --git a/java/org/apache/tomcat/util/net/SecureNio2Channel.java b/java/org/apache/tomcat/util/net/SecureNio2Channel.java
index ba16492..bbc18b0 100644
--- a/java/org/apache/tomcat/util/net/SecureNio2Channel.java
+++ b/java/org/apache/tomcat/util/net/SecureNio2Channel.java
@@ -477,26 +477,29 @@ public class SecureNio2Channel extends Nio2Channel  {
     }
 
     private class FutureRead implements Future<Integer> {
-        private ByteBuffer dst;
+        private final ByteBuffer dst;
+        private final Future<Integer> integer;
         public FutureRead(ByteBuffer dst) {
             this.dst = dst;
+            this.integer = sc.read(netInBuffer);
         }
         @Override
         public boolean cancel(boolean mayInterruptIfRunning) {
-            return false;
+            readPending = false;
+            return integer.cancel(mayInterruptIfRunning);
         }
         @Override
         public boolean isCancelled() {
-            return false;
+            return integer.isCancelled();
         }
         @Override
         public boolean isDone() {
-            return true;
+            return integer.isDone();
         }
         @Override
         public Integer get() throws InterruptedException, ExecutionException {
             try {
-                return unwrap(netInBuffer.position());
+                return unwrap(integer.get().intValue());
             } finally {
                 readPending = false;
             }
@@ -506,17 +509,17 @@ public class SecureNio2Channel extends Nio2Channel  {
                 throws InterruptedException, ExecutionException,
                 TimeoutException {
             try {
-                return unwrap(netInBuffer.position());
+                return unwrap(integer.get(timeout, unit).intValue());
             } finally {
                 readPending = false;
             }
         }
-        protected Integer unwrap(int netread) throws ExecutionException {
+        private Integer unwrap(int nRead) throws ExecutionException {
             //are we in the middle of closing or closed?
             if (closing || closed)
                 return Integer.valueOf(-1);
             //did we reach EOF? if so send EOF up one layer.
-            if (netread == -1)
+            if (nRead < 0)
                 return Integer.valueOf(-1);
             //the data read
             int read = 0;
@@ -533,16 +536,18 @@ public class SecureNio2Channel extends Nio2Channel  {
                 }
                 //compact the buffer
                 netInBuffer.compact();
-                if (unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW) {
+                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)
+                    if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                         tasks();
+                    }
                     //if we need more network data, then bail out for now.
-                    if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW)
+                    if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
                         break;
-                } else if (unwrap.getStatus()==Status.BUFFER_OVERFLOW && read > 0) {
+                    }
+                } else if (unwrap.getStatus() == Status.BUFFER_OVERFLOW && read > 0) {
                     //buffer overflow can happen, if we have read data, then
                     //empty out the dst buffer before we do another read
                     break;
@@ -557,46 +562,6 @@ public class SecureNio2Channel extends Nio2Channel  {
         }
     }
 
-    private class FutureNetRead extends FutureRead {
-        private Future<Integer> integer;
-        protected FutureNetRead(ByteBuffer dst) {
-            super(dst);
-            this.integer = sc.read(netInBuffer);
-        }
-        @Override
-        public boolean cancel(boolean mayInterruptIfRunning) {
-            return integer.cancel(mayInterruptIfRunning);
-        }
-        @Override
-        public boolean isCancelled() {
-            return integer.isCancelled();
-        }
-        @Override
-        public boolean isDone() {
-            return integer.isDone();
-        }
-        @Override
-        public Integer get() throws InterruptedException, ExecutionException {
-            try {
-                int netread = integer.get().intValue();
-                return unwrap(netread);
-            } finally {
-                readPending = false;
-            }
-        }
-        @Override
-        public Integer get(long timeout, TimeUnit unit)
-                throws InterruptedException, ExecutionException,
-                TimeoutException {
-            try {
-                int netread = integer.get(timeout, unit).intValue();
-                return unwrap(netread);
-            } finally {
-                readPending = false;
-            }
-        }
-    }
-
     /**
      * Reads a sequence of bytes from this channel into the given buffer.
      *
@@ -606,19 +571,15 @@ public class SecureNio2Channel extends Nio2Channel  {
      */
     @Override
     public Future<Integer> read(ByteBuffer dst) {
+        if (!handshakeComplete) {
+            throw new IllegalStateException(sm.getString("channel.nio.ssl.incompleteHandshake"));
+        }
         if (readPending) {
             throw new ReadPendingException();
         } else {
             readPending = true;
         }
-        //did we finish our handshake?
-        if (!handshakeComplete)
-            throw new IllegalStateException(sm.getString("channel.nio.ssl.incompleteHandshake"));
-        if (netInBuffer.position() > 0) {
-            return new FutureRead(dst);
-        } else {
-            return new FutureNetRead(dst);
-        }
+        return new FutureRead(dst);
     }
 
     private class FutureWrite implements Future<Integer> {
@@ -637,6 +598,7 @@ public class SecureNio2Channel extends Nio2Channel  {
         }
         @Override
         public boolean cancel(boolean mayInterruptIfRunning) {
+            writePending = false;
             return integer.cancel(mayInterruptIfRunning);
         }
         @Override
@@ -657,6 +619,9 @@ public class SecureNio2Channel extends Nio2Channel  {
             if (written == 0) {
                 wrap();
                 return get();
+            } else if (netOutBuffer.hasRemaining()) {
+                integer = sc.write(netOutBuffer);
+                return get();
             } else {
                 writePending = false;
                 return Integer.valueOf(written);
@@ -674,6 +639,9 @@ public class SecureNio2Channel extends Nio2Channel  {
             if (written == 0) {
                 wrap();
                 return get(timeout, unit);
+            } else if (netOutBuffer.hasRemaining()) {
+                integer = sc.write(netOutBuffer);
+                return get(timeout, unit);
             } else {
                 writePending = false;
                 return Integer.valueOf(written);
@@ -747,8 +715,9 @@ public class SecureNio2Channel extends Nio2Channel  {
                             if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
                                 tasks();
                             //if we need more network data, then bail out for now.
-                            if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW)
+                            if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
                                 break;
+                            }
                         } else if (unwrap.getStatus() == Status.BUFFER_OVERFLOW && read > 0) {
                             //buffer overflow can happen, if we have read data, then
                             //empty out the dst buffer before we do another read
@@ -784,21 +753,15 @@ public class SecureNio2Channel extends Nio2Channel  {
             handler.completed(Integer.valueOf(-1), attachment);
             return;
         }
-        if (readPending) {
-            throw new ReadPendingException();
-        } else {
-            readPending = true;
-        }
         if (!handshakeComplete) {
             throw new IllegalStateException(sm.getString("channel.nio.ssl.incompleteHandshake"));
         }
-
-        ReadCompletionHandler<A> readCompletionHandler = new ReadCompletionHandler<>(dst, handler);
-        if (netInBuffer.position() > 0 ) {
-            readCompletionHandler.completed(Integer.valueOf(netInBuffer.position()), attachment);
+        if (readPending) {
+            throw new ReadPendingException();
         } else {
-            sc.read(netInBuffer, timeout, unit, attachment, readCompletionHandler);
+            readPending = true;
         }
+        sc.read(netInBuffer, timeout, unit, attachment, new ReadCompletionHandler<>(dst, handler));
     }
 
     @Override
diff --git a/java/org/apache/tomcat/util/scan/JarFactory.java b/java/org/apache/tomcat/util/scan/JarFactory.java
index ab6fda3..09ccc94 100644
--- a/java/org/apache/tomcat/util/scan/JarFactory.java
+++ b/java/org/apache/tomcat/util/scan/JarFactory.java
@@ -53,7 +53,7 @@ public class JarFactory {
             // Assume this is pointing to a JAR file within a WAR. Java doesn't
             // support jar:jar:file:... so switch to Tomcat's war:file:...
             baseExternal = baseExternal.replaceFirst("^jar:", "war:");
-            baseExternal = baseExternal.replaceFirst("!/", "^/");
+            baseExternal = baseExternal.replaceFirst("!/", "*/");
         }
 
         return new URL("jar:" + baseExternal + "!/" + entryName);
diff --git a/java/org/apache/tomcat/websocket/LocalStrings.properties b/java/org/apache/tomcat/websocket/LocalStrings.properties
index 00c536a..2e4948b 100644
--- a/java/org/apache/tomcat/websocket/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/LocalStrings.properties
@@ -70,7 +70,7 @@ wsRemoteEndpoint.closed=Message will not be sent because the WebSocket session h
 wsRemoteEndpoint.closedDuringMessage=The remainder of the message will not be sent because the WebSocket session has been closed
 wsRemoteEndpoint.closedOutputStream=This method may not be called as the OutputStream has been closed
 wsRemoteEndpoint.closedWriter=This method may not be called as the Writer has been closed
-wsRemoteEndpoint.changeType=When sending a fragmented message, all fragments bust be of the same type
+wsRemoteEndpoint.changeType=When sending a fragmented message, all fragments must be of the same type
 wsRemoteEndpoint.concurrentMessageSend=Messages may not be sent concurrently even when using the asynchronous send messages. The client must wait for the previous message to complete before sending the next.
 wsRemoteEndpoint.flushOnCloseFailed=Batched messages still enabled after session has been closed. Unable to flush remaining batched message.
 wsRemoteEndpoint.invalidEncoder=The specified encoder of type [{0}] could not be instantiated
diff --git a/java/org/apache/tomcat/websocket/PerMessageDeflate.java b/java/org/apache/tomcat/websocket/PerMessageDeflate.java
index 6b3ea59..24492b1 100644
--- a/java/org/apache/tomcat/websocket/PerMessageDeflate.java
+++ b/java/org/apache/tomcat/websocket/PerMessageDeflate.java
@@ -316,13 +316,16 @@ public class PerMessageDeflate implements Transformation {
         List<MessagePart> allCompressedParts = new ArrayList<>();
 
         for (MessagePart uncompressedPart : uncompressedParts) {
-            if (Util.isControl(uncompressedPart.getOpCode())) {
+            byte opCode = uncompressedPart.getOpCode();
+            if (Util.isControl(opCode)) {
                 // Control messages can appear in the middle of other messages
                 // and must not be compressed. Pass it straight through
                 allCompressedParts.add(uncompressedPart);
             } else {
                 List<MessagePart> compressedParts = new ArrayList<>();
                 ByteBuffer uncompressedPayload = uncompressedPart.getPayload();
+                SendHandler uncompressedIntermediateHandler =
+                        uncompressedPart.getIntermediateHandler();
 
                 deflater.setInput(uncompressedPayload.array(),
                         uncompressedPayload.arrayOffset() + uncompressedPayload.position(),
@@ -339,8 +342,7 @@ public class PerMessageDeflate implements Transformation {
                             compressedPayload.remaining(), flush);
                     compressedPayload.position(compressedPayload.position() + written);
 
-                    if (!uncompressedPart.isFin() && compressedPayload.hasRemaining() &&
-                            deflater.needsInput()) {
+                    if (!uncompressedPart.isFin() && compressedPayload.hasRemaining() && deflater.needsInput()) {
                         // This message part has been fully processed by the
                         // deflater. Fire the send handler for this message part
                         // and move on to the next message part.
@@ -364,20 +366,23 @@ public class PerMessageDeflate implements Transformation {
                     if (fin && !full && needsInput) {
                         // End of compressed message. Drop EOM bytes and output.
                         compressedPayload.limit(compressedPayload.limit() - EOM_BYTES.length);
-                        compressedPart = createNewCompressedMessagePart(
-                                uncompressedPart, true, compressedPayload);
+                        compressedPart = new MessagePart(true, getRsv(uncompressedPart),
+                                opCode, compressedPayload, uncompressedIntermediateHandler,
+                                uncompressedIntermediateHandler);
                         deflateRequired = false;
                         startNewMessage();
                     } else if (full && !needsInput) {
                         // Write buffer full and input message not fully read.
                         // Output and start new compressed part.
-                        compressedPart = createNewCompressedMessagePart(
-                                uncompressedPart, false, compressedPayload);
+                        compressedPart = new MessagePart(false, getRsv(uncompressedPart),
+                                opCode, compressedPayload, uncompressedIntermediateHandler,
+                                uncompressedIntermediateHandler);
                     } else if (!fin && full && needsInput) {
                         // Write buffer full and input message not fully read.
                         // Output and get more data.
-                        compressedPart = createNewCompressedMessagePart(
-                                uncompressedPart, false, compressedPayload);
+                        compressedPart = new MessagePart(false, getRsv(uncompressedPart),
+                                opCode, compressedPayload, uncompressedIntermediateHandler,
+                                uncompressedIntermediateHandler);
                         deflateRequired = false;
                     } else if (fin && full && needsInput) {
                         // Write buffer full. Input fully read. Deflater may be
@@ -387,22 +392,22 @@ public class PerMessageDeflate implements Transformation {
                         // - in middle of EOM bytes
                         // - about to write EOM bytes
                         // - more data to write
-                        int eomBufferWritten = deflater.deflate(
-                                EOM_BUFFER, 0, EOM_BUFFER.length, Deflater.SYNC_FLUSH);
+                        int eomBufferWritten = deflater.deflate(EOM_BUFFER, 0, EOM_BUFFER.length, Deflater.SYNC_FLUSH);
                         if (eomBufferWritten < EOM_BUFFER.length) {
                             // EOM has just been completed
-                            compressedPayload.limit(compressedPayload.limit() -
-                                    EOM_BYTES.length + eomBufferWritten);
-                            compressedPart = createNewCompressedMessagePart(
-                                    uncompressedPart, true, compressedPayload);
+                            compressedPayload.limit(compressedPayload.limit() - EOM_BYTES.length + eomBufferWritten);
+                            compressedPart = new MessagePart(true,
+                                    getRsv(uncompressedPart), opCode, compressedPayload,
+                                    uncompressedIntermediateHandler, uncompressedIntermediateHandler);
                             deflateRequired = false;
                             startNewMessage();
                         } else {
                             // More data to write
                             // Copy bytes to new write buffer
                             writeBuffer.put(EOM_BUFFER, 0, eomBufferWritten);
-                            compressedPart = createNewCompressedMessagePart(
-                                    uncompressedPart, false, compressedPayload);
+                            compressedPart = new MessagePart(false,
+                                    getRsv(uncompressedPart), opCode, compressedPayload,
+                                    uncompressedIntermediateHandler, uncompressedIntermediateHandler);
                         }
                     } else {
                         throw new IllegalStateException("Should never happen");
@@ -439,19 +444,12 @@ public class PerMessageDeflate implements Transformation {
     }
 
 
-    private MessagePart createNewCompressedMessagePart(MessagePart uncompressedMessagePart,
-            boolean fin, ByteBuffer compressedPayload) {
-        int rsv = uncompressedMessagePart.getRsv();
-        byte opCode = uncompressedMessagePart.getOpCode();
+    private int getRsv(MessagePart uncompressedMessagePart) {
+        int result = uncompressedMessagePart.getRsv();
         if (!firstCompressedFrameWritten) {
-            rsv += RSV_BITMASK;
+            result += RSV_BITMASK;
             firstCompressedFrameWritten = true;
-        } else {
-            // This must be a continuation frame
-            opCode = 0;
         }
-        return new MessagePart(fin, rsv, opCode, compressedPayload,
-                uncompressedMessagePart.getIntermediateHandler(),
-                uncompressedMessagePart.getIntermediateHandler());
+        return result;
     }
 }
diff --git a/java/org/apache/tomcat/websocket/Util.java b/java/org/apache/tomcat/websocket/Util.java
index 2090f19..05d5d3d 100644
--- a/java/org/apache/tomcat/websocket/Util.java
+++ b/java/org/apache/tomcat/websocket/Util.java
@@ -208,6 +208,10 @@ public class Util {
         @SuppressWarnings("unchecked")
         Class<? extends T> superClazz =
                 (Class<? extends T>) clazz.getSuperclass();
+        if (superClazz == null) {
+            // Finished looking up the class hierarchy without finding anything
+            return null;
+        }
 
         TypeResult superClassTypeResult = getGenericType(type, superClazz);
         int dimension = superClassTypeResult.getDimension();
diff --git a/java/org/apache/tomcat/websocket/WsFrameClient.java b/java/org/apache/tomcat/websocket/WsFrameClient.java
index 004229d..094d1ba 100644
--- a/java/org/apache/tomcat/websocket/WsFrameClient.java
+++ b/java/org/apache/tomcat/websocket/WsFrameClient.java
@@ -16,6 +16,7 @@
  */
 package org.apache.tomcat.websocket;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.CompletionHandler;
@@ -109,6 +110,16 @@ public class WsFrameClient extends WsFrameBase {
 
         @Override
         public void completed(Integer result, Void attachment) {
+            if (result.intValue() == -1) {
+                // BZ 57762. A dropped connection will get reported as EOF
+                // rather than as an error so handle it here.
+                if (isOpen()) {
+                    // No close frame was received
+                    close(new EOFException());
+                }
+                // No data to process
+                return;
+            }
             response.flip();
             try {
                 processSocketRead();
diff --git a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
index a63caad..f8044ca 100644
--- a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
+++ b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
@@ -106,6 +106,11 @@ public class WsWebSocketContainer
     private static final Random random = new Random();
     private static final byte[] crlf = new byte[] {13, 10};
 
+    private static final byte[] GET_BYTES = "GET ".getBytes(StandardCharsets.ISO_8859_1);
+    private static final byte[] ROOT_URI_BYTES = "/".getBytes(StandardCharsets.ISO_8859_1);
+    private static final byte[] HTTP_VERSION_BYTES =
+            " HTTP/1.1\r\n".getBytes(StandardCharsets.ISO_8859_1);
+
     private volatile AsynchronousChannelGroup asynchronousChannelGroup = null;
     private final Object asynchronousChannelGroupLock = new Object();
 
@@ -531,14 +536,16 @@ public class WsWebSocketContainer
         ByteBuffer result = ByteBuffer.allocate(4 * 1024);
 
         // Request line
-        result.put("GET ".getBytes(StandardCharsets.ISO_8859_1));
-        result.put(uri.getRawPath().getBytes(StandardCharsets.ISO_8859_1));
+        result.put(GET_BYTES);
+        byte[] path = (null == uri.getPath() || "".equals(uri.getPath()))
+                ? ROOT_URI_BYTES : uri.getRawPath().getBytes(StandardCharsets.ISO_8859_1);
+        result.put(path);
         String query = uri.getRawQuery();
         if (query != null) {
             result.put((byte) '?');
             result.put(query.getBytes(StandardCharsets.ISO_8859_1));
         }
-        result.put(" HTTP/1.1\r\n".getBytes(StandardCharsets.ISO_8859_1));
+        result.put(HTTP_VERSION_BYTES);
 
         // Headers
         Iterator<Entry<String,List<String>>> iter =
diff --git a/java/org/apache/tomcat/websocket/server/WsRemoteEndpointImplServer.java b/java/org/apache/tomcat/websocket/server/WsRemoteEndpointImplServer.java
index f62f2d4..cb9b94d 100644
--- a/java/org/apache/tomcat/websocket/server/WsRemoteEndpointImplServer.java
+++ b/java/org/apache/tomcat/websocket/server/WsRemoteEndpointImplServer.java
@@ -43,8 +43,7 @@ public class WsRemoteEndpointImplServer extends WsRemoteEndpointImplBase {
 
     private static final StringManager sm =
             StringManager.getManager(Constants.PACKAGE_NAME);
-    private static final Log log =
-            LogFactory.getLog(WsHttpUpgradeHandler.class);
+    private static final Log log = LogFactory.getLog(WsRemoteEndpointImplServer.class);
 
     private static final Queue<OnResultRunnable> onResultRunnables =
             new ConcurrentLinkedQueue<>();
diff --git a/res/checkstyle/org-import-control.xml b/res/checkstyle/org-import-control.xml
index 8131963..c0bde84 100644
--- a/res/checkstyle/org-import-control.xml
+++ b/res/checkstyle/org-import-control.xml
@@ -88,7 +88,6 @@
     <allow pkg="org.apache.coyote"/>
     <allow pkg="org.apache.juli"/>
     <allow pkg="org.apache.tomcat.jni"/>
-    <allow pkg="org.apache.tomcat.spdy"/>
     <allow pkg="org.apache.tomcat.util"/>
   </subpackage>
   <subpackage name="el">
@@ -144,10 +143,6 @@
         <allow pkg="org.apache.tomcat.jni"/>
       </subpackage>
     </subpackage>
-    <subpackage name="spdy">
-      <allow pkg="org.apache.tomcat.jni"/>
-      <allow pkg="org.apache.tomcat.spdy"/>
-    </subpackage>
     <subpackage name="util">
       <allow pkg="org.apache.juli"/>
       <allow pkg="org.apache.tomcat.jni"/>
diff --git a/res/maven/mvn-pub.xml b/res/maven/mvn-pub.xml
index cdae69c..a55776b 100644
--- a/res/maven/mvn-pub.xml
+++ b/res/maven/mvn-pub.xml
@@ -281,6 +281,10 @@
                   jarFileName="catalina-tribes.jar"
                srcJarFileName="catalina-tribes-src.jar"/>
 
+    <doMavenDeploy artifactId="tomcat-storeconfig"
+                  jarFileName="catalina-storeconfig.jar"
+               srcJarFileName="catalina-storeconfig-src.jar"/>
+
     <doMavenDeploy artifactId="tomcat-jdbc"
                   jarFileName="tomcat-jdbc.jar"
                srcJarFileName="tomcat-jdbc-src.jar"/>
@@ -311,7 +315,6 @@
 
     <doMavenDeploy artifactId="tomcat-api"/>
     <doMavenDeploy artifactId="tomcat-jni"/>
-    <doMavenDeploy artifactId="tomcat-spdy"/>
     <doMavenDeploy artifactId="tomcat-util"/>
     <doMavenDeploy artifactId="tomcat-util-scan"/>
     <doMavenDeploy artifactId="tomcat-coyote"/>
diff --git a/res/maven/mvn.properties.default b/res/maven/mvn.properties.default
index 68440bd..6cfa0c1 100644
--- a/res/maven/mvn.properties.default
+++ b/res/maven/mvn.properties.default
@@ -35,7 +35,7 @@ maven.asf.release.repo.url=https://repository.apache.org/service/local/staging/d
 maven.asf.release.repo.repositoryId=apache.releases
 
 # Release version info
-maven.asf.release.deploy.version=8.0.21
+maven.asf.release.deploy.version=8.0.22
 
 #Where do we load the libraries from
 tomcat.lib.path=../../output/build/lib
diff --git a/res/maven/tomcat-spdy.pom b/res/maven/tomcat-storeconfig.pom
similarity index 84%
rename from res/maven/tomcat-spdy.pom
rename to res/maven/tomcat-storeconfig.pom
index fe50fcd..3a5eb47 100644
--- a/res/maven/tomcat-spdy.pom
+++ b/res/maven/tomcat-storeconfig.pom
@@ -18,9 +18,9 @@
 <project>
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.tomcat</groupId>
-  <artifactId>tomcat-spdy</artifactId>
+  <artifactId>tomcat-storeconfig</artifactId>
   <version>@MAVEN.DEPLOY.VERSION@</version>
-  <description>SPDY implementation</description>
+  <description>Tomcat storeconfig component</description>
   <url>http://tomcat.apache.org/</url>
   <licenses>
     <license>
@@ -32,31 +32,37 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
-      <artifactId>tomcat-jni</artifactId>
+      <artifactId>tomcat-juli</artifactId>
       <version>@MAVEN.DEPLOY.VERSION@</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
-      <artifactId>tomcat-juli</artifactId>
+      <artifactId>tomcat-coyote</artifactId>
       <version>@MAVEN.DEPLOY.VERSION@</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
-      <artifactId>tomcat-coyote</artifactId>
+      <artifactId>tomcat-tribes</artifactId>
       <version>@MAVEN.DEPLOY.VERSION@</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
-      <artifactId>tomcat-util</artifactId>
+      <artifactId>tomcat-catalina</artifactId>
       <version>@MAVEN.DEPLOY.VERSION@</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
-      <artifactId>tomcat-servlet-api</artifactId>
+      <artifactId>tomcat-catalina-ha</artifactId>
+      <version>@MAVEN.DEPLOY.VERSION@</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat-util</artifactId>
       <version>@MAVEN.DEPLOY.VERSION@</version>
       <scope>compile</scope>
     </dependency>
diff --git a/test/org/apache/catalina/connector/TesterResponse.java b/test/org/apache/catalina/connector/TesterResponse.java
index 4e3b829..8b6681f 100644
--- a/test/org/apache/catalina/connector/TesterResponse.java
+++ b/test/org/apache/catalina/connector/TesterResponse.java
@@ -37,4 +37,35 @@ public class TesterResponse extends Response {
                 message + "\")");
          */
     }
+
+    @Override
+    public void resetBuffer(boolean resetWriterStreamFlags) {
+        // NO-OP by default.
+        // There is no buffer created for this test object since no test depends
+        // on one being present or on this method resetting it.
+    }
+
+    @Override
+    public org.apache.coyote.Response getCoyoteResponse() {
+        // Lazy init
+        if (super.getCoyoteResponse() == null) {
+            this.coyoteResponse = new org.apache.coyote.Response();
+        }
+        return super.getCoyoteResponse();
+    }
+
+    @Override
+    public void setSuspended(boolean suspended) {
+        // NO-OP by default.
+        // There is no buffer created for this test object since no test depends
+        // on one being present or on this method suspending it.
+    }
+
+    @Override
+    public void reset() {
+        // Minimal implementation for tests that avoids using OutputBuffer
+        if (super.getCoyoteResponse() != null) {
+            super.getCoyoteResponse().reset();
+        }
+    }
 }
diff --git a/test/org/apache/catalina/core/TestStandardContext.java b/test/org/apache/catalina/core/TestStandardContext.java
index f7b5783..4f9b96b 100644
--- a/test/org/apache/catalina/core/TestStandardContext.java
+++ b/test/org/apache/catalina/core/TestStandardContext.java
@@ -956,11 +956,11 @@ public class TestStandardContext extends TomcatBaseTest {
 
         doTestBug57556(testContext, "", base + File.separatorChar);
         doTestBug57556(testContext, "/", base + File.separatorChar);
-        doTestBug57556(testContext, "/jsp", base + File.separatorChar+ "jsp" + File.separatorChar);
+        doTestBug57556(testContext, "/jsp", base + File.separatorChar+ "jsp");
         doTestBug57556(testContext, "/jsp/", base + File.separatorChar+ "jsp" + File.separatorChar);
         doTestBug57556(testContext, "/index.html", base + File.separatorChar + "index.html");
-        // Doesn't exist so Tomcat will assume it is a file, not a directory.
         doTestBug57556(testContext, "/foo", base + File.separatorChar + "foo");
+        doTestBug57556(testContext, "/foo/", base + File.separatorChar + "foo" + File.separatorChar);
     }
 
     @Test
diff --git a/test/org/apache/catalina/filters/TestRemoteIpFilter.java b/test/org/apache/catalina/filters/TestRemoteIpFilter.java
index 230d553..df9f833 100644
--- a/test/org/apache/catalina/filters/TestRemoteIpFilter.java
+++ b/test/org/apache/catalina/filters/TestRemoteIpFilter.java
@@ -49,7 +49,8 @@ import org.apache.catalina.Context;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.connector.Request;
-import org.apache.catalina.connector.Response;
+import org.apache.catalina.connector.TesterResponse;
+import org.apache.catalina.core.TesterContext;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.util.descriptor.web.FilterDef;
@@ -59,19 +60,25 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
 
     /**
      * Mock {@link FilterChain} to keep a handle on the passed
-     * {@link ServletRequest}.
+     * {@link ServletRequest} and (@link ServletResponse}.
      */
     public static class MockFilterChain implements FilterChain {
         private HttpServletRequest request;
+        private HttpServletResponse response;
 
         @Override
         public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
             this.request = (HttpServletRequest) request;
+            this.response = (HttpServletResponse) response;
         }
 
         public HttpServletRequest getRequest() {
             return request;
         }
+
+        public HttpServletResponse getResponse() {
+            return response;
+        }
     }
 
     public static class MockHttpServlet extends HttpServlet {
@@ -134,6 +141,20 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         public Object getAttribute(String name) {
             return getCoyoteRequest().getAttributes().get(name);
         }
+
+        @Override
+        public String getServerName() {
+            return "localhost";
+        }
+
+        @Override
+        public Context getContext() {
+            // Lazt init
+            if (super.getContext() == null) {
+                getMappingData().context = new TesterContext();
+            }
+            return super.getContext();
+        }
     }
 
     public static final String TEMP_DIR = System.getProperty("java.io.tmpdir");
@@ -184,7 +205,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setHeader("x-forwarded-proto", "http");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         boolean actualSecure = actualRequest.isSecure();
@@ -217,7 +238,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setHeader("x-forwarded-proto", "http");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         boolean actualSecure = actualRequest.isSecure();
@@ -248,7 +269,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setRemoteHost("remote-host-original-value");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         String actualXForwardedFor = request.getHeader("x-forwarded-for");
@@ -262,7 +283,6 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
 
         String actualRemoteHost = actualRequest.getRemoteHost();
         assertEquals("remoteHost", "remote-host-original-value", actualRemoteHost);
-
     }
 
     @Test
@@ -281,7 +301,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.addHeader("x-forwarded-for", "140.211.11.130, 192.168.0.10, 192.168.0.11");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
@@ -316,7 +336,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setHeader("x-forwarded-for", "140.211.11.130, proxy1, proxy2");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
@@ -350,7 +370,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.addHeader("x-forwarded-for", "proxy2");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
@@ -383,7 +403,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setHeader("x-forwarded-for", "140.211.11.130, proxy1, proxy2, 192.168.0.10, 192.168.0.11");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
@@ -415,7 +435,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setHeader("x-forwarded-for", "140.211.11.130, proxy1, proxy2");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
@@ -447,7 +467,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setHeader("x-forwarded-for", "140.211.11.130, proxy1, untrusted-proxy, proxy2");
 
         // TEST
-        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for");
@@ -483,8 +503,8 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         }
     }
 
-    private HttpServletRequest testRemoteIpFilter(FilterDef filterDef, Request request) throws LifecycleException, IOException,
-            ServletException {
+    private MockFilterChain testRemoteIpFilter(FilterDef filterDef, Request request)
+            throws LifecycleException, IOException, ServletException {
         Tomcat tomcat = getTomcatInstance();
         Context root = tomcat.addContext("", TEMP_DIR);
 
@@ -504,8 +524,10 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         MockFilterChain filterChain = new MockFilterChain();
 
         // TEST
-        remoteIpFilter.doFilter(request, new Response(), filterChain);
-        return filterChain.getRequest();
+        TesterResponse response = new TesterResponse();
+        response.setRequest(request);
+        remoteIpFilter.doFilter(request, response, filterChain);
+        return filterChain;
     }
 
     @Test
@@ -522,8 +544,7 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         request.setHeader("x-forwarded-proto", "http");
 
         // TEST
-        HttpServletRequest actualRequest =
-                testRemoteIpFilter(filterDef, request);
+        HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest();
 
         // VERIFY
         Assert.assertEquals("org.apache.catalina.AccessLog.ServerPort",
@@ -581,7 +602,6 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         httpURLConnection.addRequestProperty("x-forwarded-proto", "https");
 
         // VALIDATE
-
         Assert.assertEquals(HttpURLConnection.HTTP_OK, httpURLConnection.getResponseCode());
         HttpServletRequest request = mockServlet.getRequest();
         Assert.assertNotNull(request);
@@ -594,6 +614,98 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
         Assert.assertTrue(request.isSecure());
         Assert.assertEquals("https", request.getScheme());
         Assert.assertEquals(443, request.getServerPort());
+    }
+
+
+    @Test
+    public void testSendRedirectWithXForwardedProto01() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(false, false, 8080, 8080);
+    }
+
+
+    @Test
+    public void testSendRedirectWithXForwardedProto02() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(false, true, 8080, 8080);
+    }
+
+
+    @Test
+    public void testSendRedirectWithXForwardedProto03() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(true, false, 8080, 8080);
+    }
+
+
+    @Test
+    public void testSendRedirectWithXForwardedProto04() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(true, true, 8080, 8080);
+    }
+
+
+    @Test
+    public void testSendRedirectWithXForwardedProto05() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(false, false, 8080, 80);
+    }
 
+
+    @Test
+    public void testSendRedirectWithXForwardedProto06() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(false, false, 80, 8080);
+    }
+
+
+    @Test
+    public void testSendRedirectWithXForwardedProto07() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(false, true, 8443, 443);
+    }
+
+
+    @Test
+    public void testSendRedirectWithXForwardedProto08() throws Exception  {
+        doTestSendRedirectWithXForwardedProtol(false, true, 443, 8443);
+    }
+
+
+    private void doTestSendRedirectWithXForwardedProtol(boolean incomingIsHttps,
+            boolean headerIsHttps, int incomingPort, int headerPort) throws Exception {
+
+        // PREPARE
+        FilterDef filterDef = new FilterDef();
+        filterDef.addInitParameter("protocolHeader", "x-forwarded-proto");
+        filterDef.addInitParameter("remoteIpHeader", "x-my-forwarded-for");
+        if (headerIsHttps) {
+            filterDef.addInitParameter("httpsServerPort", Integer.toString(headerPort));
+        } else {
+            filterDef.addInitParameter("httpServerPort", Integer.toString(headerPort));
+        }
+
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.setRemoteAddr("192.168.0.10");
+        request.setServerPort(incomingPort);
+        request.setSecure(true);
+        if (incomingIsHttps) {
+            request.setScheme("https");
+        } else {
+            request.setScheme("http");
+        }
+        request.setHeader("x-my-forwarded-for", "140.211.11.130");
+        if (headerIsHttps) {
+            request.setHeader("x-forwarded-proto", "https");
+        } else {
+            request.setHeader("x-forwarded-proto", "http");
+        }
+
+        // TEST
+        HttpServletResponse actualResponse = testRemoteIpFilter(filterDef, request).getResponse();
+        actualResponse.sendRedirect("/");
+        String location = actualResponse.getHeader("Location");
+
+        // VERIFY
+        Assert.assertEquals(location,
+                Boolean.valueOf(location.startsWith("https")), Boolean.valueOf(headerIsHttps));
+        if (headerPort == 80 && !headerIsHttps || headerPort == 443 && headerIsHttps) {
+            Assert.assertTrue(location, location.contains("://localhost/"));
+        } else {
+            Assert.assertTrue(location, location.contains("://localhost:" + headerPort + "/"));
+        }
     }
 }
diff --git a/test/org/apache/catalina/loader/TestWebappClassLoaderThreadLocalMemoryLeak.java b/test/org/apache/catalina/loader/TestWebappClassLoaderThreadLocalMemoryLeak.java
index ceace03..ad2a57c 100644
--- a/test/org/apache/catalina/loader/TestWebappClassLoaderThreadLocalMemoryLeak.java
+++ b/test/org/apache/catalina/loader/TestWebappClassLoaderThreadLocalMemoryLeak.java
@@ -26,6 +26,7 @@ import java.util.logging.LogRecord;
 import javax.servlet.http.HttpServletResponse;
 
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import org.apache.catalina.Context;
@@ -36,6 +37,22 @@ import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.threads.ThreadPoolExecutor;
 
+/*
+ * These unit tests are ignored by default as they are not reliable. They have
+ * been failing regularly on Gump for some time and have recently started to
+ * fail regularly on markt's laptop.
+ *
+ * The problem is that the ThreadLocal Maps are affected by GC. If GC occurs at
+ * the wrong point, the leaking ThreadLocal will be cleaned up and the test will
+ * fail. It is not possible to force the test to pass without effectively
+ * changing the nature of the test so it no longer tests detection of leaks via
+ * ThreadLocals.
+ *
+ * The test has been left in place since it will work reasonably reliably on
+ * most systems (just not all and particularly some of the ASF's CI systems) and
+ * still may be useful if a bug is reported in this area in the future.
+ */
+ at Ignore
 public class TestWebappClassLoaderThreadLocalMemoryLeak extends TomcatBaseTest {
 
     @Test
diff --git a/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java b/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java
index 18cc21e..96d161e 100644
--- a/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java
+++ b/test/org/apache/catalina/startup/TestHostConfigAutomaticDeployment.java
@@ -1120,35 +1120,39 @@ public class TestHostConfigAutomaticDeployment extends TomcatBaseTest {
         tomcat.start();
         host.backgroundProcess();
 
-        // Update the last modified time. Add a few seconds to make sure that
-        // the OS reports a change in modification time.
+        // Update the last modified time. Make sure that the OS reports a change
+        // in modification time that HostConfig can detect.
         switch (toModify) {
             case XML:
                 if (xml == null) {
                     Assert.fail();
                 } else {
-                    xml.setLastModified(System.currentTimeMillis() + 5000);
+                    xml.setLastModified(System.currentTimeMillis() -
+                            10 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
                 }
                 break;
             case EXT:
                 if (ext == null) {
                     Assert.fail();
                 } else {
-                    ext.setLastModified(System.currentTimeMillis() + 5000);
+                    ext.setLastModified(System.currentTimeMillis() -
+                            10 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
                 }
                 break;
             case WAR:
                 if (war == null) {
                     Assert.fail();
                 } else {
-                    war.setLastModified(System.currentTimeMillis() + 5000);
+                    war.setLastModified(System.currentTimeMillis() -
+                            10 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
                 }
                 break;
             case DIR:
                 if (dir == null) {
                     Assert.fail();
                 } else {
-                    dir.setLastModified(System.currentTimeMillis() + 5000);
+                    dir.setLastModified(System.currentTimeMillis() -
+                            10 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
                 }
                 break;
             default:
@@ -1696,6 +1700,9 @@ public class TestHostConfigAutomaticDeployment extends TomcatBaseTest {
             dest = new File(external, "external" + ".war");
         }
         Files.copy(src.toPath(), dest.toPath());
+        // Make sure that HostConfig thinks the WAR has been modified.
+        dest.setLastModified(
+                System.currentTimeMillis() - 2 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
         return dest;
     }
 
@@ -1706,6 +1713,9 @@ public class TestHostConfigAutomaticDeployment extends TomcatBaseTest {
             Assert.assertTrue(parent.mkdirs());
         }
         Files.copy(XML_SOURCE.toPath(), xml.toPath());
+        // Make sure that HostConfig thinks the xml has been modified.
+        xml.setLastModified(
+                System.currentTimeMillis() - 2 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
         return xml;
     }
 
@@ -1739,6 +1749,9 @@ public class TestHostConfigAutomaticDeployment extends TomcatBaseTest {
             context.append("\" />");
             fos.write(context.toString().getBytes(StandardCharsets.ISO_8859_1));
         }
+        // Make sure that HostConfig thinks the xml has been modified.
+        xml.setLastModified(
+                System.currentTimeMillis() - 2 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
         return xml;
     }
 
@@ -1756,7 +1769,12 @@ public class TestHostConfigAutomaticDeployment extends TomcatBaseTest {
             @Override
             public FileVisitResult visitFile(Path file,
                     BasicFileAttributes attrs) throws IOException {
-                Files.copy(file, dest.resolve(src.relativize(file)));
+                Path destPath = dest.resolve(src.relativize(file));
+                Files.copy(file, destPath);
+                // Make sure that HostConfig thinks all newly copied files have
+                // been modified.
+                destPath.toFile().setLastModified(
+                        System.currentTimeMillis() - 2 * HostConfig.FILE_MODIFICATION_RESOLUTION_MS);
                 return FileVisitResult.CONTINUE;
             }
 
diff --git a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java
index 256c939..0603515 100644
--- a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java
+++ b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java
@@ -46,6 +46,19 @@ public class TestRewriteValve extends TomcatBaseTest {
         doTestRewrite("RewriteRule ^/b/(.*) /b/../a/$1", "/b/%255A", "/b/../a/%255A");
     }
 
+    // BZ 57863
+    @Test
+    public void testRewriteMap01() throws Exception {
+        doTestRewrite("RewriteMap mapa org.apache.catalina.valves.rewrite.TesterRewriteMapA\n" +
+                "RewriteRule /b/(.*).html$ /c/${mapa:$1}", "/b/a.html", "/c/aa");
+    }
+
+    @Test
+    public void testRewriteMap02() throws Exception {
+        doTestRewrite("RewriteMap mapa org.apache.catalina.valves.rewrite.TesterRewriteMapA\n" +
+                "RewriteRule /b/(.*).html$ /c/${mapa:$1|dd}", "/b/x.html", "/c/dd");
+    }
+
     private void doTestRewrite(String config, String request, String expectedURI) throws Exception {
         Tomcat tomcat = getTomcatInstance();
 
@@ -61,6 +74,7 @@ public class TestRewriteValve extends TomcatBaseTest {
         //       (http://svn.apache.org/r285186)
         Tomcat.addServlet(ctx, "snoop", new SnoopServlet());
         ctx.addServletMapping("/a/%255A", "snoop");
+        ctx.addServletMapping("/c/*", "snoop");
 
         tomcat.start();
 
diff --git a/test/org/apache/el/TesterBeanB.java b/test/org/apache/catalina/valves/rewrite/TesterRewriteMapA.java
similarity index 64%
copy from test/org/apache/el/TesterBeanB.java
copy to test/org/apache/catalina/valves/rewrite/TesterRewriteMapA.java
index 9e82f02..72e548a 100644
--- a/test/org/apache/el/TesterBeanB.java
+++ b/test/org/apache/catalina/valves/rewrite/TesterRewriteMapA.java
@@ -14,25 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.catalina.valves.rewrite;
 
-package org.apache.el;
+import java.util.HashMap;
+import java.util.Map;
 
-public class TesterBeanB {
-    private String name;
+public class TesterRewriteMapA implements RewriteMap {
 
-    public String getName() {
-        return name;
-    }
+    private static final Map<String,String> map = new HashMap<>();
 
-    public void setName(String name) {
-        this.name = name;
+    static {
+        map.put("a", "aa");
+        map.put("b", "bb");
     }
 
-    public String sayHello() {
-        return "Hello from " + name;
+    @Override
+    public String setParameters(String params) {
+        // NO-OP
+        return null;
     }
 
-    public String sayHello(String to) {
-        return "Hello " + to + " from " + name;
+    @Override
+    public String lookup(String key) {
+        return map.get(key);
     }
 }
diff --git a/test/org/apache/catalina/webresources/TestWarURLConnection.java b/test/org/apache/catalina/webresources/TestWarURLConnection.java
index 986318d..6d96afb 100644
--- a/test/org/apache/catalina/webresources/TestWarURLConnection.java
+++ b/test/org/apache/catalina/webresources/TestWarURLConnection.java
@@ -38,7 +38,7 @@ public class TestWarURLConnection {
         String fileUrl = f.toURI().toURL().toString();
 
         URL indexHtmlUrl = new URL("jar:war:" + fileUrl +
-                "^/WEB-INF/lib/test.jar!/META-INF/resources/index.html");
+                "*/WEB-INF/lib/test.jar!/META-INF/resources/index.html");
 
         URLConnection urlConn = indexHtmlUrl.openConnection();
         urlConn.connect();
diff --git a/test/org/apache/catalina/webresources/TestWarURLConnection.java b/test/org/apache/catalina/webresources/TestWarURLStreamHandler.java
similarity index 94%
copy from test/org/apache/catalina/webresources/TestWarURLConnection.java
copy to test/org/apache/catalina/webresources/TestWarURLStreamHandler.java
index 986318d..a4fd036 100644
--- a/test/org/apache/catalina/webresources/TestWarURLConnection.java
+++ b/test/org/apache/catalina/webresources/TestWarURLStreamHandler.java
@@ -24,7 +24,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-public class TestWarURLConnection {
+public class TestWarURLStreamHandler {
 
     @Before
     public void register() {
@@ -33,7 +33,7 @@ public class TestWarURLConnection {
 
 
     @Test
-    public void testContentLength() throws Exception {
+    public void testOldFormat() throws Exception {
         File f = new File("test/webresources/war-url-connection.war");
         String fileUrl = f.toURI().toURL().toString();
 
diff --git a/test/org/apache/catalina/webresources/TestWarURLConnection.java b/test/org/apache/catalina/webresources/TestWarURLStreamHandlerIntegration.java
similarity index 55%
copy from test/org/apache/catalina/webresources/TestWarURLConnection.java
copy to test/org/apache/catalina/webresources/TestWarURLStreamHandlerIntegration.java
index 986318d..e7d6a58 100644
--- a/test/org/apache/catalina/webresources/TestWarURLConnection.java
+++ b/test/org/apache/catalina/webresources/TestWarURLStreamHandlerIntegration.java
@@ -18,33 +18,34 @@ package org.apache.catalina.webresources;
 
 import java.io.File;
 import java.net.URL;
-import java.net.URLConnection;
 
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
-public class TestWarURLConnection {
-
-    @Before
-    public void register() {
-        TomcatURLStreamHandlerFactory.register();
-    }
+import org.apache.catalina.Context;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
 
+public class TestWarURLStreamHandlerIntegration extends TomcatBaseTest {
 
     @Test
-    public void testContentLength() throws Exception {
-        File f = new File("test/webresources/war-url-connection.war");
-        String fileUrl = f.toURI().toURL().toString();
+    public void testToURI() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
 
-        URL indexHtmlUrl = new URL("jar:war:" + fileUrl +
-                "^/WEB-INF/lib/test.jar!/META-INF/resources/index.html");
+        File docBase = new File("test/webresources/war-url-connection.war");
+        Context context = tomcat.addWebapp("/test", docBase.getAbsolutePath());
 
-        URLConnection urlConn = indexHtmlUrl.openConnection();
-        urlConn.connect();
+        ((StandardHost) tomcat.getHost()).setUnpackWARs(false);
 
-        int size = urlConn.getContentLength();
+        tomcat.start();
 
-        Assert.assertEquals(137, size);
+        URL url = context.getServletContext().getResource("/index.html");
+        try {
+            url.toURI();
+        } catch (Exception e) {
+            e.printStackTrace();
+            Assert.fail();
+        }
     }
 }
diff --git a/test/org/apache/el/TestMethodExpressionImpl.java b/test/org/apache/el/TestMethodExpressionImpl.java
index 29cfdde..ee71edc 100644
--- a/test/org/apache/el/TestMethodExpressionImpl.java
+++ b/test/org/apache/el/TestMethodExpressionImpl.java
@@ -467,6 +467,15 @@ public class TestMethodExpressionImpl {
 
 
     @Test
+    public void testBug53792d() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "#{beanB.sayHello().length()}", null, new Class<?>[] {});
+        Integer result = (Integer) me.invoke(context, new Object[] { "foo" });
+        assertEquals(beanB.sayHello().length(), result.intValue());
+    }
+
+
+    @Test
     public void testBug56797a() {
         MethodExpression me = factory.createMethodExpression(context,
                 "${beanAA.echo1('Hello World!')}", null , null);
@@ -482,4 +491,44 @@ public class TestMethodExpressionImpl {
         Object r = me.invoke(context, null);
         assertEquals("AA2Hello World!", r.toString());
     }
+
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testBug57855a() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "${beanAA.echo2}", null , new Class[]{String.class});
+        me.invoke(context, new Object[0]);
+    }
+
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testBug57855b() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "${beanAA.echo2}", null , new Class[]{String.class});
+        me.invoke(context, null);
+    }
+
+    @Test
+    public void testBug57855c() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "${beanB.echo}", null , new Class[]{String.class});
+        me.invoke(context, null);
+    }
+
+
+    @Test
+    public void testBug57855d() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "${beanB.echo}", null , new Class[]{String.class});
+        Object r = me.invoke(context, new String[] { "aaa" });
+        assertEquals("aaa", r.toString());
+    }
+    @Test
+    public void testBug57855e() {
+        MethodExpression me = factory.createMethodExpression(context,
+                "${beanB.echo}", null , new Class[]{String.class});
+        Object r = me.invoke(context, new String[] { "aaa", "bbb" });
+        assertEquals("aaa, bbb", r.toString());
+    }
+
 }
diff --git a/test/org/apache/el/TesterBeanB.java b/test/org/apache/el/TesterBeanB.java
index 9e82f02..efbfe23 100644
--- a/test/org/apache/el/TesterBeanB.java
+++ b/test/org/apache/el/TesterBeanB.java
@@ -35,4 +35,19 @@ public class TesterBeanB {
     public String sayHello(String to) {
         return "Hello " + to + " from " + name;
     }
+
+    public String echo(String...strings) {
+        if (strings == null) {
+            return null;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < strings.length; i++) {
+            if (i > 0) {
+                sb.append(", ");
+            }
+            sb.append(strings[i]);
+        }
+        return sb.toString();
+    }
 }
diff --git a/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java b/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java
index 025ac8c..00bc92c 100644
--- a/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java
+++ b/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java
@@ -80,4 +80,55 @@ public class TestWebSocketFrameClient extends TomcatBaseTest {
         }
     }
 
+    @Test
+    public void testConnectToRootEndpoint() throws Exception {
+
+        Tomcat tomcat = getTomcatInstance();
+        // No file system docBase required
+        Context ctx = tomcat.addContext("", null);
+        ctx.addApplicationListener(TesterEchoServer.Config.class.getName());
+        Tomcat.addServlet(ctx, "default", new DefaultServlet());
+        ctx.addServletMapping("/", "default");
+        Context ctx2 = tomcat.addContext("/foo", null);
+        ctx2.addApplicationListener(TesterEchoServer.Config.class.getName());
+        Tomcat.addServlet(ctx2, "default", new DefaultServlet());
+        ctx2.addServletMapping("/", "default");
+
+        tomcat.start();
+
+        echoTester("");
+        echoTester("/");
+        // FIXME: The ws client doesn't handle any response other than the upgrade,
+        // which may or may not be allowed. In that case, the server will return
+        // a redirect to the root of the webapp to avoid possible broken relative
+        // paths.
+        // echoTester("/foo");
+        echoTester("/foo/");
+    }
+
+    public void echoTester(String path) throws Exception {
+        WebSocketContainer wsContainer =
+                ContainerProvider.getWebSocketContainer();
+        ClientEndpointConfig clientEndpointConfig =
+                ClientEndpointConfig.Builder.create().build();
+        Session wsSession = wsContainer.connectToServer(
+                TesterProgrammaticEndpoint.class,
+                clientEndpointConfig,
+                new URI("ws://localhost:" + getPort() + path));
+        CountDownLatch latch =
+                new CountDownLatch(1);
+        BasicText handler = new BasicText(latch);
+        wsSession.addMessageHandler(handler);
+        wsSession.getBasicRemote().sendText("Hello");
+
+        handler.getLatch().await(100, TimeUnit.MILLISECONDS);
+
+        Queue<String> messages = handler.getMessages();
+        Assert.assertEquals(1, messages.size());
+        for (String message : messages) {
+            Assert.assertEquals("Hello", message);
+        }
+        wsSession.close();
+    }
+
 }
diff --git a/test/org/apache/tomcat/websocket/TesterEchoServer.java b/test/org/apache/tomcat/websocket/TesterEchoServer.java
index 406d3a8..7f22e41 100644
--- a/test/org/apache/tomcat/websocket/TesterEchoServer.java
+++ b/test/org/apache/tomcat/websocket/TesterEchoServer.java
@@ -49,6 +49,7 @@ public class TesterEchoServer {
                 sc.addEndpoint(Basic.class);
                 sc.addEndpoint(BasicLimitLow.class);
                 sc.addEndpoint(BasicLimitHigh.class);
+                sc.addEndpoint(RootEcho.class);
             } catch (DeploymentException e) {
                 throw new IllegalStateException(e);
             }
@@ -186,4 +187,21 @@ public class TesterEchoServer {
         }
     }
 
+
+    @ServerEndpoint("/")
+    public static class RootEcho {
+
+        @OnMessage
+        public void echoTextMessage(Session session, String msg) {
+            try {
+                session.getBasicRemote().sendText(msg);
+            } catch (IOException e) {
+                try {
+                    session.close();
+                } catch (IOException e1) {
+                    // Ignore
+                }
+            }
+        }
+    }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 2f20641..a4fcf17 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -44,7 +44,222 @@
   They eventually become mixed with the numbered issues. (I.e., numbered
   issues do not "pop up" wrt. others).
 -->
-<section name="Tomcat 8.0.21 (markt)">
+<section name="Tomcat 8.0.22 (markt)">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>57736</bug>: Change the format of the Tomcat specific URLs for
+        resources inside JARs that are in turn packed in a WAR. The
+        <code>^/</code> sequence has been replaced by <code>*/</code> so that
+        the resulting URLs are compliant with RFC 2396 and do not trigger
+        exceptions when converted to URIs. The old format will continue to be
+        accepted. (markt)
+      </fix>
+      <fix>
+        <bug>57752</bug>: Exclude non-cached resources from the Cache statistics
+        for resource lookups. Patch provided by Adam Mlodzinski. (markt)
+      </fix>
+      <add>
+        Allow logging of the remote port in the access log using the format
+        pattern <code>%{remote}p</code>. (rjung)
+      </add>
+      <fix>
+        <bug>57556</bug>: Refine the previous fix fo rthis issue so that the
+        real path returned only has a trialing separator if the requested path
+        ended with <code>/</code>. (markt)
+      </fix>
+      <fix>
+        <bug>57765</bug>: When checking last modified times as part of the
+        automatic deployment process, account for the fact that
+        <code>File.lastModified()</code> has a resolution of one second to
+        ensure that if a file has been modified within the last second, the
+        latest version of the file is always used. Note that a side-effect of
+        this change is that files with modification times in the future are
+        treated as if they are unmodified. (markt)
+      </fix>
+      <fix>
+        Align redeploy resource modification checking with reload modification
+        checking so that now, in both cases, a change in modification time
+        rather than an increase in modification time is used to determine if the
+        resource has changed. (markt)
+      </fix>
+      <fix>
+        Cleanup <code>o.a.tomcat.util.digester.Digester</code> from debug
+        messages that do not give any valuable information. Patch provided
+        by Polina Genova. (violetagg)
+      </fix>
+      <fix>
+        <bug>57772</bug>: When reloading a web application and a directory
+        representing an expanded WAR needs to be deleted, delete the directory
+        after the web application has been stopped rather than before to avoid
+        potential ClassNotFoundExceptions. (markt)
+      </fix>
+      <fix>
+        Fix wrong logger name of
+        <code>org.apache.catalina.webresources.StandardRoot</code>. (kfujino)
+      </fix>
+      <fix>
+        <bug>57801</bug>: Improve the error message in the start script in case
+        the PID read from the PID file is already owned by a process. (rjung)
+      </fix>
+      <fix>
+        <bug>57841</bug>: Improve error logging during web application start.
+        (markt)
+      </fix>
+      <fix>
+        <bug>57856</bug>: Ensure that any scheme/port changes implemented by the
+        <code>RemoteIpFilter</code> also affect
+        <code>HttpServletResponse.sendRedirect()</code>. (markt)
+      </fix>
+      <fix>
+        <bug>57863</bug>: Fix the RewriteMap support in RewriteValve that did
+        not use the correct key value to look up entries. Based on a patch
+        provided by Tatsuya Bessho. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>57779</bug>: When an I/O error occurs on a non-container thread
+        only dispatch to a container thread to handle the error if using Servlet
+        3+ asynchronous processing. This avoids potential deadlocks if an
+        application is performing I/O on a non-container thread without using
+        the Servlet 3+ asynchronous API. (markt)
+      </fix>
+      <scode>
+        Remove the experimental support for SPDY. No current user agent supports
+        the version of SPDY that the experiment targetted. Note: HTTP/2 support
+        is under development for Tomcat 9 and may be back-ported to Tomcat 8
+        once complete. (markt)
+      </scode>
+      <fix>
+        Possible incomplete writes with SSL NIO2. (remm)
+      </fix>
+      <fix>
+        Incorrect reads with SSL NIO2 caused by a bad strategy for handling IO
+        differences between NIO and NIO2 that don't seem to be justified.
+        (remm)
+      </fix>
+      <fix>
+        After some errors, the pending flags could remain set when using SSL
+        NIO2. (remm)
+      </fix>
+      <fix>
+        <bug>57833</bug>: When using JKS based keystores for NIO or NIO2, ensure
+        that the key alias is always converted to lower caes since that is what
+        JKS key stores expect. Based on a patch by  Santosh Giri Govind M.
+        (markt)
+      </fix>
+      <fix>
+        <bug>57837</bug>: Add <code>text/css</code> to the default list of
+        compressable MIME types. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>57845</bug>: Ensure that, if the same JSP is accessed directly and
+        via a <code><jsp-file></code> declaration in web.xml, updates to
+        the JSP are visible (subject to the normal rules on re-compilation)
+        regardless of how the JSP is accessed. (markt)
+      </fix>
+      <fix>
+        <bug>57855</bug>: Explicitly handle the case where a
+        <code>MethodExpression</code> is invoked with null or the wrong number
+        of parameters. Rather than failing with an
+        <code>ArrayIndexOutOfBoundsException</code> or a
+        <code>NullPointerException</code> throw an
+        <code>IllegalArgumentException</code> with a useful error message.
+        (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Avoid unnecessary call of <code>DeltaRequest.addSessionListener()</code>
+        in non-primary nodes. (kfujino)
+      </fix>
+      <add>
+        Add new attribute that send all actions for session across Tomcat
+        cluster nodes. (kfujino)
+      </add>
+      <fix>
+        Remove unused <code>pathname</code> attribute in mbean definition of
+        <code>BackupManager</code>. (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="WebSocket">
+    <changelog>
+      <fix>
+        <bug>57761</bug>: Ensure that the opening HTTP request is correctly
+        formatted when the WebSocket client connects to a server root. (remm)
+      </fix>
+      <fix>
+        <bug>57762</bug>: Ensure that the WebSocket client correctly detects
+        when the connection to the server is dropped. (markt)
+      </fix>
+      <fix>
+        <bug>57776</bug>: Revert the 8.0.21 fix for the
+        <code>permessage-deflate</code> implementation and incorrect op-codes
+        since the fix was unnecessary (the bug only affected trunk) and the fix
+        broke rather than fixed <code>permessage-deflate</code> if an
+        uncompressed message was converted into more than one compressed
+        message. (markt)
+      </fix>
+      <fix>
+        Fix log name typo in <code>WsRemoteEndpointImplServer</code> class,
+        caused by a copy-paste. (markt/kkolinko)
+      </fix>
+      <fix>
+        <bug>57788</bug>: Avoid NPE when looking up a class hierarchy without
+        finding anything. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <add>
+        <bug>57759</bug>: Add information to the keyAlias documentation to make
+        it clear that the order keys are read from the keystore is
+        implementation dependent. (markt)
+      </add>
+      <fix>
+        <bug>57864</bug>: Update the documentation web application to make it
+        clearer that hex values are not valid for cluster send options. Based on
+        a patch by Kyohei Nakamura. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Tribes">
+    <changelog>
+      <fix>
+        Fix a concurrency issue when a backup message that has all session data
+        and a backup message that has diff data are processing at the same time.
+        This fix ensures that <code>MapOwner</code> is set to
+        <code>ReplicatedMapEntry</code>. (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <fix>
+        Add missing pom for tomcat-storeconfig. (remm)
+      </fix>
+      <update>
+        Update optional Checkstyle library to 6.5. (kkolinko)
+      </update>
+      <fix>
+        <bug>57707</bug>: Improve error message when trying to run a release
+        build on a non-Windows platform and Wine is not available. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 8.0.21 (markt)" rtext="2015-03-26">
   <subsection name="Catalina">
     <changelog>
       <add>
@@ -207,7 +422,7 @@
         Stop caching and re-using SocketWrapper instances. With the introduction
         of upgrade and non-blocking I/O, I/O can occur on non-container threads.
         This makes it nearly impossible to track whether a SocketWrapper is
-        still being references or not. making re-use a risky proposition.
+        still being referenced or not, making re-use a risky proposition.
         (markt)
       </fix>
       <scode>
@@ -307,6 +522,10 @@
         documentation web application that stated WAR files located outside the
         appBase were never unpacked. (markt)
       </fix>
+      <update>
+        <bug>57644</bug>: Update examples to use Apache Standard Taglib 1.2.5.
+        (jboynes)
+      </update>
       <fix>
         <bug>57683</bug>: Ensure that if a client aborts their connection to the
         stock ticker example (the only way a client can disconnect), the example
@@ -317,9 +536,6 @@
         authentication that no salt and only a single iteration must be used
         when generating the digest. (markt)
       </fix>
-      <update>
-        Update examples to use Apache Standard Taglib 1.2.5. (jboynes)
-      </update>
     </changelog>
   </subsection>
   <subsection name="Extras">
diff --git a/webapps/docs/class-loader-howto.xml b/webapps/docs/class-loader-howto.xml
index 3f18f68..083fac4 100644
--- a/webapps/docs/class-loader-howto.xml
+++ b/webapps/docs/class-loader-howto.xml
@@ -156,7 +156,6 @@ loaders as it is initialized:</p>
     <li><em>tomcat-jdbc.jar</em> — An alternative database connection pool
         implementation, known as Tomcat JDBC pool. See
         <a href="jdbc-pool.html">documentation</a> for more details.</li>
-    <li><em>tomcat-spdy.jar</em> — SPDY implementation</li>
     <li><em>tomcat-util.jar</em> — Common classes used by various components of
         Apache Tomcat.</li>
     <li><em>tomcat-websocket.jar</em> — WebSocket 1.1 implementation</li>
diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml
index 7b107fe..d736e4f 100644
--- a/webapps/docs/config/ajp.xml
+++ b/webapps/docs/config/ajp.xml
@@ -445,8 +445,8 @@
     <attribute name="tomcatAuthorization" required="false">
       <p>If set to <code>true</code>, the authenticated principal will be
       propagated from the native webserver and considered already authenticated
-      in Tomcat. If the web application has one or more security constriants,
-      authorization will then be performed by Tomcat and roles asisgned to the
+      in Tomcat. If the web application has one or more security constraints,
+      authorization will then be performed by Tomcat and roles assigned to the
       authenticated principal. If the appropriate Tomcat Realm for the request
       does not recognise the provided user name, a Principal will be still be
       created but it will have no roles. The default value is
diff --git a/webapps/docs/config/cluster-manager.xml b/webapps/docs/config/cluster-manager.xml
index 9c56126..664f1fd 100644
--- a/webapps/docs/config/cluster-manager.xml
+++ b/webapps/docs/config/cluster-manager.xml
@@ -135,6 +135,13 @@
         secureRandomProvider attribute and set this attribute to the empty
         string.</p>
       </attribute>
+      <attribute name="recordAllActions" required="false">
+        <p>Flag whether send all actions for session across Tomcat cluster
+        nodes. If set to false, if already done something to the same attribute,
+        make sure don't send multiple actions across Tomcat cluster nodes.
+        In that case, sends only the actions that have been added at last.
+        Default is <code>false</code>.</p>
+      </attribute>
     </attributes>
   </subsection>
   <subsection name="org.apache.catalina.ha.session.DeltaManager Attributes">
diff --git a/webapps/docs/config/cluster.xml b/webapps/docs/config/cluster.xml
index 61208c4..6ab1c73 100644
--- a/webapps/docs/config/cluster.xml
+++ b/webapps/docs/config/cluster.xml
@@ -123,11 +123,11 @@
       <code>Channel.SEND_OPTIONS_SYNCHRONIZED_ACK = 0x0004</code><br/>
       <code>Channel.SEND_OPTIONS_ASYNCHRONOUS = 0x0008</code><br/>
       <code>Channel.SEND_OPTIONS_USE_ACK = 0x0002</code><br/>
-      So to use ACK and ASYNC messaging, the flag would be <code>10 (8+2) or 0x000B</code><br/>
+      So to use ACK and ASYNC messaging, the flag would be <code>10</code> (8+2)
+      <br/>
       Note that if you use ASYNC messaging it is possible for update messages
       for a session to be processed by the receiving nodes in a different order
-      to the order in which they were sent.
-      </p>
+      to the order in which they were sent.</p>
     </attribute>
     <attribute name="channelStartOptions" required="false">
       <p>Sets the start and stop flags for the <Channel> object used by the cluster.
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index 9e93e06..6e397cb 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -322,7 +322,8 @@
     <attribute name="compressableMimeType" required="false">
       <p>The value is a comma separated list of MIME types for which HTTP
       compression may be used.
-      The default value is <code>text/html,text/xml,text/plain</code>.</p>
+      The default value is <code>text/html,text/xml,text/plain,text/css</code>.
+      </p>
     </attribute>
 
     <attribute name="compression" required="false">
@@ -1148,8 +1149,13 @@
     </attribute>
 
     <attribute name="keyAlias" required="false">
-      <p>The alias used to for the server certificate in the keystore. If not
-      specified the first key read in the keystore will be used.</p>
+      <p>The alias used for the server key and certificate in the keystore. If
+      not specified, the first key read from the keystore will be used. The
+      order in which keys are read from the keystore is implementation
+      dependent. It may not be the case that keys are read from the keystore in
+      the same order as they were added. If more than one key is present in the
+      kesytore it is strongly recommended that a keyAlias is configured to
+      ensure that the correct key is used.</p>
     </attribute>
 
     <attribute name="keyPass" required="false">
diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml
index b635923..f395bbf 100644
--- a/webapps/docs/config/valve.xml
+++ b/webapps/docs/config/valve.xml
@@ -278,7 +278,8 @@
     <li><b>%l</b> - Remote logical username from identd (always returns
         '-')</li>
     <li><b>%m</b> - Request method (GET, POST, etc.)</li>
-    <li><b>%p</b> - Local port on which this request was received</li>
+    <li><b>%p</b> - Local port on which this request was received.
+        See also <code>%{xxx}p</code> below.</li>
     <li><b>%q</b> - Query string (prepended with a '?' if it exists)</li>
     <li><b>%r</b> - First line of the request (method and request URI)</li>
     <li><b>%s</b> - HTTP status code of the response</li>
@@ -299,15 +300,18 @@
     timestamp formats.
     It is modeled after the
     <a href="http://httpd.apache.org/">Apache HTTP Server</a> log configuration
-    syntax:
+    syntax. Each of them can be used multiple times with different <code>xxx</code> keys:
     </p>
     <ul>
-    <li><b><code>%{xxx}i</code></b> for incoming headers</li>
-    <li><b><code>%{xxx}o</code></b> for outgoing response headers</li>
-    <li><b><code>%{xxx}c</code></b> for a specific cookie</li>
-    <li><b><code>%{xxx}r</code></b> xxx is an attribute in the ServletRequest</li>
-    <li><b><code>%{xxx}s</code></b> xxx is an attribute in the HttpSession</li>
-    <li><b><code>%{xxx}t</code></b> xxx is an enhanced SimpleDateFormat pattern</li>
+    <li><b><code>%{xxx}i</code></b> write value of incoming header with name <code>xxx</code></li>
+    <li><b><code>%{xxx}o</code></b> write value of outgoing header with name <code>xxx</code></li>
+    <li><b><code>%{xxx}c</code></b> write value of cookie with name <code>xxx</code></li>
+    <li><b><code>%{xxx}r</code></b> write value of ServletRequest attribute with name <code>xxx</code></li>
+    <li><b><code>%{xxx}s</code></b> write value of HttpSession attribute with name <code>xxx</code></li>
+    <li><b><code>%{xxx}p</code></b> write local (server) port (<code>xxx==local</code>) or
+        remote (client) port (<code>xxx=remote</code>)</li>
+    <li><b><code>%{xxx}t</code></b> write timestamp at the end of the request formatted using the
+        enhanced SimpleDateFormat pattern <code>xxx</code></li>
     </ul>
 
     <p>All formats supported by SimpleDateFormat are allowed in <code>%{xxx}t</code>.
diff --git a/webapps/docs/security-howto.xml b/webapps/docs/security-howto.xml
index 4b23c26..f6b6516 100644
--- a/webapps/docs/security-howto.xml
+++ b/webapps/docs/security-howto.xml
@@ -129,15 +129,15 @@
      <p>When deploying a web application that provides management functions for
      the Tomcat instance, the following guidelines should be followed:</p>
      <ul>
-       <ol>Ensure that any users permitted to access the management application
-           have strong passwords.</ol>
-       <ol>Do not remove the use of the <a
+       <li>Ensure that any users permitted to access the management application
+           have strong passwords.</li>
+       <li>Do not remove the use of the <a
            href="config/realm.html#LockOut_Realm_-_org.apache.catalina.realm.LockOutRealm">LockOutRealm</a>
-           which prevents brute force attacks against user passwords.</ol>
-       <ol>Uncomment the <a href="config/valve.html#Remote_Address_Filter">RemoteAddrValve</a>
+           which prevents brute force attacks against user passwords.</li>
+       <li>Uncomment the <a href="config/valve.html#Remote_Address_Filter">RemoteAddrValve</a>
            in <code>/META-INF/context.xml</code> which limits access to
            localhost. If remote access is required, limit it to specific IP
-           addresses using this valve.</ol>
+           addresses using this valve.</li>
      </ul>
    </subsection>
   </section>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/tomcat8.git



More information about the pkg-java-commits mailing list