[SCM] tomcat7: Servlet and JSP engine branch, exp/master, updated. debian/7.0.35-1_exp2-3-gfd31443

Miguel Landaeta miguel at miguel.cc
Sun Mar 31 23:55:37 UTC 2013


The following commit has been merged in the exp/master branch:
commit cd6fa3f2ce1cc5f53326fc40e85c948ffce771cc
Author: Miguel Landaeta <miguel at miguel.cc>
Date:   Sun Mar 31 15:02:04 2013 -0300

    Imported Upstream version 7.0.39

diff --git a/BUILDING.txt b/BUILDING.txt
index 3cc8ef5..88c165b 100644
--- a/BUILDING.txt
+++ b/BUILDING.txt
@@ -15,7 +15,7 @@
   limitations under the License.
 ================================================================================
 
-$Id: BUILDING.txt 1430451 2013-01-08 19:11:23Z kkolinko $
+$Id: BUILDING.txt 1457383 2013-03-17 06:22:36Z kkolinko $
 
             ====================================================
             Building The Apache Tomcat @VERSION_MAJOR_MINOR@ Servlet/JSP Container
@@ -192,12 +192,28 @@ For a quick rebuild of only modified code you can use:
 
 (5) Special builds
 
-Some Tomcat components, that are included in the full release, but are not
-built during the default "deploy" build, can also be built separately.
+There are several targets in Tomcat build files that are useful to be
+called separately. They build components that you may want to build
+quickly, or ones that are included in the full release and are not built
+during the default "deploy" build.
 
-(5.1) Building API documentation (Javadoc)
+(5.1) Building documentation
 
-The API documentation can be easily built:
+The documentation web application is built during the default "deploy"
+build.
+
+It can be built quickly by using the following commands:
+
+    cd ${tomcat.source}
+    ant build-docs
+
+The output of this command will be found in the following directory:
+
+    output/build/webapps/docs
+
+
+The API documentation (Javadoc) is built during a "release" build. It is
+easy to build it separately by using the following commands:
 
     cd ${tomcat.source}
     ant javadoc
@@ -209,13 +225,24 @@ The output of this command will be found in the following directories:
     output/dist/webapps/docs/jspapi
     output/dist/webapps/docs/servletapi
 
+
 (5.2) Building the extras (commons-logging, webservices etc.)
 
+These components are documented on the "Additional Components"
+(extras.html) page of documentation. They are built during a "release"
+build.
+
+You can build them by using the following commands:
+
     cd ${tomcat.source}
     ant extras
 
 (5.3) Building the embedded packages
 
+These are built during a "release" build.
+
+You can build them by using the following commands:
+
     cd ${tomcat.source}
     ant embed
 
diff --git a/RUNNING.txt b/RUNNING.txt
index 9492304..d909928 100644
--- a/RUNNING.txt
+++ b/RUNNING.txt
@@ -15,7 +15,7 @@
   limitations under the License.
 ================================================================================
 
-$Id: RUNNING.txt 1430483 2013-01-08 20:19:13Z kkolinko $
+$Id: RUNNING.txt 1456725 2013-03-14 23:48:06Z kkolinko $
 
             ===================================================
             Running The Apache Tomcat @VERSION_MAJOR_MINOR@ Servlet/JSP Container
@@ -314,6 +314,8 @@ The file will look like the following:
   <?xml version="1.0" encoding="UTF-8"?>
   <Context docBase="${catalina.home}/webapps/manager"
     antiResourceLocking="false" privileged="true" >
+    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
+         allow="127\.0\.0\.1" />
   </Context>
 
 See Deployer chapter in User Guide and Context and Host chapters in the
diff --git a/STATUS.txt b/STATUS.txt
index 1db902c..0156de9 100644
--- a/STATUS.txt
+++ b/STATUS.txt
@@ -48,3 +48,10 @@ PATCHES PROPOSED TO BACKPORT:
   http://svn.apache.org/viewvc?rev=1430602&view=rev
   +1: markt
   -1:
+
+* Back-port r1437083 from trunk.
+  http://svn.apache.org/viewvc?view=revision&revision=1437083
+  Adds SSLContext.clearOptions method to allow clearing of SSL_OP_* options
+  in OpenSSL.
+  This will require tcnative 1.1.25 or errors may be thrown when attempting
+  to call this method.
diff --git a/bin/catalina.sh b/bin/catalina.sh
index 1690c14..f005b76 100755
--- a/bin/catalina.sh
+++ b/bin/catalina.sh
@@ -94,7 +94,7 @@
 #                   Example (all one line)
 #                   LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
 #
-# $Id: catalina.sh 1202062 2011-11-15 06:50:02Z mturk $
+# $Id: catalina.sh 1449412 2013-02-23 21:31:48Z kkolinko $
 # -----------------------------------------------------------------------------
 
 # OS specific support.  $var _must_ be set to either true or false.
@@ -228,9 +228,7 @@ if [ -z "$LOGGING_CONFIG" ]; then
 fi
 
 if [ -z "$LOGGING_MANAGER" ]; then
-  JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
-else
-  JAVA_OPTS="$JAVA_OPTS $LOGGING_MANAGER"
+  LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
 fi
 
 # Uncomment the following line to make the umask available when using the
@@ -283,7 +281,7 @@ if [ "$1" = "debug" ] ; then
         echo "Using Security Manager"
       fi
       shift
-      exec "$_RUNJDB" "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS \
+      exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
         -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
         -sourcepath "$CATALINA_HOME"/../../java \
         -Djava.security.manager \
@@ -293,7 +291,7 @@ if [ "$1" = "debug" ] ; then
         -Djava.io.tmpdir="$CATALINA_TMPDIR" \
         org.apache.catalina.startup.Bootstrap "$@" start
     else
-      exec "$_RUNJDB" "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS \
+      exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
         -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
         -sourcepath "$CATALINA_HOME"/../../java \
         -Dcatalina.base="$CATALINA_BASE" \
@@ -311,7 +309,7 @@ elif [ "$1" = "run" ]; then
       echo "Using Security Manager"
     fi
     shift
-    eval exec \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $JAVA_OPTS $CATALINA_OPTS \
+    eval exec \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
       -Djava.endorsed.dirs=\"$JAVA_ENDORSED_DIRS\" -classpath \"$CLASSPATH\" \
       -Djava.security.manager \
       -Djava.security.policy==\"$CATALINA_BASE/conf/catalina.policy\" \
@@ -320,7 +318,7 @@ elif [ "$1" = "run" ]; then
       -Djava.io.tmpdir=\"$CATALINA_TMPDIR\" \
       org.apache.catalina.startup.Bootstrap "$@" start
   else
-    eval exec \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $JAVA_OPTS $CATALINA_OPTS \
+    eval exec \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
       -Djava.endorsed.dirs=\"$JAVA_ENDORSED_DIRS\" -classpath \"$CLASSPATH\" \
       -Dcatalina.base=\"$CATALINA_BASE\" \
       -Dcatalina.home=\"$CATALINA_HOME\" \
@@ -375,7 +373,7 @@ elif [ "$1" = "start" ] ; then
       echo "Using Security Manager"
     fi
     shift
-    eval \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $JAVA_OPTS $CATALINA_OPTS \
+    eval \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
       -Djava.endorsed.dirs=\"$JAVA_ENDORSED_DIRS\" -classpath \"$CLASSPATH\" \
       -Djava.security.manager \
       -Djava.security.policy==\"$CATALINA_BASE/conf/catalina.policy\" \
@@ -386,7 +384,7 @@ elif [ "$1" = "start" ] ; then
       >> "$CATALINA_OUT" 2>&1 "&"
 
   else
-    eval \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $JAVA_OPTS $CATALINA_OPTS \
+    eval \"$_RUNJAVA\" \"$LOGGING_CONFIG\" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
       -Djava.endorsed.dirs=\"$JAVA_ENDORSED_DIRS\" -classpath \"$CLASSPATH\" \
       -Dcatalina.base=\"$CATALINA_BASE\" \
       -Dcatalina.home=\"$CATALINA_HOME\" \
@@ -436,7 +434,7 @@ elif [ "$1" = "stop" ] ; then
     fi
   fi
 
-  eval \"$_RUNJAVA\" $JAVA_OPTS \
+  eval \"$_RUNJAVA\" $LOGGING_MANAGER $JAVA_OPTS \
     -Djava.endorsed.dirs=\"$JAVA_ENDORSED_DIRS\" -classpath \"$CLASSPATH\" \
     -Dcatalina.base=\"$CATALINA_BASE\" \
     -Dcatalina.home=\"$CATALINA_HOME\" \
@@ -489,7 +487,7 @@ elif [ "$1" = "stop" ] ; then
 
 elif [ "$1" = "configtest" ] ; then
 
-    eval \"$_RUNJAVA\" $JAVA_OPTS \
+    eval \"$_RUNJAVA\" $LOGGING_MANAGER $JAVA_OPTS \
       -Djava.endorsed.dirs=\"$JAVA_ENDORSED_DIRS\" -classpath \"$CLASSPATH\" \
       -Dcatalina.base=\"$CATALINA_BASE\" \
       -Dcatalina.home=\"$CATALINA_HOME\" \
diff --git a/build.properties.default b/build.properties.default
index 3e1a0a8..d7b3245 100644
--- a/build.properties.default
+++ b/build.properties.default
@@ -21,13 +21,13 @@
 # modules that Tomcat depends on.  Copy this file to "build.properties"
 # in the top-level source directory, and customize it as needed.
 #
-# $Id: build.properties.default 1431695 2013-01-10 22:12:08Z markt $
+# $Id: build.properties.default 1459741 2013-03-22 12:32:01Z markt $
 # -----------------------------------------------------------------------------
 
 # ----- Version Control Flags -----
 version.major=7
 version.minor=0
-version.build=35
+version.build=39
 version.patch=0
 version.suffix=
 
@@ -132,7 +132,7 @@ jdt.loc.1=http://archive.eclipse.org/eclipse/downloads/drops4/${jdt.release}/ecj
 jdt.loc.2=http://download.eclipse.org/eclipse/downloads/drops4/${jdt.release}/ecj-${jdt.version}.jar
 
 # ----- Tomcat native library -----
-tomcat-native.version=1.1.24
+tomcat-native.version=1.1.27
 tomcat-native.home=${base.path}/tomcat-native-${tomcat-native.version}
 tomcat-native.tar.gz=${tomcat-native.home}/tomcat-native.tar.gz
 tomcat-native.loc.1=${base-tomcat.loc.1}/tomcat-connectors/native/${tomcat-native.version}/source/tomcat-native-${tomcat-native.version}-src.tar.gz
@@ -161,7 +161,7 @@ nsis.nsisdl.dll=${nsis.home}/Plugins/NSISdl.dll
 nsis.loc=${base-sf.loc}/nsis/nsis-2.46.zip
 
 # ----- Commons Daemon, version 1.0-Alpha or later -----
-commons-daemon.version=1.0.10
+commons-daemon.version=1.0.14
 commons-daemon.home=${base.path}/commons-daemon-${commons-daemon.version}
 commons-daemon.jar=${commons-daemon.home}/commons-daemon-${commons-daemon.version}.jar
 commons-daemon.native.win.home=${commons-daemon.home}/windows
@@ -175,7 +175,7 @@ commons-daemon.native.src.loc.2=${base-commons.loc.2}/daemon/source/commons-daem
 commons-daemon.native.win.loc.1=${base-commons.loc.1}/daemon/binaries/windows/commons-daemon-${commons-daemon.version}-bin-windows.zip
 commons-daemon.native.win.loc.2=${base-commons.loc.2}/daemon/binaries/windows/commons-daemon-${commons-daemon.version}-bin-windows.zip
 
-# ----- JUnit Unit Test Suite, version 3.7 or later -----
+# ----- JUnit Unit Test Suite, version 4.8 or later -----
 junit.home=${base.path}/junit4.8.2
 junit.lib=${junit.home}
 junit.jar=${junit.lib}/junit-4.8.2.jar
diff --git a/build.xml b/build.xml
index 01b7113..6b0d15d 100644
--- a/build.xml
+++ b/build.xml
@@ -1662,7 +1662,7 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
       <link href="../jspapi"/>
       <link href="../elapi"/>
       <link href="http://docs.oracle.com/javase/6/docs/api/"/>
-      <link href="http://commons.apache.org/io/api-release/"/>
+      <link href="http://commons.apache.org/proper/commons-io/javadocs/api-release/"/>
       <link href="http://docs.oracle.com/javaee/6/api/"/>
       <sourcepath>
         <path location="${tomcat.dist}/src/java"/>
diff --git a/conf/catalina.properties b/conf/catalina.properties
index 42c62d1..2e64815 100644
--- a/conf/catalina.properties
+++ b/conf/catalina.properties
@@ -87,9 +87,6 @@ shared.loader=
 # - Jasper JARs
 # - Tomcat JARs
 # - Common non-Tomcat JARs
-# - Sun JDK JARs
-# - OpenJDK JARs
-# - Apple JDK JARs
 tomcat.util.scan.DefaultJarScanner.jarsToSkip=\
 bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\
 annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,\
@@ -109,13 +106,6 @@ geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\
 ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\
 jmx-tools.jar,jta*.jar,log4j*.jar,mail*.jar,slf4j*.jar,\
 xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\
-access-bridge.jar,access-bridge-64.jar,dnsns.jar,jaccess.jar,ldapsec.jar,localedata.jar,\
-sunjce_provider.jar,sunmscapi.jar,sunpkcs11.jar,jhall.jar,tools.jar,\
-sunec.jar,zipfs.jar,\
-gnome-java-bridge.jar,pulse-java.jar,\
-apple_provider.jar,AppleScriptEngine.jar,CoreAudio.jar,dns_sd.jar,\
-j3daudio.jar,j3dcore.jar,j3dutils.jar,jai_core.jar,jai_codec.jar,\
-mlibwrapper_jai.jar,MRJToolkit.jar,vecmath.jar,\
 junit.jar,junit-*.jar,ant-launcher.jar
 
 # Additional JARs (over and above the default JARs listed above) to skip when
diff --git a/java/javax/servlet/http/HttpServlet.java b/java/javax/servlet/http/HttpServlet.java
index e3a448f..8305d50 100644
--- a/java/javax/servlet/http/HttpServlet.java
+++ b/java/javax/servlet/http/HttpServlet.java
@@ -750,8 +750,12 @@ class NoBodyResponse extends HttpServletResponseWrapper {
 
     // file private
     void setContentLength() {
-        if (!didSetContentLength)
-          super.setContentLength(noBody.getContentLength());
+        if (!didSetContentLength) {
+            if (writer != null) {
+                writer.flush();
+            }
+            super.setContentLength(noBody.getContentLength());
+        }
     }
 
 
diff --git a/java/javax/servlet/http/Part.java b/java/javax/servlet/http/Part.java
index 3e60e40..cbb51c8 100644
--- a/java/javax/servlet/http/Part.java
+++ b/java/javax/servlet/http/Part.java
@@ -21,24 +21,87 @@ import java.io.InputStream;
 import java.util.Collection;
 
 /**
+ * This class represents a part as uploaded to the server as part of a
+ * <code>multipart/form-data</code> request body. The part may represent either
+ * an uploaded file or form data.
+ *
  * @since Servlet 3.0
- * TODO SERVLET3 - Add comments
  */
 public interface Part {
+
+    /**
+     * Obtain an <code>InputStream</code> that can be used to retrieve the
+     * contents of the file.
+     */
     public InputStream getInputStream() throws IOException;
+
+    /**
+     * Obtain the content type passed by the browser or <code>null</code> if not
+     * defined.
+     */
     public String getContentType();
+
+    /**
+     * Obtain the name of the field in the multipart form corresponding to this
+     * part.
+     */
     public String getName();
+
+    /**
+     * Obtain the size of this part.
+     */
     public long getSize();
+
+    /**
+     * A convenience method to write an uploaded part to disk. The client code
+     * is not concerned with whether or not the part is stored in memory, or on
+     * disk in a temporary location. They just want to write the uploaded part
+     * to a file.
+     *
+     *  This method is not guaranteed to succeed if called more than once for
+     *  the same part. This allows a particular implementation to use, for
+     *  example, file renaming, where possible, rather than copying all of the
+     *  underlying data, thus gaining a significant performance benefit.
+     *
+     * @param fileName  The location into which the uploaded part should be
+     *                  stored. Relative locations are relative to {@link
+     *                  javax.servlet.MultipartConfigElement#getLocation()}
+     */
     public void write(String fileName) throws IOException;
+
+    /**
+     * Deletes the underlying storage for a part, including deleting any
+     * associated temporary disk file. Although the container will delete this
+     * storage automatically this method can be used to ensure that this is done
+     * at an earlier time, thus preserving system resources.
+     * <p>
+     * Containers are only required to delete the associated storage when the
+     * Part instance is garbage collected. Apache Tomcat will delete the
+     * associated storage when the associated request has finished processing.
+     * Behaviour of other containers may be different.
+     */
     public void delete() throws IOException;
     
     /**
-     * Obtains the value of the specified mime header for the part.
-     * @param name Header name
-     * @return The header value or <code>null</code> if the header is not
-     *         present
+     * Obtains the value of the specified part header as a String. If there are
+     * multiple headers with the same name, this method returns the first header
+     * in the part. The header name is case insensitive.
+     *
+     * @param name  Header name
+     * @return      The header value or <code>null</code> if the header is not
+     *              present
      */
     public String getHeader(String name);
+
+    /**
+     * Obtain all the values of the specified part header. If the part did not
+     * include any headers of the specified name, this method returns an empty
+     * Collection. The header name is case insensitive.
+     */
     public Collection<String> getHeaders(String name);
+
+    /**
+     * Returns a Collection of all the header names provided for this part.
+     */
     public Collection<String> getHeaderNames();
 }
diff --git a/java/org/apache/catalina/ant/AbstractCatalinaTask.java b/java/org/apache/catalina/ant/AbstractCatalinaTask.java
index abd4039..cce0d37 100644
--- a/java/org/apache/catalina/ant/AbstractCatalinaTask.java
+++ b/java/org/apache/catalina/ant/AbstractCatalinaTask.java
@@ -26,9 +26,9 @@ import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLConnection;
-import java.nio.charset.Charset;
 
-import org.apache.catalina.util.Base64;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.codec.binary.Base64;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 
@@ -39,7 +39,7 @@ import org.apache.tools.ant.Project;
  * undeploying applications.  These tasks require Ant 1.4 or later.
  *
  * @author Craig R. McClanahan
- * @version $Id: AbstractCatalinaTask.java 1138019 2011-06-21 14:29:49Z markt $
+ * @version $Id: AbstractCatalinaTask.java 1459346 2013-03-21 15:05:54Z markt $
  * @since 4.1
  */
 
@@ -201,8 +201,8 @@ public abstract class AbstractCatalinaTask extends BaseRedirectorHelperTask {
 
             // Set up an authorization header with our credentials
             String input = username + ":" + password;
-            String output =
-                Base64.encode(input.getBytes(Charset.defaultCharset()));
+            String output = Base64.encodeBase64String(
+                    input.getBytes(B2CConverter.ISO_8859_1));
             hconn.setRequestProperty("Authorization",
                                      "Basic " + output);
 
diff --git a/java/org/apache/catalina/authenticator/BasicAuthenticator.java b/java/org/apache/catalina/authenticator/BasicAuthenticator.java
index d9f265b..9930fe0 100644
--- a/java/org/apache/catalina/authenticator/BasicAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/BasicAuthenticator.java
@@ -27,12 +27,12 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.deploy.LoginConfig;
-import org.apache.catalina.util.Base64;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.CharChunk;
 import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.codec.binary.Base64;
 
 
 
@@ -42,7 +42,7 @@ import org.apache.tomcat.util.buf.MessageBytes;
  * and Digest Access Authentication."
  *
  * @author Craig R. McClanahan
- * @version $Id: BasicAuthenticator.java 1189224 2011-10-26 14:02:40Z kkolinko $
+ * @version $Id: BasicAuthenticator.java 1459346 2013-03-21 15:05:54Z markt $
  */
 
 public class BasicAuthenticator
@@ -135,21 +135,29 @@ public class BasicAuthenticator
             ByteChunk authorizationBC = authorization.getByteChunk();
             if (authorizationBC.startsWithIgnoreCase("basic ", 0)) {
                 authorizationBC.setOffset(authorizationBC.getOffset() + 6);
-                // FIXME: Add trimming
-                // authorizationBC.trim();
                 
-                CharChunk authorizationCC = authorization.getCharChunk();
-                Base64.decode(authorizationBC, authorizationCC);
+                byte[] decoded = Base64.decodeBase64(
+                        authorizationBC.getBuffer(),
+                        authorizationBC.getOffset(),
+                        authorizationBC.getLength());
                 
                 // Get username and password
-                int colon = authorizationCC.indexOf(':');
+                int colon = -1;
+                for (int i = 0; i < decoded.length; i++) {
+                    if (decoded[i] == ':') {
+                        colon = i;
+                        break;
+                    }
+                }
+
                 if (colon < 0) {
-                    username = authorizationCC.toString();
+                    username = new String(decoded, B2CConverter.ISO_8859_1);
                 } else {
-                    char[] buf = authorizationCC.getBuffer();
-                    username = new String(buf, 0, colon);
-                    password = new String(buf, colon + 1, 
-                            authorizationCC.getEnd() - colon - 1);
+                    username = new String(
+                            decoded, 0, colon, B2CConverter.ISO_8859_1);
+                    password = new String(
+                            decoded, colon + 1, decoded.length - colon - 1,
+                            B2CConverter.ISO_8859_1);
                 }
                 
                 authorizationBC.setOffset(authorizationBC.getOffset() - 6);
diff --git a/java/org/apache/catalina/authenticator/DigestAuthenticator.java b/java/org/apache/catalina/authenticator/DigestAuthenticator.java
index 644d3de..ea8b39d 100644
--- a/java/org/apache/catalina/authenticator/DigestAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/DigestAuthenticator.java
@@ -50,7 +50,7 @@ import org.apache.tomcat.util.http.parser.HttpParser;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: DigestAuthenticator.java 1405416 2012-11-03 20:55:42Z markt $
+ * @version $Id: DigestAuthenticator.java 1443407 2013-02-07 11:03:34Z markt $
  */
 
 public class DigestAuthenticator extends AuthenticatorBase {
@@ -114,6 +114,14 @@ public class DigestAuthenticator extends AuthenticatorBase {
 
 
     /**
+     * The last timestamp used to generate a nonce. Each nonce should get a
+     * unique timestamp.
+     */
+    protected long lastTimestamp = 0;
+    protected final Object lastTimestampLock = new Object();
+
+
+    /**
      * Maximum number of server nonces to keep in the cache. If not specified,
      * the default value of 1000 is used.
      */
@@ -399,6 +407,13 @@ public class DigestAuthenticator extends AuthenticatorBase {
 
         long currentTime = System.currentTimeMillis();
 
+        synchronized (lastTimestampLock) {
+            if (currentTime > lastTimestamp) {
+                lastTimestamp = currentTime;
+            } else {
+                currentTime = ++lastTimestamp;
+            }
+        }
 
         String ipTimeKey =
             request.getRemoteAddr() + ":" + currentTime + ":" + getKey();
diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
index b4497d7..849c4fc 100644
--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
@@ -52,7 +52,7 @@ import org.apache.tomcat.util.http.MimeHeaders;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: FormAuthenticator.java 1408044 2012-11-11 16:42:02Z kkolinko $
+ * @version $Id: FormAuthenticator.java 1453546 2013-03-06 20:48:18Z markt $
  */
 
 public class FormAuthenticator
@@ -539,6 +539,16 @@ public class FormAuthenticator
             return (false);
         }
 
+        // Swallow any request body since we will be replacing it
+        // Need to do this before headers are restored as AJP connector uses
+        // content length header to determine how much data needs to be read for
+        // request body
+        byte[] buffer = new byte[4096];
+        InputStream is = request.createInputStream();
+        while (is.read(buffer) >= 0) {
+            // Ignore request body
+        }
+
         // Modify our current request to reflect the original one
         request.clearCookies();
         Iterator<Cookie> cookies = saved.getCookies();
@@ -576,13 +586,6 @@ public class FormAuthenticator
         request.getCoyoteRequest().getParameters().setQueryStringEncoding(
                 request.getConnector().getURIEncoding());
 
-        // Swallow any request body since we will be replacing it
-        byte[] buffer = new byte[4096];
-        InputStream is = request.createInputStream();
-        while (is.read(buffer) >= 0) {
-            // Ignore request body
-        }
-
         ByteChunk body = saved.getBody();
 
         if (body != null) {
diff --git a/java/org/apache/catalina/authenticator/SingleSignOn.java b/java/org/apache/catalina/authenticator/SingleSignOn.java
index 2ec35b5..bce3051 100644
--- a/java/org/apache/catalina/authenticator/SingleSignOn.java
+++ b/java/org/apache/catalina/authenticator/SingleSignOn.java
@@ -55,7 +55,7 @@ import org.apache.tomcat.util.res.StringManager;
  * </ul>
  *
  * @author Craig R. McClanahan
- * @version $Id: SingleSignOn.java 1188401 2011-10-24 21:50:26Z markt $
+ * @version $Id: SingleSignOn.java 1439783 2013-01-29 08:29:57Z kfujino $
  */
 
 public class SingleSignOn extends ValveBase implements SessionListener {
@@ -214,6 +214,10 @@ public class SingleSignOn extends ValveBase implements SessionListener {
     @Override
     public void sessionEvent(SessionEvent event) {
 
+        if (!getState().isAvailable()) {
+            return;
+        }
+
         // We only care about session destroyed events
         if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
                 && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType())))
@@ -238,7 +242,8 @@ public class SingleSignOn extends ValveBase implements SessionListener {
         if (((session.getMaxInactiveInterval() > 0)
             && (System.currentTimeMillis() - session.getThisAccessedTimeInternal() >=
                 session.getMaxInactiveInterval() * 1000)) 
-            || (Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) {
+            || (Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))
+            || (!session.getManager().getContainer().getState().isAvailable())) {
             removeSession(ssoId, session);
         } else {
             // The session was logged out.
diff --git a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
index e6aba7b..bc1e64e 100644
--- a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
@@ -32,11 +32,11 @@ import org.apache.catalina.LifecycleException;
 import org.apache.catalina.connector.Request;
 import org.apache.catalina.deploy.LoginConfig;
 import org.apache.catalina.startup.Bootstrap;
-import org.apache.catalina.util.Base64;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.codec.binary.Base64;
 import org.ietf.jgss.GSSContext;
 import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
@@ -190,13 +190,12 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
         }
 
         authorizationBC.setOffset(authorizationBC.getOffset() + 10);
-        // FIXME: Add trimming
-        // authorizationBC.trim();
                 
-        ByteChunk decoded = new ByteChunk();
-        Base64.decode(authorizationBC, decoded);
+        byte[] decoded = Base64.decodeBase64(authorizationBC.getBuffer(),
+                authorizationBC.getOffset(),
+                authorizationBC.getLength());
 
-        if (decoded.getLength() == 0) {
+        if (decoded.length == 0) {
             if (log.isDebugEnabled()) {
                 log.debug(sm.getString(
                         "spnegoAuthenticator.authHeaderNoToken"));
@@ -235,8 +234,7 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
                 };
             gssContext = manager.createContext(Subject.doAs(lc.getSubject(), action));
 
-            outToken = gssContext.acceptSecContext(decoded.getBytes(),
-                    decoded.getOffset(), decoded.getLength());
+            outToken = gssContext.acceptSecContext(decoded, 0, decoded.length);
 
             if (outToken == null) {
                 if (log.isDebugEnabled()) {
@@ -283,7 +281,7 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
 
         // Send response token on success and failure
         response.setHeader("WWW-Authenticate", "Negotiate "
-                + Base64.encode(outToken));
+                + Base64.encodeBase64String(outToken));
 
         if (principal != null) {
             register(request, response, principal, Constants.SPNEGO_METHOD,
diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java
index 1c7bf2b..2b7966f 100644
--- a/java/org/apache/catalina/connector/CoyoteAdapter.java
+++ b/java/org/apache/catalina/connector/CoyoteAdapter.java
@@ -23,6 +23,7 @@ import java.util.EnumSet;
 
 import javax.servlet.RequestDispatcher;
 import javax.servlet.SessionTrackingMode;
+import javax.servlet.http.HttpServletResponse;
 
 import org.apache.catalina.Context;
 import org.apache.catalina.Host;
@@ -55,7 +56,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: CoyoteAdapter.java 1409036 2012-11-13 23:55:26Z markt $
+ * @version $Id: CoyoteAdapter.java 1452797 2013-03-05 14:04:57Z markt $
  */
 public class CoyoteAdapter implements Adapter {
 
@@ -980,28 +981,30 @@ public class CoyoteAdapter implements Adapter {
             B2CConverter conv = request.getURIConverter();
             try {
                 if (conv == null) {
-                    conv = new B2CConverter(enc);
+                    conv = new B2CConverter(enc, true);
                     request.setURIConverter(conv);
+                } else {
+                    conv.recycle();
                 }
             } catch (IOException e) {
-                // Ignore
                 log.error("Invalid URI encoding; using HTTP default");
                 connector.setURIEncoding(null);
             }
             if (conv != null) {
                 try {
-                    conv.convert(bc, cc, cc.getBuffer().length - cc.getEnd());
-                    uri.setChars(cc.getBuffer(), cc.getStart(),
-                                 cc.getLength());
+                    conv.convert(bc, cc, true);
+                    uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength());
                     return;
-                } catch (IOException e) {
-                    log.error("Invalid URI character encoding; trying ascii");
-                    cc.recycle();
+                } catch (IOException ioe) {
+                    // Should never happen as B2CConverter should replace
+                    // problematic characters
+                    request.getResponse().sendError(
+                            HttpServletResponse.SC_BAD_REQUEST);
                 }
             }
         }
 
-        // Default encoding: fast conversion
+        // Default encoding: fast conversion for ISO-8859-1
         byte[] bbuf = bc.getBuffer();
         char[] cbuf = cc.getBuffer();
         int start = bc.getStart();
@@ -1009,7 +1012,6 @@ public class CoyoteAdapter implements Adapter {
             cbuf[i] = (char) (bbuf[i + start] & 0xff);
         }
         uri.setChars(cbuf, 0, length);
-
     }
 
 
diff --git a/java/org/apache/catalina/connector/InputBuffer.java b/java/org/apache/catalina/connector/InputBuffer.java
index 0829742..14f89cb 100644
--- a/java/org/apache/catalina/connector/InputBuffer.java
+++ b/java/org/apache/catalina/connector/InputBuffer.java
@@ -347,27 +347,37 @@ public class InputBuffer extends Reader
             setConverter();
         }
 
+        boolean eof = false;
+
         if (bb.getLength() <= 0) {
             int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
             if (nRead < 0) {
-                return -1;
+                eof = true;
             }
         }
 
         if (markPos == -1) {
             cb.setOffset(0);
             cb.setEnd(0);
+        } else {
+            // Make sure there's enough space in the worst case
+            cb.makeSpace(bb.getLength());
+            if ((cb.getBuffer().length - cb.getEnd()) == 0) {
+                // We went over the limit
+                cb.setOffset(0);
+                cb.setEnd(0);
+                markPos = -1;
+            }
         }
-        int limit = bb.getLength()+cb.getStart();
-        if ( cb.getLimit() < limit ) {
-            cb.setLimit(limit);
-        }
-        state = CHAR_STATE;
-        conv.convert(bb, cb, bb.getLength());
-        bb.setOffset(bb.getEnd());
 
-        return cb.getLength();
+        state = CHAR_STATE;
+        conv.convert(bb, cb, eof);
 
+        if (cb.getLength() == 0 && eof) {
+            return -1;
+        } else {
+            return cb.getLength();
+        }
     }
 
 
diff --git a/java/org/apache/catalina/connector/OutputBuffer.java b/java/org/apache/catalina/connector/OutputBuffer.java
index f214281..1f68431 100644
--- a/java/org/apache/catalina/connector/OutputBuffer.java
+++ b/java/org/apache/catalina/connector/OutputBuffer.java
@@ -29,6 +29,7 @@ import org.apache.coyote.ActionCode;
 import org.apache.coyote.Response;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.CharChunk;
 
 
 /**
@@ -40,7 +41,7 @@ import org.apache.tomcat.util.buf.C2BConverter;
  * @author Remy Maucherat
  */
 public class OutputBuffer extends Writer
-    implements ByteChunk.ByteOutputChannel {
+    implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel {
 
 
     // -------------------------------------------------------------- Constants
@@ -61,6 +62,12 @@ public class OutputBuffer extends Writer
 
 
     /**
+     * The chunk buffer.
+     */
+    private final CharChunk cb;
+
+
+    /**
      * State of the output buffer.
      */
     private boolean initial = true;
@@ -97,6 +104,12 @@ public class OutputBuffer extends Writer
 
 
     /**
+     * Char chunk used to output chars.
+     */
+    private CharChunk outputCharChunk = new CharChunk();
+
+
+    /**
      * Encoding to use.
      */
     private String enc;
@@ -156,6 +169,10 @@ public class OutputBuffer extends Writer
         bb = new ByteChunk(size);
         bb.setLimit(size);
         bb.setByteOutputChannel(this);
+        cb = new CharChunk(size);
+        cb.setLimit(size);
+        cb.setOptimizedWrite(false);
+        cb.setCharOutputChannel(this);
 
     }
 
@@ -225,16 +242,18 @@ public class OutputBuffer extends Writer
         initial = true;
         bytesWritten = 0;
         charsWritten = 0;
-
+        
         bb.recycle();
+        cb.recycle();
+        outputCharChunk.setChars(null, 0, 0);
         closed = false;
-        doFlush = false;
         suspended = false;
-
+        doFlush = false;
+        
         if (conv!= null) {
             conv.recycle();
         }
-
+        
         gotEnc = false;
         enc = null;
 
@@ -266,9 +285,10 @@ public class OutputBuffer extends Writer
             return;
         }
 
-        // Flush the convertor if one is in use
-        if (gotEnc && conv != null) {
-            conv.flushBuffer();
+        // If there are chars, flush all of them to the byte buffer now as bytes are used to
+        // calculate the content-length (if everything fits into the byte buffer, of course).
+        if (cb.getLength() > 0) {
+            cb.flushBuffer();
         }
 
         if ((!coyoteResponse.isCommitted())
@@ -319,17 +339,15 @@ public class OutputBuffer extends Writer
             return;
         }
 
-        // Flush the convertor if one is in use
-        if (gotEnc && conv != null) {
-            conv.flushBuffer();
-        }
-
         try {
             doFlush = true;
             if (initial) {
                 coyoteResponse.sendHeaders();
                 initial = false;
             }
+            if (cb.getLength() > 0) {
+                cb.flushBuffer();
+            }
             if (bb.getLength() > 0) {
                 bb.flushBuffer();
             }
@@ -438,6 +456,33 @@ public class OutputBuffer extends Writer
     // ------------------------------------------------- Chars Handling Methods
 
 
+    /** 
+     * Convert the chars to bytes, then send the data to the client.
+     * 
+     * @param buf Char buffer to be written to the response
+     * @param off Offset
+     * @param len Length
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    @Override
+    public void realWriteChars(char buf[], int off, int len)
+        throws IOException {
+
+        outputCharChunk.setChars(buf, off, len);
+        while (outputCharChunk.getLength() > 0) { 
+            conv.convert(outputCharChunk, bb);
+            if (bb.getLength() == 0) {
+                // Break out of the loop if more chars are needed to produce any output
+                break;
+            }
+            if (outputCharChunk.getLength() > 0) {
+                bb.flushBuffer();
+            }
+        }
+
+    }
+
     @Override
     public void write(int c)
         throws IOException {
@@ -446,7 +491,7 @@ public class OutputBuffer extends Writer
             return;
         }
 
-        conv.convert((char) c);
+        cb.append((char) c);
         charsWritten++;
 
     }
@@ -473,7 +518,7 @@ public class OutputBuffer extends Writer
             return;
         }
 
-        conv.convert(c, off, len);
+        cb.append(c, off, len);
         charsWritten += len;
 
     }
@@ -494,7 +539,8 @@ public class OutputBuffer extends Writer
         if (s == null) {
             s = "null";
         }
-        conv.convert(s, off, len);
+        cb.append(s, off, len);
+        charsWritten += len;
     }
 
 
@@ -509,7 +555,8 @@ public class OutputBuffer extends Writer
         if (s == null) {
             s = "null";
         }
-        conv.convert(s);
+        cb.append(s);
+        charsWritten += s.length();
     }
 
 
@@ -541,7 +588,6 @@ public class OutputBuffer extends Writer
         }
         conv = encoders.get(enc);
         if (conv == null) {
-
             if (Globals.IS_SECURITY_ENABLED){
                 try{
                     conv = AccessController.doPrivileged(
@@ -549,7 +595,7 @@ public class OutputBuffer extends Writer
 
                                 @Override
                                 public C2BConverter run() throws IOException{
-                                    return new C2BConverter(bb, enc);
+                                    return new C2BConverter(enc);
                                 }
 
                             }
@@ -561,7 +607,7 @@ public class OutputBuffer extends Writer
                     }
                 }
             } else {
-                conv = new C2BConverter(bb, enc);
+                conv = new C2BConverter(enc);
             }
 
             encoders.put(enc, conv);
@@ -598,11 +644,8 @@ public class OutputBuffer extends Writer
     }
 
     public void reset(boolean resetWriterStreamFlags) {
-        // If a Writer was being used, there may be bytes in the converter
-        if (gotEnc && conv != null) {
-            conv.recycle();
-        }
         bb.recycle();
+        cb.recycle();
         bytesWritten = 0;
         charsWritten = 0;
         if (resetWriterStreamFlags) {
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index 151b72f..da41c8c 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -91,6 +91,7 @@ import org.apache.tomcat.util.http.fileupload.FileUploadBase.InvalidContentTypeE
 import org.apache.tomcat.util.http.fileupload.FileUploadException;
 import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
 import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
+import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
 import org.apache.tomcat.util.http.mapper.MappingData;
 import org.apache.tomcat.util.res.StringManager;
 
@@ -100,7 +101,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Craig R. McClanahan
- * @version $Id: Request.java 1356509 2012-07-02 22:43:32Z kkolinko $
+ * @version $Id: Request.java 1456935 2013-03-15 12:47:29Z markt $
  */
 
 public class Request
@@ -737,7 +738,7 @@ public class Request
     }
 
     /**
-     * URI byte to char converter (not recycled).
+     * URI byte to char converter.
      */
     protected B2CConverter URIConverter = null;
 
@@ -1939,7 +1940,6 @@ public class Request
      *
      * @return the URL decoded request URI
      */
-    @Deprecated
     public MessageBytes getDecodedRequestURIMB() {
         return coyoteRequest.decodedURI();
     }
@@ -2719,7 +2719,8 @@ public class Request
 
             parts = new ArrayList<Part>();
             try {
-                List<FileItem> items = upload.parseRequest(this);
+                List<FileItem> items =
+                        upload.parseRequest(new ServletRequestContext(this));
                 int maxPostSize = getConnector().getMaxPostSize();
                 int postSize = 0;
                 String enc = getCharacterEncoding();
@@ -2734,7 +2735,7 @@ public class Request
                 for (FileItem item : items) {
                     ApplicationPart part = new ApplicationPart(item, mce);
                     parts.add(part);
-                    if (part.getFilename() == null) {
+                    if (part.getSubmittedFileName() == null) {
                         String name = part.getName();
                         String value = null;
                         try {
diff --git a/java/org/apache/catalina/connector/Response.java b/java/org/apache/catalina/connector/Response.java
index 5c144a6..5e5b940 100644
--- a/java/org/apache/catalina/connector/Response.java
+++ b/java/org/apache/catalina/connector/Response.java
@@ -62,7 +62,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Craig R. McClanahan
- * @version $Id: Response.java 1405416 2012-11-03 20:55:42Z markt $
+ * @version $Id: Response.java 1452791 2013-03-05 13:41:19Z markt $
  */
 
 public class Response
@@ -1688,17 +1688,16 @@ public class Response
                 if (!leadingSlash) {
                     String relativePath = request.getDecodedRequestURI();
                     int pos = relativePath.lastIndexOf('/');
-                    relativePath = relativePath.substring(0, pos);
-
-                    String encodedURI = null;
+                    CharChunk encodedURI = null;
                     final String frelativePath = relativePath;
+                    final int fend = pos;
                     if (SecurityUtil.isPackageProtectionEnabled() ){
                         try{
                             encodedURI = AccessController.doPrivileged(
-                                new PrivilegedExceptionAction<String>(){
+                                new PrivilegedExceptionAction<CharChunk>(){
                                     @Override
-                                    public String run() throws IOException{
-                                        return urlEncoder.encodeURL(frelativePath);
+                                    public CharChunk run() throws IOException{
+                                        return urlEncoder.encodeURL(frelativePath, 0, fend);
                                     }
                            });
                         } catch (PrivilegedActionException pae){
@@ -1708,9 +1707,10 @@ public class Response
                             throw iae;
                         }
                     } else {
-                        encodedURI = urlEncoder.encodeURL(relativePath);
+                        encodedURI = urlEncoder.encodeURL(relativePath, 0, pos);
                     }
-                    redirectURLCC.append(encodedURI, 0, encodedURI.length());
+                    redirectURLCC.append(encodedURI);
+                    encodedURI.recycle();
                     redirectURLCC.append('/');
                 }
                 redirectURLCC.append(location, 0, location.length());
diff --git a/java/org/apache/catalina/core/ApplicationPart.java b/java/org/apache/catalina/core/ApplicationPart.java
index ac59775..a5ec758 100644
--- a/java/org/apache/catalina/core/ApplicationPart.java
+++ b/java/org/apache/catalina/core/ApplicationPart.java
@@ -128,10 +128,22 @@ public class ApplicationPart implements Part {
         return fileItem.getString(encoding);
     }
 
-    /*
-     * Adapted from FileUploadBase.getFileName()
+    /**
+     * Calls {@link #getSubmittedFileName()}.
+     *
+     * @deprecated Use {@link #getSubmittedFileName()} from Servlet 3.1 instead.
+     *             This method will be removed in Tomcat 8.
      */
+    @Deprecated
     public String getFilename() {
+        return getSubmittedFileName();
+    }
+
+    /**
+     * Adapted from FileUploadBase.getFileName(). Method name chosen to be
+     * consistent with Servlet 3.1.
+     */
+    public String getSubmittedFileName() {
         String fileName = null;
         String cd = getHeader("Content-Disposition");
         if (cd != null) {
diff --git a/java/org/apache/catalina/core/AprLifecycleListener.java b/java/org/apache/catalina/core/AprLifecycleListener.java
index 91acf09..bffbd1e 100644
--- a/java/org/apache/catalina/core/AprLifecycleListener.java
+++ b/java/org/apache/catalina/core/AprLifecycleListener.java
@@ -39,7 +39,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Filip Hanik
- * @version $Id: AprLifecycleListener.java 1353504 2012-06-25 13:01:53Z markt $
+ * @version $Id: AprLifecycleListener.java 1445210 2013-02-12 15:45:58Z markt $
  * @since 4.1
  */
 
@@ -62,7 +62,7 @@ public class AprLifecycleListener
     protected static final int TCN_REQUIRED_MINOR = 1;
     protected static final int TCN_REQUIRED_PATCH = 24;
     protected static final int TCN_RECOMMENDED_MINOR = 1;
-    protected static final int TCN_RECOMMENDED_PV = 24;
+    protected static final int TCN_RECOMMENDED_PV = 27;
 
 
     // ---------------------------------------------- Properties
diff --git a/java/org/apache/catalina/core/DefaultInstanceManager.java b/java/org/apache/catalina/core/DefaultInstanceManager.java
index 66a7e9e..5da6d7d 100644
--- a/java/org/apache/catalina/core/DefaultInstanceManager.java
+++ b/java/org/apache/catalina/core/DefaultInstanceManager.java
@@ -55,7 +55,7 @@ import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
- * @version $Id: DefaultInstanceManager.java 1431300 2013-01-10 11:47:49Z markt $
+ * @version $Id: DefaultInstanceManager.java 1437338 2013-01-23 11:02:35Z markt $
  */
 public class DefaultInstanceManager implements InstanceManager {
 
@@ -349,9 +349,9 @@ public class DefaultInstanceManager implements InstanceManager {
                                 annotations.add(new AnnotationCacheEntry(
                                         method.getName(),
                                         method.getParameterTypes(),
-                                        injections.get(method.getName()),
+                                        injections.get(fieldName),
                                         AnnotationCacheEntryType.SETTER));
-                                break;
+                                continue;
                             }
                         }
                         if (method.isAnnotationPresent(Resource.class)) {
diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties
index 2f84a84..6c1c275 100644
--- a/java/org/apache/catalina/core/LocalStrings.properties
+++ b/java/org/apache/catalina/core/LocalStrings.properties
@@ -153,6 +153,7 @@ standardContext.reloadingCompleted=Reloading Context with name [{0}] is complete
 standardContext.reloadingFailed=Reloading this Context failed due to previous errors
 standardContext.reloadingStarted=Reloading Context with name [{0}] has started
 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.servletMap.name=Servlet mapping specifies an unknown servlet name {0}
diff --git a/java/org/apache/catalina/core/LocalStrings_es.properties b/java/org/apache/catalina/core/LocalStrings_es.properties
index f63a994..0de9215 100644
--- a/java/org/apache/catalina/core/LocalStrings_es.properties
+++ b/java/org/apache/catalina/core/LocalStrings_es.properties
@@ -132,7 +132,7 @@ standardContext.notWrapper = El Hijo de un Contexto debe de ser un Arropador (Wr
 standardContext.parameter.duplicate = Duplicado par\u00E1metro de inicializaci\u00F3n de contexto [{0}]
 standardContext.parameter.required = Es necesario poner nombre de par\u00E1metro y valor de par\u00E1metro
 standardContext.pathInvalid = Una ruta de contexto debe de ser o una cadena vac\u00EDa o comenzar con "/". La ruta [{0}] no cumple con estos criterios y ha sido cambiada por [{1}]
-standardContext.reloadingCompleted = Se ha completado la Regarga de este Contexto
+standardContext.reloadingCompleted = Se ha completado la recarga de este Contexto
 standardContext.reloadingFailed = Fall\u00F3 la recarga de este Contexto debido a errores previos
 standardContext.reloadingStarted = Ha comenzado la recarga de Contexto [{0}]
 standardContext.resourcesStart = Error arrancando Recursos est\u00E1ticos
diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java
index 7075813..6cafb4f 100644
--- a/java/org/apache/catalina/core/StandardContext.java
+++ b/java/org/apache/catalina/core/StandardContext.java
@@ -127,7 +127,7 @@ import org.apache.tomcat.util.scan.StandardJarScanner;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: StandardContext.java 1431321 2013-01-10 12:36:17Z markt $
+ * @version $Id: StandardContext.java 1454958 2013-03-10 23:31:03Z markt $
  */
 
 public class StandardContext extends ContainerBase
@@ -4494,6 +4494,96 @@ public class StandardContext extends ContainerBase
         return result;
     }
 
+    /**
+     * Gets the maximum processing time of all servlets in this
+     * StandardContext.
+     *
+     * @return Maximum processing time of all servlets in this
+     * StandardContext
+     */
+    public long getMaxTime() {
+
+        long result = 0;
+        long time;
+
+        Container[] children = findChildren();
+        if (children != null) {
+            for( int i=0; i< children.length; i++ ) {
+                time = ((StandardWrapper)children[i]).getMaxTime();
+                if (time > result)
+                    result = time;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the minimum processing time of all servlets in this
+     * StandardContext.
+     *
+     * @return Minimum processing time of all servlets in this
+     * StandardContext
+     */
+    public long getMinTime() {
+
+        long result = -1;
+        long time;
+
+        Container[] children = findChildren();
+        if (children != null) {
+            for( int i=0; i< children.length; i++ ) {
+                time = ((StandardWrapper)children[i]).getMinTime();
+                if (result < 0 || time < result)
+                    result = time;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the cumulative request count of all servlets in this
+     * StandardContext.
+     *
+     * @return Cumulative request count of all servlets in this
+     * StandardContext
+     */
+    public int getRequestCount() {
+
+        int result = 0;
+
+        Container[] children = findChildren();
+        if (children != null) {
+            for( int i=0; i< children.length; i++ ) {
+                result += ((StandardWrapper)children[i]).getRequestCount();
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the cumulative error count of all servlets in this
+     * StandardContext.
+     *
+     * @return Cumulative error count of all servlets in this
+     * StandardContext
+     */
+    public int getErrorCount() {
+
+        int result = 0;
+
+        Container[] children = findChildren();
+        if (children != null) {
+            for( int i=0; i< children.length; i++ ) {
+                result += ((StandardWrapper)children[i]).getErrorCount();
+            }
+        }
+
+        return result;
+    }
+
 
     /**
      * Return the real path for a given virtual path, if possible; otherwise
@@ -5280,7 +5370,7 @@ public class StandardContext extends ContainerBase
                     entry.getKey().onStartup(entry.getValue(),
                             getServletContext());
                 } catch (ServletException e) {
-                    // TODO: Log error
+                    log.error(sm.getString("standardContext.sciFail"), e);
                     ok = false;
                     break;
                 }
@@ -5299,9 +5389,6 @@ public class StandardContext extends ContainerBase
                 if ((manager != null) && (manager instanceof Lifecycle)) {
                     ((Lifecycle) getManager()).start();
                 }
-    
-                // Start ContainerBackgroundProcessor thread
-                super.threadStart();
             } catch(Exception e) {
                 log.error("Error manager.start()", e);
                 ok = false;
@@ -5320,6 +5407,8 @@ public class StandardContext extends ContainerBase
                 loadOnStartup(findChildren());
             }
             
+            // Start ContainerBackgroundProcessor thread
+            super.threadStart();
         } finally {
             // Unbinding thread
             unbindThread(oldCCL);
@@ -5465,6 +5554,9 @@ public class StandardContext extends ContainerBase
             
             ClassLoader old = bindThread();
             try {
+                // Stop ContainerBackgroundProcessor thread
+                threadStop();
+
                 for (int i = 0; i < children.length; i++) {
                     children[i].stop();
                 }
@@ -5472,9 +5564,6 @@ public class StandardContext extends ContainerBase
                 // Stop our filters
                 filterStop();
             
-                // Stop ContainerBackgroundProcessor thread
-                threadStop();
-            
                 if (manager != null && manager instanceof Lifecycle &&
                         ((Lifecycle) manager).getState().isAvailable()) {
                     ((Lifecycle) manager).stop();
diff --git a/java/org/apache/catalina/core/StandardWrapper.java b/java/org/apache/catalina/core/StandardWrapper.java
index b7fa056..90ea542 100644
--- a/java/org/apache/catalina/core/StandardWrapper.java
+++ b/java/org/apache/catalina/core/StandardWrapper.java
@@ -78,7 +78,7 @@ import org.apache.tomcat.util.modeler.Util;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: StandardWrapper.java 1429186 2013-01-05 01:43:28Z kkolinko $
+ * @version $Id: StandardWrapper.java 1443354 2013-02-07 08:47:59Z markt $
  */
 @SuppressWarnings("deprecation") // SingleThreadModel
 public class StandardWrapper extends ContainerBase
@@ -588,13 +588,20 @@ public class StandardWrapper extends ContainerBase
         
         // The logic to determine this safely is more complex than one might
         // expect. allocate() already has the necessary logic so re-use it.
+        // Make sure the Servlet is loaded with the right class loader
+        ClassLoader old = Thread.currentThread().getContextClassLoader();
+        ClassLoader webappClassLoader =
+                ((Context) getParent()).getLoader().getClassLoader();
         try {
+            Thread.currentThread().setContextClassLoader(webappClassLoader);
             Servlet s = allocate();
             deallocate(s);
         } catch (Throwable t) {
             ExceptionUtils.handleThrowable(t);
+        } finally {
+            Thread.currentThread().setContextClassLoader(old);
         }
-        return (singleThreadModel);
+        return singleThreadModel;
 
     }
 
@@ -1206,7 +1213,6 @@ public class StandardWrapper extends ContainerBase
 
     /**
      * {@inheritDoc}
-     * @throws ClassNotFoundException 
      */
     @Override
     public void servletSecurityAnnotationScan() throws ServletException {
diff --git a/java/org/apache/catalina/core/mbeans-descriptors.xml b/java/org/apache/catalina/core/mbeans-descriptors.xml
index fc7f6e4..71f8f06 100644
--- a/java/org/apache/catalina/core/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/core/mbeans-descriptors.xml
@@ -264,6 +264,26 @@
                type="long"
                writeable="false" />
                
+    <attribute name="maxTime"
+               description="Maximum execution time of all servlets in this context"
+               type="long"
+               writeable="false" />
+
+    <attribute name="minTime"
+               description="Minimum execution time of all servlets in this context"
+               type="long"
+               writeable="false" />
+
+    <attribute name="requestCount"
+               description="Cumulative request count of all servlets in this context"
+               type="int"
+               writeable="false" />
+
+    <attribute name="errorCount"
+               description="Cumulative error count of all servlets in this context"
+               type="int"
+               writeable="false" />
+
     <attribute name="publicId"
                description="The public identifier of the DTD for the web application deployment descriptor version that is being parsed"
                type="java.lang.String"
diff --git a/java/org/apache/catalina/deploy/NamingResources.java b/java/org/apache/catalina/deploy/NamingResources.java
index 41c4a93..9b13bb0 100644
--- a/java/org/apache/catalina/deploy/NamingResources.java
+++ b/java/org/apache/catalina/deploy/NamingResources.java
@@ -49,7 +49,7 @@ import org.apache.tomcat.util.res.StringManager;
  * Naming Context and their associated JNDI context.
  *
  * @author Remy Maucherat
- * @version $Id: NamingResources.java 1346377 2012-06-05 13:05:49Z kkolinko $
+ * @version $Id: NamingResources.java 1437321 2013-01-23 10:23:32Z markt $
  */
 
 public class NamingResources extends LifecycleMBeanBase implements Serializable {
@@ -1190,7 +1190,7 @@ public class NamingResources extends LifecycleMBeanBase implements Serializable
                 // No match - ignore this injection target
                 continue;
             }
-            targetType = convertPrimitiveType(targetType);
+            targetType = Introspection.convertPrimitiveType(targetType);
 
             if (typeClass == null) {
                 // Need to find a common type amongst the injection targets
@@ -1243,26 +1243,4 @@ public class NamingResources extends LifecycleMBeanBase implements Serializable
         }
         return null;
     }
-
-    private Class<?> convertPrimitiveType(Class<?> clazz) {
-        if (clazz.equals(char.class)) {
-            return Character.class;
-        } else if (clazz.equals(int.class)) {
-            return Integer.class;
-        } else if (clazz.equals(boolean.class)) {
-            return Boolean.class;
-        } else if (clazz.equals(double.class)) {
-            return Double.class;
-        } else if (clazz.equals(byte.class)) {
-            return Byte.class;
-        } else if (clazz.equals(short.class)) {
-            return Short.class;
-        } else if (clazz.equals(long.class)) {
-            return Long.class;
-        } else if (clazz.equals(float.class)) {
-            return Float.class;
-        } else {
-            return clazz;
-        }
-    }
 }
diff --git a/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java b/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java
index c20e60c..f5a6724 100644
--- a/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java
+++ b/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java
@@ -193,7 +193,7 @@ public class ClusterSingleSignOn
     @Override
     protected void associate(String ssoId, Session session) {
 
-        if (cluster != null) {
+        if (cluster != null && cluster.getMembers().length > 0) {
             messageNumber++;
             SingleSignOnMessage msg =
                 new SingleSignOnMessage(cluster.getLocalMember(),
@@ -233,7 +233,7 @@ public class ClusterSingleSignOn
     @Override
     protected void deregister(String ssoId, Session session) {
 
-        if (cluster != null) {
+        if (cluster != null && cluster.getMembers().length > 0) {
             messageNumber++;
             SingleSignOnMessage msg =
                 new SingleSignOnMessage(cluster.getLocalMember(),
@@ -271,7 +271,7 @@ public class ClusterSingleSignOn
     @Override
     protected void deregister(String ssoId) {
 
-        if (cluster != null) {
+        if (cluster != null && cluster.getMembers().length > 0) {
             messageNumber++;
             SingleSignOnMessage msg =
                 new SingleSignOnMessage(cluster.getLocalMember(),
@@ -310,7 +310,7 @@ public class ClusterSingleSignOn
     protected void register(String ssoId, Principal principal, String authType,
                   String username, String password) {
 
-        if (cluster != null) {
+        if (cluster != null && cluster.getMembers().length > 0) {
             messageNumber++;
             SingleSignOnMessage msg =
                 new SingleSignOnMessage(cluster.getLocalMember(),
@@ -374,7 +374,7 @@ public class ClusterSingleSignOn
     protected void update(String ssoId, Principal principal, String authType,
                           String username, String password) {
 
-        if (cluster != null) {
+        if (cluster != null && cluster.getMembers().length > 0) {
             messageNumber++;
             SingleSignOnMessage msg =
                 new SingleSignOnMessage(cluster.getLocalMember(),
@@ -418,7 +418,7 @@ public class ClusterSingleSignOn
     @Override
     protected void removeSession(String ssoId, Session session) {
 
-        if (cluster != null) {
+        if (cluster != null && cluster.getMembers().length > 0) {
             messageNumber++;
             SingleSignOnMessage msg =
                 new SingleSignOnMessage(cluster.getLocalMember(),
diff --git a/java/org/apache/catalina/ha/session/DeltaManager.java b/java/org/apache/catalina/ha/session/DeltaManager.java
index 78a83fa..bf709b6 100644
--- a/java/org/apache/catalina/ha/session/DeltaManager.java
+++ b/java/org/apache/catalina/ha/session/DeltaManager.java
@@ -62,7 +62,7 @@ import org.apache.tomcat.util.res.StringManager;
  * @author Craig R. McClanahan
  * @author Jean-Francois Arcand
  * @author Peter Rossbach
- * @version $Id: DeltaManager.java 1300907 2012-03-15 10:57:17Z markt $
+ * @version $Id: DeltaManager.java 1436252 2013-01-21 10:06:33Z kfujino $
  */
 
 public class DeltaManager extends ClusterManagerBase{
@@ -542,7 +542,7 @@ public class DeltaManager extends ClusterManagerBase{
         // original sessionID
         String orgSessionID = session.getId();
         super.changeSessionId(session);
-        if (notify) {
+        if (notify && cluster.getMembers().length > 0) {
             // changed sessionID
             String newSessionID = session.getId();
             try {
@@ -1176,11 +1176,14 @@ public class DeltaManager extends ClusterManagerBase{
      *            session id
      */
     protected void sessionExpired(String id) {
-        counterSend_EVT_SESSION_EXPIRED++ ;
-        SessionMessage msg = new SessionMessageImpl(getName(),SessionMessage.EVT_SESSION_EXPIRED, null, id, id+ "-EXPIRED-MSG");
-        msg.setTimestamp(System.currentTimeMillis());
-        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.expire",getName(), id));
-        send(msg);
+        if(cluster.getMembers().length > 0 ) {
+            counterSend_EVT_SESSION_EXPIRED++ ;
+            SessionMessage msg = new SessionMessageImpl(getName(),
+                    SessionMessage.EVT_SESSION_EXPIRED, null, id, id+ "-EXPIRED-MSG");
+            msg.setTimestamp(System.currentTimeMillis());
+            if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.expire",getName(), id));
+            send(msg);
+        }
     }
 
     /**
diff --git a/java/org/apache/catalina/loader/WebappClassLoader.java b/java/org/apache/catalina/loader/WebappClassLoader.java
index f6a065e..e0b2586 100644
--- a/java/org/apache/catalina/loader/WebappClassLoader.java
+++ b/java/org/apache/catalina/loader/WebappClassLoader.java
@@ -27,7 +27,6 @@ import java.io.InputStream;
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.net.MalformedURLException;
@@ -119,7 +118,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Remy Maucherat
  * @author Craig R. McClanahan
- * @version $Id: WebappClassLoader.java 1361987 2012-07-16 12:20:10Z rjung $
+ * @version $Id: WebappClassLoader.java 1441430 2013-02-01 12:52:06Z markt $
  */
 public class WebappClassLoader
     extends URLClassLoader
@@ -2463,27 +2462,11 @@ public class WebappClassLoader
                     }
                 }
             }
-        } catch (SecurityException e) {
-            log.warn(sm.getString("webappClassLoader.checkThreadLocalsForLeaksFail",
-                    contextName), e);
-        } catch (NoSuchFieldException e) {
-            log.warn(sm.getString("webappClassLoader.checkThreadLocalsForLeaksFail",
-                    contextName), e);
-        } catch (ClassNotFoundException e) {
-            log.warn(sm.getString("webappClassLoader.checkThreadLocalsForLeaksFail",
-                    contextName), e);
-        } catch (IllegalArgumentException e) {
-            log.warn(sm.getString("webappClassLoader.checkThreadLocalsForLeaksFail",
-                    contextName), e);
-        } catch (IllegalAccessException e) {
-            log.warn(sm.getString("webappClassLoader.checkThreadLocalsForLeaksFail",
-                    contextName), e);
-        } catch (InvocationTargetException e) {
-            log.warn(sm.getString("webappClassLoader.checkThreadLocalsForLeaksFail",
-                    contextName), e);
-        } catch (NoSuchMethodException e) {
-            log.warn(sm.getString("webappClassLoader.checkThreadLocalsForLeaksFail",
-                    contextName), e);
+        } catch (Throwable t) {
+            ExceptionUtils.handleThrowable(t);
+            log.warn(sm.getString(
+                    "webappClassLoader.checkThreadLocalsForLeaksFail",
+                    getContextName()), t);
         }
     }
 
@@ -2500,18 +2483,19 @@ public class WebappClassLoader
             Object[] table = (Object[]) internalTableField.get(map);
             if (table != null) {
                 for (int j =0; j < table.length; j++) {
-                    if (table[j] != null) {
+                    Object obj = table[j];
+                    if (obj != null) {
                         boolean potentialLeak = false;
                         // Check the key
-                        Object key = ((Reference<?>) table[j]).get();
+                        Object key = ((Reference<?>) obj).get();
                         if (this.equals(key) || loadedByThisOrChild(key)) {
                             potentialLeak = true;
                         }
                         // Check the value
                         Field valueField =
-                            table[j].getClass().getDeclaredField("value");
+                                obj.getClass().getDeclaredField("value");
                         valueField.setAccessible(true);
-                        Object value = valueField.get(table[j]);
+                        Object value = valueField.get(obj);
                         if (this.equals(value) || loadedByThisOrChild(value)) {
                             potentialLeak = true;
                         }
diff --git a/java/org/apache/catalina/loader/WebappLoader.java b/java/org/apache/catalina/loader/WebappLoader.java
index 1810007..8cfddc1 100644
--- a/java/org/apache/catalina/loader/WebappLoader.java
+++ b/java/org/apache/catalina/loader/WebappLoader.java
@@ -5,9 +5,9 @@
  * 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.
@@ -79,7 +79,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: WebappLoader.java 1430536 2013-01-08 21:07:06Z kkolinko $
+ * @version $Id: WebappLoader.java 1451065 2013-02-28 00:53:29Z markt $
  */
 
 public class WebappLoader extends LifecycleMBeanBase
@@ -148,7 +148,7 @@ public class WebappLoader extends LifecycleMBeanBase
 
     /**
      * The Java class name of the ClassLoader implementation to be used.
-     * This class should extend WebappClassLoader, otherwise, a different 
+     * This class should extend WebappClassLoader, otherwise, a different
      * loader implementation must be used.
      */
     private String loaderClass =
@@ -440,7 +440,7 @@ public class WebappLoader extends LifecycleMBeanBase
     /**
      * Return the set of repositories defined for this class loader.
      * If none are defined, a zero-length array is returned.
-     * For security reason, returns a clone of the Array (since 
+     * For security reason, returns a clone of the Array (since
      * String are immutable).
      */
     @Override
@@ -481,7 +481,7 @@ public class WebappLoader extends LifecycleMBeanBase
     }
 
 
-    /** 
+    /**
      * Classpath, as set in org.apache.catalina.jsp_classpath context
      * property
      *
@@ -558,7 +558,7 @@ public class WebappLoader extends LifecycleMBeanBase
             setState(LifecycleState.STARTING);
             return;
         }
-        
+
         // Register a stream handler factory for the JNDI protocol
         URLStreamHandlerFactory streamHandlerFactory =
                 DirContextURLStreamHandlerFactory.getInstance();
@@ -572,7 +572,7 @@ public class WebappLoader extends LifecycleMBeanBase
             } catch (Throwable t) {
                 ExceptionUtils.handleThrowable(t);
                 // This is likely a dual registration
-                log.info("Dual registration of jndi stream handler: " 
+                log.info("Dual registration of jndi stream handler: "
                          + t.getMessage());
             }
         }
@@ -617,7 +617,7 @@ public class WebappLoader extends LifecycleMBeanBase
             String contextName = ctx.getName();
             if (!contextName.startsWith("/")) {
                 contextName = "/" + contextName;
-            }   
+            }
             ObjectName cloname = new ObjectName
                 (MBeanUtils.getDomain(ctx) + ":type=WebappClassLoader,context="
                  + contextName + ",host=" + ctx.getParent().getName());
@@ -668,7 +668,7 @@ public class WebappLoader extends LifecycleMBeanBase
             String contextName = ctx.getName();
             if (!contextName.startsWith("/")) {
                 contextName = "/" + contextName;
-            }   
+            }
             ObjectName cloname = new ObjectName
                 (MBeanUtils.getDomain(ctx) + ":type=WebappClassLoader,context="
                  + contextName + ",host=" + ctx.getParent().getName());
@@ -758,7 +758,7 @@ public class WebappLoader extends LifecycleMBeanBase
                 classLoader.addPermission
                     (new FilePermission(workDirPath, "read,write"));
                 classLoader.addPermission
-                    (new FilePermission(workDirPath + File.separator + "-", 
+                    (new FilePermission(workDirPath + File.separator + "-",
                                         "read,write,delete"));
             } catch (IOException e) {
                 // Ignore
@@ -833,7 +833,7 @@ public class WebappLoader extends LifecycleMBeanBase
     /**
      * Configure the repositories for our class loader, based on the
      * associated Context.
-     * @throws IOException 
+     * @throws IOException
      */
     private void setRepositories() throws IOException {
 
@@ -852,7 +852,7 @@ public class WebappLoader extends LifecycleMBeanBase
             log.info("No work dir for " + servletContext);
         }
 
-        if( log.isDebugEnabled() && workDir != null) 
+        if( log.isDebugEnabled() && workDir != null)
             log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
 
         classLoader.setWorkDir(workDir);
@@ -984,12 +984,12 @@ public class WebappLoader extends LifecycleMBeanBase
                     ioe.initCause(e);
                     throw ioe;
                 }
-                
+
                 if (!(obj instanceof Resource))
                     continue;
-                    
+
                 Resource jarResource = (Resource) obj;
-                    
+
                 if (copyJars) {
                     if (!copy(jarResource.streamContent(),
                               new FileOutputStream(destFile))) {
@@ -1003,10 +1003,10 @@ public class WebappLoader extends LifecycleMBeanBase
                     classLoader.addJar(filename, jarFile, destFile);
                 } catch (Exception ex) {
                     // Catch the exception if there is an empty jar file
-                    // Should ignore and continue loading other jar files 
+                    // Should ignore and continue loading other jar files
                     // in the dir
                 }
-                    
+
                 loaderRepositories.add( filename );
             }
         }
@@ -1028,7 +1028,7 @@ public class WebappLoader extends LifecycleMBeanBase
             return;
 
         if (container instanceof StandardContext) {
-            String baseClasspath = 
+            String baseClasspath =
                 ((StandardContext) container).getCompilerClasspath();
             if (baseClasspath != null) {
                 servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
@@ -1041,44 +1041,27 @@ public class WebappLoader extends LifecycleMBeanBase
 
         // Assemble the class path information from our class loader chain
         ClassLoader loader = getClassLoader();
-        int n = 0;
+
+        if (delegate && loader != null) {
+            // Skip the webapp loader for now as delegation is enabled
+            loader = loader.getParent();
+        }
+
         while (loader != null) {
-            if (!(loader instanceof URLClassLoader)) {
-                String cp=getClasspath( loader );
-                if( cp==null ) {
-                    log.info( "Unknown loader " + loader + " " + loader.getClass());
-                } else {
-                    if (n > 0) 
-                        classpath.append(File.pathSeparator);
-                    classpath.append(cp);
-                    n++;
-                }
+            if (!buildClassPath(servletContext, classpath, loader)) {
                 break;
-                //continue;
-            }
-            URL repositories[] =
-                ((URLClassLoader) loader).getURLs();
-            for (int i = 0; i < repositories.length; i++) {
-                String repository = repositories[i].toString();
-                if (repository.startsWith("file://"))
-                    repository = utf8Decode(repository.substring(7));
-                else if (repository.startsWith("file:"))
-                    repository = utf8Decode(repository.substring(5));
-                else if (repository.startsWith("jndi:"))
-                    repository =
-                        servletContext.getRealPath(repository.substring(5));
-                else
-                    continue;
-                if (repository == null)
-                    continue;
-                if (n > 0)
-                    classpath.append(File.pathSeparator);
-                classpath.append(repository);
-                n++;
             }
             loader = loader.getParent();
         }
 
+        if (delegate) {
+            // Delegation was enabled, go back and add the webapp paths
+            loader = getClassLoader();
+            if (loader != null) {
+                buildClassPath(servletContext, classpath, loader);
+            }
+        }
+
         this.classpath=classpath.toString();
 
         // Store the assembled class path as a servlet context attribute
@@ -1087,6 +1070,43 @@ public class WebappLoader extends LifecycleMBeanBase
 
     }
 
+
+    private boolean buildClassPath(ServletContext servletContext,
+            StringBuilder classpath, ClassLoader loader) {
+        if (loader instanceof URLClassLoader) {
+            URL repositories[] =
+                    ((URLClassLoader) loader).getURLs();
+                for (int i = 0; i < repositories.length; i++) {
+                    String repository = repositories[i].toString();
+                    if (repository.startsWith("file://"))
+                        repository = utf8Decode(repository.substring(7));
+                    else if (repository.startsWith("file:"))
+                        repository = utf8Decode(repository.substring(5));
+                    else if (repository.startsWith("jndi:"))
+                        repository =
+                            servletContext.getRealPath(repository.substring(5));
+                    else
+                        continue;
+                    if (repository == null)
+                        continue;
+                    if (classpath.length() > 0)
+                        classpath.append(File.pathSeparator);
+                    classpath.append(repository);
+                }
+        } else {
+            String cp = getClasspath(loader);
+            if (cp == null) {
+                log.info( "Unknown loader " + loader + " " + loader.getClass());
+            } else {
+                if (classpath.length() > 0)
+                    classpath.append(File.pathSeparator);
+                classpath.append(cp);
+            }
+            return false;
+        }
+        return true;
+    }
+
     private String utf8Decode(String input) {
         String result = null;
         try {
@@ -1197,19 +1217,19 @@ public class WebappLoader extends LifecycleMBeanBase
 
     @Override
     protected String getObjectNameKeyProperties() {
-        
+
         StringBuilder name = new StringBuilder("type=Loader");
-        
+
         if (container instanceof Context) {
             name.append(",context=");
             Context context = (Context) container;
-            
+
             String contextName = context.getName();
             if (!contextName.startsWith("/")) {
                 name.append("/");
-            }   
+            }
             name.append(contextName);
-            
+
             name.append(",host=");
             name.append(context.getParent().getName());
         } else {
@@ -1217,7 +1237,7 @@ public class WebappLoader extends LifecycleMBeanBase
             name.append(",container=");
             name.append(container.getName());
         }
-        
+
         return name.toString();
     }
 
diff --git a/java/org/apache/catalina/manager/StatusTransformer.java b/java/org/apache/catalina/manager/StatusTransformer.java
index 7d98903..850b7b8 100644
--- a/java/org/apache/catalina/manager/StatusTransformer.java
+++ b/java/org/apache/catalina/manager/StatusTransformer.java
@@ -46,7 +46,7 @@ import org.apache.tomcat.util.ExceptionUtils;
  * use XSLT, that is unnecessarily complex.
  *
  * @author Peter Lin
- * @version $Id: StatusTransformer.java 1409014 2012-11-13 22:58:01Z kkolinko $
+ * @version $Id: StatusTransformer.java 1453106 2013-03-06 00:48:45Z kkolinko $
  */
 
 public class StatusTransformer {
@@ -265,7 +265,7 @@ public class StatusTransformer {
                 writer.write(" usageInit='" + usage.getInit() + "'");
                 writer.write(" usageCommitted='" + usage.getCommitted() + "'");
                 writer.write(" usageMax='" + usage.getMax() + "'");
-                writer.write(" usageUsed='" + usage.getInit() + "'/>");
+                writer.write(" usageUsed='" + usage.getUsed() + "'/>");
             }
 
             writer.write("</jvm>");
diff --git a/java/org/apache/catalina/realm/DataSourceRealm.java b/java/org/apache/catalina/realm/DataSourceRealm.java
index b7dba78..9c2920a 100644
--- a/java/org/apache/catalina/realm/DataSourceRealm.java
+++ b/java/org/apache/catalina/realm/DataSourceRealm.java
@@ -42,7 +42,7 @@ import org.apache.naming.ContextBindings;
 * @author Craig R. McClanahan
 * @author Carson McDonald
 * @author Ignacio Ortega
-* @version $Revision: 1348499 $
+* @version $Revision: 1437507 $
 */
 
 public class DataSourceRealm
@@ -455,7 +455,7 @@ public class DataSourceRealm
         } catch(SQLException e) {
             containerLog.error(
                     sm.getString("dataSourceRealm.getPassword.exception",
-                                 username));
+                                 username), e);
         } finally {
             try {
                 if (rs != null) {
@@ -467,7 +467,7 @@ public class DataSourceRealm
             } catch (SQLException e) {
                     containerLog.error(
                         sm.getString("dataSourceRealm.getPassword.exception",
-                             username));
+                             username), e);
                 
             }
         }
@@ -548,7 +548,7 @@ public class DataSourceRealm
             return list;
         } catch(SQLException e) {
             containerLog.error(
-                sm.getString("dataSourceRealm.getRoles.exception", username));
+                sm.getString("dataSourceRealm.getRoles.exception", username), e);
         }
         finally {
             try {
@@ -561,7 +561,7 @@ public class DataSourceRealm
             } catch (SQLException e) {
                     containerLog.error(
                         sm.getString("dataSourceRealm.getRoles.exception",
-                                     username));
+                                     username), e);
             }
         }
         
diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java
index 3ca725f..b9e23e1 100644
--- a/java/org/apache/catalina/realm/JNDIRealm.java
+++ b/java/org/apache/catalina/realm/JNDIRealm.java
@@ -17,7 +17,6 @@
 
 package org.apache.catalina.realm;
 
-import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.Charset;
@@ -54,9 +53,8 @@ import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 
 import org.apache.catalina.LifecycleException;
-import org.apache.catalina.util.Base64;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.codec.binary.Base64;
 import org.ietf.jgss.GSSCredential;
 
 /**
@@ -174,7 +172,7 @@ import org.ietf.jgss.GSSCredential;
  *
  * @author John Holman
  * @author Craig R. McClanahan
- * @version $Id: JNDIRealm.java 1361774 2012-07-15 19:43:28Z markt $
+ * @version $Id: JNDIRealm.java 1459346 2013-03-21 15:05:54Z markt $
  */
 
 public class JNDIRealm extends RealmBase {
@@ -1575,7 +1573,9 @@ public class JNDIRealm extends RealmBase {
                     password = password.substring(5);
                     md.reset();
                     md.update(credentials.getBytes(Charset.defaultCharset()));
-                    String digestedPassword = Base64.encode(md.digest());
+                    byte[] decoded = Base64.decodeBase64(md.digest());
+                    String digestedPassword =
+                            new String(decoded, B2CConverter.ISO_8859_1);
                     validated = password.equals(digestedPassword);
                 }
             } else if (password.startsWith("{SSHA}")) {
@@ -1588,31 +1588,15 @@ public class JNDIRealm extends RealmBase {
                     md.update(credentials.getBytes(Charset.defaultCharset()));
 
                     // Decode stored password.
-                    ByteChunk pwbc = new ByteChunk(password.length());
-                    try {
-                        pwbc.append(password.getBytes(Charset.defaultCharset()),
-                                0, password.length());
-                    } catch (IOException e) {
-                        // Should never happen
-                        containerLog.error("Could not append password bytes to chunk: ", e);
-                    }
-
-                    CharChunk decoded = new CharChunk();
-                    Base64.decode(pwbc, decoded);
-                    char[] pwarray = decoded.getBuffer();
+                    byte[] decoded = Base64.decodeBase64(password);
 
                     // Split decoded password into hash and salt.
                     final int saltpos = 20;
                     byte[] hash = new byte[saltpos];
-                    for (int i=0; i< hash.length; i++) {
-                        hash[i] = (byte) pwarray[i];
-                    }
+                    System.arraycopy(decoded, 0, hash, 0, saltpos);
 
-                    byte[] salt = new byte[pwarray.length - saltpos];
-                    for (int i=0; i< salt.length; i++)
-                        salt[i] = (byte)pwarray[i+saltpos];
+                    md.update(decoded, saltpos, decoded.length - saltpos);
 
-                    md.update(salt);
                     byte[] dp = md.digest();
 
                     validated = Arrays.equals(dp, hash);
diff --git a/java/org/apache/catalina/realm/RealmBase.java b/java/org/apache/catalina/realm/RealmBase.java
index d69d7b0..4dc80ae 100644
--- a/java/org/apache/catalina/realm/RealmBase.java
+++ b/java/org/apache/catalina/realm/RealmBase.java
@@ -67,7 +67,7 @@ import org.ietf.jgss.GSSName;
  * location) are identical to those currently supported by Tomcat 3.X.
  *
  * @author Craig R. McClanahan
- * @version $Id: RealmBase.java 1379208 2012-08-30 22:59:07Z markt $
+ * @version $Id: RealmBase.java 1434688 2013-01-17 14:33:29Z markt $
  */
 
 public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
@@ -406,9 +406,10 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
                                   String md5a2) {
 
         // In digest auth, digests are always lower case
-        String md5a1 = getDigest(username, realm).toLowerCase(Locale.ENGLISH);
+        String md5a1 = getDigest(username, realm);
         if (md5a1 == null)
             return null;
+        md5a1 = md5a1.toLowerCase(Locale.ENGLISH);
         String serverDigestValue;
         if (qop == null) {
             serverDigestValue = md5a1 + ":" + nonce + ":" + md5a2;
diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java
index 2e05a46..126fc50 100644
--- a/java/org/apache/catalina/startup/ContextConfig.java
+++ b/java/org/apache/catalina/startup/ContextConfig.java
@@ -109,7 +109,7 @@ import org.xml.sax.SAXParseException;
  *
  * @author Craig R. McClanahan
  * @author Jean-Francois Arcand
- * @version $Id: ContextConfig.java 1430808 2013-01-09 11:57:57Z markt $
+ * @version $Id: ContextConfig.java 1456982 2013-03-15 15:07:15Z violetagg $
  */
 public class ContextConfig implements LifecycleListener {
 
@@ -1850,6 +1850,17 @@ public class ContextConfig implements LifecycleListener {
     }
 
 
+    /**
+     * Parses the given source and stores the parsed data in the given web.xml
+     * representation. The byte stream will be closed at the end of the parse
+     * operation.
+     *
+     * @param source Input source containing the XML data to be parsed
+     * @param dest The object representation of common elements of web.xml and
+     *             web-fragment.xml
+     * @param fragment Specifies whether the source is web-fragment.xml or
+     *                 web.xml
+     */
     protected void parseWebXml(InputSource source, WebXml dest,
             boolean fragment) {
 
@@ -1897,6 +1908,15 @@ public class ContextConfig implements LifecycleListener {
         } finally {
             digester.reset();
             ruleSet.recycle();
+
+            InputStream is = source.getByteStream();
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (Throwable t) {
+                    ExceptionUtils.handleThrowable(t);
+                }
+            }
         }
     }
 
@@ -2103,13 +2123,7 @@ public class ContextConfig implements LifecycleListener {
 
         ClassParser parser = new ClassParser(is, null);
         JavaClass clazz = parser.parse();
-        try {
-            checkHandlesTypes(clazz);
-        } catch (StackOverflowError soe) {
-            throw new IllegalStateException(sm.getString(
-                    "contextConfig.annotationsStackOverflow",
-                    context.getName()), soe);
-        }
+        checkHandlesTypes(clazz);
 
         if (handlesTypesOnly) {
             return;
@@ -2159,7 +2173,14 @@ public class ContextConfig implements LifecycleListener {
             populateJavaClassCache(className, javaClass);
             JavaClassCacheEntry entry = javaClassCache.get(className);
             if (entry.getSciSet() == null) {
-                populateSCIsForCacheEntry(entry);
+                try {
+                    populateSCIsForCacheEntry(entry);
+                } catch (StackOverflowError soe) {
+                    throw new IllegalStateException(sm.getString(
+                            "contextConfig.annotationsStackOverflow",
+                            context.getName(),
+                            classHierarchyToString(className, entry)));
+                }
             }
             if (entry.getSciSet().size() > 0) {
                 // Need to try and load the class
@@ -2211,6 +2232,30 @@ public class ContextConfig implements LifecycleListener {
     }
 
 
+    private String classHierarchyToString(String className,
+            JavaClassCacheEntry entry) {
+        JavaClassCacheEntry start = entry;
+        StringBuilder msg = new StringBuilder(className);
+        msg.append("->");
+
+        String parentName = entry.getSuperclassName();
+        JavaClassCacheEntry parent = javaClassCache.get(parentName);
+        int count = 0;
+
+        while (count < 100 && parent != null && parent != start) {
+            msg.append(parentName);
+            msg.append("->");
+
+            count ++;
+            parentName = parent.getSuperclassName();
+            parent = javaClassCache.get(parentName);
+        }
+
+        msg.append(parentName);
+
+        return msg.toString();
+    }
+
     private void populateJavaClassCache(String className, JavaClass javaClass) {
         if (javaClassCache.containsKey(className)) {
             return;
@@ -2637,13 +2682,6 @@ public class ContextConfig implements LifecycleListener {
                     parseWebXml(source, fragment, true);
                 }
             } finally {
-                if (is != null) {
-                    try {
-                        is.close();
-                    } catch (IOException ioe) {
-                        // Ignore
-                    }
-                }
                 if (jar != null) {
                     jar.close();
                 }
@@ -2683,13 +2721,6 @@ public class ContextConfig implements LifecycleListener {
                     parseWebXml(source, fragment, true);
                 }
             } finally {
-                if (stream != null) {
-                    try {
-                        stream.close();
-                    } catch (Throwable t) {
-                        ExceptionUtils.handleThrowable(t);
-                    }
-                }
                 fragment.setURL(file.toURI().toURL());
                 if (fragment.getName() == null) {
                     fragment.setName(fragment.getURL().toString());
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 575420c..efd45eb 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -73,7 +73,7 @@ import org.apache.tomcat.util.res.StringManager;
  *
  * @author Craig R. McClanahan
  * @author Remy Maucherat
- * @version $Id: HostConfig.java 1408166 2012-11-12 01:26:59Z markt $
+ * @version $Id: HostConfig.java 1441344 2013-02-01 08:47:40Z kkolinko $
  */
 public class HostConfig
     implements LifecycleListener {
@@ -612,7 +612,7 @@ public class HostConfig
                 } catch (Exception e) {
                     log.error(sm.getString(
                             "hostConfig.deployDescriptor.error",
-                            contextXml.getAbsolutePath()));
+                            contextXml.getAbsolutePath()), e);
                     context = new FailedContext();
                 } finally {
                     digester.reset();
@@ -906,7 +906,7 @@ public class HostConfig
                     } catch (Exception e) {
                         log.error(sm.getString(
                                 "hostConfig.deployDescriptor.error",
-                                war.getAbsolutePath()));
+                                war.getAbsolutePath()), e);
                         context = new FailedContext();
                     } finally {
                         digester.reset();
@@ -924,7 +924,7 @@ public class HostConfig
                     } catch (Exception e) {
                         log.error(sm.getString(
                                 "hostConfig.deployDescriptor.error",
-                                war.getAbsolutePath()));
+                                war.getAbsolutePath()), e);
                     } finally {
                         if (context == null) {
                             context = new FailedContext();
@@ -1067,7 +1067,7 @@ public class HostConfig
                     } catch (Exception e) {
                         log.error(sm.getString(
                                 "hostConfig.deployDescriptor.error",
-                                xml));
+                                xml), e);
                         context = new FailedContext();
                     } finally {
                         digester.reset();
diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties
index d83905c..69a92f5 100644
--- a/java/org/apache/catalina/startup/LocalStrings.properties
+++ b/java/org/apache/catalina/startup/LocalStrings.properties
@@ -18,7 +18,7 @@ catalina.noCluster=Cluster RuleSet not found due to [{0}]. Cluster configuration
 catalina.shutdownHookFail=The shutdown hook experienced an error while trying to stop the server
 catalina.stopServer=No shutdown port configured. Shut down server through OS signal. Server not shut down.
 contextConfig.altDDNotFound=alt-dd file {0} not found
-contextConfig.annotationsStackOverflow=Unable to complete the scan for annotations for web application [{0}]. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies
+contextConfig.annotationsStackOverflow=Unable to complete the scan for annotations for web application [{0}] due to a StackOverflowError. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies. The class hierarchy being processed was [{1}]
 contextConfig.applicationUrl=Unable to determine URL for application web.xml
 contextConfig.applicationMissing=Missing application web.xml, using defaults only
 contextConfig.applicationParse=Parse error in application web.xml file at {0}
diff --git a/java/org/apache/catalina/startup/WebAnnotationSet.java b/java/org/apache/catalina/startup/WebAnnotationSet.java
index 4c25403..aaa04f7 100644
--- a/java/org/apache/catalina/startup/WebAnnotationSet.java
+++ b/java/org/apache/catalina/startup/WebAnnotationSet.java
@@ -41,7 +41,7 @@ import org.apache.tomcat.util.res.StringManager;
  * classes (<code>/WEB-INF/classes</code> and <code>/WEB-INF/lib</code>).</p>
  *
  * @author Fabien Carrion
- * @version $Id: WebAnnotationSet.java 1346377 2012-06-05 13:05:49Z kkolinko $
+ * @version $Id: WebAnnotationSet.java 1437321 2013-01-23 10:23:32Z markt $
  */
 
 public class WebAnnotationSet {
@@ -265,7 +265,7 @@ public class WebAnnotationSet {
                     Resource annotation = field.getAnnotation(Resource.class);
                     String defaultName =
                             classClass.getName() + SEPARATOR + field.getName();
-                    String defaultType = field.getType().getCanonicalName();
+                    Class<?> defaultType = field.getType();
                     addResource(context, annotation, defaultName, defaultType);
                 }
             }
@@ -290,8 +290,8 @@ public class WebAnnotationSet {
                     String defaultName = classClass.getName() + SEPARATOR +
                             Introspection.getPropertyName(method);
 
-                    String defaultType =
-                            (method.getParameterTypes()[0]).getCanonicalName();
+                    Class<?> defaultType =
+                            (method.getParameterTypes()[0]);
                     addResource(context, annotation, defaultName, defaultType);
                 }
             }
@@ -309,7 +309,7 @@ public class WebAnnotationSet {
     }
 
     protected static void addResource(Context context, Resource annotation,
-            String defaultName, String defaultType) {
+            String defaultName, Class<?> defaultType) {
         String name = getName(annotation, defaultName);
         String type = getType(annotation, defaultType);
             
@@ -412,14 +412,14 @@ public class WebAnnotationSet {
     }
 
 
-    private static String getType(Resource annotation, String defaultType) {
-        String type = annotation.type().getCanonicalName();
-        if (type == null || type.equals("java.lang.Object")) {
+    private static String getType(Resource annotation, Class<?> defaultType) {
+        Class<?> type = annotation.type();
+        if (type == null || type.equals(Object.class)) {
             if (defaultType != null) {
                 type = defaultType;
             }
         }
-        return type;
+        return Introspection.convertPrimitiveType(type).getCanonicalName();
     }
 
 
diff --git a/java/org/apache/catalina/tribes/group/GroupChannel.java b/java/org/apache/catalina/tribes/group/GroupChannel.java
index b4a6efc..8354da5 100644
--- a/java/org/apache/catalina/tribes/group/GroupChannel.java
+++ b/java/org/apache/catalina/tribes/group/GroupChannel.java
@@ -53,7 +53,7 @@ import org.apache.juli.logging.LogFactory;
  * The channel has an chain of interceptors that can modify the message or perform other logic.<br>
  * It manages a complete group, both membership and replication.
  * @author Filip Hanik
- * @version $Id: GroupChannel.java 1142678 2011-07-04 14:08:42Z kkolinko $
+ * @version $Id: GroupChannel.java 1437908 2013-01-24 08:57:41Z markt $
  */
 public class GroupChannel extends ChannelInterceptorBase implements ManagedChannel {
     private static final Log log = LogFactory.getLog(GroupChannel.class);
@@ -169,7 +169,7 @@ public class GroupChannel extends ChannelInterceptorBase implements ManagedChann
 
     /**
      * Send a message to the destinations specified
-     * @param destination Member[] - destination.length > 1
+     * @param destination Member[] - destination.length > 0
      * @param msg Serializable - the message to send
      * @param options int - sender options, options can trigger guarantee levels and different interceptors to
      * react to the message see class documentation for the <code>Channel</code> object.<br>
@@ -184,7 +184,7 @@ public class GroupChannel extends ChannelInterceptorBase implements ManagedChann
 
     /**
      *
-     * @param destination Member[] - destination.length > 1
+     * @param destination Member[] - destination.length > 0
      * @param msg Serializable - the message to send
      * @param options int - sender options, options can trigger guarantee levels and different interceptors to
      * react to the message see class documentation for the <code>Channel</code> object.<br>
diff --git a/java/org/apache/catalina/tribes/membership/MemberImpl.java b/java/org/apache/catalina/tribes/membership/MemberImpl.java
index f546e14..b54c127 100644
--- a/java/org/apache/catalina/tribes/membership/MemberImpl.java
+++ b/java/org/apache/catalina/tribes/membership/MemberImpl.java
@@ -32,7 +32,7 @@ import org.apache.catalina.tribes.transport.SenderState;
  * Carries the host, and port of the this or other cluster nodes.
  *
  * @author Filip Hanik
- * @version $Id: MemberImpl.java 1380072 2012-09-02 22:26:09Z markt $
+ * @version $Id: MemberImpl.java 1439669 2013-01-28 22:10:44Z kkolinko $
  */
 public class MemberImpl implements Member, java.io.Externalizable {
 
@@ -534,7 +534,8 @@ public class MemberImpl implements Member, java.io.Externalizable {
      */
     @Override
     public String toString()  {
-        StringBuilder buf = new StringBuilder("org.apache.catalina.tribes.membership.MemberImpl[");
+        StringBuilder buf = new StringBuilder(getClass().getName());
+        buf.append("[");
         buf.append(getName()).append(",");
         buf.append(getHostname()).append(",");
         buf.append(port).append(", alive=");
diff --git a/java/org/apache/catalina/util/Base64.java b/java/org/apache/catalina/util/Base64.java
index aef4f97..158ba5e 100644
--- a/java/org/apache/catalina/util/Base64.java
+++ b/java/org/apache/catalina/util/Base64.java
@@ -17,7 +17,8 @@
 
 package org.apache.catalina.util;
 
-import org.apache.tomcat.util.buf.B2CConverter;
+import javax.xml.bind.DatatypeConverter;
+
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.CharChunk;
 
@@ -29,20 +30,20 @@ import org.apache.tomcat.util.buf.CharChunk;
  * Internet Message Bodies. Reference 1996
  *
  * @author Jeffrey Rodriguez
- * @version $Id: Base64.java 1233424 2012-01-19 15:18:06Z markt $
+ * @version $Id: Base64.java 1459346 2013-03-21 15:05:54Z markt $
+ *
+ * @deprecated  Use {@link org.apache.tomcat.util.codec.binary.Base64}
+ *              This class will be removed in Tomcat 8.
  */
+ at Deprecated
 public final class  Base64
 {
-    private static final int  BASELENGTH         = 255;
-    private static final int  LOOKUPLENGTH       = 64;
-    private static final int  TWENTYFOURBITGROUP = 24;
-    private static final int  EIGHTBIT           = 8;
-    private static final int  SIXTEENBIT         = 16;
-    private static final int  FOURBYTE           = 4;
-    private static final int  SIGN               = -128;
-    private static final byte PAD                = (byte) '=';
-    private static byte [] base64Alphabet       = new byte[BASELENGTH];
-    private static byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
+    private static final int  BASELENGTH              = 255;
+    private static final int  LOOKUPLENGTH            = 64;
+    private static final int  FOURBYTE                = 4;
+    private static final byte PAD                     = (byte) '=';
+    private static final byte [] base64Alphabet       = new byte[BASELENGTH];
+    private static final byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
 
     static
     {
@@ -84,93 +85,13 @@ public final class  Base64
      *
      * @param binaryData Array containing binary data to encode.
      * @return Base64-encoded data.
+     *
+     * @deprecated  Use {@link DatatypeConverter#printBase64Binary(byte[])}.
+     *              This method will be removed in Tomcat 8.0.x.
      */
+    @Deprecated
     public static String encode(byte[] binaryData) {
-        int      lengthDataBits    = binaryData.length*EIGHTBIT;
-        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
-        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
-        byte     encodedData[]     = null;
-
-
-        if (fewerThan24bits != 0)
-        {
-            //data not divisible by 24 bit
-            encodedData = new byte[ (numberTriplets + 1 ) * 4 ];
-        }
-        else
-        {
-            // 16 or 8 bit
-            encodedData = new byte[ numberTriplets * 4 ];
-        }
-
-        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
-
-        int encodedIndex = 0;
-        int dataIndex   = 0;
-        int i           = 0;
-        //log.debug("number of triplets = " + numberTriplets);
-        for ( i = 0; i<numberTriplets; i++ )
-        {
-            dataIndex = i*3;
-            b1 = binaryData[dataIndex];
-            b2 = binaryData[dataIndex + 1];
-            b3 = binaryData[dataIndex + 2];
-
-            //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
-
-            l  = (byte)(b2 & 0x0f);
-            k  = (byte)(b1 & 0x03);
-
-            encodedIndex = i * 4;
-            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
-            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
-            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
-
-            encodedData[encodedIndex]   = lookUpBase64Alphabet[ val1 ];
-            //log.debug( "val2 = " + val2 );
-            //log.debug( "k4   = " + (k<<4) );
-            //log.debug(  "vak  = " + (val2 | (k<<4)) );
-            encodedData[encodedIndex+1] =
-                lookUpBase64Alphabet[ val2 | ( k<<4 )];
-            encodedData[encodedIndex+2] =
-                lookUpBase64Alphabet[ (l <<2 ) | val3 ];
-            encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
-        }
-
-        // form integral number of 6-bit groups
-        dataIndex    = i*3;
-        encodedIndex = i*4;
-        if (fewerThan24bits == EIGHTBIT )
-        {
-            b1 = binaryData[dataIndex];
-            k = (byte) ( b1 &0x03 );
-            //log.debug("b1=" + b1);
-            //log.debug("b1<<2 = " + (b1>>2) );
-            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
-            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
-            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
-            encodedData[encodedIndex + 2] = PAD;
-            encodedData[encodedIndex + 3] = PAD;
-        }
-        else if (fewerThan24bits == SIXTEENBIT)
-        {
-
-            b1 = binaryData[dataIndex];
-            b2 = binaryData[dataIndex +1 ];
-            l = (byte) (b2 & 0x0f);
-            k = (byte) (b1 & 0x03);
-
-            byte val1 = ((b1 & SIGN) == 0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
-            byte val2 = ((b2 & SIGN) == 0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
-
-            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
-            encodedData[encodedIndex + 1] =
-                lookUpBase64Alphabet[ val2 | ( k<<4 )];
-            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
-            encodedData[encodedIndex + 3] = PAD;
-        }
-
-        return new String(encodedData, B2CConverter.ISO_8859_1);
+        return DatatypeConverter.printBase64Binary(binaryData);
     }
 
     /**
diff --git a/java/org/apache/catalina/util/Introspection.java b/java/org/apache/catalina/util/Introspection.java
index ffdab47..833f740 100644
--- a/java/org/apache/catalina/util/Introspection.java
+++ b/java/org/apache/catalina/util/Introspection.java
@@ -153,4 +153,34 @@ public class Introspection {
         }
         return clazz;
     }
+
+    /**
+     * Converts the primitive type to its corresponding wrapper.
+     *
+     * @param clazz
+     *            Class that will be evaluated
+     * @return if the parameter is a primitive type returns its wrapper;
+     *         otherwise returns the same class
+     */
+    public static Class<?> convertPrimitiveType(Class<?> clazz) {
+        if (clazz.equals(char.class)) {
+            return Character.class;
+        } else if (clazz.equals(int.class)) {
+            return Integer.class;
+        } else if (clazz.equals(boolean.class)) {
+            return Boolean.class;
+        } else if (clazz.equals(double.class)) {
+            return Double.class;
+        } else if (clazz.equals(byte.class)) {
+            return Byte.class;
+        } else if (clazz.equals(short.class)) {
+            return Short.class;
+        } else if (clazz.equals(long.class)) {
+            return Long.class;
+        } else if (clazz.equals(float.class)) {
+            return Float.class;
+        } else {
+            return clazz;
+        }
+    }
 }
diff --git a/java/org/apache/catalina/valves/AccessLogValve.java b/java/org/apache/catalina/valves/AccessLogValve.java
index d799e0e..f1364fb 100644
--- a/java/org/apache/catalina/valves/AccessLogValve.java
+++ b/java/org/apache/catalina/valves/AccessLogValve.java
@@ -156,7 +156,7 @@ import org.apache.tomcat.util.buf.B2CConverter;
  * @author Takayuki Kaneko
  * @author Peter Rossbach
  *
- * @version $Id: AccessLogValve.java 1417424 2012-12-05 14:00:15Z rjung $
+ * @version $Id: AccessLogValve.java 1456499 2013-03-14 15:55:43Z markt $
  */
 
 public class AccessLogValve extends ValveBase implements AccessLog {
@@ -856,7 +856,18 @@ public class AccessLogValve extends ValveBase implements AccessLog {
      *  Set the date format date based log rotation.
      */
     public void setFileDateFormat(String fileDateFormat) {
-        this.fileDateFormat = fileDateFormat;
+        String newFormat;
+        if (fileDateFormat == null) {
+            newFormat = "";
+        } else {
+            newFormat = fileDateFormat;
+        }
+        this.fileDateFormat = newFormat;
+
+        synchronized (this) {
+            fileDateFormatter = new SimpleDateFormat(newFormat, Locale.US);
+            fileDateFormatter.setTimeZone(TimeZone.getDefault());
+        }
     }
 
 
@@ -967,6 +978,34 @@ public class AccessLogValve extends ValveBase implements AccessLog {
 
 
     /**
+     * Rotate the log file if necessary.
+     */
+    public void rotate() {
+        if (rotatable) {
+            // Only do a logfile switch check once a second, max.
+            long systime = System.currentTimeMillis();
+            if ((systime - rotationLastChecked) > 1000) {
+                synchronized(this) {
+                    if ((systime - rotationLastChecked) > 1000) {
+                        rotationLastChecked = systime;
+
+                        String tsDate;
+                        // Check for a change of date
+                        tsDate = fileDateFormatter.format(new Date(systime));
+
+                        // If the date has changed, switch log files
+                        if (!dateStamp.equals(tsDate)) {
+                            close(true);
+                            dateStamp = tsDate;
+                            open();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Rename the existing log file to something else. Then open the
      * old log file name up once again. Intended to be called by a JMX
      * agent.
@@ -1097,28 +1136,8 @@ public class AccessLogValve extends ValveBase implements AccessLog {
      * @param message Message to be logged
      */
     public void log(String message) {
-        if (rotatable) {
-            // Only do a logfile switch check once a second, max.
-            long systime = System.currentTimeMillis();
-            if ((systime - rotationLastChecked) > 1000) {
-                synchronized(this) {
-                    if ((systime - rotationLastChecked) > 1000) {
-                        rotationLastChecked = systime;
-
-                        String tsDate;
-                        // Check for a change of date
-                        tsDate = fileDateFormatter.format(new Date(systime));
 
-                        // If the date has changed, switch log files
-                        if (!dateStamp.equals(tsDate)) {
-                            close(true);
-                            dateStamp = tsDate;
-                            open();
-                        }
-                    }
-                }
-            }
-        }
+        rotate();
 
         /* In case something external rotated the file instead */
         if (checkExists) {
@@ -1230,10 +1249,6 @@ public class AccessLogValve extends ValveBase implements AccessLog {
 
         // Initialize the Date formatters
         String format = getFileDateFormat();
-        if (format == null || format.length() == 0) {
-            format = "yyyy-MM-dd";
-            setFileDateFormat(format);
-        }
         fileDateFormatter = new SimpleDateFormat(format, Locale.US);
         fileDateFormatter.setTimeZone(TimeZone.getDefault());
         dateStamp = fileDateFormatter.format(new Date(System.currentTimeMillis()));
diff --git a/java/org/apache/catalina/valves/ErrorReportValve.java b/java/org/apache/catalina/valves/ErrorReportValve.java
index d3a9061..2252c87 100644
--- a/java/org/apache/catalina/valves/ErrorReportValve.java
+++ b/java/org/apache/catalina/valves/ErrorReportValve.java
@@ -44,7 +44,7 @@ import org.apache.tomcat.util.ExceptionUtils;
  * @author <a href="mailto:nicolaken at supereva.it">Nicola Ken Barozzi</a> Aisa
  * @author <a href="mailto:stefano at apache.org">Stefano Mazzocchi</a>
  * @author Yoav Shapira
- * @version $Id: ErrorReportValve.java 1416537 2012-12-03 14:21:12Z markt $
+ * @version $Id: ErrorReportValve.java 1445329 2013-02-12 20:08:43Z markt $
  */
 
 public class ErrorReportValve extends ValveBase {
@@ -179,7 +179,8 @@ public class ErrorReportValve extends ValveBase {
             }
         }
 
-        // Do nothing if there is no report for the specified status code
+        // Do nothing if there is no report for the specified status code and
+        // no error message provided
         String report = null;
         try {
             report = sm.getString("http." + statusCode);
@@ -187,7 +188,11 @@ public class ErrorReportValve extends ValveBase {
             ExceptionUtils.handleThrowable(t);
         }
         if (report == null) {
-            return;
+            if (message.length() == 0) {
+                return;
+            } else {
+                report = sm.getString("errorReportValve.noDescription");
+            }
         }
 
         StringBuilder sb = new StringBuilder();
diff --git a/java/org/apache/catalina/valves/LocalStrings.properties b/java/org/apache/catalina/valves/LocalStrings.properties
index 07b0116..5064ae9 100644
--- a/java/org/apache/catalina/valves/LocalStrings.properties
+++ b/java/org/apache/catalina/valves/LocalStrings.properties
@@ -42,6 +42,7 @@ errorReportValve.exception=exception
 errorReportValve.rootCause=root cause
 errorReportValve.note=note
 errorReportValve.rootCauseInLogs=The full stack trace of the root cause is available in the {0} logs.
+errorReportValve.noDescription=No description available
 
 # Remote IP valve
 remoteIpValve.syntax=Invalid regular expressions [{0}] provided.
diff --git a/java/org/apache/catalina/valves/mbeans-descriptors.xml b/java/org/apache/catalina/valves/mbeans-descriptors.xml
index b1810b7..1f6e2f8 100644
--- a/java/org/apache/catalina/valves/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/valves/mbeans-descriptors.xml
@@ -114,6 +114,12 @@
                type="java.lang.String"/>
 
     <operation name="rotate"
+               description="Check if the log file is due to be rotated and rotate if it is"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+
+    <operation name="rotate"
                description="Move the existing log file to a new name"
                impact="ACTION"
                returnType="boolean">
@@ -282,6 +288,12 @@
                type="java.lang.String"/>
 
     <operation name="rotate"
+               description="Check if the log file is due to be rotated and rotate if it is"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+
+    <operation name="rotate"
                description="Move the existing log file to a new name"
                impact="ACTION"
                returnType="boolean">
diff --git a/java/org/apache/catalina/websocket/StreamInbound.java b/java/org/apache/catalina/websocket/StreamInbound.java
index fb13ab1..e401ff2 100644
--- a/java/org/apache/catalina/websocket/StreamInbound.java
+++ b/java/org/apache/catalina/websocket/StreamInbound.java
@@ -27,6 +27,7 @@ import java.nio.charset.UnmappableCharacterException;
 import org.apache.coyote.http11.upgrade.UpgradeInbound;
 import org.apache.coyote.http11.upgrade.UpgradeOutbound;
 import org.apache.coyote.http11.upgrade.UpgradeProcessor;
+import org.apache.tomcat.util.buf.Utf8Decoder;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 
 /**
diff --git a/java/org/apache/catalina/websocket/Utf8Decoder.java b/java/org/apache/catalina/websocket/Utf8Decoder.java
deleted file mode 100644
index 7a0b173..0000000
--- a/java/org/apache/catalina/websocket/Utf8Decoder.java
+++ /dev/null
@@ -1,207 +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.catalina.websocket;
-
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-
-import org.apache.tomcat.util.buf.B2CConverter;
-
-/**
- * Decodes bytes to UTF-8. Extracted from Apache Harmony and modified to reject
- * code points from U+D800 to U+DFFF as per RFC3629. The standard Java decoder
- * does not reject these.
- */
-public class Utf8Decoder extends CharsetDecoder {
-
-    // The next table contains information about UTF-8 charset and
-    // correspondence of 1st byte to the length of sequence
-    // For information please visit http://www.ietf.org/rfc/rfc3629.txt
-    //
-    // Please note, o means 0, actually.
-    // -------------------------------------------------------------------
-    // 0         1         2         3          Value
-    // -------------------------------------------------------------------
-    // oxxxxxxx                                 00000000 00000000 0xxxxxxx
-    // 11oyyyyy  1oxxxxxx                       00000000 00000yyy yyxxxxxx
-    // 111ozzzz  1oyyyyyy  1oxxxxxx             00000000 zzzzyyyy yyxxxxxx
-    // 1111ouuu  1ouuzzzz  1oyyyyyy  1oxxxxxx   000uuuuu zzzzyyyy yyxxxxxx
-
-    private static final int remainingBytes[] = {
-            // 1owwwwww
-            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-            // 11oyyyyy
-            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-            1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-            // 111ozzzz
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            // 1111ouuu
-            3, 3, 3, 3, 3, 3, 3, 3,
-            // > 11110111
-            -1, -1, -1, -1, -1, -1, -1, -1 };
-
-    private static final int remainingNumbers[] = {
-                   0, //                0                 1                2           3
-                4224, // (01o00000b <<  6)+(1o000000b)
-              401536, // (011o0000b << 12)+(1o000000b <<  6)+(1o000000b)
-            29892736  // (0111o000b << 18)+(1o000000b << 12)+(1o000000b << 6)+(1o000000b)
-    };
-
-    private static final int lowerEncodingLimit[] = { -1, 0x80, 0x800, 0x10000 };
-
-    public Utf8Decoder() {
-        super(B2CConverter.UTF_8, 1.0f, 1.0f);
-    }
-
-    @Override
-    protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
-        if (in.hasArray() && out.hasArray()) {
-            return decodeHasArray(in, out);
-        }
-        return decodeNotHasArray(in, out);
-    }
-
-    private CoderResult decodeNotHasArray(ByteBuffer in, CharBuffer out) {
-        int outRemaining = out.remaining();
-        int pos = in.position();
-        int limit = in.limit();
-        try {
-            while (pos < limit) {
-                if (outRemaining == 0) {
-                    return CoderResult.OVERFLOW;
-                }
-
-                int jchar = in.get();
-                if (jchar < 0) {
-                    jchar = jchar & 0x7F;
-                    int tail = remainingBytes[jchar];
-                    if (tail == -1) {
-                        return CoderResult.malformedForLength(1);
-                    }
-                    if (limit - pos < 1 + tail) {
-                        return CoderResult.UNDERFLOW;
-                    }
-
-                    int nextByte;
-                    for (int i = 0; i < tail; i++) {
-                        nextByte = in.get() & 0xFF;
-                        if ((nextByte & 0xC0) != 0x80) {
-                            return CoderResult
-                                    .malformedForLength(1 + i);
-                        }
-                        jchar = (jchar << 6) + nextByte;
-                    }
-                    jchar -= remainingNumbers[tail];
-                    if (jchar < lowerEncodingLimit[tail]) {
-                        // Should have been encoded in a fewer octets
-                        return CoderResult.malformedForLength(1);
-                    }
-                    pos += tail;
-                }
-                if (jchar <= 0xffff) {
-                  out.put((char) jchar);
-                  outRemaining--;
-                } else {
-                  if (outRemaining < 2) {
-                      return CoderResult.OVERFLOW;
-                  }
-                  out.put((char) ((jchar >> 0xA) + 0xD7C0));
-                  out.put((char) ((jchar & 0x3FF) + 0xDC00));
-                  outRemaining -= 2;
-                }
-                pos++;
-            }
-            return CoderResult.UNDERFLOW;
-        } finally {
-            in.position(pos);
-        }
-    }
-
-    private CoderResult decodeHasArray(ByteBuffer in, CharBuffer out) {
-        int outRemaining = out.remaining();
-        int pos = in.position();
-        int limit = in.limit();
-        final byte[] bArr = in.array();
-        final char[] cArr = out.array();
-        final int inIndexLimit = limit + in.arrayOffset();
-
-        int inIndex = pos + in.arrayOffset();
-        int outIndex = out.position() + out.arrayOffset();
-
-        // if someone would change the limit in process,
-        // he would face consequences
-        for (; inIndex < inIndexLimit && outRemaining > 0; inIndex++) {
-            int jchar = bArr[inIndex];
-            if (jchar < 0) {
-                jchar = jchar & 0x7F;
-                int tail = remainingBytes[jchar];
-
-                if (tail == -1) {
-                    in.position(inIndex - in.arrayOffset());
-                    out.position(outIndex - out.arrayOffset());
-                    return CoderResult.malformedForLength(1);
-                }
-                if (inIndexLimit - inIndex < 1 + tail) {
-                    break;
-                }
-
-                for (int i = 0; i < tail; i++) {
-                    int nextByte = bArr[inIndex + i + 1] & 0xFF;
-                    if ((nextByte & 0xC0) != 0x80) {
-                        in.position(inIndex - in.arrayOffset());
-                        out.position(outIndex - out.arrayOffset());
-                        return CoderResult.malformedForLength(1 + i);
-                    }
-                    jchar = (jchar << 6) + nextByte;
-                }
-                jchar -= remainingNumbers[tail];
-                if (jchar < lowerEncodingLimit[tail]) {
-                    // Should have been encoded in fewer octets
-                    in.position(inIndex - in.arrayOffset());
-                    out.position(outIndex - out.arrayOffset());
-                    return CoderResult.malformedForLength(1);
-                }
-                inIndex += tail;
-            }
-            // Note: This is the additional test added
-            if (jchar >= 0xD800 && jchar <=0xDFFF) {
-                return CoderResult.unmappableForLength(3);
-            }
-            if (jchar <= 0xffff) {
-              cArr[outIndex++] = (char) jchar;
-              outRemaining--;
-            } else {
-              if (outRemaining < 2) {
-                  return CoderResult.OVERFLOW;
-              }
-              cArr[outIndex++] = (char) ((jchar >> 0xA) + 0xD7C0);
-              cArr[outIndex++] = (char) ((jchar & 0x3FF) + 0xDC00);
-              outRemaining -= 2;
-            }
-        }
-        in.position(inIndex - in.arrayOffset());
-        out.position(outIndex - out.arrayOffset());
-        return (outRemaining == 0 && inIndex < inIndexLimit) ?
-                CoderResult.OVERFLOW :
-                CoderResult.UNDERFLOW;
-    }
-}
diff --git a/java/org/apache/catalina/websocket/WsFrame.java b/java/org/apache/catalina/websocket/WsFrame.java
index 7cdc14e..4573b26 100644
--- a/java/org/apache/catalina/websocket/WsFrame.java
+++ b/java/org/apache/catalina/websocket/WsFrame.java
@@ -24,6 +24,7 @@ import java.nio.charset.CoderResult;
 
 import org.apache.catalina.util.Conversions;
 import org.apache.coyote.http11.upgrade.UpgradeProcessor;
+import org.apache.tomcat.util.buf.Utf8Decoder;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
diff --git a/java/org/apache/catalina/websocket/WsOutbound.java b/java/org/apache/catalina/websocket/WsOutbound.java
index 2f3ef07..9eacd14 100644
--- a/java/org/apache/catalina/websocket/WsOutbound.java
+++ b/java/org/apache/catalina/websocket/WsOutbound.java
@@ -269,6 +269,10 @@ public class WsOutbound {
         if (closed) {
             return;
         }
+
+        // Send any partial data we have
+        doFlush(false);
+
         closed = true;
 
         upgradeOutbound.write(0x88);
@@ -329,7 +333,7 @@ public class WsOutbound {
             throw new IOException(sm.getString("outbound.closed"));
         }
 
-        doFlush(true);
+        doFlush(false);
 
         upgradeOutbound.write(0x80 | opcode);
         if (data == null) {
@@ -355,6 +359,10 @@ public class WsOutbound {
     private void doWriteBytes(ByteBuffer buffer, boolean finalFragment)
             throws IOException {
 
+        if (closed) {
+            throw new IOException(sm.getString("outbound.closed"));
+        }
+
         // Work out the first byte
         int first = 0x00;
         if (finalFragment) {
@@ -391,7 +399,8 @@ public class WsOutbound {
         }
 
         // Write the content
-        upgradeOutbound.write(buffer.array(), 0, buffer.limit());
+        upgradeOutbound.write(buffer.array(), buffer.arrayOffset(),
+                buffer.limit());
         upgradeOutbound.flush();
 
         // Reset
diff --git a/java/org/apache/coyote/Request.java b/java/org/apache/coyote/Request.java
index 7ae8f63..8ea54af 100644
--- a/java/org/apache/coyote/Request.java
+++ b/java/org/apache/coyote/Request.java
@@ -140,7 +140,7 @@ public final class Request {
 
     private int bytesRead=0;
     // Time of the request - useful to avoid repeated calls to System.currentTime
-    private long startTime = 0L;
+    private long startTime = -1;
     private int available = 0;
 
     private RequestInfo reqProcessorMX=new RequestInfo(this);
@@ -506,6 +506,8 @@ public final class Request {
         remoteUser.recycle();
         authType.recycle();
         attributes.clear();
+
+        startTime = -1;
     }
 
     // -------------------- Info  --------------------
diff --git a/java/org/apache/coyote/http11/AbstractHttp11Processor.java b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
index c493ccc..8daac7a 100644
--- a/java/org/apache/coyote/http11/AbstractHttp11Processor.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
@@ -937,7 +937,12 @@ public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
                     response.setStatus(503);
                     error = true;
                 } else {
-                    request.setStartTime(System.currentTimeMillis());
+                    // Make sure that connectors that are non-blocking during
+                    // header processing (NIO) only set the start time the first
+                    // time a request is processed.
+                    if (request.getStartTime() < 0) {
+                        request.setStartTime(System.currentTimeMillis());
+                    }
                     keptAlive = true;
                     // Set this every time in case limit has been changed via JMX
                     request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
diff --git a/java/org/apache/coyote/http11/Http11AprProtocol.java b/java/org/apache/coyote/http11/Http11AprProtocol.java
index 103d853..06b6d37 100644
--- a/java/org/apache/coyote/http11/Http11AprProtocol.java
+++ b/java/org/apache/coyote/http11/Http11AprProtocol.java
@@ -191,6 +191,12 @@ public class Http11AprProtocol extends AbstractHttp11Protocol {
     public int getSSLVerifyDepth() { return ((AprEndpoint)endpoint).getSSLVerifyDepth(); }
     public void setSSLVerifyDepth(int SSLVerifyDepth) { ((AprEndpoint)endpoint).setSSLVerifyDepth(SSLVerifyDepth); }
     
+    /**
+     * Disable SSL compression.
+     */
+    public boolean getSSLDisableCompression() { return ((AprEndpoint)endpoint).getSSLDisableCompression(); }
+    public void setSSLDisableCompression(boolean disable) { ((AprEndpoint)endpoint).setSSLDisableCompression(disable); }
+
     // ----------------------------------------------------- JMX related methods
 
     @Override
diff --git a/java/org/apache/coyote/http11/InternalNioInputBuffer.java b/java/org/apache/coyote/http11/InternalNioInputBuffer.java
index d6c43bf..e25beba 100644
--- a/java/org/apache/coyote/http11/InternalNioInputBuffer.java
+++ b/java/org/apache/coyote/http11/InternalNioInputBuffer.java
@@ -145,7 +145,8 @@ public class InternalNioInputBuffer extends AbstractInputBuffer<NioChannel> {
 
 
     /**
-     * Maximum allowed size of the HTTP request line plus headers.
+     * Maximum allowed size of the HTTP request line plus headers plus any
+     * leading blank lines.
      */
     private final int headerBufferSize;
 
@@ -154,18 +155,6 @@ public class InternalNioInputBuffer extends AbstractInputBuffer<NioChannel> {
      */
     private int socketReadBufferSize;
 
-    /**
-     * Additional size we allocate to the buffer to be more effective when
-     * skipping empty lines that may precede the request.
-     */
-    private static final int skipBlankLinesSize = 1024;
-
-    /**
-     * How many bytes in the buffer are occupied by skipped blank lines that
-     * precede the request.
-     */
-    private int skipBlankLinesBytes;
-
 
     // --------------------------------------------------------- Public Methods
 
@@ -234,22 +223,15 @@ public class InternalNioInputBuffer extends AbstractInputBuffer<NioChannel> {
                     if (useAvailableDataOnly) {
                         return false;
                     }
-                    // Ignore bytes that were read
-                    pos = lastValid = 0;
                     // Do a simple read with a short timeout
-                    if ( readSocket(true, false)==0 ) return false;
+                    if (!fill(true, false)) {
+                        return false;
+                    }
                 }
                 chr = buf[pos++];
             } while ((chr == Constants.CR) || (chr == Constants.LF));
             pos--;
-            if (pos >= skipBlankLinesSize) {
-                // Move data, to have enough space for further reading
-                // of headers and body
-                System.arraycopy(buf, pos, buf, 0, lastValid - pos);
-                lastValid -= pos;
-                pos = 0;
-            }
-            skipBlankLinesBytes = pos;
+
             parsingRequestLineStart = pos;
             parsingRequestLinePhase = 2;
             if (log.isDebugEnabled()) {
@@ -481,7 +463,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer<NioChannel> {
             // limitation to enforce the meaning of headerBufferSize
             // From the way how buf is allocated and how blank lines are being
             // read, it should be enough to check (1) only.
-            if (pos - skipBlankLinesBytes > headerBufferSize
+            if (pos > headerBufferSize
                     || buf.length - pos < socketReadBufferSize) {
                 throw new IllegalArgumentException(
                         sm.getString("iib.requestheadertoolarge.error"));
@@ -768,8 +750,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer<NioChannel> {
         socketReadBufferSize =
             socket.getBufHandler().getReadBuffer().capacity();
 
-        int bufLength = skipBlankLinesSize + headerBufferSize
-                + socketReadBufferSize;
+        int bufLength = headerBufferSize + socketReadBufferSize;
         if (buf == null || buf.length < bufLength) {
             buf = new byte[bufLength];
         }
@@ -795,7 +776,7 @@ public class InternalNioInputBuffer extends AbstractInputBuffer<NioChannel> {
 
         if (parsingHeader) {
 
-            if (lastValid == buf.length) {
+            if (lastValid > headerBufferSize) {
                 throw new IllegalArgumentException
                     (sm.getString("iib.requestheadertoolarge.error"));
             }
diff --git a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
index 088172d..50deee6 100644
--- a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
+++ b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
@@ -160,7 +160,10 @@ public class ChunkedInputFilter implements InputFilter {
         int result = 0;
 
         if (pos >= lastValid) {
-            readBytes();
+            if (readBytes() < 0) {
+                throw new IOException(
+                        "Unexpected end of stream whilst reading request body");
+            }
         }
 
         if (remaining > (lastValid - pos)) {
@@ -398,7 +401,7 @@ public class ChunkedInputFilter implements InputFilter {
      */
     protected void parseEndChunk() throws IOException {
 
-        // Handle option trailer headers
+        // Handle optional trailer headers
         while (parseHeader()) {
             // Loop until we run out of headers
         }
diff --git a/java/org/apache/jasper/JspC.java b/java/org/apache/jasper/JspC.java
index 90614a7..85034cf 100644
--- a/java/org/apache/jasper/JspC.java
+++ b/java/org/apache/jasper/JspC.java
@@ -1516,7 +1516,7 @@ public class JspC extends Task implements Options {
         URL urlsA[]=new URL[urls.size()];
         urls.toArray(urlsA);
         loader = new URLClassLoader(urlsA, this.getClass().getClassLoader());
-
+        context.setClassLoader(loader);
     }
 
     /**
diff --git a/java/org/apache/jasper/compiler/DefaultErrorHandler.java b/java/org/apache/jasper/compiler/DefaultErrorHandler.java
index 2b54e51..41a955a 100644
--- a/java/org/apache/jasper/compiler/DefaultErrorHandler.java
+++ b/java/org/apache/jasper/compiler/DefaultErrorHandler.java
@@ -87,7 +87,8 @@ class DefaultErrorHandler implements ErrorHandler {
                 buf.append(details[i].getJspExtract());
             } else {
                 args = new Object[] {
-                        Integer.valueOf(details[i].getJavaLineNumber()) };
+                        Integer.valueOf(details[i].getJavaLineNumber()),
+                        details[i].getJavaFileName() };
                 buf.append(Constants.NEWLINE);
                 buf.append(Constants.NEWLINE);
                 buf.append(Localizer.getMessage("jsp.error.java.line.number",
diff --git a/java/org/apache/jasper/compiler/ELInterpreter.java b/java/org/apache/jasper/compiler/ELInterpreter.java
new file mode 100644
index 0000000..d2c5bce
--- /dev/null
+++ b/java/org/apache/jasper/compiler/ELInterpreter.java
@@ -0,0 +1,46 @@
+/*
+ * 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.jasper.compiler;
+
+import org.apache.jasper.JspCompilationContext;
+
+/**
+ * Defines the interface for the expression language interpreter. This allows
+ * users to provide custom EL interpreter implementations that can optimise
+ * EL processing for an application by , for example, performing code generation
+ * for simple expressions.
+ */
+public interface ELInterpreter {
+
+    /**
+     * Returns the string representing the code that will be inserted into the
+     * servlet generated for JSP. The default implementation creates a call to
+     * {@link org.apache.jasper.runtime.PageContextImpl#proprietaryEvaluate(
+     * String, Class, javax.servlet.jsp.PageContext,
+     * org.apache.jasper.runtime.ProtectedFunctionMapper, boolean)} but other
+     * implementations may produce more optimised code.
+     *
+     * @param expression a String containing zero or more "${}" expressions
+     * @param expectedType the expected type of the interpreted result
+     * @param fnmapvar Variable pointing to a function map.
+     * @param xmlEscape True if the result should do XML escaping
+     * @return a String representing a call to the EL interpreter.
+     */
+    public String interpreterCall(JspCompilationContext context,
+            boolean isTagFile, String expression,
+            Class<?> expectedType, String fnmapvar, boolean xmlEscape);
+}
diff --git a/java/org/apache/jasper/compiler/ELInterpreterFactory.java b/java/org/apache/jasper/compiler/ELInterpreterFactory.java
new file mode 100644
index 0000000..0804a00
--- /dev/null
+++ b/java/org/apache/jasper/compiler/ELInterpreterFactory.java
@@ -0,0 +1,104 @@
+/*
+ * 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.jasper.compiler;
+
+import javax.servlet.ServletContext;
+
+import org.apache.jasper.JspCompilationContext;
+
+/**
+ * Provides {@link ELInterpreter} instances for JSP compilation.
+ *
+ * The search order is as follows:
+ * <ol>
+ * <li>ELInterpreter instance or implementation class name provided as a
+ *     ServletContext attribute</li>
+ * <li>Implementation class named in a ServletContext initialisation parameter
+ *     </li>
+ * <li>Default implementation</li>
+ * </ol>
+ */
+public class ELInterpreterFactory {
+
+    public static final String EL_INTERPRETER_CLASS_NAME =
+            ELInterpreter.class.getName();
+
+    private static final ELInterpreter DEFAULT_INSTANCE =
+            new DefaultELInterpreter();
+
+
+    /**
+     * Obtain the correct EL Interpreter for the given web application.
+     */
+    public static ELInterpreter getELInterpreter(ServletContext context)
+            throws Exception {
+
+        ELInterpreter result = null;
+
+        // Search for an implementation
+        // 1. ServletContext attribute (set by application or cached by a
+        //    previous call to this method).
+        Object attribute = context.getAttribute(EL_INTERPRETER_CLASS_NAME);
+        if (attribute instanceof ELInterpreter) {
+            return (ELInterpreter) attribute;
+        } else if (attribute instanceof String) {
+            result = createInstance(context, (String) attribute);
+        }
+
+        // 2. ServletContext init parameter
+        if (result == null) {
+            String className =
+                    context.getInitParameter(EL_INTERPRETER_CLASS_NAME);
+            if (className != null) {
+                result = createInstance(context, className);
+            }
+        }
+
+        // 3. Default
+        if (result == null) {
+            result = DEFAULT_INSTANCE;
+        }
+
+        // Cache the result for next time
+        context.setAttribute(EL_INTERPRETER_CLASS_NAME, result);
+        return result;
+    }
+
+
+    private static ELInterpreter createInstance(ServletContext context,
+            String className) throws Exception {
+        return (ELInterpreter) context.getClassLoader().loadClass(
+                    className).newInstance();
+    }
+
+
+    private ELInterpreterFactory() {
+        // Utility class. Hide default constructor.
+    }
+
+
+    public static class DefaultELInterpreter implements ELInterpreter {
+
+        @Override
+        public String interpreterCall(JspCompilationContext context,
+                boolean isTagFile, String expression,
+                Class<?> expectedType, String fnmapvar, boolean xmlEscape) {
+            return JspUtil.interpreterCall(isTagFile, expression, expectedType,
+                    fnmapvar, xmlEscape);
+        }
+    }
+}
diff --git a/java/org/apache/jasper/compiler/Generator.java b/java/org/apache/jasper/compiler/Generator.java
index 08fdf8f..067df13 100644
--- a/java/org/apache/jasper/compiler/Generator.java
+++ b/java/org/apache/jasper/compiler/Generator.java
@@ -125,6 +125,8 @@ class Generator {
     
     private final DateFormat timestampFormat;
 
+    private final ELInterpreter elInterpreter;
+
     /**
      * @param s
      *            the input string
@@ -831,8 +833,8 @@ class Generator {
                 }
                 return v;
             } else if (attr.isELInterpreterInput()) {
-                v = JspUtil.interpreterCall(this.isTagFile, v, expectedType,
-                        attr.getEL().getMapName(), false);
+                v = elInterpreter.interpreterCall(ctxt, this.isTagFile, v,
+                        expectedType, attr.getEL().getMapName(), false);
                 if (encode) {
                     return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
                             + v + ", request.getCharacterEncoding())";
@@ -917,9 +919,10 @@ class Generator {
             n.setBeginJavaLine(out.getJavaLine());
             if (!pageInfo.isELIgnored() && (n.getEL() != null)) {
                 out.printil("out.write("
-                        + JspUtil.interpreterCall(this.isTagFile, n.getType() +
-                                "{" + n.getText() + "}", String.class,
-                                n.getEL().getMapName(), false) + ");");
+                        + elInterpreter.interpreterCall(ctxt, this.isTagFile,
+                                n.getType() + "{" + n.getText() + "}",
+                                String.class, n.getEL().getMapName(), false) +
+                        ");");
             } else {
                 out.printil("out.write("
                         + quote(n.getType() + "{" + n.getText() + "}") + ");");
@@ -2977,8 +2980,8 @@ class Generator {
                     // run attrValue through the expression interpreter
                     String mapName = (attr.getEL() != null) ? attr.getEL()
                             .getMapName() : null;
-                    attrValue = JspUtil.interpreterCall(this.isTagFile, attrValue,
-                            c[0], mapName, false);
+                    attrValue = elInterpreter.interpreterCall(ctxt,
+                            this.isTagFile, attrValue, c[0], mapName, false);
                 }
             } else {
                 attrValue = convertString(c[0], attrValue, localName,
@@ -3416,7 +3419,7 @@ class Generator {
     /**
      * Constructor.
      */
-    Generator(ServletWriter out, Compiler compiler) {
+    Generator(ServletWriter out, Compiler compiler) throws JasperException {
         this.out = out;
         methodsBuffered = new ArrayList<GenBuffer>();
         charArrayBuffer = null;
@@ -3425,6 +3428,16 @@ class Generator {
         fragmentHelperClass = new FragmentHelperClass("Helper");
         pageInfo = compiler.getPageInfo();
 
+        ELInterpreter elInterpreter = null;
+        try {
+            elInterpreter = ELInterpreterFactory.getELInterpreter(
+                    compiler.getCompilationContext().getServletContext());
+        } catch (Exception e) {
+            err.jspError("jsp.error.el_interpreter_class.instantiation",
+                    e.getMessage());
+        }
+        this.elInterpreter = elInterpreter;
+
         /*
          * Temporary hack. If a JSP page uses the "extends" attribute of the
          * page directive, the _jspInit() method of the generated servlet class
diff --git a/java/org/apache/jasper/resources/LocalStrings.properties b/java/org/apache/jasper/resources/LocalStrings.properties
index b0a77d5..4fe8a19 100644
--- a/java/org/apache/jasper/resources/LocalStrings.properties
+++ b/java/org/apache/jasper/resources/LocalStrings.properties
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# $Id: LocalStrings.properties 1377085 2012-08-24 20:21:07Z markt $
+# $Id: LocalStrings.properties 1445192 2013-02-12 14:54:52Z markt $
 #
 # Default localized string information
 # Localized this the Default Locale as is en_US
@@ -335,7 +335,7 @@ jsp.error.needAlternateJavaEncoding=Default java encoding {0} is invalid on your
 #Error when compiling, used for jsp line number error messages
 jsp.error.single.line.number=An error occurred at line: {0} in the jsp file: {1}
 jsp.error.multiple.line.number=\n\nAn error occurred between lines: {0} and {1} in the jsp file: {2}\n\n
-jsp.error.java.line.number=An error occurred at line: {0} in the generated java file
+jsp.error.java.line.number=An error occurred at line: [{0}] in the generated java file: [{1}]
 jsp.error.location=line: {0}, column: {1}
 jsp.error.corresponding.servlet=Generated servlet error:\n
 jsp.error.empty.body.not.allowed=Empty body not allowed for {0}
@@ -492,3 +492,6 @@ xmlParser.skipBomFail=Failed to skip BOM when parsing XML input stream
 
 jsp.tldCache.noTldInJar=No TLD files were found in [{0}]. Consider adding the JAR to the tomcat.util.scan.DefaultJarScanner.jarsToSkip or org.apache.catalina.startup.TldConfig.jarsToSkip property in CATALINA_BASE/conf/catalina.properties file.
 jsp.tldCache.noTldSummary=At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
+
+#ELInterpreter
+jsp.error.el_interpreter_class.instantiation=Failed to load or instantiate ELInterpreter class [{0}]
\ No newline at end of file
diff --git a/java/org/apache/jasper/resources/LocalStrings_es.properties b/java/org/apache/jasper/resources/LocalStrings_es.properties
index b63b137..c65e019 100644
--- a/java/org/apache/jasper/resources/LocalStrings_es.properties
+++ b/java/org/apache/jasper/resources/LocalStrings_es.properties
@@ -12,7 +12,7 @@
 # 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.
-# $Id: LocalStrings_es.properties 1138849 2011-06-23 12:18:20Z markt $
+# $Id: LocalStrings_es.properties 1445192 2013-02-12 14:54:52Z markt $
 #
 # Default localized string information
 # Localized para Locale es_ES
@@ -337,7 +337,7 @@ jsp.error.multiple.line.number = \n\
     \n\
     Ha tenido lugar un error entre las l\u00EDneas\: {0} y {1} en el archivo jsp\: {2}\n\
     \n
-jsp.error.java.line.number = Ha tenido lugar un error en la l\u00EDnea\: {0} en el fichero java generado
+jsp.error.java.line.number = Ha tenido lugar un error en la l\u00EDnea\: [{0}] en el fichero java generado: [{1}]
 jsp.error.location = l\u00EDnea\: {0}, columna\: {1}
 jsp.error.corresponding.servlet = Error de servlet generado\:\n
 jsp.error.empty.body.not.allowed = Cuerpo vac\u00EDo no permitido para {0}
@@ -480,3 +480,6 @@ jsp.message.jsp_unload_check = Revisando JSPs para descaga en contexto [{0}], co
 xmlParser.skipBomFail = No pude saltar BOM al analizar flujo de entrada XML 
 jsp.tldCache.noTldInJar = No se han hallado ficheros TLD en [{0}]. Considera a\u00F1adir el JAR a la propiedad tomcat.util.scan.DefaultJarScanner.jarsToSkip en el fichero  CATALINA_BASE/conf/catalina.propeperties.
 jsp.tldCache.noTldSummary = Al menos un JAR, que se ha explorado buscando TLDs, a\u00FAn no conten\u00EDa TLDs. Activar historial de depuraci\u00F3n para este historiador para una completa lista de los JARs que fueron explorados y de los que nos se hall\u00F3 TLDs. Saltarse JARs no necesarios durante la exploraci\u00F3n puede dar lugar a una mejora de tiempo significativa en el arranque y compilaci\u00F3n de JSP .
+
+#ELInterpreter
+jsp.error.el_interpreter_class.instantiation=No se puede cargar la clase ELInterpreter llamada [{0}]
\ No newline at end of file
diff --git a/java/org/apache/jasper/resources/LocalStrings_fr.properties b/java/org/apache/jasper/resources/LocalStrings_fr.properties
index 446101b..597ca1a 100644
--- a/java/org/apache/jasper/resources/LocalStrings_fr.properties
+++ b/java/org/apache/jasper/resources/LocalStrings_fr.properties
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# $Id: LocalStrings_fr.properties 919748 2010-03-06 11:49:56Z rjung $
+# $Id: LocalStrings_fr.properties 1445192 2013-02-12 14:54:52Z markt $
 #
 # Default localized string information
 # Localized this the Default Locale as is fr_FR
@@ -314,3 +314,6 @@ jsp.error.attributes.not.allowed = {0} ne doit avoir aucun attribut
 #jsp.error.jspoutput.nonemptybody=
 #jsp.error.jspoutput.invalidUse=
 #jsp.error.invalid.bean=
+
+#ELInterpreter
+jsp.error.el_interpreter_class.instantiation=Impossible de charger ou d''instancier la classe ELInterpreter [{0}]
\ No newline at end of file
diff --git a/java/org/apache/jasper/resources/LocalStrings_ja.properties b/java/org/apache/jasper/resources/LocalStrings_ja.properties
index 319fa27..389456f 100644
--- a/java/org/apache/jasper/resources/LocalStrings_ja.properties
+++ b/java/org/apache/jasper/resources/LocalStrings_ja.properties
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# $Id: LocalStrings_ja.properties 898289 2010-01-12 11:42:46Z markt $
+# $Id: LocalStrings_ja.properties 1445192 2013-02-12 14:54:52Z markt $
 #
 # Default localized string information
 # Localized this the Default Locale as is ja_JP
@@ -415,3 +415,5 @@ jsp.error.unbalanced.endtag=\u7d42\u4e86\u30bf\u30b0 \"</{0}\" \u306e\u5bfe\u
 jsp.error.invalid.bean=useBean\u306e\u30af\u30e9\u30b9\u5c5e\u6027 {0} \u306e\u5024\u304c\u7121\u52b9\u3067\u3059
 jsp.error.prefix.use_before_dcl=\u3053\u306e\u30bf\u30b0\u6307\u793a\u5b50\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3001\u3059\u3067\u306b\u30d5\u30a1\u30a4\u30eb {1} \u306e {2} \u884c\u76ee\u306e\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059
 
+#ELInterpreter
+jsp.error.el_interpreter_class.instantiation=ELInterpreter class\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f [{0}]
\ No newline at end of file
diff --git a/java/org/apache/jasper/runtime/JspContextWrapper.java b/java/org/apache/jasper/runtime/JspContextWrapper.java
index 8a906d1..fe44638 100644
--- a/java/org/apache/jasper/runtime/JspContextWrapper.java
+++ b/java/org/apache/jasper/runtime/JspContextWrapper.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.jasper.runtime;
 
 import java.io.IOException;
@@ -77,10 +76,22 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
 
     private HashMap<String, Object> originalNestedVars;
 
+    private ServletContext servletContext = null;
+
+    private ELContext elContext = null;
+
+    private PageContext rootJspCtxt;
+
     public JspContextWrapper(JspContext jspContext,
             ArrayList<String> nestedVars, ArrayList<String> atBeginVars,
             ArrayList<String> atEndVars, Map<String,String> aliases) {
         this.invokingJspCtxt = (PageContext) jspContext;
+        if (jspContext instanceof JspContextWrapper) {
+            rootJspCtxt = ((JspContextWrapper)jspContext).rootJspCtxt;
+        }
+        else {
+            rootJspCtxt = invokingJspCtxt;
+        }
         this.nestedVars = nestedVars;
         this.atBeginVars = atBeginVars;
         this.atEndVars = atEndVars;
@@ -123,7 +134,7 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
             return pageAttributes.get(name);
         }
 
-        return invokingJspCtxt.getAttribute(name, scope);
+        return rootJspCtxt.getAttribute(name, scope);
     }
 
     @Override
@@ -156,7 +167,7 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
                 removeAttribute(name, PAGE_SCOPE);
             }
         } else {
-            invokingJspCtxt.setAttribute(name, value, scope);
+            rootJspCtxt.setAttribute(name, value, scope);
         }
     }
 
@@ -170,13 +181,13 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
 
         Object o = pageAttributes.get(name);
         if (o == null) {
-            o = invokingJspCtxt.getAttribute(name, REQUEST_SCOPE);
+            o = rootJspCtxt.getAttribute(name, REQUEST_SCOPE);
             if (o == null) {
                 if (getSession() != null) {
-                    o = invokingJspCtxt.getAttribute(name, SESSION_SCOPE);
+                    o = rootJspCtxt.getAttribute(name, SESSION_SCOPE);
                 }
                 if (o == null) {
-                    o = invokingJspCtxt.getAttribute(name, APPLICATION_SCOPE);
+                    o = rootJspCtxt.getAttribute(name, APPLICATION_SCOPE);
                 }
             }
         }
@@ -193,11 +204,11 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
         }
 
         pageAttributes.remove(name);
-        invokingJspCtxt.removeAttribute(name, REQUEST_SCOPE);
+        rootJspCtxt.removeAttribute(name, REQUEST_SCOPE);
         if (getSession() != null) {
-            invokingJspCtxt.removeAttribute(name, SESSION_SCOPE);
+            rootJspCtxt.removeAttribute(name, SESSION_SCOPE);
         }
-        invokingJspCtxt.removeAttribute(name, APPLICATION_SCOPE);
+        rootJspCtxt.removeAttribute(name, APPLICATION_SCOPE);
     }
 
     @Override
@@ -211,7 +222,7 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
         if (scope == PAGE_SCOPE) {
             pageAttributes.remove(name);
         } else {
-            invokingJspCtxt.removeAttribute(name, scope);
+            rootJspCtxt.removeAttribute(name, scope);
         }
     }
 
@@ -226,7 +237,7 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
         if (pageAttributes.get(name) != null) {
             return PAGE_SCOPE;
         } else {
-            return invokingJspCtxt.getAttributesScope(name);
+            return rootJspCtxt.getAttributesScope(name);
         }
     }
 
@@ -236,7 +247,7 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
             return Collections.enumeration(pageAttributes.keySet());
         }
 
-        return invokingJspCtxt.getAttributeNamesInScope(scope);
+        return rootJspCtxt.getAttributeNamesInScope(scope);
     }
 
     @Override
@@ -246,12 +257,12 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
 
     @Override
     public JspWriter getOut() {
-        return invokingJspCtxt.getOut();
+        return rootJspCtxt.getOut();
     }
 
     @Override
     public HttpSession getSession() {
-        return invokingJspCtxt.getSession();
+        return rootJspCtxt.getSession();
     }
 
     @Override
@@ -266,7 +277,7 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
 
     @Override
     public ServletResponse getResponse() {
-        return invokingJspCtxt.getResponse();
+        return rootJspCtxt.getResponse();
     }
 
     @Override
@@ -281,7 +292,10 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
 
     @Override
     public ServletContext getServletContext() {
-        return invokingJspCtxt.getServletContext();
+        if (servletContext == null) {
+            servletContext = rootJspCtxt.getServletContext();
+        }
+        return servletContext;
     }
 
     @Override
@@ -481,7 +495,10 @@ public class JspContextWrapper extends PageContext implements VariableResolver {
     public ELContext getELContext() {
         // instead decorate!!!
         
-        return this.invokingJspCtxt.getELContext();
+        if (elContext == null) {
+            elContext = rootJspCtxt.getELContext();
+        }
+        return elContext;
         
         /*
         if (this.elContext != null) {
diff --git a/java/org/apache/jasper/servlet/JspCServletContext.java b/java/org/apache/jasper/servlet/JspCServletContext.java
index ec97119..f82a0ce 100644
--- a/java/org/apache/jasper/servlet/JspCServletContext.java
+++ b/java/org/apache/jasper/servlet/JspCServletContext.java
@@ -78,9 +78,14 @@ public class JspCServletContext implements ServletContext {
     protected URL myResourceBaseURL;
 
 
-    // ----------------------------------------------------------- Constructors
+    /**
+     * Web application class loader.
+     */
+    private ClassLoader loader;
 
 
+    // ----------------------------------------------------------- Constructors
+
     /**
      * Create a new instance of this ServletContext implementation.
      *
@@ -612,7 +617,12 @@ public class JspCServletContext implements ServletContext {
 
     @Override
     public ClassLoader getClassLoader() {
-        return null;
+        return loader;
+    }
+
+
+    public void setClassLoader(ClassLoader loader) {
+        this.loader = loader;
     }
 
 
diff --git a/java/org/apache/naming/resources/DirContextURLConnection.java b/java/org/apache/naming/resources/DirContextURLConnection.java
index 03bd8ec..87a6aec 100644
--- a/java/org/apache/naming/resources/DirContextURLConnection.java
+++ b/java/org/apache/naming/resources/DirContextURLConnection.java
@@ -53,7 +53,7 @@ import org.apache.tomcat.util.http.FastHttpDateFormat;
  * content is directly returned.
  * 
  * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
- * @version $Revision: 1429991 $
+ * @version $Revision: 1452791 $
  */
 public class DirContextURLConnection extends URLConnection {
 
@@ -439,7 +439,9 @@ public class DirContextURLConnection extends URLConnection {
                     collection.list("/");
                 while (enumeration.hasMoreElements()) {
                     NameClassPair ncp = enumeration.nextElement();
-                    result.addElement(URL_ENCODER.encodeURL(ncp.getName()));
+                    String s = ncp.getName();
+                    result.addElement(
+                            URL_ENCODER.encodeURL(s, 0, s.length()).toString());
                 }
             } catch (NamingException e) {
                 // Unexpected exception
diff --git a/java/org/apache/tomcat/jni/SSL.java b/java/org/apache/tomcat/jni/SSL.java
index 8310b78..473f19d 100644
--- a/java/org/apache/tomcat/jni/SSL.java
+++ b/java/org/apache/tomcat/jni/SSL.java
@@ -20,7 +20,7 @@ package org.apache.tomcat.jni;
 /** SSL
  *
  * @author Mladen Turk
- * @version $Id: SSL.java 1199985 2011-11-09 21:43:23Z schultz $
+ * @version $Id: SSL.java 1435769 2013-01-20 00:09:48Z markt $
  */
 
 public final class SSL {
@@ -115,6 +115,8 @@ public final class SSL {
     public static final int SSL_OP_ALL                              = 0x00000FFF;
     /* As server, disallow session resumption on renegotiation */
     public static final int SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000;
+    /* Don't use compression even if supported */
+    public static final int SSL_OP_NO_COMPRESSION                         = 0x00020000;
     /* Permit unsafe legacy renegotiation */
     public static final int SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION      = 0x00040000;
     /* If set, always create a new key when using tmp_eddh parameters */
@@ -339,15 +341,16 @@ public final class SSL {
     public static native String getLastError();
 
     /**
-     * Return true if SSL_OP_ if defined.
-     * <p>
-     * Currently used for testing weather the
-     * SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION is supported by OpenSSL.
-     * <p>
-     * @param op SSL_OP to test.
-     * @return true if SSL_OP is supported by OpenSSL library.
+     * Return true if all the requested SSL_OP_* are supported by OpenSSL.
+     * 
+     * <i>Note that for versions of tcnative < 1.1.25, this method will
+     * return <code>true</code> if and only if <code>op</code>=
+     * {@link #SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION} and tcnative
+     * supports that flag.</i>
+     *
+     * @param op Bitwise-OR of all SSL_OP_* to test.
+     * 
+     * @return true if all SSL_OP_* are supported by OpenSSL library.
      */
     public static native boolean hasOp(int op);
-
 }
-
diff --git a/java/org/apache/tomcat/util/buf/B2CConverter.java b/java/org/apache/tomcat/util/buf/B2CConverter.java
index 7b94e7c..4492fbd 100644
--- a/java/org/apache/tomcat/util/buf/B2CConverter.java
+++ b/java/org/apache/tomcat/util/buf/B2CConverter.java
@@ -17,34 +17,24 @@
 package org.apache.tomcat.util.buf;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 
 import org.apache.tomcat.util.res.StringManager;
 
-/** Efficient conversion of bytes  to character .
- *
- *  This uses the standard JDK mechanism - a reader - but provides mechanisms
- *  to recycle all the objects that are used. It is compatible with JDK1.1
- *  and up,
- *  ( nio is better, but it's not available even in 1.2 or 1.3 )
- *
- *  Not used in the current code, the performance gain is not very big
- *  in the current case ( since String is created anyway ), but it will
- *  be used in a later version or after the remaining optimizations.
+/**
+ * NIO based character decoder.
  */
 public class B2CConverter {
 
-
-    private static final org.apache.juli.logging.Log log=
-        org.apache.juli.logging.LogFactory.getLog( B2CConverter.class );
-
     private static final StringManager sm =
         StringManager.getManager(Constants.Package);
 
@@ -54,13 +44,16 @@ public class B2CConverter {
     public static final Charset ISO_8859_1;
     public static final Charset UTF_8;
 
+    // Protected so unit tests can use it
+    protected static final int LEFTOVER_SIZE = 9;
+
     static {
         for (Charset charset: Charset.availableCharsets().values()) {
             encodingToCharsetCache.put(
-                    charset.name().toLowerCase(Locale.US), charset);
+                    charset.name().toLowerCase(Locale.ENGLISH), charset);
             for (String alias : charset.aliases()) {
                 encodingToCharsetCache.put(
-                        alias.toLowerCase(Locale.US), charset);
+                        alias.toLowerCase(Locale.ENGLISH), charset);
             }
         }
         Charset iso88591 = null;
@@ -77,185 +70,138 @@ public class B2CConverter {
     }
 
     public static Charset getCharset(String enc)
-            throws UnsupportedEncodingException{
+            throws UnsupportedEncodingException {
 
         // Encoding names should all be ASCII
-        String lowerCaseEnc = enc.toLowerCase(Locale.US);
+        String lowerCaseEnc = enc.toLowerCase(Locale.ENGLISH);
+
+        return getCharsetLower(lowerCaseEnc);
+    }
+
+    /**
+     * Only to be used when it is known that the encoding name is in lower case.
+     */
+    public static Charset getCharsetLower(String lowerCaseEnc)
+            throws UnsupportedEncodingException {
 
         Charset charset = encodingToCharsetCache.get(lowerCaseEnc);
 
         if (charset == null) {
             // Pre-population of the cache means this must be invalid
             throw new UnsupportedEncodingException(
-                    sm.getString("b2cConverter.unknownEncoding", enc));
+                    sm.getString("b2cConverter.unknownEncoding", lowerCaseEnc));
         }
         return charset;
     }
 
-    private IntermediateInputStream iis;
-    private ReadConvertor conv;
-    private CharsetDecoder decoder;
-    private String encoding;
+    private final CharsetDecoder decoder;
+    private ByteBuffer bb = null;
+    private CharBuffer cb = null;
 
     /**
-     * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
+     * Leftover buffer used for incomplete characters.
      */
-    @Deprecated
-    protected B2CConverter() {
-    }
+    private final ByteBuffer leftovers;
 
-    /** Create a converter, with bytes going to a byte buffer
-     */
-    public B2CConverter(String encoding)
-        throws IOException
-    {
-        this.encoding=encoding;
-        reset();
+    public B2CConverter(String encoding) throws IOException {
+        this(encoding, false);
     }
 
+    public B2CConverter(String encoding, boolean replaceOnError)
+            throws IOException {
+        byte[] left = new byte[LEFTOVER_SIZE];
+        leftovers = ByteBuffer.wrap(left);
+        CodingErrorAction action;
+        if (replaceOnError) {
+            action = CodingErrorAction.REPLACE;
+        } else {
+            action = CodingErrorAction.REPORT;
+        }
+        Charset charset = getCharset(encoding);
+        // Special case. Use the Apache Harmony based UTF-8 decoder because it
+        // - a) rejects invalid sequences that the JVM decoder does not
+        // - b) fails faster for some invalid sequences
+        if (charset.equals(UTF_8)) {
+            decoder = new Utf8Decoder();
+        } else {
+            decoder = charset.newDecoder();
+        }
+        decoder.onMalformedInput(action);
+        decoder.onUnmappableCharacter(action);
+    }
 
-    /** Reset the internal state, empty the buffers.
-     *  The encoding remain in effect, the internal buffers remain allocated.
+    /** 
+     * Reset the decoder state.
      */
-    public  void recycle() {
-        conv.recycle();
+    public void recycle() {
         decoder.reset();
+        leftovers.position(0);
     }
 
-    static final int BUFFER_SIZE=8192;
-    char result[]=new char[BUFFER_SIZE];
-
     /**
-     * Convert a buffer of bytes into a chars.
-     *
-     * @param bb    Input byte buffer
-     * @param cb    Output char buffer
-     * @param limit Number of bytes to convert
-     * @throws IOException
+     * Convert the given bytes to characters.
+     * 
+     * @param bc byte input
+     * @param cc char output
+     * @param endOfInput    Is this all of the available data
      */
-    public void convert( ByteChunk bb, CharChunk cb, int limit)
-        throws IOException
-    {
-        iis.setByteChunk( bb );
-        try {
-            // read from the reader
-            int bbLengthBeforeRead = 0;
-            while( limit > 0 ) {
-                int size = limit < BUFFER_SIZE ? limit : BUFFER_SIZE;
-                bbLengthBeforeRead = bb.getLength();
-                int cnt=conv.read( result, 0, size );
-                if( cnt <= 0 ) {
-                    // End of stream ! - we may be in a bad state
-                    if(log.isDebugEnabled()) {
-                        log.debug("B2CConverter: EOF");
-                    }
-                    return;
-                }
-                if(log.isDebugEnabled()) {
-                    log.debug("B2CConverter: Converted: " +
-                            new String(result, 0, cnt));
-                }
-                cb.append( result, 0, cnt );
-                limit = limit - (bbLengthBeforeRead - bb.getLength());
-            }
-        } catch( IOException ex) {
-            if(log.isDebugEnabled()) {
-                log.debug("B2CConverter: Reseting the converter " + ex.toString());
+    public void convert(ByteChunk bc, CharChunk cc, boolean endOfInput)
+            throws IOException {
+        if ((bb == null) || (bb.array() != bc.getBuffer())) {
+            // Create a new byte buffer if anything changed
+            bb = ByteBuffer.wrap(bc.getBuffer(), bc.getStart(), bc.getLength());
+        } else {
+            // Initialize the byte buffer
+            bb.limit(bc.getEnd());
+            bb.position(bc.getStart());
+        }
+        if ((cb == null) || (cb.array() != cc.getBuffer())) {
+            // Create a new char buffer if anything changed
+            cb = CharBuffer.wrap(cc.getBuffer(), cc.getEnd(), 
+                    cc.getBuffer().length - cc.getEnd());
+        } else {
+            // Initialize the char buffer
+            cb.limit(cc.getBuffer().length);
+            cb.position(cc.getEnd());
+        }
+        CoderResult result = null;
+        // Parse leftover if any are present
+        if (leftovers.position() > 0) {
+            int pos = cb.position();
+            // Loop until one char is decoded or there is a decoder error
+            do {
+                leftovers.put(bc.substractB());
+                leftovers.flip();
+                result = decoder.decode(leftovers, cb, endOfInput);
+                leftovers.position(leftovers.limit());
+                leftovers.limit(leftovers.array().length);
+            } while (result.isUnderflow() && (cb.position() == pos));
+            if (result.isError() || result.isMalformed()) {
+                result.throwException();
             }
-            reset();
-            throw ex;
+            bb.position(bc.getStart());
+            leftovers.position(0);
         }
-    }
-
-
-    public void reset() throws IOException {
-        // Re-create the reader and iis
-        iis = new IntermediateInputStream();
-        decoder = getCharset(encoding).newDecoder();
-        conv = new ReadConvertor(iis, decoder);
-    }
-
-}
-
-// -------------------- Private implementation --------------------
-
-
-
-/**
- *
- */
-final class ReadConvertor extends InputStreamReader {
-
-    /** Create a converter.
-     */
-    public ReadConvertor(IntermediateInputStream in, CharsetDecoder decoder) {
-        super(in, decoder);
-    }
-
-    /** Overridden - will do nothing but reset internal state.
-     */
-    @Override
-    public  final void close() throws IOException {
-        // NOTHING
-        // Calling super.close() would reset out and cb.
-    }
-
-    @Override
-    public  final int read(char cbuf[], int off, int len)
-        throws IOException
-    {
-        // will do the conversion and call write on the output stream
-        return super.read( cbuf, off, len );
-    }
-
-    /** Reset the buffer
-     */
-    public  final void recycle() {
-        try {
-            // Must clear super's buffer.
-            while (ready()) {
-                // InputStreamReader#skip(long) will allocate buffer to skip.
-                read();
+        // Do the decoding and get the results into the byte chunk and the char
+        // chunk
+        result = decoder.decode(bb, cb, endOfInput);
+        if (result.isError() || result.isMalformed()) {
+            result.throwException();
+        } else if (result.isOverflow()) {
+            // Propagate current positions to the byte chunk and char chunk, if
+            // this continues the char buffer will get resized
+            bc.setOffset(bb.position());
+            cc.setEnd(cb.position());
+        } else if (result.isUnderflow()) {
+            // Propagate current positions to the byte chunk and char chunk
+            bc.setOffset(bb.position());
+            cc.setEnd(cb.position());
+            // Put leftovers in the leftovers byte buffer
+            if (bc.getLength() > 0) {
+                leftovers.limit(leftovers.array().length);
+                leftovers.position(bc.getLength());
+                bc.substract(leftovers.array(), 0, bc.getLength());
             }
-        } catch(IOException ioe){
         }
     }
 }
-
-
-/** Special output stream where close() is overridden, so super.close()
-    is never called.
-
-    This allows recycling. It can also be disabled, so callbacks will
-    not be called if recycling the converter and if data was not flushed.
-*/
-final class IntermediateInputStream extends InputStream {
-    ByteChunk bc = null;
-
-    public IntermediateInputStream() {
-    }
-
-    @Override
-    public  final void close() throws IOException {
-        // shouldn't be called - we filter it out in writer
-        throw new IOException("close() called - shouldn't happen ");
-    }
-
-    @Override
-    public  final  int read(byte cbuf[], int off, int len) throws IOException {
-        return bc.substract(cbuf, off, len);
-    }
-
-    @Override
-    public  final int read() throws IOException {
-        return bc.substract();
-    }
-
-    // -------------------- Internal methods --------------------
-
-
-    void setByteChunk( ByteChunk mb ) {
-        bc = mb;
-    }
-
-}
diff --git a/java/org/apache/tomcat/util/buf/ByteChunk.java b/java/org/apache/tomcat/util/buf/ByteChunk.java
index 00ee920..ffe6df2 100644
--- a/java/org/apache/tomcat/util/buf/ByteChunk.java
+++ b/java/org/apache/tomcat/util/buf/ByteChunk.java
@@ -397,6 +397,7 @@ public final class ByteChunk implements Cloneable, Serializable {
 
     }
 
+
     /**
      * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
      */
@@ -421,6 +422,23 @@ public final class ByteChunk implements Cloneable, Serializable {
 
     }
 
+
+    public byte substractB()
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.realReadBytes( buff, 0, buff.length );
+            if (n < 0)
+                return -1;
+        }
+
+        return (buff[start++]);
+
+    }
+
+
     public int substract( byte src[], int off, int len )
         throws IOException {
 
diff --git a/java/org/apache/tomcat/util/buf/C2BConverter.java b/java/org/apache/tomcat/util/buf/C2BConverter.java
index 42a0984..45ced89 100644
--- a/java/org/apache/tomcat/util/buf/C2BConverter.java
+++ b/java/org/apache/tomcat/util/buf/C2BConverter.java
@@ -16,295 +16,112 @@
  */
 package org.apache.tomcat.util.buf;
 
-import java.io.BufferedWriter;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.res.StringManager;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
 
 /**
- * Efficient conversion of character to bytes.
- *
- * This uses the standard JDK mechanism - a writer - but provides mechanisms to
- * recycle all the objects that are used. Input is buffered to improve
- * performance.
+ * NIO based character encoder.
  */
 public final class C2BConverter {
 
-    private static final Log log = LogFactory.getLog(C2BConverter.class);
-    private static final StringManager sm =
-            StringManager.getManager(Constants.Package);
-
-    private final String encoding;
-    private BufferedWriter writer;
-    private WriteConvertor conv;
-    private IntermediateOutputStream ios;
-    private ByteChunk bb;
+    protected CharsetEncoder encoder = null;
+    protected ByteBuffer bb = null;
+    protected CharBuffer cb = null;
 
     /**
-     * Create a converter, with bytes going to a byte buffer.
+     * Leftover buffer used for multi-characters characters.
      */
-    public C2BConverter(ByteChunk output, String encoding) throws IOException {
-        this.bb = output;
-        this.encoding = encoding;
-        init();
-    }
+    protected CharBuffer leftovers = null;
 
-    /**
-     * Create a converter
-     * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
-     */
-    @Deprecated
     public C2BConverter(String encoding) throws IOException {
-        this(new ByteChunk(1024), encoding);
-    }
-
-    /**
-     * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
-     */
-    @Deprecated
-    public ByteChunk getByteChunk() {
-        return bb;
-    }
-
-    /**
-     * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
-     */
-    @Deprecated
-    public String getEncoding() {
-        return encoding;
-    }
-
-    /**
-     * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
-     */
-    @Deprecated
-    public void setByteChunk(ByteChunk bb) {
-        this.bb=bb;
-        ios.setByteChunk( bb );
+        encoder = B2CConverter.getCharset(encoding).newEncoder();
+        // FIXME: See if unmappable/malformed behavior configuration is needed
+        //        in practice
+        encoder.onUnmappableCharacter(CodingErrorAction.REPLACE)
+            .onMalformedInput(CodingErrorAction.REPLACE);
+        char[] left = new char[4];
+        leftovers = CharBuffer.wrap(left);
     }
 
     /**
-     * Reset the internal state, empty the buffers.
-     * The encoding remain in effect, the internal buffers remain allocated.
+     * Reset the encoder state.
      */
-    public final void recycle() {
-        // Disable any output
-        ios.disable();
-        // Flush out the BufferedWriter and WriteConvertor
-        try {
-            writer.flush();
-        } catch (IOException e) {
-            log.warn(sm.getString("c2bConverter.recycleFailed"), e);
-            try {
-                init();
-            } catch (IOException ignore) {
-                // Should never happen since this means encoding is invalid and
-                // in that case, the constructor will have failed.
-            }
-        }
-        // Re-enable ready for re-use
-        ios.enable();
-        bb.recycle();
-    }
-
-    private void init() throws IOException {
-        ios = new IntermediateOutputStream(bb);
-        conv = new WriteConvertor(ios, B2CConverter.getCharset(encoding));
-        writer = new BufferedWriter(conv);
+    public void recycle() {
+        encoder.reset();
+        leftovers.position(0);
     }
 
-    /**
-     * Generate the bytes using the specified encoding.
-     */
-    public final void convert(char c[], int off, int len) throws IOException {
-        writer.write(c, off, len);
+    public boolean isUndeflow() {
+        return (leftovers.position() > 0);
     }
 
     /**
-     * Generate the bytes using the specified encoding.
+     * Convert the given characters to bytes.
+     * 
+     * @param cc char input
+     * @param bc byte output
      */
-    public final void convert(String s, int off, int len) throws IOException {
-        writer.write(s, off, len);
-    }
-
-    /**
-     * Generate the bytes using the specified encoding.
-     */
-    public final void convert(String s) throws IOException {
-        writer.write(s);
-    }
-
-    /**
-     * Generate the bytes using the specified encoding.
-     */
-    public final void convert(char c) throws IOException {
-        writer.write(c);
-    }
-
-    /**
-     * Convert a message bytes chars to bytes
-     * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
-     */
-    @Deprecated
-    public final void convert(MessageBytes mb) throws IOException {
-        int type=mb.getType();
-        if( type==MessageBytes.T_BYTES ) {
-            return;
+    public void convert(CharChunk cc, ByteChunk bc) 
+            throws IOException {
+        if ((bb == null) || (bb.array() != bc.getBuffer())) {
+            // Create a new byte buffer if anything changed
+            bb = ByteBuffer.wrap(bc.getBuffer(), bc.getEnd(), 
+                    bc.getBuffer().length - bc.getEnd());
+        } else {
+            // Initialize the byte buffer
+            bb.limit(bc.getBuffer().length);
+            bb.position(bc.getEnd());
         }
-        ByteChunk orig=bb;
-        setByteChunk( mb.getByteChunk());
-        bb.recycle();
-        bb.allocate( 32, -1 );
-
-        if( type==MessageBytes.T_STR ) {
-            convert( mb.getString() );
-            // System.out.println("XXX Converting " + mb.getString() );
-        } else if( type==MessageBytes.T_CHARS ) {
-            CharChunk charC=mb.getCharChunk();
-            convert( charC.getBuffer(),
-                                charC.getOffset(), charC.getLength());
-            //System.out.println("XXX Converting " + mb.getCharChunk() );
+        if ((cb == null) || (cb.array() != cc.getBuffer())) {
+            // Create a new char buffer if anything changed
+            cb = CharBuffer.wrap(cc.getBuffer(), cc.getStart(), 
+                    cc.getLength());
         } else {
-            if (log.isDebugEnabled()) {
-                log.debug("XXX unknowon type " + type );
+            // Initialize the char buffer
+            cb.limit(cc.getEnd());
+            cb.position(cc.getStart());
+        }
+        CoderResult result = null;
+        // Parse leftover if any are present
+        if (leftovers.position() > 0) {
+            int pos = bb.position();
+            // Loop until one char is encoded or there is a encoder error
+            do {
+                leftovers.put((char) cc.substract());
+                leftovers.flip();
+                result = encoder.encode(leftovers, bb, false);
+                leftovers.position(leftovers.limit());
+                leftovers.limit(leftovers.array().length);
+            } while (result.isUnderflow() && (bb.position() == pos));
+            if (result.isError() || result.isMalformed()) {
+                result.throwException();
             }
+            cb.position(cc.getStart());
+            leftovers.position(0);
         }
-        flushBuffer();
-        //System.out.println("C2B: XXX " + bb.getBuffer() + bb.getLength());
-        setByteChunk(orig);
-    }
-
-    /**
-     * Flush any internal buffers into the ByteOutput or the internal byte[].
-     */
-    public final void flushBuffer() throws IOException {
-        writer.flush();
-    }
-
-}
-
-// -------------------- Private implementation --------------------
-/**
- * Special writer class, where close() is overridden. The default implementation
- * would set byteOutputter to null, and the writer can't be recycled.
- *
- * Note that the flush method will empty the internal buffers _and_ call
- * flush on the output stream - that's why we use an intermediary output stream
- * that overrides flush(). The idea is to  have full control: flushing the
- * char->byte converter should be independent of flushing the OutputStream.
- *
- * When a WriteConverter is created, it'll allocate one or 2 byte buffers,
- * with a 8k size that can't be changed ( at least in JDK1.1 -> 1.4 ). It would
- * also allocate a ByteOutputter or equivalent - again some internal buffers.
- *
- * It is essential to keep  this object around and reuse it. You can use either
- * pools or per thread data - but given that in most cases a converter will be
- * needed for every thread and most of the time only 1 ( or 2 ) encodings will
- * be used, it is far better to keep it per thread and eliminate the pool
- * overhead too.
- */
- final class WriteConvertor extends OutputStreamWriter {
-
-    /**
-     * Create a converter.
-     */
-    public WriteConvertor(IntermediateOutputStream out, Charset charset) {
-        super(out, charset);
-    }
-
-    /**
-     * This is a NOOP.
-     */
-    @Override
-    public final void close() throws IOException {
-        // NOTHING
-        // Calling super.close() would reset out and cb.
-    }
-
-    /**
-     *  Flush the characters only.
-     */
-    @Override
-    public final void flush() throws IOException {
-        // Will flushBuffer and out()
-        // flushBuffer put any remaining chars in the byte[]
-        super.flush();
-    }
-
-    @Override
-    public final void write(char cbuf[], int off, int len) throws IOException {
-        // Will do the conversion and call write on the output stream
-        super.write( cbuf, off, len );
-    }
-}
-
-
-/**
- * Special output stream where close() is overridden, so super.close()
- * is never called.
- *
- * This allows recycling. It can also be disabled, so callbacks will
- * not be called if recycling the converter and if data was not flushed.
- */
-final class IntermediateOutputStream extends OutputStream {
-    private ByteChunk tbuff;
-    private boolean enabled = true;
-
-    public IntermediateOutputStream(ByteChunk tbuff) {
-        this.tbuff=tbuff;
-    }
-
-    @Override
-    public final void close() throws IOException {
-        // shouldn't be called - we filter it out in writer
-        throw new IOException("close() called - shouldn't happen ");
-    }
-
-    @Override
-    public final void flush() throws IOException {
-        // nothing - write will go directly to the buffer,
-        // we don't keep any state
-    }
-
-    @Override
-    public final void write(byte cbuf[], int off, int len) throws IOException {
-        // will do the conversion and call write on the output stream
-        if( enabled ) {
-            tbuff.append( cbuf, off, len );
+        // Do the decoding and get the results into the byte chunk and the char
+        // chunk
+        result = encoder.encode(cb, bb, false);
+        if (result.isError() || result.isMalformed()) {
+            result.throwException();
+        } else if (result.isOverflow()) {
+            // Propagate current positions to the byte chunk and char chunk
+            bc.setEnd(bb.position());
+            cc.setOffset(cb.position());
+        } else if (result.isUnderflow()) {
+            // Propagate current positions to the byte chunk and char chunk
+            bc.setEnd(bb.position());
+            cc.setOffset(cb.position());
+            // Put leftovers in the leftovers char buffer
+            if (cc.getLength() > 0) {
+                leftovers.limit(leftovers.array().length);
+                leftovers.position(cc.getLength());
+                cc.substract(leftovers.array(), 0, cc.getLength());
+            }
         }
     }
-
-    @Override
-    public final void write(int i) throws IOException {
-        throw new IOException("write( int ) called - shouldn't happen ");
-    }
-
-    // -------------------- Internal methods --------------------
-    /**
-     * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards.
-     */
-    @Deprecated
-    void setByteChunk(ByteChunk bb) {
-        tbuff = bb;
-    }
-
-    /**
-     * Temporary disable - this is used to recycle the converter without
-     * generating an output if the buffers were not flushed.
-     */
-    final void disable() {
-        enabled = false;
-    }
-
-    /**
-     * Re-enable - used to recycle the converter.
-     */
-    final void enable() {
-        enabled = true;
-    }
 }
diff --git a/java/org/apache/tomcat/util/buf/CharChunk.java b/java/org/apache/tomcat/util/buf/CharChunk.java
index f123120..2320126 100644
--- a/java/org/apache/tomcat/util/buf/CharChunk.java
+++ b/java/org/apache/tomcat/util/buf/CharChunk.java
@@ -468,7 +468,7 @@ public final class CharChunk implements Cloneable, Serializable, CharSequence {
     /** Make space for len chars. If len is small, allocate
      *        a reserve space too. Never grow bigger than limit.
      */
-    private void makeSpace(int count)
+    public void makeSpace(int count)
     {
         char[] tmp = null;
 
diff --git a/java/org/apache/tomcat/util/buf/UEncoder.java b/java/org/apache/tomcat/util/buf/UEncoder.java
index 2331c5f..8c700dd 100644
--- a/java/org/apache/tomcat/util/buf/UEncoder.java
+++ b/java/org/apache/tomcat/util/buf/UEncoder.java
@@ -16,9 +16,7 @@
  */
 package org.apache.tomcat.util.buf;
 
-import java.io.CharArrayWriter;
 import java.io.IOException;
-import java.io.Writer;
 import java.util.BitSet;
 
 /** Efficient implementation for encoders.
@@ -33,14 +31,13 @@ import java.util.BitSet;
  */
 public final class UEncoder {
 
-    private static final org.apache.juli.logging.Log log=
-        org.apache.juli.logging.LogFactory.getLog(UEncoder.class );
-
     // Not static - the set may differ ( it's better than adding
     // an extra check for "/", "+", etc
     private BitSet safeChars=null;
     private C2BConverter c2b=null;
     private ByteChunk bb=null;
+    private CharChunk cb=null;
+    private CharChunk output=null;
 
     private String encoding="UTF8";
 
@@ -61,93 +58,69 @@ public final class UEncoder {
     }
 
 
-    /** URL Encode string, using a specified encoding.
-     *
-     * @param buf The writer
-     * @param s string to be encoded
-     * @throws IOException If an I/O error occurs
-     */
-    public void urlEncode( Writer buf, String s )
-            throws IOException {
-        if( c2b==null ) {
-            bb=new ByteChunk(16); // small enough.
-            c2b=new C2BConverter( bb, encoding );
-        }
-
-        for (int i = 0; i < s.length(); i++) {
-            int c = s.charAt(i);
-            if( safeChars.get( c ) ) {
-                if(log.isDebugEnabled()) {
-                    log.debug("Encoder: Safe: " + (char)c);
-                }
-                buf.write((char)c);
-            } else {
-                if(log.isDebugEnabled()) {
-                    log.debug("Encoder: Unsafe:  " + (char)c);
-                }
-                c2b.convert( (char)c );
-
-                // "surrogate" - UTF is _not_ 16 bit, but 21 !!!!
-                // ( while UCS is 31 ). Amazing...
-                if (c >= 0xD800 && c <= 0xDBFF) {
-                    if ( (i+1) < s.length()) {
-                        int d = s.charAt(i+1);
-                        if (d >= 0xDC00 && d <= 0xDFFF) {
-                            if(log.isDebugEnabled()) {
-                                log.debug("Encoder: Unsafe:  " + c);
-                            }
-                            c2b.convert( (char)d);
-                            i++;
-                        }
-                    }
-                }
-
-                c2b.flushBuffer();
-
-                urlEncode( buf, bb.getBuffer(), bb.getOffset(),
-                           bb.getLength() );
-                bb.recycle();
-            }
-        }
-    }
-
-    /**
-     */
-    public void urlEncode( Writer buf, byte bytes[], int off, int len)
-            throws IOException {
-        for( int j=off; j< len; j++ ) {
-            buf.write( '%' );
-            char ch = Character.forDigit((bytes[j] >> 4) & 0xF, 16);
-            if(log.isDebugEnabled()) {
-                log.debug("Encoder: Encode:  " + ch);
-            }
-            buf.write(ch);
-            ch = Character.forDigit(bytes[j] & 0xF, 16);
-            if(log.isDebugEnabled()) {
-                log.debug("Encoder: Encode:  " + ch);
-            }
-            buf.write(ch);
-        }
-    }
-
-    /**
-     * Utility function to re-encode the URL.
-     * Still has problems with charset, since UEncoder mostly
-     * ignores it.
-     */
-    public String encodeURL(String uri) {
-        String outUri=null;
-        try {
-            // XXX optimize - recycle, etc
-            CharArrayWriter out = new CharArrayWriter();
-            urlEncode(out, uri);
-            outUri=out.toString();
-        } catch (IOException iex) {
-        }
-        return outUri;
-    }
-
-
+   /**
+    * URL Encode string, using a specified encoding.
+    *
+    * @param s string to be encoded
+    * @param start the beginning index, inclusive
+    * @param end the ending index, exclusive
+    * @throws IOException If an I/O error occurs
+    */
+   public CharChunk encodeURL(String s, int start, int end)
+       throws IOException {
+       if (c2b == null) {
+           bb = new ByteChunk(8); // small enough.
+           cb = new CharChunk(2); // small enough.
+           output = new CharChunk(64); // small enough.
+           c2b = new C2BConverter(encoding);
+       } else {
+           bb.recycle();
+           cb.recycle();
+           output.recycle();
+       }
+
+       for (int i = start; i < end; i++) {
+           char c = s.charAt(i);
+           if (safeChars.get(c)) {
+               output.append(c);
+           } else {
+               cb.append(c);
+               c2b.convert(cb, bb);
+
+               // "surrogate" - UTF is _not_ 16 bit, but 21 !!!!
+               // ( while UCS is 31 ). Amazing...
+               if (c >= 0xD800 && c <= 0xDBFF) {
+                   if ((i+1) < end) {
+                       char d = s.charAt(i+1);
+                       if (d >= 0xDC00 && d <= 0xDFFF) {
+                           cb.append(d);
+                           c2b.convert(cb, bb);
+                           i++;
+                       }
+                   }
+               }
+
+               urlEncode(output, bb);
+               cb.recycle();
+               bb.recycle();
+           }
+       }
+       
+       return output;
+   }
+
+   protected void urlEncode(CharChunk out, ByteChunk bb)
+       throws IOException {
+       byte[] bytes = bb.getBuffer();
+       for (int j = bb.getStart(); j < bb.getEnd(); j++) {
+           out.append('%');
+           char ch = Character.forDigit((bytes[j] >> 4) & 0xF, 16);
+           out.append(ch);
+           ch = Character.forDigit(bytes[j] & 0xF, 16);
+           out.append(ch);
+       }
+   }
+   
     // -------------------- Internal implementation --------------------
 
     private void initSafeChars() {
diff --git a/java/org/apache/tomcat/util/buf/Utf8Decoder.java b/java/org/apache/tomcat/util/buf/Utf8Decoder.java
new file mode 100644
index 0000000..3d9a335
--- /dev/null
+++ b/java/org/apache/tomcat/util/buf/Utf8Decoder.java
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.buf;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+
+/**
+ * Decodes bytes to UTF-8. Extracted from Apache Harmony and modified to reject
+ * code points from U+D800 to U+DFFF as per RFC3629. The standard Java decoder
+ * does not reject these. It has also been modified to reject code points
+ * greater than U+10FFFF which the standard Java decoder rejects but the harmony
+ * one does not.
+ */
+public class Utf8Decoder extends CharsetDecoder {
+
+    // The next table contains information about UTF-8 charset and
+    // correspondence of 1st byte to the length of sequence
+    // For information please visit http://www.ietf.org/rfc/rfc3629.txt
+    //
+    // Please note, o means 0, actually.
+    // -------------------------------------------------------------------
+    // 0 1 2 3 Value
+    // -------------------------------------------------------------------
+    // oxxxxxxx                            00000000 00000000 0xxxxxxx
+    // 11oyyyyy 1oxxxxxx                   00000000 00000yyy yyxxxxxx
+    // 111ozzzz 1oyyyyyy 1oxxxxxx          00000000 zzzzyyyy yyxxxxxx
+    // 1111ouuu 1ouuzzzz 1oyyyyyy 1oxxxxxx 000uuuuu zzzzyyyy yyxxxxxx
+    private static final int remainingBytes[] = {
+            // 1owwwwww
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            // 11oyyyyy
+            -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+            // 111ozzzz
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+            // 1111ouuu
+            3, 3, 3, 3, 3, -1, -1, -1,
+            // > 11110111
+            -1, -1, -1, -1, -1, -1, -1, -1};
+    private static final int remainingNumbers[] = {0, // 0 1 2 3
+            4224, // (01o00000b << 6)+(1o000000b)
+            401536, // (011o0000b << 12)+(1o000000b << 6)+(1o000000b)
+            29892736 // (0111o000b << 18)+(1o000000b << 12)+(1o000000b <<
+                     // 6)+(1o000000b)
+    };
+    private static final int lowerEncodingLimit[] = {-1, 0x80, 0x800, 0x10000};
+
+
+    public Utf8Decoder() {
+        super(B2CConverter.UTF_8, 1.0f, 1.0f);
+    }
+
+
+    @Override
+    protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
+        if (in.hasArray() && out.hasArray()) {
+            return decodeHasArray(in, out);
+        }
+        return decodeNotHasArray(in, out);
+    }
+
+
+    private CoderResult decodeNotHasArray(ByteBuffer in, CharBuffer out) {
+        int outRemaining = out.remaining();
+        int pos = in.position();
+        int limit = in.limit();
+        try {
+            while (pos < limit) {
+                if (outRemaining == 0) {
+                    return CoderResult.OVERFLOW;
+                }
+                int jchar = in.get();
+                if (jchar < 0) {
+                    jchar = jchar & 0x7F;
+                    int tail = remainingBytes[jchar];
+                    if (tail == -1) {
+                        return CoderResult.malformedForLength(1);
+                    }
+                    if (limit - pos < 1 + tail) {
+                        // No early test for invalid sequences here as peeking
+                        // at the next byte is harder
+                        return CoderResult.UNDERFLOW;
+                    }
+                    int nextByte;
+                    for (int i = 0; i < tail; i++) {
+                        nextByte = in.get() & 0xFF;
+                        if ((nextByte & 0xC0) != 0x80) {
+                            return CoderResult.malformedForLength(1 + i);
+                        }
+                        jchar = (jchar << 6) + nextByte;
+                    }
+                    jchar -= remainingNumbers[tail];
+                    if (jchar < lowerEncodingLimit[tail]) {
+                        // Should have been encoded in a fewer octets
+                        return CoderResult.malformedForLength(1);
+                    }
+                    pos += tail;
+                }
+                // Apache Tomcat added test
+                if (jchar >= 0xD800 && jchar <= 0xDFFF) {
+                    return CoderResult.unmappableForLength(3);
+                }
+                // Apache Tomcat added test
+                if (jchar > 0x10FFFF) {
+                    return CoderResult.unmappableForLength(4);
+                }
+                if (jchar <= 0xffff) {
+                    out.put((char) jchar);
+                    outRemaining--;
+                } else {
+                    if (outRemaining < 2) {
+                        return CoderResult.OVERFLOW;
+                    }
+                    out.put((char) ((jchar >> 0xA) + 0xD7C0));
+                    out.put((char) ((jchar & 0x3FF) + 0xDC00));
+                    outRemaining -= 2;
+                }
+                pos++;
+            }
+            return CoderResult.UNDERFLOW;
+        } finally {
+            in.position(pos);
+        }
+    }
+
+
+    private CoderResult decodeHasArray(ByteBuffer in, CharBuffer out) {
+        int outRemaining = out.remaining();
+        int pos = in.position();
+        int limit = in.limit();
+        final byte[] bArr = in.array();
+        final char[] cArr = out.array();
+        final int inIndexLimit = limit + in.arrayOffset();
+        int inIndex = pos + in.arrayOffset();
+        int outIndex = out.position() + out.arrayOffset();
+        // if someone would change the limit in process,
+        // he would face consequences
+        for (; inIndex < inIndexLimit && outRemaining > 0; inIndex++) {
+            int jchar = bArr[inIndex];
+            if (jchar < 0) {
+                jchar = jchar & 0x7F;
+                // If first byte is invalid, tail will be set to -1
+                int tail = remainingBytes[jchar];
+                if (tail == -1) {
+                    in.position(inIndex - in.arrayOffset());
+                    out.position(outIndex - out.arrayOffset());
+                    return CoderResult.malformedForLength(1);
+                }
+                // Additional checks to detect invalid sequences ASAP
+                // Checks derived from Unicode 6.2, Chapter 3, Table 3-7
+                // Check 2nd byte
+                int tailAvailable = inIndexLimit - inIndex - 1;
+                if (tailAvailable > 0) {
+                    // First byte C2..DF, second byte 80..BF
+                    if (jchar > 0x41 && jchar < 0x60 &&
+                            (bArr[inIndex + 1] & 0xC0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                    // First byte E0, second byte A0..BF
+                    if (jchar == 0x60 && (bArr[inIndex + 1] & 0xE0) != 0xA0) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                    // First byte E1..EC, second byte 80..BF
+                    if (jchar > 0x60 && jchar < 0x6D &&
+                            (bArr[inIndex + 1] & 0xC0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                    // First byte ED, second byte 80..9F
+                    if (jchar == 0x6D && (bArr[inIndex + 1] & 0xE0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                    // First byte EE..EF, second byte 80..BF
+                    if (jchar > 0x6D && jchar < 0x70 &&
+                            (bArr[inIndex + 1] & 0xC0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                    // First byte F0, second byte 90..BF
+                    if (jchar == 0x70 &&
+                            ((bArr[inIndex + 1] & 0xFF) < 0x90 ||
+                            (bArr[inIndex + 1] & 0xFF) > 0xBF)) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                    // First byte F1..F3, second byte 80..BF
+                    if (jchar > 0x70 && jchar < 0x74 &&
+                            (bArr[inIndex + 1] & 0xC0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                    // First byte F4, second byte 80..8F
+                    if (jchar == 0x74 &&
+                            (bArr[inIndex + 1] & 0xF0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1);
+                    }
+                }
+                // Check third byte if present and expected
+                if (tailAvailable > 1 && tail > 1) {
+                    if ((bArr[inIndex + 2] & 0xC0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(2);
+                    }
+                }
+                // Check fourth byte if present and expected
+                if (tailAvailable > 2 && tail > 2) {
+                    if ((bArr[inIndex + 3] & 0xC0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(3);
+                    }
+                }
+                if (tailAvailable < tail) {
+                    break;
+                }
+                for (int i = 0; i < tail; i++) {
+                    int nextByte = bArr[inIndex + i + 1] & 0xFF;
+                    if ((nextByte & 0xC0) != 0x80) {
+                        in.position(inIndex - in.arrayOffset());
+                        out.position(outIndex - out.arrayOffset());
+                        return CoderResult.malformedForLength(1 + i);
+                    }
+                    jchar = (jchar << 6) + nextByte;
+                }
+                jchar -= remainingNumbers[tail];
+                if (jchar < lowerEncodingLimit[tail]) {
+                    // Should have been encoded in fewer octets
+                    in.position(inIndex - in.arrayOffset());
+                    out.position(outIndex - out.arrayOffset());
+                    return CoderResult.malformedForLength(1);
+                }
+                inIndex += tail;
+            }
+            // Apache Tomcat added test
+            if (jchar >= 0xD800 && jchar <= 0xDFFF) {
+                return CoderResult.unmappableForLength(3);
+            }
+            // Apache Tomcat added test
+            if (jchar > 0x10FFFF) {
+                return CoderResult.unmappableForLength(4);
+            }
+            if (jchar <= 0xffff) {
+                cArr[outIndex++] = (char) jchar;
+                outRemaining--;
+            } else {
+                if (outRemaining < 2) {
+                    return CoderResult.OVERFLOW;
+                }
+                cArr[outIndex++] = (char) ((jchar >> 0xA) + 0xD7C0);
+                cArr[outIndex++] = (char) ((jchar & 0x3FF) + 0xDC00);
+                outRemaining -= 2;
+            }
+        }
+        in.position(inIndex - in.arrayOffset());
+        out.position(outIndex - out.arrayOffset());
+        return (outRemaining == 0 && inIndex < inIndexLimit) ?
+                CoderResult.OVERFLOW :
+                CoderResult.UNDERFLOW;
+    }
+}
diff --git a/java/org/apache/tomcat/util/codec/BinaryDecoder.java b/java/org/apache/tomcat/util/codec/BinaryDecoder.java
new file mode 100644
index 0000000..dd80af9
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/BinaryDecoder.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec;
+
+/**
+ * Defines common decoding methods for byte array decoders.
+ *
+ * @version $Id: BinaryDecoder.java 1459218 2013-03-21 10:31:50Z markt $
+ */
+public interface BinaryDecoder extends Decoder {
+
+    /**
+     * Decodes a byte array and returns the results as a byte array.
+     *
+     * @param source
+     *            A byte array which has been encoded with the appropriate encoder
+     * @return a byte array that contains decoded content
+     * @throws DecoderException
+     *             A decoder exception is thrown if a Decoder encounters a failure condition during the decode process.
+     */
+    byte[] decode(byte[] source) throws DecoderException;
+}
+
diff --git a/java/org/apache/tomcat/util/codec/BinaryEncoder.java b/java/org/apache/tomcat/util/codec/BinaryEncoder.java
new file mode 100644
index 0000000..7c220e1
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/BinaryEncoder.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec;
+
+/**
+ * Defines common encoding methods for byte array encoders.
+ *
+ * @version $Id: BinaryEncoder.java 1459218 2013-03-21 10:31:50Z markt $
+ */
+public interface BinaryEncoder extends Encoder {
+
+    /**
+     * Encodes a byte array and return the encoded data as a byte array.
+     *
+     * @param source
+     *            Data to be encoded
+     * @return A byte array containing the encoded data
+     * @throws EncoderException
+     *             thrown if the Encoder encounters a failure condition during the encoding process.
+     */
+    byte[] encode(byte[] source) throws EncoderException;
+}
+
diff --git a/java/org/apache/tomcat/util/codec/Decoder.java b/java/org/apache/tomcat/util/codec/Decoder.java
new file mode 100644
index 0000000..a2fdf87
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/Decoder.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec;
+
+/**
+ * Provides the highest level of abstraction for Decoders.
+ * <p>
+ * This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface.
+ * Allows a user to pass a generic Object to any Decoder implementation in the codec package.
+ * <p>
+ * One of the two interfaces at the center of the codec package.
+ *
+ * @version $Id: Decoder.java 1459218 2013-03-21 10:31:50Z markt $
+ */
+public interface Decoder {
+
+    /**
+     * Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will
+     * try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a
+     * {@link ClassCastException} occurs this decode method will throw a DecoderException.
+     *
+     * @param source
+     *            the object to decode
+     * @return a 'decoded" object
+     * @throws DecoderException
+     *             a decoder exception can be thrown for any number of reasons. Some good candidates are that the
+     *             parameter passed to this method is null, a param cannot be cast to the appropriate type for a
+     *             specific encoder.
+     */
+    Object decode(Object source) throws DecoderException;
+}
+
diff --git a/java/org/apache/tomcat/util/codec/DecoderException.java b/java/org/apache/tomcat/util/codec/DecoderException.java
new file mode 100644
index 0000000..6d94a5e
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/DecoderException.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec;
+
+/**
+ * Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder}
+ * encounters a decoding specific exception such as invalid data, or characters outside of the expected range.
+ *
+ * @version $Id: DecoderException.java 1459218 2013-03-21 10:31:50Z markt $
+ */
+public class DecoderException extends Exception {
+
+    /**
+     * Declares the Serial Version Uid.
+     *
+     * @see <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may
+     * subsequently be initialized by a call to {@link #initCause}.
+     *
+     * @since 1.4
+     */
+    public DecoderException() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
+     * be initialized by a call to {@link #initCause}.
+     *
+     * @param message
+     *            The detail message which is saved for later retrieval by the {@link #getMessage()} method.
+     */
+    public DecoderException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and cause.
+     * <p>
+     * Note that the detail message associated with <code>cause</code> is not automatically incorporated into this
+     * exception's detail message.
+     *
+     * @param message
+     *            The detail message which is saved for later retrieval by the {@link #getMessage()} method.
+     * @param cause
+     *            The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
+     *            value is permitted, and indicates that the cause is nonexistent or unknown.
+     * @since 1.4
+     */
+    public DecoderException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail message of <code>(cause==null ?
+     * null : cause.toString())</code> (which typically contains the class and detail message of <code>cause</code>).
+     * This constructor is useful for exceptions that are little more than wrappers for other throwables.
+     *
+     * @param cause
+     *            The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
+     *            value is permitted, and indicates that the cause is nonexistent or unknown.
+     * @since 1.4
+     */
+    public DecoderException(final Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/org/apache/tomcat/util/codec/Encoder.java b/java/org/apache/tomcat/util/codec/Encoder.java
new file mode 100644
index 0000000..2958fa6
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/Encoder.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec;
+
+/**
+ * Provides the highest level of abstraction for Encoders.
+ * <p>
+ * This is the sister interface of {@link Decoder}.  Every implementation of Encoder provides this
+ * common generic interface which allows a user to pass a generic Object to any Encoder implementation
+ * in the codec package.
+ *
+ * @version $Id: Encoder.java 1459218 2013-03-21 10:31:50Z markt $
+ */
+public interface Encoder {
+
+    /**
+     * Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be
+     * <code>byte[]</code> or <code>String</code>s depending on the implementation used.
+     *
+     * @param source
+     *            An object to encode
+     * @return An "encoded" Object
+     * @throws EncoderException
+     *             An encoder exception is thrown if the encoder experiences a failure condition during the encoding
+     *             process.
+     */
+    Object encode(Object source) throws EncoderException;
+}
+
diff --git a/java/org/apache/tomcat/util/codec/EncoderException.java b/java/org/apache/tomcat/util/codec/EncoderException.java
new file mode 100644
index 0000000..6d49688
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/EncoderException.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec;
+
+/**
+ * Thrown when there is a failure condition during the encoding process. This exception is thrown when an
+ * {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum,
+ * characters outside of the expected range.
+ *
+ * @version $Id: EncoderException.java 1459218 2013-03-21 10:31:50Z markt $
+ */
+public class EncoderException extends Exception {
+
+    /**
+     * Declares the Serial Version Uid.
+     *
+     * @see <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may
+     * subsequently be initialized by a call to {@link #initCause}.
+     *
+     * @since 1.4
+     */
+    public EncoderException() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
+     * be initialized by a call to {@link #initCause}.
+     *
+     * @param message
+     *            a useful message relating to the encoder specific error.
+     */
+    public EncoderException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and cause.
+     *
+     * <p>
+     * Note that the detail message associated with <code>cause</code> is not automatically incorporated into this
+     * exception's detail message.
+     * </p>
+     *
+     * @param message
+     *            The detail message which is saved for later retrieval by the {@link #getMessage()} method.
+     * @param cause
+     *            The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
+     *            value is permitted, and indicates that the cause is nonexistent or unknown.
+     * @since 1.4
+     */
+    public EncoderException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail message of <code>(cause==null ?
+     * null : cause.toString())</code> (which typically contains the class and detail message of <code>cause</code>).
+     * This constructor is useful for exceptions that are little more than wrappers for other throwables.
+     *
+     * @param cause
+     *            The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null}
+     *            value is permitted, and indicates that the cause is nonexistent or unknown.
+     * @since 1.4
+     */
+    public EncoderException(final Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/org/apache/tomcat/util/codec/binary/Base64.java b/java/org/apache/tomcat/util/codec/binary/Base64.java
new file mode 100644
index 0000000..87ef970
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/binary/Base64.java
@@ -0,0 +1,779 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec.binary;
+
+import java.math.BigInteger;
+
+/**
+ * Provides Base64 encoding and decoding as defined by <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
+ *
+ * <p>
+ * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
+ * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
+ * </p>
+ * <p>
+ * The class can be parameterized in the following manner with various constructors:
+ * <ul>
+ * <li>URL-safe mode: Default off.</li>
+ * <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of
+ * 4 in the encoded data.
+ * <li>Line separator: Default is CRLF ("\r\n")</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only
+ * encode/decode character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252,
+ * UTF-8, etc).
+ * </p>
+ * <p>
+ * This class is thread-safe.
+ * </p>
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
+ * @since 1.0
+ * @version $Id: Base64.java 1459346 2013-03-21 15:05:54Z markt $
+ */
+public class Base64 extends BaseNCodec {
+
+    /**
+     * BASE32 characters are 6 bits in length.
+     * They are formed by taking a block of 3 octets to form a 24-bit string,
+     * which is converted into 4 BASE64 characters.
+     */
+    private static final int BITS_PER_ENCODED_BYTE = 6;
+    private static final int BYTES_PER_UNENCODED_BLOCK = 3;
+    private static final int BYTES_PER_ENCODED_BLOCK = 4;
+
+    /**
+     * Chunk separator per RFC 2045 section 2.1.
+     *
+     * <p>
+     * N.B. The next major release may break compatibility and make this field private.
+     * </p>
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
+     */
+    static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
+     * equivalents as specified in Table 1 of RFC 2045.
+     *
+     * Thanks to "commons" project in ws.apache.org for this code.
+     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+     */
+    private static final byte[] STANDARD_ENCODE_TABLE = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    /**
+     * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
+     * changed to - and _ to make the encoded Base64 results more URL-SAFE.
+     * This table is only used when the Base64's mode is set to URL-SAFE.
+     */
+    private static final byte[] URL_SAFE_ENCODE_TABLE = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
+    };
+
+    /**
+     * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified
+     * in Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
+     * alphabet but fall within the bounds of the array are translated to -1.
+     *
+     * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
+     * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
+     *
+     * Thanks to "commons" project in ws.apache.org for this code.
+     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+     */
+    private static final byte[] DECODE_TABLE = {
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54,
+            55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
+            5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+            24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+            35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+    };
+
+    /**
+     * Base64 uses 6-bit fields.
+     */
+    /** Mask used to extract 6 bits, used when encoding */
+    private static final int MASK_6BITS = 0x3f;
+
+    // The static final fields above are used for the original static byte[] methods on Base64.
+    // The private member fields below are used with the new streaming approach, which requires
+    // some state be preserved between calls of encode() and decode().
+
+    /**
+     * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
+     * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
+     * between the two modes.
+     */
+    private final byte[] encodeTable;
+
+    // Only one decode table currently; keep for consistency with Base32 code
+    private final byte[] decodeTable = DECODE_TABLE;
+
+    /**
+     * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
+     */
+    private final byte[] lineSeparator;
+
+    /**
+     * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
+     * <code>decodeSize = 3 + lineSeparator.length;</code>
+     */
+    private final int decodeSize;
+
+    /**
+     * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
+     * <code>encodeSize = 4 + lineSeparator.length;</code>
+     */
+    private final int encodeSize;
+
+    /**
+     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
+     * <p>
+     * When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE.
+     * </p>
+     *
+     * <p>
+     * When decoding all variants are supported.
+     * </p>
+     */
+    public Base64() {
+        this(0);
+    }
+
+    /**
+     * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
+     * <p>
+     * When encoding the line length is 76, the line separator is CRLF, and the encoding table is
+     * STANDARD_ENCODE_TABLE.
+     * </p>
+     *
+     * <p>
+     * When decoding all variants are supported.
+     * </p>
+     *
+     * @param urlSafe
+     *            if {@code true}, URL-safe encoding is used. In most cases this should be set to {@code false}.
+     * @since 1.4
+     */
+    public Base64(final boolean urlSafe) {
+        this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
+    }
+
+    /**
+     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
+     * <p>
+     * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is
+     * STANDARD_ENCODE_TABLE.
+     * </p>
+     * <p>
+     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
+     * </p>
+     * <p>
+     * When decoding all variants are supported.
+     * </p>
+     *
+     * @param lineLength
+     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
+     *            4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
+     *            decoding.
+     * @since 1.4
+     */
+    public Base64(final int lineLength) {
+        this(lineLength, CHUNK_SEPARATOR);
+    }
+
+    /**
+     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
+     * <p>
+     * When encoding the line length and line separator are given in the constructor, and the encoding table is
+     * STANDARD_ENCODE_TABLE.
+     * </p>
+     * <p>
+     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
+     * </p>
+     * <p>
+     * When decoding all variants are supported.
+     * </p>
+     *
+     * @param lineLength
+     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
+     *            4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
+     *            decoding.
+     * @param lineSeparator
+     *            Each line of encoded data will end with this sequence of bytes.
+     * @throws IllegalArgumentException
+     *             Thrown when the provided lineSeparator included some base64 characters.
+     * @since 1.4
+     */
+    public Base64(final int lineLength, final byte[] lineSeparator) {
+        this(lineLength, lineSeparator, false);
+    }
+
+    /**
+     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
+     * <p>
+     * When encoding the line length and line separator are given in the constructor, and the encoding table is
+     * STANDARD_ENCODE_TABLE.
+     * </p>
+     * <p>
+     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
+     * </p>
+     * <p>
+     * When decoding all variants are supported.
+     * </p>
+     *
+     * @param lineLength
+     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
+     *            4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
+     *            decoding.
+     * @param lineSeparator
+     *            Each line of encoded data will end with this sequence of bytes.
+     * @param urlSafe
+     *            Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
+     *            operations. Decoding seamlessly handles both modes.
+     *            <b>Note: no padding is added when using the URL-safe alphabet.</b>
+     * @throws IllegalArgumentException
+     *             The provided lineSeparator included some base64 characters. That's not going to work!
+     * @since 1.4
+     */
+    public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
+        super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK,
+                lineLength,
+                lineSeparator == null ? 0 : lineSeparator.length);
+        // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
+        // @see test case Base64Test.testConstructors()
+        if (lineSeparator != null) {
+            if (containsAlphabetOrPad(lineSeparator)) {
+                final String sep = StringUtils.newStringUtf8(lineSeparator);
+                throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
+            }
+            if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE
+                this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
+                this.lineSeparator = new byte[lineSeparator.length];
+                System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
+            } else {
+                this.encodeSize = BYTES_PER_ENCODED_BLOCK;
+                this.lineSeparator = null;
+            }
+        } else {
+            this.encodeSize = BYTES_PER_ENCODED_BLOCK;
+            this.lineSeparator = null;
+        }
+        this.decodeSize = this.encodeSize - 1;
+        this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
+    }
+
+    /**
+     * Returns our current encode mode. True if we're URL-SAFE, false otherwise.
+     *
+     * @return true if we're in URL-SAFE mode, false otherwise.
+     * @since 1.4
+     */
+    public boolean isUrlSafe() {
+        return this.encodeTable == URL_SAFE_ENCODE_TABLE;
+    }
+
+    /**
+     * <p>
+     * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
+     * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, to flush last
+     * remaining bytes (if not multiple of 3).
+     * </p>
+     * <p><b>Note: no padding is added when encoding using the URL-safe alphabet.</b></p>
+     * <p>
+     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
+     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+     * </p>
+     *
+     * @param in
+     *            byte[] array of binary data to base64 encode.
+     * @param inPos
+     *            Position to start reading data from.
+     * @param inAvail
+     *            Amount of bytes available from input for encoding.
+     * @param context
+     *            the context to be used
+     */
+    @Override
+    void encode(final byte[] in, int inPos, final int inAvail, final Context context) {
+        if (context.eof) {
+            return;
+        }
+        // inAvail < 0 is how we're informed of EOF in the underlying data we're
+        // encoding.
+        if (inAvail < 0) {
+            context.eof = true;
+            if (0 == context.modulus && lineLength == 0) {
+                return; // no leftovers to process and not using chunking
+            }
+            final byte[] buffer = ensureBufferSize(encodeSize, context);
+            final int savedPos = context.pos;
+            switch (context.modulus) { // 0-2
+                case 0 : // nothing to do here
+                    break;
+                case 1 : // 8 bits = 6 + 2
+                    // top 6 bits:
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS];
+                    // remaining 2:
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS];
+                    // URL-SAFE skips the padding to further reduce size.
+                    if (encodeTable == STANDARD_ENCODE_TABLE) {
+                        buffer[context.pos++] = PAD;
+                        buffer[context.pos++] = PAD;
+                    }
+                    break;
+
+                case 2 : // 16 bits = 6 + 6 + 4
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS];
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS];
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS];
+                    // URL-SAFE skips the padding to further reduce size.
+                    if (encodeTable == STANDARD_ENCODE_TABLE) {
+                        buffer[context.pos++] = PAD;
+                    }
+                    break;
+                default:
+                    throw new IllegalStateException("Impossible modulus "+context.modulus);
+            }
+            context.currentLinePos += context.pos - savedPos; // keep track of current line position
+            // if currentPos == 0 we are at the start of a line, so don't add CRLF
+            if (lineLength > 0 && context.currentLinePos > 0) {
+                System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
+                context.pos += lineSeparator.length;
+            }
+        } else {
+            for (int i = 0; i < inAvail; i++) {
+                final byte[] buffer = ensureBufferSize(encodeSize, context);
+                context.modulus = (context.modulus+1) % BYTES_PER_UNENCODED_BLOCK;
+                int b = in[inPos++];
+                if (b < 0) {
+                    b += 256;
+                }
+                context.ibitWorkArea = (context.ibitWorkArea << 8) + b; //  BITS_PER_BYTE
+                if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS];
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS];
+                    buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS];
+                    buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS];
+                    context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
+                    if (lineLength > 0 && lineLength <= context.currentLinePos) {
+                        System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
+                        context.pos += lineSeparator.length;
+                        context.currentLinePos = 0;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
+     * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
+     * call is not necessary when decoding, but it doesn't hurt, either.
+     * </p>
+     * <p>
+     * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
+     * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
+     * garbage-out philosophy: it will not check the provided data for validity.
+     * </p>
+     * <p>
+     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
+     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+     * </p>
+     *
+     * @param in
+     *            byte[] array of ascii data to base64 decode.
+     * @param inPos
+     *            Position to start reading data from.
+     * @param inAvail
+     *            Amount of bytes available from input for encoding.
+     * @param context
+     *            the context to be used
+     */
+    @Override
+    void decode(final byte[] in, int inPos, final int inAvail, final Context context) {
+        if (context.eof) {
+            return;
+        }
+        if (inAvail < 0) {
+            context.eof = true;
+        }
+        for (int i = 0; i < inAvail; i++) {
+            final byte[] buffer = ensureBufferSize(decodeSize, context);
+            final byte b = in[inPos++];
+            if (b == PAD) {
+                // We're done.
+                context.eof = true;
+                break;
+            } else {
+                if (b >= 0 && b < DECODE_TABLE.length) {
+                    final int result = DECODE_TABLE[b];
+                    if (result >= 0) {
+                        context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK;
+                        context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
+                        if (context.modulus == 0) {
+                            buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS);
+                            buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
+                            buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
+                        }
+                    }
+                }
+            }
+        }
+
+        // Two forms of EOF as far as base64 decoder is concerned: actual
+        // EOF (-1) and first time '=' character is encountered in stream.
+        // This approach makes the '=' padding characters completely optional.
+        if (context.eof && context.modulus != 0) {
+            final byte[] buffer = ensureBufferSize(decodeSize, context);
+
+            // We have some spare bits remaining
+            // Output all whole multiples of 8 bits and ignore the rest
+            switch (context.modulus) {
+//              case 0 : // impossible, as excluded above
+                case 1 : // 6 bits - ignore entirely
+                    // TODO not currently tested; perhaps it is impossible?
+                    break;
+                case 2 : // 12 bits = 8 + 4
+                    context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
+                    buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
+                    break;
+                case 3 : // 18 bits = 8 + 8 + 2
+                    context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
+                    buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
+                    buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
+                    break;
+                default:
+                    throw new IllegalStateException("Impossible modulus "+context.modulus);
+            }
+        }
+    }
+
+    /**
+     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
+     * method treats whitespace as valid.
+     *
+     * @param arrayOctet
+     *            byte array to test
+     * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
+     *         {@code false}, otherwise
+     * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0.
+     */
+    @Deprecated
+    public static boolean isArrayByteBase64(final byte[] arrayOctet) {
+        return isBase64(arrayOctet);
+    }
+
+    /**
+     * Returns whether or not the <code>octet</code> is in the base 64 alphabet.
+     *
+     * @param octet
+     *            The value to test
+     * @return {@code true} if the value is defined in the the base 64 alphabet, {@code false} otherwise.
+     * @since 1.4
+     */
+    public static boolean isBase64(final byte octet) {
+        return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1);
+    }
+
+    /**
+     * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the
+     * method treats whitespace as valid.
+     *
+     * @param base64
+     *            String to test
+     * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if
+     *         the String is empty; {@code false}, otherwise
+     *  @since 1.5
+     */
+    public static boolean isBase64(final String base64) {
+        return isBase64(StringUtils.getBytesUtf8(base64));
+    }
+
+    /**
+     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
+     * method treats whitespace as valid.
+     *
+     * @param arrayOctet
+     *            byte array to test
+     * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
+     *         {@code false}, otherwise
+     * @since 1.5
+     */
+    public static boolean isBase64(final byte[] arrayOctet) {
+        for (int i = 0; i < arrayOctet.length; i++) {
+            if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm but does not chunk the output.
+     *
+     * @param binaryData
+     *            binary data to encode
+     * @return byte[] containing Base64 characters in their UTF-8 representation.
+     */
+    public static byte[] encodeBase64(final byte[] binaryData) {
+        return encodeBase64(binaryData, false);
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm but does not chunk the output.
+     *
+     * NOTE:  We changed the behaviour of this method from multi-line chunking (commons-codec-1.4) to
+     * single-line non-chunking (commons-codec-1.5).
+     *
+     * @param binaryData
+     *            binary data to encode
+     * @return String containing Base64 characters.
+     * @since 1.4 (NOTE:  1.4 chunked the output, whereas 1.5 does not).
+     */
+    public static String encodeBase64String(final byte[] binaryData) {
+        return StringUtils.newStringUtf8(encodeBase64(binaryData, false));
+    }
+
+    /**
+     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
+     * url-safe variation emits - and _ instead of + and / characters.
+     * <b>Note: no padding is added.</b>
+     * @param binaryData
+     *            binary data to encode
+     * @return byte[] containing Base64 characters in their UTF-8 representation.
+     * @since 1.4
+     */
+    public static byte[] encodeBase64URLSafe(final byte[] binaryData) {
+        return encodeBase64(binaryData, false, true);
+    }
+
+    /**
+     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
+     * url-safe variation emits - and _ instead of + and / characters.
+     * <b>Note: no padding is added.</b>
+     * @param binaryData
+     *            binary data to encode
+     * @return String containing Base64 characters
+     * @since 1.4
+     */
+    public static String encodeBase64URLSafeString(final byte[] binaryData) {
+        return StringUtils.newStringUtf8(encodeBase64(binaryData, false, true));
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
+     *
+     * @param binaryData
+     *            binary data to encode
+     * @return Base64 characters chunked in 76 character blocks
+     */
+    public static byte[] encodeBase64Chunked(final byte[] binaryData) {
+        return encodeBase64(binaryData, true);
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
+     *
+     * @param binaryData
+     *            Array containing binary data to encode.
+     * @param isChunked
+     *            if {@code true} this encoder will chunk the base64 output into 76 character blocks
+     * @return Base64-encoded data.
+     * @throws IllegalArgumentException
+     *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
+     */
+    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) {
+        return encodeBase64(binaryData, isChunked, false);
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
+     *
+     * @param binaryData
+     *            Array containing binary data to encode.
+     * @param isChunked
+     *            if {@code true} this encoder will chunk the base64 output into 76 character blocks
+     * @param urlSafe
+     *            if {@code true} this encoder will emit - and _ instead of the usual + and / characters.
+     *            <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
+     * @return Base64-encoded data.
+     * @throws IllegalArgumentException
+     *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
+     * @since 1.4
+     */
+    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) {
+        return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
+     *
+     * @param binaryData
+     *            Array containing binary data to encode.
+     * @param isChunked
+     *            if {@code true} this encoder will chunk the base64 output into 76 character blocks
+     * @param urlSafe
+     *            if {@code true} this encoder will emit - and _ instead of the usual + and / characters.
+     *            <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
+     * @param maxResultSize
+     *            The maximum result size to accept.
+     * @return Base64-encoded data.
+     * @throws IllegalArgumentException
+     *             Thrown when the input array needs an output array bigger than maxResultSize
+     * @since 1.4
+     */
+    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked,
+                                      final boolean urlSafe, final int maxResultSize) {
+        if (binaryData == null || binaryData.length == 0) {
+            return binaryData;
+        }
+
+        // Create this so can use the super-class method
+        // Also ensures that the same roundings are performed by the ctor and the code
+        final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
+        final long len = b64.getEncodedLength(binaryData);
+        if (len > maxResultSize) {
+            throw new IllegalArgumentException("Input array too big, the output array would be bigger (" +
+                len +
+                ") than the specified maximum size of " +
+                maxResultSize);
+        }
+
+        return b64.encode(binaryData);
+    }
+
+    /**
+     * Decodes a Base64 String into octets
+     *
+     * @param base64String
+     *            String containing Base64 data
+     * @return Array containing decoded data.
+     * @since 1.4
+     */
+    public static byte[] decodeBase64(final String base64String) {
+        return new Base64().decode(base64String);
+    }
+
+    /**
+     * Decodes Base64 data into octets
+     *
+     * @param base64Data
+     *            Byte array containing Base64 data
+     * @return Array containing decoded data.
+     */
+    public static byte[] decodeBase64(final byte[] base64Data) {
+        return decodeBase64(base64Data, 0, base64Data.length);
+    }
+
+    public  static byte[] decodeBase64(
+            final byte[] base64Data, final int off, final int len) {
+        return new Base64().decode(base64Data, off, len);
+    }
+
+    // Implementation of the Encoder Interface
+
+    // Implementation of integer encoding used for crypto
+    /**
+     * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
+     *
+     * @param pArray
+     *            a byte array containing base64 character data
+     * @return A BigInteger
+     * @since 1.4
+     */
+    public static BigInteger decodeInteger(final byte[] pArray) {
+        return new BigInteger(1, decodeBase64(pArray));
+    }
+
+    /**
+     * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
+     *
+     * @param bigInt
+     *            a BigInteger
+     * @return A byte array containing base64 character data
+     * @throws NullPointerException
+     *             if null is passed in
+     * @since 1.4
+     */
+    public static byte[] encodeInteger(final BigInteger bigInt) {
+        if (bigInt == null) {
+            throw new NullPointerException("encodeInteger called with null parameter");
+        }
+        return encodeBase64(toIntegerBytes(bigInt), false);
+    }
+
+    /**
+     * Returns a byte-array representation of a <code>BigInteger</code> without sign bit.
+     *
+     * @param bigInt
+     *            <code>BigInteger</code> to be converted
+     * @return a byte array representation of the BigInteger parameter
+     */
+    static byte[] toIntegerBytes(final BigInteger bigInt) {
+        int bitlen = bigInt.bitLength();
+        // round bitlen
+        bitlen = ((bitlen + 7) >> 3) << 3;
+        final byte[] bigBytes = bigInt.toByteArray();
+
+        if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
+            return bigBytes;
+        }
+        // set up params for copying everything but sign bit
+        int startSrc = 0;
+        int len = bigBytes.length;
+
+        // if bigInt is exactly byte-aligned, just skip signbit in copy
+        if ((bigInt.bitLength() % 8) == 0) {
+            startSrc = 1;
+            len--;
+        }
+        final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
+        final byte[] resizedBytes = new byte[bitlen / 8];
+        System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
+        return resizedBytes;
+    }
+
+    /**
+     * Returns whether or not the <code>octet</code> is in the Base64 alphabet.
+     *
+     * @param octet
+     *            The value to test
+     * @return {@code true} if the value is defined in the the Base64 alphabet {@code false} otherwise.
+     */
+    @Override
+    protected boolean isInAlphabet(final byte octet) {
+        return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
+    }
+
+}
diff --git a/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java b/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java
new file mode 100644
index 0000000..4740335
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java
@@ -0,0 +1,503 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec.binary;
+
+import org.apache.tomcat.util.codec.BinaryDecoder;
+import org.apache.tomcat.util.codec.BinaryEncoder;
+import org.apache.tomcat.util.codec.DecoderException;
+import org.apache.tomcat.util.codec.EncoderException;
+
+/**
+ * Abstract superclass for Base-N encoders and decoders.
+ *
+ * <p>
+ * This class is thread-safe.
+ * </p>
+ *
+ * @version $Id: BaseNCodec.java 1459390 2013-03-21 16:38:39Z markt $
+ */
+public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
+
+    /**
+     * Holds thread context so classes can be thread-safe.
+     *
+     * This class is not itself thread-safe; each thread must allocate its own copy.
+     *
+     * @since 1.7
+     */
+    static class Context {
+
+        /**
+         * Place holder for the bytes we're dealing with for our based logic.
+         * Bitwise operations store and extract the encoding or decoding from this variable.
+         */
+        int ibitWorkArea;
+
+        /**
+         * Place holder for the bytes we're dealing with for our based logic.
+         * Bitwise operations store and extract the encoding or decoding from this variable.
+         */
+        long lbitWorkArea;
+
+        /**
+         * Buffer for streaming.
+         */
+        byte[] buffer;
+
+        /**
+         * Position where next character should be written in the buffer.
+         */
+        int pos;
+
+        /**
+         * Position where next character should be read from the buffer.
+         */
+        int readPos;
+
+        /**
+         * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless,
+         * and must be thrown away.
+         */
+        boolean eof;
+
+        /**
+         * Variable tracks how many characters have been written to the current line. Only used when encoding. We use
+         * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0).
+         */
+        int currentLinePos;
+
+        /**
+         * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This
+         * variable helps track that.
+         */
+        int modulus;
+
+        Context() {
+        }
+
+        /**
+         * Returns a String useful for debugging (especially within a debugger.)
+         *
+         * @return a String useful for debugging.
+         */
+        @SuppressWarnings("boxing") // OK to ignore boxing here
+        @Override
+        public String toString() {
+            return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " +
+                    "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), buffer, currentLinePos, eof,
+                    ibitWorkArea, lbitWorkArea, modulus, pos, readPos);
+        }
+    }
+
+    /**
+     * EOF
+     *
+     * @since 1.7
+     */
+    static final int EOF = -1;
+
+    /**
+     *  MIME chunk size per RFC 2045 section 6.8.
+     *
+     * <p>
+     * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
+     * equal signs.
+     * </p>
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
+     */
+    public static final int MIME_CHUNK_SIZE = 76;
+
+    /**
+     * PEM chunk size per RFC 1421 section 4.3.2.4.
+     *
+     * <p>
+     * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
+     * equal signs.
+     * </p>
+     *
+     * @see <a href="http://tools.ietf.org/html/rfc1421">RFC 1421 section 4.3.2.4</a>
+     */
+    public static final int PEM_CHUNK_SIZE = 64;
+
+    private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
+
+    /**
+     * Defines the default buffer size - currently {@value}
+     * - must be large enough for at least one encoded block+separator
+     */
+    private static final int DEFAULT_BUFFER_SIZE = 128;
+
+    /** Mask used to extract 8 bits, used in decoding bytes */
+    protected static final int MASK_8BITS = 0xff;
+
+    /**
+     * Byte used to pad output.
+     */
+    protected static final byte PAD_DEFAULT = '='; // Allow static access to default
+
+    protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later
+
+    /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */
+    private final int unencodedBlockSize;
+
+    /** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */
+    private final int encodedBlockSize;
+
+    /**
+     * Chunksize for encoding. Not used when decoding.
+     * A value of zero or less implies no chunking of the encoded data.
+     * Rounded down to nearest multiple of encodedBlockSize.
+     */
+    protected final int lineLength;
+
+    /**
+     * Size of chunk separator. Not used unless {@link #lineLength} > 0.
+     */
+    private final int chunkSeparatorLength;
+
+    /**
+     * Note <code>lineLength</code> is rounded down to the nearest multiple of {@link #encodedBlockSize}
+     * If <code>chunkSeparatorLength</code> is zero, then chunking is disabled.
+     * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
+     * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
+     * @param lineLength if > 0, use chunking with a length <code>lineLength</code>
+     * @param chunkSeparatorLength the chunk separator length, if relevant
+     */
+    protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
+                         final int lineLength, final int chunkSeparatorLength) {
+        this.unencodedBlockSize = unencodedBlockSize;
+        this.encodedBlockSize = encodedBlockSize;
+        final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0;
+        this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
+        this.chunkSeparatorLength = chunkSeparatorLength;
+    }
+
+    /**
+     * Returns true if this object has buffered data for reading.
+     *
+     * @param context the context to be used
+     * @return true if there is data still available for reading.
+     */
+    boolean hasData(final Context context) {  // package protected for access from I/O streams
+        return context.buffer != null;
+    }
+
+    /**
+     * Returns the amount of buffered data available for reading.
+     *
+     * @param context the context to be used
+     * @return The amount of buffered data available for reading.
+     */
+    int available(final Context context) {  // package protected for access from I/O streams
+        return context.buffer != null ? context.pos - context.readPos : 0;
+    }
+
+    /**
+     * Get the default buffer size. Can be overridden.
+     *
+     * @return {@link #DEFAULT_BUFFER_SIZE}
+     */
+    protected int getDefaultBufferSize() {
+        return DEFAULT_BUFFER_SIZE;
+    }
+
+    /**
+     * Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}.
+     * @param context the context to be used
+     */
+    private byte[] resizeBuffer(final Context context) {
+        if (context.buffer == null) {
+            context.buffer = new byte[getDefaultBufferSize()];
+            context.pos = 0;
+            context.readPos = 0;
+        } else {
+            final byte[] b = new byte[context.buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
+            System.arraycopy(context.buffer, 0, b, 0, context.buffer.length);
+            context.buffer = b;
+        }
+        return context.buffer;
+    }
+
+    /**
+     * Ensure that the buffer has room for <code>size</code> bytes
+     *
+     * @param size minimum spare space required
+     * @param context the context to be used
+     */
+    protected byte[] ensureBufferSize(final int size, final Context context){
+        if ((context.buffer == null) || (context.buffer.length < context.pos + size)){
+            return resizeBuffer(context);
+        }
+        return context.buffer;
+    }
+
+    /**
+     * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
+     * bytes. Returns how many bytes were actually extracted.
+     * <p>
+     * Package protected for access from I/O streams.
+     *
+     * @param b
+     *            byte[] array to extract the buffered data into.
+     * @param bPos
+     *            position in byte[] array to start extraction at.
+     * @param bAvail
+     *            amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
+     * @param context
+     *            the context to be used
+     * @return The number of bytes successfully extracted into the provided byte[] array.
+     */
+    int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) {
+        if (context.buffer != null) {
+            final int len = Math.min(available(context), bAvail);
+            System.arraycopy(context.buffer, context.readPos, b, bPos, len);
+            context.readPos += len;
+            if (context.readPos >= context.pos) {
+                context.buffer = null; // so hasData() will return false, and this method can return -1
+            }
+            return len;
+        }
+        return context.eof ? EOF : 0;
+    }
+
+    /**
+     * Checks if a byte value is whitespace or not.
+     * Whitespace is taken to mean: space, tab, CR, LF
+     * @param byteToCheck
+     *            the byte to check
+     * @return true if byte is whitespace, false otherwise
+     */
+    protected static boolean isWhiteSpace(final byte byteToCheck) {
+        switch (byteToCheck) {
+            case ' ' :
+            case '\n' :
+            case '\r' :
+            case '\t' :
+                return true;
+            default :
+                return false;
+        }
+    }
+
+    /**
+     * Encodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
+     * the Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[].
+     *
+     * @param obj
+     *            Object to encode
+     * @return An object (of type byte[]) containing the Base-N encoded data which corresponds to the byte[] supplied.
+     * @throws EncoderException
+     *             if the parameter supplied is not of type byte[]
+     */
+    @Override
+    public Object encode(final Object obj) throws EncoderException {
+        if (!(obj instanceof byte[])) {
+            throw new EncoderException("Parameter supplied to Base-N encode is not a byte[]");
+        }
+        return encode((byte[]) obj);
+    }
+
+    /**
+     * Encodes a byte[] containing binary data, into a String containing characters in the Base-N alphabet.
+     * Uses UTF8 encoding.
+     *
+     * @param pArray
+     *            a byte array containing binary data
+     * @return A String containing only Base-N character data
+     */
+    public String encodeToString(final byte[] pArray) {
+        return StringUtils.newStringUtf8(encode(pArray));
+    }
+
+    /**
+     * Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet.
+     * Uses UTF8 encoding.
+     *
+     * @param pArray a byte array containing binary data
+     * @return String containing only character data in the appropriate alphabet.
+    */
+    public String encodeAsString(final byte[] pArray){
+        return StringUtils.newStringUtf8(encode(pArray));
+    }
+
+    /**
+     * Decodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
+     * the Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String.
+     *
+     * @param obj
+     *            Object to decode
+     * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String
+     *         supplied.
+     * @throws DecoderException
+     *             if the parameter supplied is not of type byte[]
+     */
+    @Override
+    public Object decode(final Object obj) throws DecoderException {
+        if (obj instanceof byte[]) {
+            return decode((byte[]) obj);
+        } else if (obj instanceof String) {
+            return decode((String) obj);
+        } else {
+            throw new DecoderException("Parameter supplied to Base-N decode is not a byte[] or a String");
+        }
+    }
+
+    /**
+     * Decodes a String containing characters in the Base-N alphabet.
+     *
+     * @param pArray
+     *            A String containing Base-N character data
+     * @return a byte array containing binary data
+     */
+    public byte[] decode(final String pArray) {
+        return decode(StringUtils.getBytesUtf8(pArray));
+    }
+
+    /**
+     * Decodes a byte[] containing characters in the Base-N alphabet.
+     *
+     * @param pArray
+     *            A byte array containing Base-N character data
+     * @return a byte array containing binary data
+     */
+    @Override
+    public byte[] decode(final byte[] pArray) {
+        return decode(pArray, 0, pArray.length);
+    }
+
+    public byte[] decode(final byte[] pArray, final int off, final int len) {
+        if (pArray == null || len == 0) {
+            return new byte[0];
+        }
+        final Context context = new Context();
+        decode(pArray, off, len, context);
+        decode(pArray, off, EOF, context); // Notify decoder of EOF.
+        final byte[] result = new byte[context.pos];
+        readResults(result, 0, result.length, context);
+        return result;
+    }
+
+    /**
+     * Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet.
+     *
+     * @param pArray
+     *            a byte array containing binary data
+     * @return A byte array containing only the basen alphabetic character data
+     */
+    @Override
+    public byte[] encode(final byte[] pArray) {
+        if (pArray == null || pArray.length == 0) {
+            return pArray;
+        }
+        final Context context = new Context();
+        encode(pArray, 0, pArray.length, context);
+        encode(pArray, 0, EOF, context); // Notify encoder of EOF.
+        final byte[] buf = new byte[context.pos - context.readPos];
+        readResults(buf, 0, buf.length, context);
+        return buf;
+    }
+
+    // package protected for access from I/O streams
+    abstract void encode(byte[] pArray, int i, int length, Context context);
+
+    // package protected for access from I/O streams
+    abstract void decode(byte[] pArray, int i, int length, Context context);
+
+    /**
+     * Returns whether or not the <code>octet</code> is in the current alphabet.
+     * Does not allow whitespace or pad.
+     *
+     * @param value The value to test
+     *
+     * @return {@code true} if the value is defined in the current alphabet, {@code false} otherwise.
+     */
+    protected abstract boolean isInAlphabet(byte value);
+
+    /**
+     * Tests a given byte array to see if it contains only valid characters within the alphabet.
+     * The method optionally treats whitespace and pad as valid.
+     *
+     * @param arrayOctet byte array to test
+     * @param allowWSPad if {@code true}, then whitespace and PAD are also allowed
+     *
+     * @return {@code true} if all bytes are valid characters in the alphabet or if the byte array is empty;
+     *         {@code false}, otherwise
+     */
+    public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) {
+        for (int i = 0; i < arrayOctet.length; i++) {
+            if (!isInAlphabet(arrayOctet[i]) &&
+                    (!allowWSPad || (arrayOctet[i] != PAD) && !isWhiteSpace(arrayOctet[i]))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Tests a given String to see if it contains only valid characters within the alphabet.
+     * The method treats whitespace and PAD as valid.
+     *
+     * @param basen String to test
+     * @return {@code true} if all characters in the String are valid characters in the alphabet or if
+     *         the String is empty; {@code false}, otherwise
+     * @see #isInAlphabet(byte[], boolean)
+     */
+    public boolean isInAlphabet(final String basen) {
+        return isInAlphabet(StringUtils.getBytesUtf8(basen), true);
+    }
+
+    /**
+     * Tests a given byte array to see if it contains any characters within the alphabet or PAD.
+     *
+     * Intended for use in checking line-ending arrays
+     *
+     * @param arrayOctet
+     *            byte array to test
+     * @return {@code true} if any byte is a valid character in the alphabet or PAD; {@code false} otherwise
+     */
+    protected boolean containsAlphabetOrPad(final byte[] arrayOctet) {
+        if (arrayOctet == null) {
+            return false;
+        }
+        for (final byte element : arrayOctet) {
+            if (PAD == element || isInAlphabet(element)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Calculates the amount of space needed to encode the supplied array.
+     *
+     * @param pArray byte[] array which will later be encoded
+     *
+     * @return amount of space needed to encoded the supplied array.
+     * Returns a long since a max-len array will require > Integer.MAX_VALUE
+     */
+    public long getEncodedLength(final byte[] pArray) {
+        // Calculate non-chunked size - rounded up to allow for padding
+        // cast to long is needed to avoid possibility of overflow
+        long len = ((pArray.length + unencodedBlockSize-1)  / unencodedBlockSize) * (long) encodedBlockSize;
+        if (lineLength > 0) { // We're using chunking
+            // Round up to nearest multiple
+            len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength;
+        }
+        return len;
+    }
+}
diff --git a/java/org/apache/tomcat/util/codec/binary/StringUtils.java b/java/org/apache/tomcat/util/codec/binary/StringUtils.java
new file mode 100644
index 0000000..da86132
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/binary/StringUtils.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.codec.binary;
+
+import java.nio.charset.Charset;
+
+import org.apache.tomcat.util.buf.B2CConverter;
+
+/**
+ * Converts String to and from bytes using the encodings required by the Java specification. These encodings are
+ * specified in <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">
+ * Standard charsets</a>.
+ *
+ * <p>This class is immutable and thread-safe.</p>
+ *
+ * @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
+ * @version $Id: StringUtils.java 1459218 2013-03-21 10:31:50Z markt $
+ * @since 1.4
+ */
+public class StringUtils {
+
+    /**
+     * Calls {@link String#getBytes(Charset)}
+     *
+     * @param string
+     *            The string to encode (if null, return null).
+     * @param charset
+     *            The {@link Charset} to encode the {@code String}
+     * @return the encoded bytes
+     */
+    private static byte[] getBytes(final String string, final Charset charset) {
+        if (string == null) {
+            return null;
+        }
+        return string.getBytes(charset);
+    }
+
+    /**
+     * Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte
+     * array.
+     *
+     * @param string
+     *            the String to encode, may be {@code null}
+     * @return encoded bytes, or {@code null} if the input string was {@code null}
+     * @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
+     */
+    public static byte[] getBytesUtf8(final String string) {
+        return getBytes(string, B2CConverter.UTF_8);
+    }
+
+    /**
+     * Constructs a new <code>String</code> by decoding the specified array of bytes using the given charset.
+     *
+     * @param bytes
+     *            The bytes to be decoded into characters
+     * @param charset
+     *            The {@link Charset} to encode the {@code String}
+     * @return A new <code>String</code> decoded from the specified array of bytes using the given charset,
+     *         or {@code null} if the input byte array was {@code null}.
+     */
+    private static String newString(final byte[] bytes, final Charset charset) {
+        return bytes == null ? null : new String(bytes, charset);
+    }
+
+    /**
+     * Constructs a new <code>String</code> by decoding the specified array of bytes using the UTF-8 charset.
+     *
+     * @param bytes
+     *            The bytes to be decoded into characters
+     * @return A new <code>String</code> decoded from the specified array of bytes using the UTF-8 charset,
+     *         or {@code null} if the input byte array was {@code null}.
+     */
+    public static String newStringUtf8(final byte[] bytes) {
+        return newString(bytes, B2CConverter.UTF_8);
+    }
+
+}
diff --git a/java/org/apache/tomcat/util/codec/binary/package.html b/java/org/apache/tomcat/util/codec/binary/package.html
new file mode 100644
index 0000000..13345ec
--- /dev/null
+++ b/java/org/apache/tomcat/util/codec/binary/package.html
@@ -0,0 +1,21 @@
+<!--
+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.
+-->
+<html>
+ <body>
+  Base64, Base32, Binary, and Hexadecimal String encoding and decoding.
+ </body>
+</html>
diff --git a/java/org/apache/tomcat/util/http/fileupload/ByteArrayOutputStream.java b/java/org/apache/tomcat/util/http/fileupload/ByteArrayOutputStream.java
index 3c41a61..9d074e3 100644
--- a/java/org/apache/tomcat/util/http/fileupload/ByteArrayOutputStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/ByteArrayOutputStream.java
@@ -19,7 +19,6 @@ package org.apache.tomcat.util.http.fileupload;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -35,7 +34,7 @@ import java.util.List;
  * this class can be called after the stream has been closed without
  * generating an <tt>IOException</tt>.
  * <p>
- * This is an alternative implementation of the java.io.ByteArrayOutputStream
+ * This is an alternative implementation of the {@link java.io.ByteArrayOutputStream}
  * class. The original implementation only allocates 32 bytes at the beginning.
  * As this class is designed for heavy duty it starts at 1024 bytes. In contrast
  * to the original it doesn't reallocate the whole memory block but allocates
@@ -44,9 +43,7 @@ import java.util.List;
  * designed to behave exactly like the original. The only exception is the
  * deprecated toString(int) method that has been ignored.
  * 
- * @author <a href="mailto:jeremias at apache.org">Jeremias Maerki</a>
- * @author Holger Hoffstatte
- * @version $Id: ByteArrayOutputStream.java 881562 2009-11-17 22:03:22Z markt $
+ * @version $Id: ByteArrayOutputStream.java 1456969 2013-03-15 14:37:04Z markt $
  */
 public class ByteArrayOutputStream extends OutputStream {
 
@@ -54,7 +51,7 @@ public class ByteArrayOutputStream extends OutputStream {
     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 
     /** The list of buffers, which grows and never reduces. */
-    private List<byte[]> buffers = new ArrayList<byte[]>();
+    private final List<byte[]> buffers = new ArrayList<byte[]>();
     /** The index of the current buffer. */
     private int currentBufferIndex;
     /** The total count of bytes in all the filled buffers. */
@@ -84,18 +81,9 @@ public class ByteArrayOutputStream extends OutputStream {
             throw new IllegalArgumentException(
                 "Negative initial size: " + size);
         }
-        needNewBuffer(size);
-    }
-
-    /**
-     * Return the appropriate <code>byte[]</code> buffer 
-     * specified by index.
-     *
-     * @param index  the index of the buffer required
-     * @return the buffer
-     */
-    private byte[] getBuffer(int index) {
-        return buffers.get(index);
+        synchronized (this) {
+            needNewBuffer(size);
+        }
     }
 
     /**
@@ -110,7 +98,7 @@ public class ByteArrayOutputStream extends OutputStream {
             filledBufferSum += currentBuffer.length;
             
             currentBufferIndex++;
-            currentBuffer = getBuffer(currentBufferIndex);
+            currentBuffer = buffers.get(currentBufferIndex);
         } else {
             //Creating new buffer
             int newBufferSize;
@@ -188,7 +176,7 @@ public class ByteArrayOutputStream extends OutputStream {
      * @return total number of bytes read from the input stream
      *         (and written to this stream)
      * @throws IOException if an I/O error occurs while reading the input stream
-     * @since Commons IO 1.4
+     * @since 1.4
      */
     public synchronized int write(InputStream in) throws IOException {
         int readCount = 0;
@@ -208,14 +196,6 @@ public class ByteArrayOutputStream extends OutputStream {
     }
 
     /**
-     * Return the current size of the byte array.
-     * @return the current size of the byte array
-     */
-    public synchronized int size() {
-        return count;
-    }
-
-    /**
      * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
      * this class can be called after the stream has been closed without
      * generating an <tt>IOException</tt>.
@@ -229,16 +209,6 @@ public class ByteArrayOutputStream extends OutputStream {
     }
 
     /**
-     * @see java.io.ByteArrayOutputStream#reset()
-     */
-    public synchronized void reset() {
-        count = 0;
-        filledBufferSum = 0;
-        currentBufferIndex = 0;
-        currentBuffer = getBuffer(currentBufferIndex);
-    }
-
-    /**
      * Writes the entire contents of this byte stream to the
      * specified output stream.
      *
@@ -248,8 +218,7 @@ public class ByteArrayOutputStream extends OutputStream {
      */
     public synchronized void writeTo(OutputStream out) throws IOException {
         int remaining = count;
-        for (int i = 0; i < buffers.size(); i++) {
-            byte[] buf = getBuffer(i);
+        for (byte[] buf : buffers) {
             int c = Math.min(buf.length, remaining);
             out.write(buf, 0, c);
             remaining -= c;
@@ -273,8 +242,7 @@ public class ByteArrayOutputStream extends OutputStream {
         }
         byte newbuf[] = new byte[remaining];
         int pos = 0;
-        for (int i = 0; i < buffers.size(); i++) {
-            byte[] buf = getBuffer(i);
+        for (byte[] buf : buffers) {
             int c = Math.min(buf.length, remaining);
             System.arraycopy(buf, 0, newbuf, pos, c);
             pos += c;
@@ -295,18 +263,4 @@ public class ByteArrayOutputStream extends OutputStream {
     public String toString() {
         return new String(toByteArray());
     }
-
-    /**
-     * Gets the curent contents of this byte stream as a string
-     * using the specified encoding.
-     *
-     * @param enc  the name of the character encoding
-     * @return the string converted from the byte array
-     * @throws UnsupportedEncodingException if the encoding is not supported
-     * @see java.io.ByteArrayOutputStream#toString(String)
-     */
-    public String toString(String enc) throws UnsupportedEncodingException {
-        return new String(toByteArray(), enc);
-    }
-
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java b/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java
index 6e54e8f..84943b7 100644
--- a/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java
@@ -17,7 +17,6 @@
 package org.apache.tomcat.util.http.fileupload;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -34,10 +33,7 @@ import java.io.OutputStream;
  * you want to store it in memory (for speed), but if the file is large you want
  * to store it to file (to avoid memory issues).
  *
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- * @author gaxzerow
- *
- * @version $Id: DeferredFileOutputStream.java 881533 2009-11-17 21:21:41Z markt $
+ * @version $Id: DeferredFileOutputStream.java 1456969 2013-03-15 14:37:04Z markt $
  */
 public class DeferredFileOutputStream
     extends ThresholdingOutputStream
@@ -69,23 +65,17 @@ public class DeferredFileOutputStream
     /**
      * The temporary file prefix.
      */
-    private String prefix;
+    private final String prefix;
 
     /**
      * The temporary file suffix.
      */
-    private String suffix;
+    private final String suffix;
 
     /**
      * The directory to use for temporary files.
      */
-    private File directory;
-
-    
-    /**
-     * True when close() has been called successfully.
-     */
-    private boolean closed = false;
+    private final File directory;
 
     // ----------------------------------------------------------- Constructors
 
@@ -99,31 +89,26 @@ public class DeferredFileOutputStream
      */
     public DeferredFileOutputStream(int threshold, File outputFile)
     {
-        super(threshold);
-        this.outputFile = outputFile;
-
-        memoryOutputStream = new ByteArrayOutputStream();
-        currentOutputStream = memoryOutputStream;
+        this(threshold,  outputFile, null, null, null);
     }
 
 
     /**
      * Constructs an instance of this class which will trigger an event at the
-     * specified threshold, and save data to a temporary file beyond that point.
+     * specified threshold, and save data either to a file beyond that point.
      *
      * @param threshold  The number of bytes at which to trigger an event.
+     * @param outputFile The file to which data is saved beyond the threshold.
      * @param prefix Prefix to use for the temporary file.
      * @param suffix Suffix to use for the temporary file.
      * @param directory Temporary file directory.
-     *
-     * @since Commons IO 1.4
      */
-    public DeferredFileOutputStream(int threshold, String prefix, String suffix, File directory)
-    {
-        this(threshold, (File)null);
-        if (prefix == null) {
-            throw new IllegalArgumentException("Temporary file prefix is missing");
-        }
+    private DeferredFileOutputStream(int threshold, File outputFile, String prefix, String suffix, File directory) {
+        super(threshold);
+        this.outputFile = outputFile;
+
+        memoryOutputStream = new ByteArrayOutputStream();
+        currentOutputStream = memoryOutputStream;
         this.prefix = prefix;
         this.suffix = suffix;
         this.directory = directory;
@@ -176,21 +161,21 @@ public class DeferredFileOutputStream
      * Determines whether or not the data for this output stream has been
      * retained in memory.
      *
-     * @return <code>true</code> if the data is available in memory;
-     *         <code>false</code> otherwise.
+     * @return {@code true} if the data is available in memory;
+     *         {@code false} otherwise.
      */
     public boolean isInMemory()
     {
-        return (!isThresholdExceeded());
+        return !isThresholdExceeded();
     }
 
 
     /**
      * Returns the data for this output stream as an array of bytes, assuming
      * that the data has been retained in memory. If the data was written to
-     * disk, this method returns <code>null</code>.
+     * disk, this method returns {@code null}.
      *
-     * @return The data for this output stream, or <code>null</code> if no such
+     * @return The data for this output stream, or {@code null} if no such
      *         data is available.
      */
     public byte[] getData()
@@ -208,13 +193,13 @@ public class DeferredFileOutputStream
      * the temporary file created or null.
      * <p>
      * If the constructor specifying the file is used then it returns that
-     * same output file, even when threashold has not been reached.
+     * same output file, even when threshold has not been reached.
      * <p>
      * If constructor specifying a temporary file prefix/suffix is used
-     * then the temporary file created once the threashold is reached is returned
-     * If the threshold was not reached then <code>null</code> is returned.
+     * then the temporary file created once the threshold is reached is returned
+     * If the threshold was not reached then {@code null} is returned.
      *
-     * @return The file for this output stream, or <code>null</code> if no such
+     * @return The file for this output stream, or {@code null} if no such
      *         file exists.
      */
     public File getFile()
@@ -232,39 +217,5 @@ public class DeferredFileOutputStream
     public void close() throws IOException
     {
         super.close();
-        closed = true;
-    }
-    
-    
-    /**
-     * Writes the data from this output stream to the specified output stream,
-     * after it has been closed.
-     *
-     * @param out output stream to write to.
-     * @exception IOException if this stream is not yet closed or an error occurs.
-     */
-    public void writeTo(OutputStream out) throws IOException 
-    {
-        // we may only need to check if this is closed if we are working with a file
-        // but we should force the habit of closing wether we are working with
-        // a file or memory.
-        if (!closed)
-        {
-            throw new IOException("Stream not closed");
-        }
-        
-        if(isInMemory())
-        {
-            memoryOutputStream.writeTo(out);
-        }
-        else
-        {
-            FileInputStream fis = new FileInputStream(outputFile);
-            try {
-                IOUtils.copy(fis, out);
-            } finally {
-                IOUtils.closeQuietly(fis);
-            }
-        }
     }
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java b/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java
index df16f2a..d4e6f8d 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java
@@ -5,9 +5,9 @@
  * 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.
@@ -19,8 +19,11 @@ package org.apache.tomcat.util.http.fileupload;
 import java.io.File;
 import java.lang.ref.PhantomReference;
 import java.lang.ref.ReferenceQueue;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Vector;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
 
 /**
  * Keeps track of files awaiting deletion, and deletes them when an associated
@@ -36,27 +39,29 @@ import java.util.Vector;
  * {@link #exitWhenFinished}, typically in
  * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar.
  *
- * @author Noel Bergman
- * @author Martin Cooper
- * @version $Id: FileCleaner.java 490987 2006-12-29 12:11:48Z scolebourne $
+ * @version $Id$
  */
 public class FileCleaningTracker {
     /**
      * Queue of <code>Tracker</code> instances being watched.
      */
-    ReferenceQueue /* Tracker */ q = new ReferenceQueue();
+    private final ReferenceQueue<Object> q = new ReferenceQueue<Object>();
     /**
      * Collection of <code>Tracker</code> instances in existence.
      */
-    final Collection<Tracker> trackers = new Vector<Tracker>();  // synchronized
+    private final Collection<Tracker> trackers = Collections.synchronizedSet(new HashSet<Tracker>()); // synchronized
+    /**
+     * Collection of File paths that failed to delete.
+     */
+    private final List<String> deleteFailures = Collections.synchronizedList(new ArrayList<String>());
     /**
      * Whether to terminate the thread when the tracking is complete.
      */
-    volatile boolean exitWhenFinished = false;
+    private volatile boolean exitWhenFinished = false;
     /**
      * The thread that will clean up registered files.
      */
-    Thread reaper;
+    private Thread reaper;
 
     //-----------------------------------------------------------------------
     /**
@@ -90,38 +95,8 @@ public class FileCleaningTracker {
     }
 
     /**
-     * Track the specified file, using the provided marker, deleting the file
-     * when the marker instance is garbage collected.
-     * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
-     *
-     * @param path  the full path to the file to be tracked, not null
-     * @param marker  the marker object used to track the file, not null
-     * @throws NullPointerException if the path is null
-     */
-    public void track(String path, Object marker) {
-        track(path, marker, (FileDeleteStrategy) null);
-    }
-
-    /**
-     * Track the specified file, using the provided marker, deleting the file
-     * when the marker instance is garbage collected.
-     * The speified deletion strategy is used.
-     *
-     * @param path  the full path to the file to be tracked, not null
-     * @param marker  the marker object used to track the file, not null
-     * @param deleteStrategy  the strategy to delete the file, null means normal
-     * @throws NullPointerException if the path is null
-     */
-    public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) {
-        if (path == null) {
-            throw new NullPointerException("The path must not be null");
-        }
-        addTracker(path, marker, deleteStrategy);
-    }
-
-    /**
      * Adds a tracker to the list of trackers.
-     * 
+     *
      * @param path  the full path to the file to be tracked, not null
      * @param marker  the marker object used to track the file, not null
      * @param deleteStrategy  the strategy to delete the file, null means normal
@@ -140,48 +115,6 @@ public class FileCleaningTracker {
 
     //-----------------------------------------------------------------------
     /**
-     * Retrieve the number of files currently being tracked, and therefore
-     * awaiting deletion.
-     *
-     * @return the number of files being tracked
-     */
-    public int getTrackCount() {
-        return trackers.size();
-    }
-
-    /**
-     * Call this method to cause the file cleaner thread to terminate when
-     * there are no more objects being tracked for deletion.
-     * <p>
-     * In a simple environment, you don't need this method as the file cleaner
-     * thread will simply exit when the JVM exits. In a more complex environment,
-     * with multiple class loaders (such as an application server), you should be
-     * aware that the file cleaner thread will continue running even if the class
-     * loader it was started from terminates. This can consitute a memory leak.
-     * <p>
-     * For example, suppose that you have developed a web application, which
-     * contains the commons-io jar file in your WEB-INF/lib directory. In other
-     * words, the FileCleaner class is loaded through the class loader of your
-     * web application. If the web application is terminated, but the servlet
-     * container is still running, then the file cleaner thread will still exist,
-     * posing a memory leak.
-     * <p>
-     * This method allows the thread to be terminated. Simply call this method
-     * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}.
-     * One called, no new objects can be tracked by the file cleaner.
-     */
-    public synchronized void exitWhenFinished() {
-        // synchronized block protects reaper
-        exitWhenFinished = true;
-        if (reaper != null) {
-            synchronized (reaper) {
-                reaper.interrupt();
-            }
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    /**
      * The reaper thread.
      */
     private final class Reaper extends Thread {
@@ -200,17 +133,16 @@ public class FileCleaningTracker {
         public void run() {
             // thread exits when exitWhenFinished is true and there are no more tracked objects
             while (exitWhenFinished == false || trackers.size() > 0) {
-                Tracker tracker = null;
                 try {
                     // Wait for a tracker to remove.
-                    tracker = (Tracker) q.remove();
-                } catch (Exception e) {
-                    continue;
-                }
-                if (tracker != null) {
-                    tracker.delete();
-                    tracker.clear();
+                    Tracker tracker = (Tracker) q.remove(); // cannot return null
                     trackers.remove(tracker);
+                    if (!tracker.delete()) {
+                        deleteFailures.add(tracker.getPath());
+                    }
+                    tracker.clear();
+                } catch (InterruptedException e) {
+                    continue;
                 }
             }
         }
@@ -220,7 +152,7 @@ public class FileCleaningTracker {
     /**
      * Inner class which acts as the reference for a file pending deletion.
      */
-    private static final class Tracker extends PhantomReference {
+    private static final class Tracker extends PhantomReference<Object> {
 
         /**
          * The full path to the file being tracked.
@@ -239,17 +171,26 @@ public class FileCleaningTracker {
          * @param marker  the marker object used to track the file, not null
          * @param queue  the queue on to which the tracker will be pushed, not null
          */
-        Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue queue) {
+        Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue<? super Object> queue) {
             super(marker, queue);
             this.path = path;
-            this.deleteStrategy = (deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy);
+            this.deleteStrategy = deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy;
+        }
+
+        /**
+         * Return the path.
+         *
+         * @return the path
+         */
+        public String getPath() {
+            return path;
         }
 
         /**
          * Deletes the file associated with this tracker instance.
          *
-         * @return <code>true</code> if the file was deleted successfully;
-         *         <code>false</code> otherwise.
+         * @return {@code true} if the file was deleted successfully;
+         *         {@code false} otherwise.
          */
         public boolean delete() {
             return deleteStrategy.deleteQuietly(new File(path));
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileDeleteStrategy.java b/java/org/apache/tomcat/util/http/fileupload/FileDeleteStrategy.java
index 090a8ba..55a2605 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileDeleteStrategy.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileDeleteStrategy.java
@@ -28,9 +28,8 @@ import java.io.IOException;
  * <p>
  * This class captures the strategy to use and is designed for user subclassing.
  *
- * @author Stephen Colebourne
- * @version $Id: FileDeleteStrategy.java 881533 2009-11-17 21:21:41Z markt $
- * @since Commons IO 1.3
+ * @version $Id: FileDeleteStrategy.java 1456969 2013-03-15 14:37:04Z markt $
+ * @since 1.3
  */
 public class FileDeleteStrategy {
 
@@ -39,11 +38,6 @@ public class FileDeleteStrategy {
      * the deletion of directories that are not empty.
      */
     public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal");
-    /**
-     * The singleton instance for forced file deletion, which always deletes,
-     * even if the file represents a non-empty directory.
-     */
-    public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy();
 
     /** The name of the strategy. */
     private final String name;
@@ -81,22 +75,6 @@ public class FileDeleteStrategy {
     }
 
     /**
-     * Deletes the file object, which may be a file or a directory.
-     * If the file does not exist, the method just returns.
-     * <p>
-     * Subclass writers should override {@link #doDelete(File)}, not this method.
-     *
-     * @param fileToDelete  the file to delete, not null
-     * @throws NullPointerException if the file is null
-     * @throws IOException if an error occurs during file deletion
-     */
-    public void delete(File fileToDelete) throws IOException {
-        if (fileToDelete.exists() && doDelete(fileToDelete) == false) {
-            throw new IOException("Deletion failed: " + fileToDelete);
-        }
-    }
-
-    /**
      * Actually deletes the file object, which may be a file or a directory.
      * <p>
      * This method is designed for subclasses to override.
@@ -144,7 +122,7 @@ public class FileDeleteStrategy {
          * if the file exists.
          *
          * @param fileToDelete  the file to delete, not null
-         * @return Always returns <code>true</code>
+         * @return Always returns {@code true}
          * @throws NullPointerException if the file is null
          * @throws IOException if an error occurs during file deletion
          */
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItem.java b/java/org/apache/tomcat/util/http/fileupload/FileItem.java
index 748d90b..1543bcc 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItem.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItem.java
@@ -43,19 +43,13 @@ import java.io.UnsupportedEncodingException;
  * implementation of this interface to also implement
  * <code>javax.activation.DataSource</code> with minimal additional work.
  *
- * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:sean at informage.net">Sean Legassick</a>
- * @author <a href="mailto:jvanzyl at apache.org">Jason van Zyl</a>
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- *
- * @version $Id: FileItem.java 1373051 2012-08-14 19:47:38Z markt $
+ * @version $Id: FileItem.java 1458206 2013-03-19 10:13:17Z markt $
+ * @since 1.3 additionally implements FileItemHeadersSupport
  */
-public interface FileItem extends Serializable {
-
+public interface FileItem extends Serializable, FileItemHeadersSupport {
 
     // ------------------------------- Methods from javax.activation.DataSource
 
-
     /**
      * Returns an {@link java.io.InputStream InputStream} that can be
      * used to retrieve the contents of the file.
@@ -67,7 +61,6 @@ public interface FileItem extends Serializable {
      */
     InputStream getInputStream() throws IOException;
 
-
     /**
      * Returns the content type passed by the browser or <code>null</code> if
      * not defined.
@@ -77,7 +70,6 @@ public interface FileItem extends Serializable {
      */
     String getContentType();
 
-
     /**
      * Returns the original filename in the client's filesystem, as provided by
      * the browser (or other client software). In most cases, this will be the
@@ -92,10 +84,8 @@ public interface FileItem extends Serializable {
      */
     String getName();
 
-
     // ------------------------------------------------------- FileItem methods
 
-
     /**
      * Provides a hint as to whether or not the file contents will be read
      * from memory.
@@ -105,7 +95,6 @@ public interface FileItem extends Serializable {
      */
     boolean isInMemory();
 
-
     /**
      * Returns the size of the file item.
      *
@@ -113,7 +102,6 @@ public interface FileItem extends Serializable {
      */
     long getSize();
 
-
     /**
      * Returns the contents of the file item as an array of bytes.
      *
@@ -121,7 +109,6 @@ public interface FileItem extends Serializable {
      */
     byte[] get();
 
-
     /**
      * Returns the contents of the file item as a String, using the specified
      * encoding.  This method uses {@link #get()} to retrieve the
@@ -136,7 +123,6 @@ public interface FileItem extends Serializable {
      */
     String getString(String encoding) throws UnsupportedEncodingException;
 
-
     /**
      * Returns the contents of the file item as a String, using the default
      * character encoding.  This method uses {@link #get()} to retrieve the
@@ -146,7 +132,6 @@ public interface FileItem extends Serializable {
      */
     String getString();
 
-
     /**
      * A convenience method to write an uploaded item to disk. The client code
      * is not concerned with whether or not the item is stored in memory, or on
@@ -165,7 +150,6 @@ public interface FileItem extends Serializable {
      */
     void write(File file) throws Exception;
 
-
     /**
      * Deletes the underlying storage for a file item, including deleting any
      * associated temporary disk file. Although this storage will be deleted
@@ -175,7 +159,6 @@ public interface FileItem extends Serializable {
      */
     void delete();
 
-
     /**
      * Returns the name of the field in the multipart form corresponding to
      * this file item.
@@ -184,7 +167,6 @@ public interface FileItem extends Serializable {
      */
     String getFieldName();
 
-
     /**
      * Sets the field name used to reference this file item.
      *
@@ -192,7 +174,6 @@ public interface FileItem extends Serializable {
      */
     void setFieldName(String name);
 
-
     /**
      * Determines whether or not a <code>FileItem</code> instance represents
      * a simple form field.
@@ -202,7 +183,6 @@ public interface FileItem extends Serializable {
      */
     boolean isFormField();
 
-
     /**
      * Specifies whether or not a <code>FileItem</code> instance represents
      * a simple form field.
@@ -212,13 +192,12 @@ public interface FileItem extends Serializable {
      */
     void setFormField(boolean state);
 
-
     /**
      * Returns an {@link java.io.OutputStream OutputStream} that can
      * be used for storing the contents of the file.
      *
      * @return An {@link java.io.OutputStream OutputStream} that can be used
-     *         for storing the contents of the file.
+     *         for storing the contensts of the file.
      *
      * @throws IOException if an error occurs.
      */
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemFactory.java b/java/org/apache/tomcat/util/http/fileupload/FileItemFactory.java
index 18f0df7..9be45ba 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItemFactory.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItemFactory.java
@@ -16,15 +16,12 @@
  */
 package org.apache.tomcat.util.http.fileupload;
 
-
 /**
  * <p>A factory interface for creating {@link FileItem} instances. Factories
  * can provide their own custom configuration, over and above that provided
  * by the default file upload implementation.</p>
  *
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- *
- * @version $Id: FileItemFactory.java 881493 2009-11-17 20:30:39Z markt $
+ * @version $Id: FileItemFactory.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public interface FileItemFactory {
 
@@ -47,4 +44,5 @@ public interface FileItemFactory {
             boolean isFormField,
             String fileName
             );
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java b/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java
index 429b438..4f2a50d 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java
@@ -23,12 +23,15 @@ import java.util.Iterator;
  * item that was received within a <code>multipart/form-data</code> POST
  * request.</p>
  *
- * @author Michael C. Macaluso
- * @since 1.3
+ * @since 1.2.1
+ *
+ * @version $Id$
  */
 public interface FileItemHeaders {
+
     /**
      * Returns the value of the specified part header as a <code>String</code>.
+     *
      * If the part did not include a header of the specified name, this method
      * return <code>null</code>.  If there are multiple headers with the same
      * name, this method returns the first header in the item.  The header
@@ -44,34 +47,30 @@ public interface FileItemHeaders {
     /**
      * <p>
      * Returns all the values of the specified item header as an
-     * <code>Enumeration</code> of <code>String</code> objects.
+     * <code>Iterator</code> of <code>String</code> objects.
      * </p>
      * <p>
      * If the item did not include any headers of the specified name, this
-     * method returns an empty <code>Enumeration</code>. The header name is
+     * method returns an empty <code>Iterator</code>. The header name is
      * case insensitive.
      * </p>
      *
      * @param name a <code>String</code> specifying the header name
-     * @return an <code>Enumeration</code> containing the values of the
+     * @return an <code>Iterator</code> containing the values of the
      *         requested header. If the item does not have any headers of
-     *         that name, return an empty <code>Enumeration</code>
+     *         that name, return an empty <code>Iterator</code>
      */
     Iterator<String> getHeaders(String name);
 
     /**
      * <p>
-     * Returns an <code>Enumeration</code> of all the header names.
-     * </p>
-     * <p>
-     * If the item did not include any headers of the specified name, this
-     * method returns an empty <code>Enumeration</code>. The header name is
-     * case insensitive.
+     * Returns an <code>Iterator</code> of all the header names.
      * </p>
      *
-     * @return an <code>Enumeration</code> containing the values of the
-     *         requested header. If the item does not have any headers of
-     *         that name return an empty <code>Enumeration</code>
+     * @return an <code>Iterator</code> containing all of the names of
+     *         headers provided with this file item. If the item does not have
+     *         any headers return an empty <code>Iterator</code>
      */
     Iterator<String> getHeaderNames();
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java b/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java
index 1cafdeb..c06b946 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java
@@ -20,13 +20,15 @@ package org.apache.tomcat.util.http.fileupload;
  * Interface that will indicate that {@link FileItem} or {@link FileItemStream}
  * implementations will accept the headers read for the item.
  *
- * @author Michael C. Macaluso
- * @since 1.3
+ * @since 1.2.1
  *
  * @see FileItem
  * @see FileItemStream
+ *
+ * @version $Id$
  */
 public interface FileItemHeadersSupport {
+
     /**
      * Returns the collection of headers defined locally within this item.
      *
@@ -44,4 +46,5 @@ public interface FileItemHeadersSupport {
      *         for this instance.
      */
     void setHeaders(FileItemHeaders headers);
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java b/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java
index 7279c75..bd113df 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java
@@ -15,17 +15,21 @@
  * limitations under the License.
  */
 package org.apache.tomcat.util.http.fileupload;
-import java.io.IOException;
 
+import java.io.IOException;
 
 /**
  * An iterator, as returned by
  * {@link FileUploadBase#getItemIterator(RequestContext)}.
+ *
+ * @version $Id: FileItemIterator.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public interface FileItemIterator {
+
     /**
      * Returns, whether another instance of {@link FileItemStream}
      * is available.
+     *
      * @throws FileUploadException Parsing or processing the
      *   file item failed.
      * @throws IOException Reading the file item failed.
@@ -36,6 +40,7 @@ public interface FileItemIterator {
 
     /**
      * Returns the next available {@link FileItemStream}.
+     *
      * @throws java.util.NoSuchElementException No more items are available. Use
      * {@link #hasNext()} to prevent this exception.
      * @throws FileUploadException Parsing or processing the
@@ -45,4 +50,5 @@ public interface FileItemIterator {
      *   access to the next file item.
      */
     FileItemStream next() throws FileUploadException, IOException;
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemStream.java b/java/org/apache/tomcat/util/http/fileupload/FileItemStream.java
index 92f9487..50a6237 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItemStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItemStream.java
@@ -19,7 +19,6 @@ package org.apache.tomcat.util.http.fileupload;
 import java.io.IOException;
 import java.io.InputStream;
 
-
 /**
  * <p> This interface provides access to a file or form item that was
  * received within a <code>multipart/form-data</code> POST request.
@@ -31,8 +30,11 @@ import java.io.InputStream;
  * its associated instances of {@link FileItemStream}: By invoking
  * {@link java.util.Iterator#hasNext()} on the iterator, you discard all data,
  * which hasn't been read so far from the previous data.</p>
+ *
+ * @version $Id: FileItemStream.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public interface FileItemStream extends FileItemHeadersSupport {
+
     /**
      * This exception is thrown, if an attempt is made to read
      * data from the {@link InputStream}, which has been returned
@@ -41,15 +43,19 @@ public interface FileItemStream extends FileItemHeadersSupport {
      * iterator, which created the {@link FileItemStream}.
      */
     public static class ItemSkippedException extends IOException {
+
         /**
          * The exceptions serial version UID, which is being used
          * when serializing an exception instance.
          */
         private static final long serialVersionUID = -7280778431581963740L;
+
     }
 
-    /** Creates an {@link InputStream}, which allows to read the
+    /**
+     * Creates an {@link InputStream}, which allows to read the
      * items contents.
+     *
      * @return The input stream, from which the items data may
      *   be read.
      * @throws IllegalStateException The method was already invoked on
@@ -94,4 +100,5 @@ public interface FileItemStream extends FileItemHeadersSupport {
      *         field; <code>false</code> if it represents an uploaded file.
      */
     boolean isFormField();
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUpload.java b/java/org/apache/tomcat/util/http/fileupload/FileUpload.java
index da983cc..fb062b9 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileUpload.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileUpload.java
@@ -16,7 +16,6 @@
  */
 package org.apache.tomcat.util.http.fileupload;
 
-
 /**
  * <p>High level API for processing file uploads.</p>
  *
@@ -31,32 +30,24 @@ package org.apache.tomcat.util.http.fileupload;
  * used to create them; a given part may be in memory, on disk, or somewhere
  * else.</p>
  *
- * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:dlr at collab.net">Daniel Rall</a>
- * @author <a href="mailto:jvanzyl at apache.org">Jason van Zyl</a>
- * @author <a href="mailto:jmcnally at collab.net">John McNally</a>
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- * @author Sean C. Sullivan
- *
- * @version $Id: FileUpload.java 981816 2010-08-03 10:44:58Z markt $
+ * @version $Id: FileUpload.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public class FileUpload
     extends FileUploadBase {
 
     // ----------------------------------------------------------- Data members
 
-
     /**
      * The factory to use to create new form items.
      */
     private FileItemFactory fileItemFactory;
 
-
     // ----------------------------------------------------------- Constructors
 
-
     /**
-     * Constructs an uninitialised instance of this class. A factory must be
+     * Constructs an uninitialised instance of this class.
+     *
+     * A factory must be
      * configured, using <code>setFileItemFactory()</code>, before attempting
      * to parse requests.
      *
@@ -66,7 +57,6 @@ public class FileUpload
         super();
     }
 
-
     /**
      * Constructs an instance of this class which uses the supplied factory to
      * create <code>FileItem</code> instances.
@@ -79,10 +69,8 @@ public class FileUpload
         this.fileItemFactory = fileItemFactory;
     }
 
-
     // ----------------------------------------------------- Property accessors
 
-
     /**
      * Returns the factory class used when creating file items.
      *
@@ -93,7 +81,6 @@ public class FileUpload
         return fileItemFactory;
     }
 
-
     /**
      * Sets the factory class to use when creating file items.
      *
@@ -104,5 +91,4 @@ public class FileUpload
         this.fileItemFactory = factory;
     }
 
-
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
index 0e5c342..eb40ace 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
@@ -20,7 +20,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -47,14 +47,7 @@ import org.apache.tomcat.util.http.fileupload.util.Streams;
  * used to create them; a given part may be in memory, on disk, or somewhere
  * else.</p>
  *
- * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:dlr at collab.net">Daniel Rall</a>
- * @author <a href="mailto:jvanzyl at apache.org">Jason van Zyl</a>
- * @author <a href="mailto:jmcnally at collab.net">John McNally</a>
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- * @author Sean C. Sullivan
- *
- * @version $Id: FileUploadBase.java 1154575 2011-08-06 20:19:29Z markt $
+ * @version $Id: FileUploadBase.java 1458566 2013-03-19 23:14:59Z markt $
  */
 public abstract class FileUploadBase {
 
@@ -88,16 +81,13 @@ public abstract class FileUploadBase {
         return false;
     }
 
-
     // ----------------------------------------------------- Manifest constants
 
-
     /**
      * HTTP content type header name.
      */
     public static final String CONTENT_TYPE = "Content-type";
 
-
     /**
      * HTTP content disposition header name.
      */
@@ -108,40 +98,33 @@ public abstract class FileUploadBase {
      */
     public static final String CONTENT_LENGTH = "Content-length";
 
-
     /**
      * Content-disposition value for form data.
      */
     public static final String FORM_DATA = "form-data";
 
-
     /**
      * Content-disposition value for file attachment.
      */
     public static final String ATTACHMENT = "attachment";
 
-
     /**
      * Part of HTTP content type header.
      */
     public static final String MULTIPART = "multipart/";
 
-
     /**
      * HTTP content type header for multipart forms.
      */
     public static final String MULTIPART_FORM_DATA = "multipart/form-data";
 
-
     /**
      * HTTP content type header for multiple uploads.
      */
     public static final String MULTIPART_MIXED = "multipart/mixed";
 
-
     // ----------------------------------------------------------- Data members
 
-
     /**
      * The maximum size permitted for the complete request, as opposed to
      * {@link #fileSizeMax}. A value of -1 indicates no maximum.
@@ -166,7 +149,6 @@ public abstract class FileUploadBase {
 
     // ----------------------------------------------------- Property accessors
 
-
     /**
      * Returns the factory class used when creating file items.
      *
@@ -174,7 +156,6 @@ public abstract class FileUploadBase {
      */
     public abstract FileItemFactory getFileItemFactory();
 
-
     /**
      * Sets the factory class to use when creating file items.
      *
@@ -182,7 +163,6 @@ public abstract class FileUploadBase {
      */
     public abstract void setFileItemFactory(FileItemFactory factory);
 
-
     /**
      * Returns the maximum allowed size of a complete request, as opposed
      * to {@link #getFileSizeMax()}.
@@ -197,7 +177,6 @@ public abstract class FileUploadBase {
         return sizeMax;
     }
 
-
     /**
      * Sets the maximum allowed size of a complete request, as opposed
      * to {@link #setFileSizeMax(long)}.
@@ -246,7 +225,6 @@ public abstract class FileUploadBase {
         return headerEncoding;
     }
 
-
     /**
      * Specifies the character encoding to be used when reading the headers of
      * individual part. When not specified, or <code>null</code>, the request
@@ -259,10 +237,8 @@ public abstract class FileUploadBase {
         headerEncoding = encoding;
     }
 
-
     // --------------------------------------------------------- Public methods
 
-
     /**
      * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
      * compliant <code>multipart/form-data</code> stream.
@@ -281,7 +257,12 @@ public abstract class FileUploadBase {
      */
     public FileItemIterator getItemIterator(RequestContext ctx)
     throws FileUploadException, IOException {
-        return new FileItemIteratorImpl(ctx);
+        try {
+            return new FileItemIteratorImpl(ctx);
+        } catch (FileUploadIOException e) {
+            // unwrap encapsulated SizeException
+            throw (FileUploadException) e.getCause();
+        }
     }
 
     /**
@@ -304,31 +285,25 @@ public abstract class FileUploadBase {
             FileItemIterator iter = getItemIterator(ctx);
             FileItemFactory fac = getFileItemFactory();
             if (fac == null) {
-                throw new NullPointerException(
-                    "No FileItemFactory has been set.");
+                throw new NullPointerException("No FileItemFactory has been set.");
             }
             while (iter.hasNext()) {
                 final FileItemStream item = iter.next();
                 // Don't use getName() here to prevent an InvalidFileNameException.
-                final String fileName = ((org.apache.tomcat.util.http.fileupload.FileUploadBase.FileItemIteratorImpl.FileItemStreamImpl) item).name;
-                FileItem fileItem = fac.createItem(item.getFieldName(),
-                        item.getContentType(), item.isFormField(),
-                        fileName);
+                final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name;
+                FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(),
+                                                   item.isFormField(), fileName);
                 items.add(fileItem);
                 try {
-                    Streams.copy(item.openStream(), fileItem.getOutputStream(),
-                            true);
+                    Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
                 } catch (FileUploadIOException e) {
                     throw (FileUploadException) e.getCause();
                 } catch (IOException e) {
-                    throw new IOFileUploadException(
-                            "Processing of " + MULTIPART_FORM_DATA
-                            + " request failed. " + e.getMessage(), e);
-                }
-                if (fileItem instanceof FileItemHeadersSupport) {
-                    final FileItemHeaders fih = item.getHeaders();
-                    ((FileItemHeadersSupport) fileItem).setHeaders(fih);
+                    throw new IOFileUploadException(String.format("Processing of %s request failed. %s",
+                                                           MULTIPART_FORM_DATA, e.getMessage()), e);
                 }
+                final FileItemHeaders fih = item.getHeaders();
+                fileItem.setHeaders(fih);
             }
             successful = true;
             return items;
@@ -338,8 +313,7 @@ public abstract class FileUploadBase {
             throw new FileUploadException(e.getMessage(), e);
         } finally {
             if (!successful) {
-                for (Iterator<FileItem> iterator = items.iterator(); iterator.hasNext();) {
-                    FileItem fileItem = iterator.next();
+                for (FileItem fileItem : items) {
                     try {
                         fileItem.delete();
                     } catch (Exception e) {
@@ -350,9 +324,41 @@ public abstract class FileUploadBase {
         }
     }
 
+    /**
+     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+     * compliant <code>multipart/form-data</code> stream.
+     *
+     * @param ctx The context for the request to be parsed.
+     *
+     * @return A map of <code>FileItem</code> instances parsed from the request.
+     *
+     * @throws FileUploadException if there are problems reading/parsing
+     *                             the request or storing files.
+     *
+     * @since 1.3
+     */
+    public Map<String, List<FileItem>> parseParameterMap(RequestContext ctx)
+            throws FileUploadException {
+        final List<FileItem> items = parseRequest(ctx);
+        final Map<String, List<FileItem>> itemsMap =
+                new HashMap<String, List<FileItem>>(items.size());
+
+        for (FileItem fileItem : items) {
+            String fieldName = fileItem.getFieldName();
+            List<FileItem> mappedItems = itemsMap.get(fieldName);
 
-    // ------------------------------------------------------ Protected methods
+            if (mappedItems == null) {
+                mappedItems = new ArrayList<FileItem>();
+                itemsMap.put(fieldName, mappedItems);
+            }
 
+            mappedItems.add(fileItem);
+        }
+
+        return itemsMap;
+    }
+
+    // ------------------------------------------------------ Protected methods
 
     /**
      * Retrieves the boundary from the <code>Content-type</code> header.
@@ -367,7 +373,7 @@ public abstract class FileUploadBase {
         parser.setLowerCaseNames(true);
         // Parameter parser can handle null input
         Map<String,String> params =
-            parser.parse(contentType, new char[] {';', ','});
+                parser.parse(contentType, new char[] {';', ','});
         String boundaryStr = params.get("boundary");
 
         if (boundaryStr == null) {
@@ -378,7 +384,6 @@ public abstract class FileUploadBase {
         return boundary;
     }
 
-
     /**
      * Retrieves the file name from the <code>Content-disposition</code>
      * header.
@@ -422,7 +427,6 @@ public abstract class FileUploadBase {
         return fileName;
     }
 
-
     /**
      * Retrieves the field name from the <code>Content-disposition</code>
      * header.
@@ -448,8 +452,7 @@ public abstract class FileUploadBase {
             ParameterParser parser = new ParameterParser();
             parser.setLowerCaseNames(true);
             // Parameter parser can handle null input
-            Map<String,String> params =
-                parser.parse(pContentDisposition, ';');
+            Map<String,String> params = parser.parse(pContentDisposition, ';');
             fieldName = params.get("name");
             if (fieldName != null) {
                 fieldName = fieldName.trim();
@@ -479,7 +482,7 @@ public abstract class FileUploadBase {
             if (start == end) {
                 break;
             }
-            String header = headerPart.substring(start, end);
+            StringBuilder header = new StringBuilder(headerPart.substring(start, end));
             start = end + 2;
             while (start < len) {
                 int nonWs = start;
@@ -495,10 +498,10 @@ public abstract class FileUploadBase {
                 }
                 // Continuation line found
                 end = parseEndOfLine(headerPart, nonWs);
-                header += " " + headerPart.substring(nonWs, end);
+                header.append(" ").append(headerPart.substring(nonWs, end));
                 start = end + 2;
             }
-            parseHeaderLine(headers, header);
+            parseHeaderLine(headers, header.toString());
         }
         return headers;
     }
@@ -556,34 +559,50 @@ public abstract class FileUploadBase {
      * {@link FileUploadBase#getItemIterator(RequestContext)}.
      */
     private class FileItemIteratorImpl implements FileItemIterator {
+
         /**
          * Default implementation of {@link FileItemStream}.
          */
         class FileItemStreamImpl implements FileItemStream {
-            /** The file items content type.
+
+            /**
+             * The file items content type.
              */
             private final String contentType;
-            /** The file items field name.
+
+            /**
+             * The file items field name.
              */
             private final String fieldName;
-            /** The file items file name.
+
+            /**
+             * The file items file name.
              */
             private final String name;
-            /** Whether the file item is a form field.
+
+            /**
+             * Whether the file item is a form field.
              */
             private final boolean formField;
-            /** The file items input stream.
+
+            /**
+             * The file items input stream.
              */
             private final InputStream stream;
-            /** Whether the file item was already opened.
+
+            /**
+             * Whether the file item was already opened.
              */
             private boolean opened;
-            /** The headers, if any.
+
+            /**
+             * The headers, if any.
              */
             private FileItemHeaders headers;
 
             /**
              * Creates a new instance.
+             *
              * @param pName The items file name, or null.
              * @param pFieldName The items field name.
              * @param pContentType The items content type, or null.
@@ -605,10 +624,8 @@ public abstract class FileUploadBase {
                             &&  pContentLength > fileSizeMax) {
                         FileSizeLimitExceededException e =
                             new FileSizeLimitExceededException(
-                                "The field " + fieldName
-                                + " exceeds its maximum permitted "
-                                + " size of " + fileSizeMax
-                                + " bytes.",
+                                String.format("The field %s exceeds its maximum permitted size of %s bytes.",
+                                        fieldName, Long.valueOf(fileSizeMax)),
                                 pContentLength, fileSizeMax);
                         e.setFileName(pName);
                         e.setFieldName(pFieldName);
@@ -621,10 +638,8 @@ public abstract class FileUploadBase {
                             itemStream.close(true);
                             FileSizeLimitExceededException e =
                                 new FileSizeLimitExceededException(
-                                    "The field " + fieldName
-                                    + " exceeds its maximum permitted "
-                                    + " size of " + pSizeMax
-                                    + " bytes.",
+                                    String.format("The field %s exceeds its maximum permitted size of %s bytes.",
+                                           fieldName, Long.valueOf(pSizeMax)),
                                     pCount, pSizeMax);
                             e.setFieldName(fieldName);
                             e.setFileName(name);
@@ -637,6 +652,7 @@ public abstract class FileUploadBase {
 
             /**
              * Returns the items content type, or null.
+             *
              * @return Content type, if known, or null.
              */
             @Override
@@ -646,6 +662,7 @@ public abstract class FileUploadBase {
 
             /**
              * Returns the items field name.
+             *
              * @return Field name.
              */
             @Override
@@ -655,6 +672,7 @@ public abstract class FileUploadBase {
 
             /**
              * Returns the items file name.
+             *
              * @return File name, if known, or null.
              * @throws InvalidFileNameException The file name contains a NUL character,
              *   which might be an indicator of a security attack. If you intend to
@@ -668,6 +686,7 @@ public abstract class FileUploadBase {
 
             /**
              * Returns, whether this is a form field.
+             *
              * @return True, if the item is a form field,
              *   otherwise false.
              */
@@ -679,6 +698,7 @@ public abstract class FileUploadBase {
             /**
              * Returns an input stream, which may be used to
              * read the items contents.
+             *
              * @return Opened input stream.
              * @throws IOException An I/O error occurred.
              */
@@ -696,6 +716,7 @@ public abstract class FileUploadBase {
 
             /**
              * Closes the file item.
+             *
              * @throws IOException An I/O error occurred.
              */
             void close() throws IOException {
@@ -704,6 +725,7 @@ public abstract class FileUploadBase {
 
             /**
              * Returns the file item headers.
+             *
              * @return The items header object
              */
             @Override
@@ -713,43 +735,52 @@ public abstract class FileUploadBase {
 
             /**
              * Sets the file item headers.
+             *
              * @param pHeaders The items header object
              */
             @Override
             public void setHeaders(FileItemHeaders pHeaders) {
                 headers = pHeaders;
             }
+
         }
 
         /**
          * The multi part stream to process.
          */
         private final MultipartStream multi;
+
         /**
          * The notifier, which used for triggering the
          * {@link ProgressListener}.
          */
         private final MultipartStream.ProgressNotifier notifier;
+
         /**
          * The boundary, which separates the various parts.
          */
         private final byte[] boundary;
+
         /**
          * The item, which we currently process.
          */
         private FileItemStreamImpl currentItem;
+
         /**
          * The current items field name.
          */
         private String currentFieldName;
+
         /**
          * Whether we are currently skipping the preamble.
          */
         private boolean skipPreamble;
+
         /**
          * Whether the current item may still be read.
          */
         private boolean itemValid;
+
         /**
          * Whether we have seen the end of the file.
          */
@@ -757,6 +788,7 @@ public abstract class FileUploadBase {
 
         /**
          * Creates a new instance.
+         *
          * @param ctx The request context.
          * @throws FileUploadException An error occurred while
          *   parsing the request.
@@ -771,44 +803,34 @@ public abstract class FileUploadBase {
             String contentType = ctx.getContentType();
             if ((null == contentType)
                     || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) {
-                throw new InvalidContentTypeException(
-                        "the request doesn't contain a "
-                        + MULTIPART_FORM_DATA
-                        + " or "
-                        + MULTIPART_MIXED
-                        + " stream, content type header is "
-                        + contentType);
+                throw new InvalidContentTypeException(String.format(
+                        "the request doesn't contain a %s or %s stream, content type header is %s",
+                        MULTIPART_FORM_DATA, MULTIPART_FORM_DATA, contentType));
             }
 
             InputStream input = ctx.getInputStream();
 
+            final long requestSize = ((UploadContext) ctx).contentLength();
+
             if (sizeMax >= 0) {
-                int requestSize = ctx.getContentLength();
-                if (requestSize == -1) {
-                    input = new LimitedInputStream(input, sizeMax) {
-                        @Override
-                        protected void raiseError(long pSizeMax, long pCount)
-                                throws IOException {
-                            FileUploadException ex =
-                                new SizeLimitExceededException(
-                                    "the request was rejected because"
-                                    + " its size (" + pCount
-                                    + ") exceeds the configured maximum"
-                                    + " (" + pSizeMax + ")",
-                                    pCount, pSizeMax);
-                            throw new FileUploadIOException(ex);
-                        }
-                    };
-                } else {
-                    if (sizeMax >= 0 && requestSize > sizeMax) {
-                        throw new SizeLimitExceededException(
-                                "the request was rejected because its size ("
-                                + requestSize
-                                + ") exceeds the configured maximum ("
-                                + sizeMax + ")",
-                                requestSize, sizeMax);
-                    }
+                if (requestSize != -1 && requestSize > sizeMax) {
+                    throw new SizeLimitExceededException(String.format(
+                            "the request was rejected because its size (%s) exceeds the configured maximum (%s)",
+                            Long.valueOf(requestSize),
+                            Long.valueOf(sizeMax)),
+                            requestSize, sizeMax);
                 }
+                input = new LimitedInputStream(input, sizeMax) {
+                    @Override
+                    protected void raiseError(long pSizeMax, long pCount)
+                            throws IOException {
+                        FileUploadException ex = new SizeLimitExceededException(
+                        String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
+                               Long.valueOf(pCount), Long.valueOf(pSizeMax)),
+                               pCount, pSizeMax);
+                        throw new FileUploadIOException(ex);
+                    }
+                };
             }
 
             String charEncoding = headerEncoding;
@@ -818,13 +840,10 @@ public abstract class FileUploadBase {
 
             boundary = getBoundary(contentType);
             if (boundary == null) {
-                throw new FileUploadException(
-                        "the request was rejected because "
-                        + "no multipart boundary was found");
+                throw new FileUploadException("the request was rejected because no multipart boundary was found");
             }
 
-            notifier = new MultipartStream.ProgressNotifier(listener,
-                    ctx.getContentLength());
+            notifier = new MultipartStream.ProgressNotifier(listener, requestSize);
             multi = new MultipartStream(input, boundary, notifier);
             multi.setHeaderEncoding(charEncoding);
 
@@ -833,7 +852,8 @@ public abstract class FileUploadBase {
         }
 
         /**
-         * Called for finding the nex item, if any.
+         * Called for finding the next item, if any.
+         *
          * @return True, if an next item was found, otherwise false.
          * @throws IOException An I/O error occurred.
          */
@@ -916,6 +936,7 @@ public abstract class FileUploadBase {
         /**
          * Returns, whether another instance of {@link FileItemStream}
          * is available.
+         *
          * @throws FileUploadException Parsing or processing the
          *   file item failed.
          * @throws IOException Reading the file item failed.
@@ -930,11 +951,17 @@ public abstract class FileUploadBase {
             if (itemValid) {
                 return true;
             }
-            return findNextItem();
+            try {
+                return findNextItem();
+            } catch (FileUploadIOException e) {
+                // unwrap encapsulated SizeException
+                throw (FileUploadException) e.getCause();
+            }
         }
 
         /**
          * Returns the next available {@link FileItemStream}.
+         *
          * @throws java.util.NoSuchElementException No more items are
          *   available. Use {@link #hasNext()} to prevent this exception.
          * @throws FileUploadException Parsing or processing the
@@ -951,6 +978,7 @@ public abstract class FileUploadBase {
             itemValid = false;
             return currentItem;
         }
+
     }
 
     /**
@@ -958,32 +986,23 @@ public abstract class FileUploadBase {
      * {@link FileUploadException} in an {@link IOException}.
      */
     public static class FileUploadIOException extends IOException {
-        /** The exceptions UID, for serializing an instance.
-         */
-        private static final long serialVersionUID = -7047616958165584154L;
-        /** The exceptions cause; we overwrite the parent
-         * classes field, which is available since Java
-         * 1.4 only.
-         */
-        private final FileUploadException cause;
 
-        /**
-         * Creates a <code>FileUploadIOException</code> with the
-         * given cause.
-         * @param pCause The exceptions cause, if any, or null.
-         */
-        public FileUploadIOException(FileUploadException pCause) {
-            // We're not doing super(pCause) cause of 1.3 compatibility.
-            cause = pCause;
+        private static final long serialVersionUID = -3082868232248803474L;
+
+        public FileUploadIOException() {
+            super();
         }
 
-        /**
-         * Returns the exceptions cause.
-         * @return The exceptions cause, if any, or null.
-         */
-        @Override
-        public Throwable getCause() {
-            return cause;
+        public FileUploadIOException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public FileUploadIOException(String message) {
+            super(message);
+        }
+
+        public FileUploadIOException(Throwable cause) {
+            super(cause);
         }
     }
 
@@ -992,7 +1011,9 @@ public abstract class FileUploadBase {
      */
     public static class InvalidContentTypeException
             extends FileUploadException {
-        /** The exceptions UID, for serializing an instance.
+
+        /**
+         * The exceptions UID, for serializing an instance.
          */
         private static final long serialVersionUID = -9073026332015646668L;
 
@@ -1013,46 +1034,42 @@ public abstract class FileUploadBase {
         public InvalidContentTypeException(String message) {
             super(message);
         }
+
     }
 
     /**
      * Thrown to indicate an IOException.
      */
     public static class IOFileUploadException extends FileUploadException {
-        /** The exceptions UID, for serializing an instance.
-         */
-        private static final long serialVersionUID = 1749796615868477269L;
-        /** The exceptions cause; we overwrite the parent
-         * classes field, which is available since Java
-         * 1.4 only.
-         */
-        private final IOException cause;
 
-        /**
-         * Creates a new instance with the given cause.
-         * @param pMsg The detail message.
-         * @param pException The exceptions cause.
-         */
-        public IOFileUploadException(String pMsg, IOException pException) {
-            super(pMsg);
-            cause = pException;
+        private static final long serialVersionUID = -5858565745868986701L;
+
+        public IOFileUploadException() {
+            super();
         }
 
-        /**
-         * Returns the exceptions cause.
-         * @return The exceptions cause, if any, or null.
-         */
-        @Override
-        public Throwable getCause() {
-            return cause;
+        public IOFileUploadException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public IOFileUploadException(String message) {
+            super(message);
+        }
+
+        public IOFileUploadException(Throwable cause) {
+            super(cause);
         }
     }
 
-    /** This exception is thrown, if a requests permitted size
+    /**
+     * This exception is thrown, if a requests permitted size
      * is exceeded.
      */
     public abstract static class SizeException extends FileUploadException {
 
+        /**
+         * Serial version UID, being used, if serialized.
+         */
         private static final long serialVersionUID = -8776225574705254126L;
 
         /**
@@ -1067,6 +1084,7 @@ public abstract class FileUploadBase {
 
         /**
          * Creates a new instance.
+         *
          * @param message The detail message.
          * @param actual The actual number of bytes in the request.
          * @param permitted The requests size limit, in bytes.
@@ -1081,6 +1099,7 @@ public abstract class FileUploadBase {
          * Retrieves the actual size of the request.
          *
          * @return The actual size of the request.
+         * @since 1.3
          */
         public long getActualSize() {
             return actual;
@@ -1090,10 +1109,12 @@ public abstract class FileUploadBase {
          * Retrieves the permitted size of the request.
          *
          * @return The permitted size of the request.
+         * @since 1.3
          */
         public long getPermittedSize() {
             return permitted;
         }
+
     }
 
     /**
@@ -1101,7 +1122,9 @@ public abstract class FileUploadBase {
      */
     public static class SizeLimitExceededException
             extends SizeException {
-        /** The exceptions UID, for serializing an instance.
+
+        /**
+         * The exceptions UID, for serializing an instance.
          */
         private static final long serialVersionUID = -2474893167098052828L;
 
@@ -1117,6 +1140,7 @@ public abstract class FileUploadBase {
                 long permitted) {
             super(message, actual, permitted);
         }
+
     }
 
     /**
@@ -1124,7 +1148,9 @@ public abstract class FileUploadBase {
      */
     public static class FileSizeLimitExceededException
             extends SizeException {
-        /** The exceptions UID, for serializing an instance.
+
+        /**
+         * The exceptions UID, for serializing an instance.
          */
         private static final long serialVersionUID = 8150776562029630058L;
 
@@ -1154,6 +1180,7 @@ public abstract class FileUploadBase {
         /**
          * Returns the file name of the item, which caused the
          * exception.
+         *
          * @return File name, if known, or null.
          */
         public String getFileName() {
@@ -1163,6 +1190,8 @@ public abstract class FileUploadBase {
         /**
          * Sets the file name of the item, which caused the
          * exception.
+         *
+         * @param pFileName the file name of the item, which caused the exception.
          */
         public void setFileName(String pFileName) {
             fileName = pFileName;
@@ -1171,6 +1200,7 @@ public abstract class FileUploadBase {
         /**
          * Returns the field name of the item, which caused the
          * exception.
+         *
          * @return Field name, if known, or null.
          */
         public String getFieldName() {
@@ -1180,14 +1210,19 @@ public abstract class FileUploadBase {
         /**
          * Sets the field name of the item, which caused the
          * exception.
+         *
+         * @param pFieldName the field name of the item,
+         *        which caused the exception.
          */
         public void setFieldName(String pFieldName) {
             fieldName = pFieldName;
         }
+
     }
 
     /**
      * Returns the progress listener.
+     *
      * @return The progress listener, if any, or null.
      */
     public ProgressListener getProgressListener() {
@@ -1196,9 +1231,11 @@ public abstract class FileUploadBase {
 
     /**
      * Sets the progress listener.
+     *
      * @param pListener The progress listener, if any. Defaults to null.
      */
     public void setProgressListener(ProgressListener pListener) {
         listener = pListener;
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadException.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadException.java
index 0010bab..56334d1 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileUploadException.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadException.java
@@ -16,87 +16,26 @@
  */
 package org.apache.tomcat.util.http.fileupload;
 
-import java.io.PrintStream;
-import java.io.PrintWriter;
-
-
 /**
  * Exception for errors encountered while processing the request.
- *
- * @author <a href="mailto:jmcnally at collab.net">John McNally</a>
- * @version $Id: FileUploadException.java 881533 2009-11-17 21:21:41Z markt $
  */
 public class FileUploadException extends Exception {
-    /**
-     * Serial version UID, being used, if the exception
-     * is serialized.
-     */
-    private static final long serialVersionUID = 8881893724388807504L;
-    /**
-     * The exceptions cause. We overwrite the cause of
-     * the super class, which isn't available in Java 1.3.
-     */
-    private final Throwable cause;
-
-    /**
-     * Constructs a new <code>FileUploadException</code> without message.
-     */
-    public FileUploadException() {
-        this(null, null);
-    }
 
-    /**
-     * Constructs a new <code>FileUploadException</code> with specified detail
-     * message.
-     *
-     * @param msg the error message.
-     */
-    public FileUploadException(final String msg) {
-        this(msg, null);
-    }
+    private static final long serialVersionUID = -4222909057964038517L;
 
-    /**
-     * Creates a new <code>FileUploadException</code> with the given
-     * detail message and cause.
-     * @param msg The exceptions detail message.
-     * @param cause The exceptions cause.
-     */
-    public FileUploadException(String msg, Throwable cause) {
-        super(msg);
-        this.cause = cause;
+    public FileUploadException() {
+        super();
     }
 
-    /**
-     * Prints this throwable and its backtrace to the specified print stream.
-     *
-     * @param stream <code>PrintStream</code> to use for output
-     */
-    @Override
-    public void printStackTrace(PrintStream stream) {
-        super.printStackTrace(stream);
-        if (cause != null) {
-            stream.println("Caused by:");
-            cause.printStackTrace(stream);
-        }
+    public FileUploadException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    /**
-     * Prints this throwable and its backtrace to the specified
-     * print writer.
-     *
-     * @param writer <code>PrintWriter</code> to use for output
-     */
-    @Override
-    public void printStackTrace(PrintWriter writer) {
-        super.printStackTrace(writer);
-        if (cause != null) {
-            writer.println("Caused by:");
-            cause.printStackTrace(writer);
-        }
+    public FileUploadException(String message) {
+        super(message);
     }
 
-    @Override
-    public Throwable getCause() {
-        return cause;
+    public FileUploadException(Throwable cause) {
+        super(cause);
     }
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUtils.java b/java/org/apache/tomcat/util/http/fileupload/FileUtils.java
index a5f7c63..43acb6d 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileUtils.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileUtils.java
@@ -40,21 +40,7 @@ import java.io.IOException;
  * <p>
  * Origin of code: Excalibur, Alexandria, Commons-Utils
  *
- * @author <a href="mailto:burton at relativity.yi.org">Kevin A. Burton</A>
- * @author <a href="mailto:sanders at apache.org">Scott Sanders</a>
- * @author <a href="mailto:dlr at finemaltcoding.com">Daniel Rall</a>
- * @author <a href="mailto:Christoph.Reck at dlr.de">Christoph.Reck</a>
- * @author <a href="mailto:peter at apache.org">Peter Donald</a>
- * @author <a href="mailto:jefft at apache.org">Jeff Turner</a>
- * @author Matthew Hawthorne
- * @author <a href="mailto:jeremias at apache.org">Jeremias Maerki</a>
- * @author Stephen Colebourne
- * @author Ian Springer
- * @author Chris Eldredge
- * @author Jim Harrington
- * @author Niall Pemberton
- * @author Sandy McArthur
- * @version $Id: FileUtils.java 992409 2010-09-03 18:35:59Z markt $
+ * @version $Id: FileUtils.java 1456969 2013-03-15 14:37:04Z markt $
  */
 public class FileUtils {
 
@@ -77,7 +63,10 @@ public class FileUtils {
             return;
         }
 
-        cleanDirectory(directory);
+        if (!isSymlink(directory)) {
+            cleanDirectory(directory);
+        }
+
         if (!directory.delete()) {
             String message =
                 "Unable to delete directory " + directory + ".";
@@ -85,7 +74,6 @@ public class FileUtils {
         }
     }
 
-
     /**
      * Cleans a directory without deleting it.
      *
@@ -109,8 +97,7 @@ public class FileUtils {
         }
 
         IOException exception = null;
-        for (int i = 0; i < files.length; i++) {
-            File file = files[i];
+        for (File file : files) {
             try {
                 forceDelete(file);
             } catch (IOException ioe) {
@@ -122,8 +109,7 @@ public class FileUtils {
             throw exception;
         }
     }
-    
-    
+
     //-----------------------------------------------------------------------
     /**
      * Deletes a file. If file is a directory, delete it and all sub-directories.
@@ -135,8 +121,8 @@ public class FileUtils {
      *      (java.io.File methods returns a boolean)</li>
      * </ul>
      *
-     * @param file  file or directory to delete, must not be <code>null</code>
-     * @throws NullPointerException if the directory is <code>null</code>
+     * @param file  file or directory to delete, must not be {@code null}
+     * @throws NullPointerException if the directory is {@code null}
      * @throws FileNotFoundException if the file was not found
      * @throws IOException in case deletion is unsuccessful
      */
@@ -160,8 +146,8 @@ public class FileUtils {
      * Schedules a file to be deleted when JVM exits.
      * If file is directory delete it and all sub-directories.
      *
-     * @param file  file or directory to delete, must not be <code>null</code>
-     * @throws NullPointerException if the file is <code>null</code>
+     * @param file  file or directory to delete, must not be {@code null}
+     * @throws NullPointerException if the file is {@code null}
      * @throws IOException in case deletion is unsuccessful
      */
     public static void forceDeleteOnExit(File file) throws IOException {
@@ -175,8 +161,8 @@ public class FileUtils {
     /**
      * Schedules a directory recursively for deletion on JVM exit.
      *
-     * @param directory  directory to delete, must not be <code>null</code>
-     * @throws NullPointerException if the directory is <code>null</code>
+     * @param directory  directory to delete, must not be {@code null}
+     * @throws NullPointerException if the directory is {@code null}
      * @throws IOException in case deletion is unsuccessful
      */
     private static void deleteDirectoryOnExit(File directory) throws IOException {
@@ -184,15 +170,17 @@ public class FileUtils {
             return;
         }
 
-        cleanDirectoryOnExit(directory);
         directory.deleteOnExit();
+        if (!isSymlink(directory)) {
+            cleanDirectoryOnExit(directory);
+        }
     }
 
     /**
      * Cleans a directory without deleting it.
      *
-     * @param directory  directory to clean, must not be <code>null</code>
-     * @throws NullPointerException if the directory is <code>null</code>
+     * @param directory  directory to clean, must not be {@code null}
+     * @throws NullPointerException if the directory is {@code null}
      * @throws IOException in case cleaning is unsuccessful
      */
     private static void cleanDirectoryOnExit(File directory) throws IOException {
@@ -212,8 +200,7 @@ public class FileUtils {
         }
 
         IOException exception = null;
-        for (int i = 0; i < files.length; i++) {
-            File file = files[i];
+        for (File file : files) {
             try {
                 forceDeleteOnExit(file);
             } catch (IOException ioe) {
@@ -225,4 +212,43 @@ public class FileUtils {
             throw exception;
         }
     }
+
+
+    /**
+     * Determines whether the specified file is a Symbolic Link rather than an actual file.
+     * <p>
+     * Will not return true if there is a Symbolic Link anywhere in the path,
+     * only if the specific file is.
+     * <p>
+     * <b>Note:</b> the current implementation always returns {@code false} if
+     * the system is detected as Windows using
+     * {@link File#separatorChar} == '\\'
+     *
+     * @param file the file to check
+     * @return true if the file is a Symbolic Link
+     * @throws IOException if an IO error occurs while checking the file
+     * @since 2.0
+     */
+    public static boolean isSymlink(File file) throws IOException {
+        if (file == null) {
+            throw new NullPointerException("File must not be null");
+        }
+        //FilenameUtils.isSystemWindows()
+        if (File.separatorChar == '\\') {
+            return false;
+        }
+        File fileInCanonicalDir = null;
+        if (file.getParent() == null) {
+            fileInCanonicalDir = file;
+        } else {
+            File canonicalDir = file.getParentFile().getCanonicalFile();
+            fileInCanonicalDir = new File(canonicalDir, file.getName());
+        }
+
+        if (fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) {
+            return false;
+        } else {
+            return true;
+        }
+    }
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/IOUtils.java b/java/org/apache/tomcat/util/http/fileupload/IOUtils.java
index f4103de..f1cec0c 100644
--- a/java/org/apache/tomcat/util/http/fileupload/IOUtils.java
+++ b/java/org/apache/tomcat/util/http/fileupload/IOUtils.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
-
 /**
  * General IO stream manipulation utilities.
  * <p>
@@ -52,23 +51,20 @@ import java.io.OutputStream;
  * <p>
  * Origin of code: Excalibur.
  *
- * @author Peter Donald
- * @author Jeff Turner
- * @author Matthew Hawthorne
- * @author Stephen Colebourne
- * @author Gareth Davis
- * @author Ian Springer
- * @author Niall Pemberton
- * @author Sandy McArthur
- * @version $Id: IOUtils.java 992409 2010-09-03 18:35:59Z markt $
+ * @version $Id: IOUtils.java 1456969 2013-03-15 14:37:04Z markt $
  */
 public class IOUtils {
     // NOTE: This class is focussed on InputStream, OutputStream, Reader and
     // Writer. Each method should take at least one of these as a parameter,
     // or return one of them.
 
+    private static final int EOF = -1;
+
     /**
-     * The default buffer size to use.
+     * The default buffer size ({@value}) to use for
+     * {@link #copyLarge(InputStream, OutputStream)}
+     * and
+     * {@link #copyLarge(Reader, Writer)}
      */
     private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
 
@@ -79,25 +75,6 @@ public class IOUtils {
         super();
     }
 
-
-    /**
-     * Unconditionally close an <code>InputStream</code>.
-     * <p>
-     * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
-     * This is typically used in finally blocks.
-     *
-     * @param input  the InputStream to close, may be null or already closed
-     */
-    public static void closeQuietly(InputStream input) {
-        try {
-            if (input != null) {
-                input.close();
-            }
-        } catch (IOException ioe) {
-            // ignore
-        }
-    }
-
     // copy from InputStream
     //-----------------------------------------------------------------------
     /**
@@ -114,11 +91,10 @@ public class IOUtils {
      * 
      * @param input  the <code>InputStream</code> to read from
      * @param output  the <code>OutputStream</code> to write to
-     * @return the number of bytes copied
+     * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE
      * @throws NullPointerException if the input or output is null
      * @throws IOException if an I/O error occurs
-     * @throws ArithmeticException if the byte count is too large
-     * @since Commons IO 1.1
+     * @since 1.1
      */
     public static int copy(InputStream input, OutputStream output) throws IOException {
         long count = copyLarge(input, output);
@@ -134,25 +110,26 @@ public class IOUtils {
      * <p>
      * This method buffers the input internally, so there is no need to use a
      * <code>BufferedInputStream</code>.
-     * 
+     * <p>
+     * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
+     *
      * @param input  the <code>InputStream</code> to read from
      * @param output  the <code>OutputStream</code> to write to
      * @return the number of bytes copied
      * @throws NullPointerException if the input or output is null
      * @throws IOException if an I/O error occurs
-     * @since Commons IO 1.3
+     * @since 1.3
      */
     public static long copyLarge(InputStream input, OutputStream output)
             throws IOException {
+
         byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
         long count = 0;
         int n = 0;
-        while (-1 != (n = input.read(buffer))) {
+        while (EOF != (n = input.read(buffer))) {
             output.write(buffer, 0, n);
             count += n;
         }
         return count;
     }
-
-
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java b/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java
index f86b6f5..c582589 100644
--- a/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java
+++ b/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java
@@ -16,7 +16,6 @@
  */
 package org.apache.tomcat.util.http.fileupload;
 
-
 /**
  * This exception is thrown in case of an invalid file name.
  * A file name is invalid, if it contains a NUL character.
@@ -26,13 +25,25 @@ package org.apache.tomcat.util.http.fileupload;
  * checks for the extension ".png"), while, depending on the underlying
  * C library, it might create a file named "foo.exe", as the NUL
  * character is the string terminator in C.
+ *
+ * @version $Id: InvalidFileNameException.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public class InvalidFileNameException extends RuntimeException {
+
+    /**
+     * Serial version UID, being used, if the exception
+     * is serialized.
+     */
     private static final long serialVersionUID = 7922042602454350470L;
+
+    /**
+     * The file name causing the exception.
+     */
     private final String name;
 
     /**
      * Creates a new instance.
+     *
      * @param pName The file name causing the exception.
      * @param pMessage A human readable error message.
      */
@@ -43,8 +54,11 @@ public class InvalidFileNameException extends RuntimeException {
 
     /**
      * Returns the invalid file name.
+     *
+     * @return the invalid file name.
      */
     public String getName() {
         return name;
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
index 31ac2de..f4d8ead 100644
--- a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
@@ -22,6 +22,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 
+import org.apache.tomcat.util.http.fileupload.FileUploadBase.FileUploadIOException;
 import org.apache.tomcat.util.http.fileupload.util.Closeable;
 import org.apache.tomcat.util.http.fileupload.util.Streams;
 
@@ -79,32 +80,39 @@ import org.apache.tomcat.util.http.fileupload.util.Streams;
  *   }
  * </pre>
  *
- * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- * @author Sean C. Sullivan
- *
- * @version $Id: MultipartStream.java 1154575 2011-08-06 20:19:29Z markt $
+ * @version $Id: MultipartStream.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public class MultipartStream {
+
     /**
      * Internal class, which is used to invoke the
      * {@link ProgressListener}.
      */
     public static class ProgressNotifier {
-        /** The listener to invoke.
+        /**
+         * The listener to invoke.
          */
         private final ProgressListener listener;
-        /** Number of expected bytes, if known, or -1.
+
+        /**
+         * Number of expected bytes, if known, or -1.
          */
         private final long contentLength;
-        /** Number of bytes, which have been read so far.
+
+        /**
+         * Number of bytes, which have been read so far.
          */
         private long bytesRead;
-        /** Number of items, which have been read so far.
+
+        /**
+         * Number of items, which have been read so far.
          */
         private int items;
-        /** Creates a new instance with the given listener
+
+        /**
+         * Creates a new instance with the given listener
          * and content length.
+         *
          * @param pListener The listener to invoke.
          * @param pContentLength The expected content length.
          */
@@ -112,7 +120,10 @@ public class MultipartStream {
             listener = pListener;
             contentLength = pContentLength;
         }
-        /** Called to indicate that bytes have been read.
+
+        /**
+         * Called to indicate that bytes have been read.
+         *
          * @param pBytes Number of bytes, which have been read.
          */
         void noteBytesRead(int pBytes) {
@@ -122,126 +133,110 @@ public class MultipartStream {
             bytesRead += pBytes;
             notifyListener();
         }
-        /** Called to indicate, that a new file item has been detected.
+
+        /**
+         * Called to indicate, that a new file item has been detected.
          */
         void noteItem() {
             ++items;
             notifyListener();
         }
-        /** Called for notifying the listener.
+
+        /**
+         * Called for notifying the listener.
          */
         private void notifyListener() {
             if (listener != null) {
                 listener.update(bytesRead, contentLength, items);
             }
         }
+
     }
 
     // ----------------------------------------------------- Manifest constants
 
-
     /**
      * The Carriage Return ASCII character value.
      */
     public static final byte CR = 0x0D;
 
-
     /**
      * The Line Feed ASCII character value.
      */
     public static final byte LF = 0x0A;
 
-
     /**
      * The dash (-) ASCII character value.
      */
     public static final byte DASH = 0x2D;
 
-
     /**
      * The maximum length of <code>header-part</code> that will be
      * processed (10 kilobytes = 10240 bytes.).
      */
     public static final int HEADER_PART_SIZE_MAX = 10240;
 
-
     /**
      * The default length of the buffer used for processing a request.
      */
     protected static final int DEFAULT_BUFSIZE = 4096;
 
-
     /**
      * A byte sequence that marks the end of <code>header-part</code>
      * (<code>CRLFCRLF</code>).
      */
-    protected static final byte[] HEADER_SEPARATOR = {
-        CR, LF, CR, LF };
-
+    protected static final byte[] HEADER_SEPARATOR = {CR, LF, CR, LF};
 
     /**
      * A byte sequence that that follows a delimiter that will be
      * followed by an encapsulation (<code>CRLF</code>).
      */
-    protected static final byte[] FIELD_SEPARATOR = {
-        CR, LF};
-
+    protected static final byte[] FIELD_SEPARATOR = {CR, LF};
 
     /**
      * A byte sequence that that follows a delimiter of the last
      * encapsulation in the stream (<code>--</code>).
      */
-    protected static final byte[] STREAM_TERMINATOR = {
-        DASH, DASH};
-
+    protected static final byte[] STREAM_TERMINATOR = {DASH, DASH};
 
     /**
      * A byte sequence that precedes a boundary (<code>CRLF--</code>).
      */
-    protected static final byte[] BOUNDARY_PREFIX = {
-        CR, LF, DASH, DASH};
-
+    protected static final byte[] BOUNDARY_PREFIX = {CR, LF, DASH, DASH};
 
     // ----------------------------------------------------------- Data members
 
-
     /**
      * The input stream from which data is read.
      */
     private final InputStream input;
 
-
     /**
      * The length of the boundary token plus the leading <code>CRLF--</code>.
      */
     private int boundaryLength;
 
-
     /**
      * The amount of data, in bytes, that must be kept in the buffer in order
      * to detect delimiters reliably.
      */
     private int keepRegion;
 
-
     /**
      * The byte sequence that partitions the stream.
      */
     private byte[] boundary;
 
-
     /**
      * The length of the buffer used for processing the request.
      */
     private final int bufSize;
 
-
     /**
      * The buffer used for processing the request.
      */
     private final byte[] buffer;
 
-
     /**
      * The index of first valid character in the buffer.
      * <br>
@@ -249,7 +244,6 @@ public class MultipartStream {
      */
     private int head;
 
-
     /**
      * The index of last valid character in the buffer + 1.
      * <br>
@@ -257,13 +251,11 @@ public class MultipartStream {
      */
     private int tail;
 
-
     /**
      * The content encoding to use when reading headers.
      */
     private String headerEncoding;
 
-
     /**
      * The progress notifier, if any, or null.
      */
@@ -312,7 +304,6 @@ public class MultipartStream {
         tail = 0;
     }
 
-
     /**
      * <p> Constructs a <code>MultipartStream</code> with a default size buffer.
      *
@@ -333,12 +324,10 @@ public class MultipartStream {
 
     // --------------------------------------------------------- Public methods
 
-
     /**
      * Retrieves the character encoding used when reading the headers of an
      * individual part. When not specified, or <code>null</code>, the platform
      * default encoding is used.
-
      *
      * @return The encoding used to read part headers.
      */
@@ -346,7 +335,6 @@ public class MultipartStream {
         return headerEncoding;
     }
 
-
     /**
      * Specifies the character encoding to be used when reading the headers of
      * individual parts. When not specified, or <code>null</code>, the platform
@@ -358,7 +346,6 @@ public class MultipartStream {
         headerEncoding = encoding;
     }
 
-
     /**
      * Reads a byte from the <code>buffer</code>, and refills it as
      * necessary.
@@ -384,7 +371,6 @@ public class MultipartStream {
         return buffer[head++];
     }
 
-
     /**
      * Skips a <code>boundary</code> token, and checks whether more
      * <code>encapsulations</code> are contained in the stream.
@@ -392,11 +378,12 @@ public class MultipartStream {
      * @return <code>true</code> if there are more encapsulations in
      *         this stream; <code>false</code> otherwise.
      *
-     * @throws MalformedStreamException if the stream ends unexpecetedly or
+     * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits
+     * @throws MalformedStreamException if the stream ends unexpectedly or
      *                                  fails to follow required syntax.
      */
     public boolean readBoundary()
-            throws MalformedStreamException {
+            throws FileUploadIOException, MalformedStreamException {
         byte[] marker = new byte[2];
         boolean nextChunk = false;
 
@@ -422,13 +409,15 @@ public class MultipartStream {
                 throw new MalformedStreamException(
                 "Unexpected characters follow a boundary");
             }
+        } catch (FileUploadIOException e) {
+            // wraps a SizeException, re-throw as it will be unwrapped later
+            throw e;
         } catch (IOException e) {
             throw new MalformedStreamException("Stream ended unexpectedly");
         }
         return nextChunk;
     }
 
-
     /**
      * <p>Changes the boundary token used for partitioning the stream.
      *
@@ -458,7 +447,6 @@ public class MultipartStream {
                 boundary.length);
     }
 
-
     /**
      * <p>Reads the <code>header-part</code> of the current
      * <code>encapsulation</code>.
@@ -472,10 +460,10 @@ public class MultipartStream {
      *
      * @return The <code>header-part</code> of the current encapsulation.
      *
-     * @throws MalformedStreamException if the stream ends unexpecetedly.
+     * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits.
+     * @throws MalformedStreamException if the stream ends unexpectedly.
      */
-    public String readHeaders()
-    throws MalformedStreamException {
+    public String readHeaders() throws FileUploadIOException, MalformedStreamException {
         int i = 0;
         byte b;
         // to support multi-byte characters
@@ -484,13 +472,16 @@ public class MultipartStream {
         while (i < HEADER_SEPARATOR.length) {
             try {
                 b = readByte();
+            } catch (FileUploadIOException e) {
+                // wraps a SizeException, re-throw as it will be unwrapped later
+                throw e;
             } catch (IOException e) {
                 throw new MalformedStreamException("Stream ended unexpectedly");
             }
             if (++size > HEADER_PART_SIZE_MAX) {
-                throw new MalformedStreamException(
-                        "Header section has more than " + HEADER_PART_SIZE_MAX
-                        + " bytes (maybe it is not properly terminated)");
+                throw new MalformedStreamException(String.format(
+                        "Header section has more than %s bytes (maybe it is not properly terminated)",
+                        Integer.valueOf(HEADER_PART_SIZE_MAX)));
             }
             if (b == HEADER_SEPARATOR[i]) {
                 i++;
@@ -516,7 +507,6 @@ public class MultipartStream {
         return headers;
     }
 
-
     /**
      * <p>Reads <code>body-data</code> from the current
      * <code>encapsulation</code> and writes its contents into the
@@ -562,13 +552,10 @@ public class MultipartStream {
      * @throws MalformedStreamException if the stream ends unexpectedly.
      * @throws IOException              if an i/o error occurs.
      */
-    public int discardBodyData()
-    throws MalformedStreamException,
-    IOException {
+    public int discardBodyData() throws MalformedStreamException, IOException {
         return readBodyData(null);
     }
 
-
     /**
      * Finds the beginning of the first <code>encapsulation</code>.
      *
@@ -577,8 +564,7 @@ public class MultipartStream {
      *
      * @throws IOException if an i/o error occurs.
      */
-    public boolean skipPreamble()
-    throws IOException {
+    public boolean skipPreamble() throws IOException {
         // First delimiter may be not preceeded with a CRLF.
         System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2);
         boundaryLength = boundary.length - 2;
@@ -600,7 +586,6 @@ public class MultipartStream {
         }
     }
 
-
     /**
      * Compares <code>count</code> first bytes in the arrays
      * <code>a</code> and <code>b</code>.
@@ -623,7 +608,6 @@ public class MultipartStream {
         return true;
     }
 
-
     /**
      * Searches for a byte of specified value in the <code>buffer</code>,
      * starting at the specified <code>position</code>.
@@ -645,7 +629,6 @@ public class MultipartStream {
         return -1;
     }
 
-
     /**
      * Searches for the <code>boundary</code> in the <code>buffer</code>
      * region delimited by <code>head</code> and <code>tail</code>.
@@ -681,10 +664,12 @@ public class MultipartStream {
      * Thrown to indicate that the input stream fails to follow the
      * required syntax.
      */
-    public static class MalformedStreamException
-            extends IOException {
+    public static class MalformedStreamException extends IOException {
 
-        private static final long serialVersionUID = 1L;
+        /**
+         * The UID to use when serializing this instance.
+         */
+        private static final long serialVersionUID = 6466926458059796677L;
 
         /**
          * Constructs a <code>MalformedStreamException</code> with no
@@ -703,16 +688,19 @@ public class MultipartStream {
         public MalformedStreamException(String message) {
             super(message);
         }
-    }
 
+    }
 
     /**
      * Thrown upon attempt of setting an invalid boundary token.
      */
-    public static class IllegalBoundaryException
-            extends IOException {
+    public static class IllegalBoundaryException extends IOException {
 
-        private static final long serialVersionUID = 1L;
+
+        /**
+         * The UID to use when serializing this instance.
+         */
+        private static final long serialVersionUID = -161533165102632918L;
 
         /**
          * Constructs an <code>IllegalBoundaryException</code> with no
@@ -731,23 +719,32 @@ public class MultipartStream {
         public IllegalBoundaryException(String message) {
             super(message);
         }
+
     }
 
     /**
      * An {@link InputStream} for reading an items contents.
      */
     public class ItemInputStream extends InputStream implements Closeable {
-        /** The number of bytes, which have been read so far.
+
+        /**
+         * The number of bytes, which have been read so far.
          */
         private long total;
-        /** The number of bytes, which must be hold, because
+
+        /**
+         * The number of bytes, which must be hold, because
          * they might be a part of the boundary.
          */
         private int pad;
-        /** The current offset in the buffer.
+
+        /**
+         * The current offset in the buffer.
          */
         private int pos;
-        /** Whether the stream is already closed.
+
+        /**
+         * Whether the stream is already closed.
          */
         private boolean closed;
 
@@ -775,6 +772,7 @@ public class MultipartStream {
         /**
          * Returns the number of bytes, which have been read
          * by the stream.
+         *
          * @return Number of bytes, which have been read so far.
          */
         public long getBytesRead() {
@@ -784,6 +782,7 @@ public class MultipartStream {
         /**
          * Returns the number of bytes, which are currently
          * available, without blocking.
+         *
          * @throws IOException An I/O error occurs.
          * @return Number of bytes in the buffer.
          */
@@ -795,12 +794,14 @@ public class MultipartStream {
             return pos - head;
         }
 
-        /** Offset when converting negative bytes to integers.
+        /**
+         * Offset when converting negative bytes to integers.
          */
         private static final int BYTE_POSITIVE_OFFSET = 256;
 
         /**
          * Returns the next byte in the stream.
+         *
          * @return The next byte in the stream, as a non-negative
          *   integer, or -1 for EOF.
          * @throws IOException An I/O error occurred.
@@ -810,10 +811,8 @@ public class MultipartStream {
             if (closed) {
                 throw new FileItemStream.ItemSkippedException();
             }
-            if (available() == 0) {
-                if (makeAvailable() == 0) {
-                    return -1;
-                }
+            if (available() == 0 && makeAvailable() == 0) {
+                return -1;
             }
             ++total;
             int b = buffer[head++];
@@ -825,6 +824,7 @@ public class MultipartStream {
 
         /**
          * Reads bytes into the given buffer.
+         *
          * @param b The destination buffer, where to write to.
          * @param off Offset of the first byte in the buffer.
          * @param len Maximum number of bytes to read.
@@ -856,6 +856,7 @@ public class MultipartStream {
 
         /**
          * Closes the input stream.
+         *
          * @throws IOException An I/O error occurred.
          */
         @Override
@@ -865,6 +866,7 @@ public class MultipartStream {
 
         /**
          * Closes the input stream.
+         *
          * @param pCloseUnderlying Whether to close the underlying stream
          *   (hard close)
          * @throws IOException An I/O error occurred.
@@ -893,6 +895,7 @@ public class MultipartStream {
 
         /**
          * Skips the given number of bytes.
+         *
          * @param bytes Number of bytes to skip.
          * @return The number of bytes, which have actually been
          *   skipped.
@@ -917,6 +920,7 @@ public class MultipartStream {
 
         /**
          * Attempts to read more data.
+         *
          * @return Number of available bytes
          * @throws IOException An I/O error occurred.
          */
@@ -958,11 +962,14 @@ public class MultipartStream {
 
         /**
          * Returns, whether the stream is closed.
+         *
          * @return True, if the stream is closed, otherwise false.
          */
         @Override
         public boolean isClosed() {
             return closed;
         }
+
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java b/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java
index 42dadc2..49cacb1 100644
--- a/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java
+++ b/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java
@@ -16,13 +16,17 @@
  */
 package org.apache.tomcat.util.http.fileupload;
 
+import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 
+import org.apache.tomcat.util.http.fileupload.util.mime.MimeUtility;
+
 /**
  * A simple parser intended to parse sequences of name/value pairs.
- * Parameter values are exptected to be enclosed in quotes if they
+ *
+ * Parameter values are expected to be enclosed in quotes if they
  * contain unsafe characters, such as '=' characters or separators.
  * Parameter values are optional and can be omitted.
  *
@@ -30,10 +34,10 @@ import java.util.Map;
  *  <code>param1 = value; param2 = "anything goes; really"; param3</code>
  * </p>
  *
- * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @version $Id: ParameterParser.java 1456935 2013-03-15 12:47:29Z markt $
  */
-
 public class ParameterParser {
+
     /**
      * String to be parsed.
      */
@@ -100,13 +104,12 @@ public class ParameterParser {
             i2--;
         }
         // Strip away quotation marks if necessary
-        if (quoted) {
-            if (((i2 - i1) >= 2)
-                && (chars[i1] == '"')
-                && (chars[i2 - 1] == '"')) {
-                i1++;
-                i2--;
-            }
+        if (quoted
+            && ((i2 - i1) >= 2)
+            && (chars[i1] == '"')
+            && (chars[i2 - 1] == '"')) {
+            i1++;
+            i2--;
         }
         String result = null;
         if (i2 > i1) {
@@ -234,11 +237,9 @@ public class ParameterParser {
             int idx = str.length();
             for (int i = 0;  i < separators.length;  i++) {
                 int tmp = str.indexOf(separators[i]);
-                if (tmp != -1) {
-                    if (tmp < idx) {
-                        idx = tmp;
-                        separator = separators[i];
-                    }
+                if (tmp != -1 && tmp < idx) {
+                    idx = tmp;
+                    separator = separators[i];
                 }
             }
         }
@@ -265,24 +266,24 @@ public class ParameterParser {
      * Extracts a map of name/value pairs from the given array of
      * characters. Names are expected to be unique.
      *
-     * @param inputChars the array of characters that contains a sequence of
+     * @param chars the array of characters that contains a sequence of
      * name/value pairs
      * @param separator the name/value pairs separator
      *
      * @return a map of name/value pairs
      */
-    public Map<String,String> parse(final char[] inputChars, char separator) {
-        if (inputChars == null) {
+    public Map<String,String> parse(final char[] chars, char separator) {
+        if (chars == null) {
             return new HashMap<String,String>();
         }
-        return parse(inputChars, 0, inputChars.length, separator);
+        return parse(chars, 0, chars.length, separator);
     }
 
     /**
      * Extracts a map of name/value pairs from the given array of
      * characters. Names are expected to be unique.
      *
-     * @param inputChars the array of characters that contains a sequence of
+     * @param chars the array of characters that contains a sequence of
      * name/value pairs
      * @param offset - the initial offset.
      * @param length - the length.
@@ -291,16 +292,16 @@ public class ParameterParser {
      * @return a map of name/value pairs
      */
     public Map<String,String> parse(
-        final char[] inputChars,
+        final char[] chars,
         int offset,
         int length,
         char separator) {
 
-        if (inputChars == null) {
+        if (chars == null) {
             return new HashMap<String,String>();
         }
         HashMap<String,String> params = new HashMap<String,String>();
-        this.chars = inputChars;
+        this.chars = chars;
         this.pos = offset;
         this.len = length;
 
@@ -314,6 +315,14 @@ public class ParameterParser {
                 pos++; // skip '='
                 paramValue = parseQuotedToken(new char[] {
                         separator });
+
+                if (paramValue != null) {
+                    try {
+                        paramValue = MimeUtility.decodeText(paramValue);
+                    } catch (UnsupportedEncodingException e) {
+                        // let's keep the original value in this case
+                    }
+                }
             }
             if (hasChar() && (chars[pos] == separator)) {
                 pos++; // skip separator
@@ -322,9 +331,11 @@ public class ParameterParser {
                 if (this.lowerCaseNames) {
                     paramName = paramName.toLowerCase(Locale.ENGLISH);
                 }
+
                 params.put(paramName, paramValue);
             }
         }
         return params;
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/ProgressListener.java b/java/org/apache/tomcat/util/http/fileupload/ProgressListener.java
index 61744ca..c7a120b 100644
--- a/java/org/apache/tomcat/util/http/fileupload/ProgressListener.java
+++ b/java/org/apache/tomcat/util/http/fileupload/ProgressListener.java
@@ -16,13 +16,17 @@
  */
 package org.apache.tomcat.util.http.fileupload;
 
-
 /**
  * The {@link ProgressListener} may be used to display a progress bar
  * or do stuff like that.
+ *
+ * @version $Id: ProgressListener.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public interface ProgressListener {
-    /** Updates the listeners status information.
+
+    /**
+     * Updates the listeners status information.
+     *
      * @param pBytesRead The total number of bytes, which have been read
      *   so far.
      * @param pContentLength The total number of bytes, which are being
@@ -31,4 +35,5 @@ public interface ProgressListener {
      *   read. (0 = no item so far, 1 = first item is being read, ...)
      */
     void update(long pBytesRead, long pContentLength, int pItems);
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/RequestContext.java b/java/org/apache/tomcat/util/http/fileupload/RequestContext.java
index 8df6b48..4add247 100644
--- a/java/org/apache/tomcat/util/http/fileupload/RequestContext.java
+++ b/java/org/apache/tomcat/util/http/fileupload/RequestContext.java
@@ -21,14 +21,12 @@ import java.io.InputStream;
 
 /**
  * <p>Abstracts access to the request information needed for file uploads. This
- * interfsace should be implemented for each type of request that may be
+ * interface should be implemented for each type of request that may be
  * handled by FileUpload, such as servlets and portlets.</p>
  *
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- *
  * @since FileUpload 1.1
  *
- * @version $Id: RequestContext.java 987920 2010-08-22 15:34:34Z markt $
+ * @version $Id: RequestContext.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public interface RequestContext {
 
@@ -47,13 +45,6 @@ public interface RequestContext {
     String getContentType();
 
     /**
-     * Retrieve the content length of the request.
-     *
-     * @return The content length of the request.
-     */
-    int getContentLength();
-
-    /**
      * Retrieve the input stream for the request.
      *
      * @return The input stream for the request.
@@ -61,4 +52,5 @@ public interface RequestContext {
      * @throws IOException if a problem occurs.
      */
     InputStream getInputStream() throws IOException;
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/ThresholdingOutputStream.java b/java/org/apache/tomcat/util/http/fileupload/ThresholdingOutputStream.java
index 097ff4d..62886dc 100644
--- a/java/org/apache/tomcat/util/http/fileupload/ThresholdingOutputStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/ThresholdingOutputStream.java
@@ -34,9 +34,7 @@ import java.io.OutputStream;
  * is actually reached, since it triggers when a pending write operation would
  * cause the threshold to be exceeded.
  *
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- *
- * @version $Id: ThresholdingOutputStream.java 881533 2009-11-17 21:21:41Z markt $
+ * @version $Id: ThresholdingOutputStream.java 1456969 2013-03-15 14:37:04Z markt $
  */
 public abstract class ThresholdingOutputStream
     extends OutputStream
@@ -48,7 +46,7 @@ public abstract class ThresholdingOutputStream
     /**
      * The threshold at which the event will be triggered.
      */
-    private int threshold;
+    private final int threshold;
 
 
     /**
@@ -171,37 +169,15 @@ public abstract class ThresholdingOutputStream
 
 
     /**
-     * Returns the threshold, in bytes, at which an event will be triggered.
-     *
-     * @return The threshold point, in bytes.
-     */
-    public int getThreshold()
-    {
-        return threshold;
-    }
-
-
-    /**
-     * Returns the number of bytes that have been written to this output stream.
-     *
-     * @return The number of bytes written.
-     */
-    public long getByteCount()
-    {
-        return written;
-    }
-
-
-    /**
      * Determines whether or not the configured threshold has been exceeded for
      * this output stream.
      *
-     * @return <code>true</code> if the threshold has been reached;
-     *         <code>false</code> otherwise.
+     * @return {@code true} if the threshold has been reached;
+     *         {@code false} otherwise.
      */
     public boolean isThresholdExceeded()
     {
-        return (written > threshold);
+        return written > threshold;
     }
 
 
@@ -220,23 +196,13 @@ public abstract class ThresholdingOutputStream
      */
     protected void checkThreshold(int count) throws IOException
     {
-        if (!thresholdExceeded && (written + count > threshold))
+        if (!thresholdExceeded && written + count > threshold)
         {
             thresholdExceeded = true;
             thresholdReached();
         }
     }
 
-    /**
-     * Resets the byteCount to zero.  You can call this from 
-     * {@link #thresholdReached()} if you want the event to be triggered again. 
-     */
-    protected void resetByteCount() 
-    {
-        this.thresholdExceeded = false;
-        this.written = 0;
-    }
-
     // ------------------------------------------------------- Abstract methods
 
 
diff --git a/java/org/apache/tomcat/util/http/fileupload/UploadContext.java b/java/org/apache/tomcat/util/http/fileupload/UploadContext.java
new file mode 100644
index 0000000..4fc3bf7
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/UploadContext.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload;
+
+/**
+ * Enhanced access to the request information needed for file uploads,
+ * which fixes the Content Length data access in {@link RequestContext}.
+ *
+ * The reason of introducing this new interface is just for backward compatibility
+ * and it might vanish for a refactored 2.x version moving the new method into
+ * RequestContext again.
+ *
+ * @since 1.3
+ */
+public interface UploadContext extends RequestContext {
+
+    /**
+     * Retrieve the content length of the request.
+     *
+     * @return The content length of the request.
+     * @since 1.3
+     */
+    long contentLength();
+
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
index f6e7da0..e8734c0 100644
--- a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
+++ b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
@@ -29,17 +29,17 @@ import java.io.ObjectOutputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.tomcat.util.http.fileupload.DeferredFileOutputStream;
 import org.apache.tomcat.util.http.fileupload.FileItem;
 import org.apache.tomcat.util.http.fileupload.FileItemHeaders;
-import org.apache.tomcat.util.http.fileupload.FileItemHeadersSupport;
 import org.apache.tomcat.util.http.fileupload.FileUploadException;
 import org.apache.tomcat.util.http.fileupload.IOUtils;
 import org.apache.tomcat.util.http.fileupload.ParameterParser;
 import org.apache.tomcat.util.http.fileupload.util.Streams;
 
-
 /**
  * <p> The default implementation of the
  * {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} interface.
@@ -68,19 +68,12 @@ import org.apache.tomcat.util.http.fileupload.util.Streams;
  * your web application ends. See the section on "Resource cleanup"
  * in the users guide of commons-fileupload.</p>
  *
- * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:sean at informage.net">Sean Legassick</a>
- * @author <a href="mailto:jvanzyl at apache.org">Jason van Zyl</a>
- * @author <a href="mailto:jmcnally at apache.org">John McNally</a>
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- * @author Sean C. Sullivan
- *
  * @since FileUpload 1.1
  *
- * @version $Id: DiskFileItem.java 1154575 2011-08-06 20:19:29Z markt $
+ * @version $Id: DiskFileItem.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public class DiskFileItem
-    implements FileItem, FileItemHeadersSupport {
+    implements FileItem {
 
     // ----------------------------------------------------- Manifest constants
 
@@ -89,7 +82,6 @@ public class DiskFileItem
      */
     private static final long serialVersionUID = 2237570099615271025L;
 
-
     /**
      * Default content charset to be used when no explicit charset
      * parameter is provided by the sender. Media subtypes of the
@@ -98,48 +90,40 @@ public class DiskFileItem
      */
     public static final String DEFAULT_CHARSET = "ISO-8859-1";
 
-
     // ----------------------------------------------------------- Data members
 
-
     /**
      * UID used in unique file name generation.
      */
     private static final String UID =
-            new java.rmi.server.UID().toString()
-                .replace(':', '_').replace('-', '_');
+            UUID.randomUUID().toString().replace('-', '_');
 
     /**
      * Counter used in unique identifier generation.
      */
-    private static int counter = 0;
-
+    private static final AtomicInteger COUNTER = new AtomicInteger(0);
 
     /**
      * The name of the form field as provided by the browser.
      */
     private String fieldName;
 
-
     /**
      * The content type passed by the browser, or <code>null</code> if
      * not defined.
      */
     private String contentType;
 
-
     /**
      * Whether or not this item is a simple form field.
      */
     private boolean isFormField;
 
-
     /**
      * The original filename in the user's filesystem.
      */
     private String fileName;
 
-
     /**
      * The size of the item, in bytes. This is used to cache the size when a
      * file item is moved from its original location.
@@ -152,19 +136,16 @@ public class DiskFileItem
      */
     private int sizeThreshold;
 
-
     /**
      * The directory in which uploaded files will be stored, if stored on disk.
      */
     private File repository;
 
-
     /**
      * Cached contents of the file.
      */
     private byte[] cachedContent;
 
-
     /**
      * Output stream for this item.
      */
@@ -187,7 +168,6 @@ public class DiskFileItem
 
     // ----------------------------------------------------------- Constructors
 
-
     /**
      * Constructs a new <code>DiskFileItem</code> instance.
      *
@@ -216,10 +196,8 @@ public class DiskFileItem
         this.repository = repository;
     }
 
-
     // ------------------------------- Methods from javax.activation.DataSource
 
-
     /**
      * Returns an {@link java.io.InputStream InputStream} that can be
      * used to retrieve the contents of the file.
@@ -242,7 +220,6 @@ public class DiskFileItem
         return new ByteArrayInputStream(cachedContent);
     }
 
-
     /**
      * Returns the content type passed by the agent or <code>null</code> if
      * not defined.
@@ -255,7 +232,6 @@ public class DiskFileItem
         return contentType;
     }
 
-
     /**
      * Returns the content charset passed by the agent or <code>null</code> if
      * not defined.
@@ -271,7 +247,6 @@ public class DiskFileItem
         return params.get("charset");
     }
 
-
     /**
      * Returns the original filename in the client's filesystem.
      *
@@ -279,17 +254,16 @@ public class DiskFileItem
      * @throws org.apache.tomcat.util.http.fileupload.InvalidFileNameException
      *   The file name contains a NUL character, which might be an indicator of
      *   a security attack. If you intend to use the file name anyways, catch
-     *   the exception and use InvalidFileNameException#getName().
+     *   the exception and use {@link
+     *   org.apache.tomcat.util.http.fileupload.InvalidFileNameException#getName()}.
      */
     @Override
     public String getName() {
         return Streams.checkFileName(fileName);
     }
 
-
     // ------------------------------------------------------- FileItem methods
 
-
     /**
      * Provides a hint as to whether or not the file contents will be read
      * from memory.
@@ -305,7 +279,6 @@ public class DiskFileItem
         return dfos.isInMemory();
     }
 
-
     /**
      * Returns the size of the file.
      *
@@ -324,7 +297,6 @@ public class DiskFileItem
         }
     }
 
-
     /**
      * Returns the contents of the file as an array of bytes.  If the
      * contents of the file were not yet cached in memory, they will be
@@ -342,10 +314,10 @@ public class DiskFileItem
         }
 
         byte[] fileData = new byte[(int) getSize()];
-        FileInputStream fis = null;
+        InputStream fis = null;
 
         try {
-            fis = new FileInputStream(dfos.getFile());
+            fis = new BufferedInputStream(new FileInputStream(dfos.getFile()));
             fis.read(fileData);
         } catch (IOException e) {
             fileData = null;
@@ -362,7 +334,6 @@ public class DiskFileItem
         return fileData;
     }
 
-
     /**
      * Returns the contents of the file as a String, using the specified
      * encoding.  This method uses {@link #get()} to retrieve the
@@ -381,15 +352,14 @@ public class DiskFileItem
         return new String(get(), charset);
     }
 
-
     /**
      * Returns the contents of the file as a String, using the default
      * character encoding.  This method uses {@link #get()} to retrieve the
      * contents of the file.
      *
-     * @return The contents of the file, as a string.
+     * <b>TODO</b> Consider making this method throw UnsupportedEncodingException.
      *
-     * TODO Consider making this method throw UnsupportedEncodingException.
+     * @return The contents of the file, as a string.
      */
     @Override
     public String getString() {
@@ -405,7 +375,6 @@ public class DiskFileItem
         }
     }
 
-
     /**
      * A convenience method to write an uploaded item to disk. The client code
      * is not concerned with whether or not the item is stored in memory, or on
@@ -485,7 +454,6 @@ public class DiskFileItem
         }
     }
 
-
     /**
      * Deletes the underlying storage for a file item, including deleting any
      * associated temporary disk file. Although this storage will be deleted
@@ -502,7 +470,6 @@ public class DiskFileItem
         }
     }
 
-
     /**
      * Returns the name of the field in the multipart form corresponding to
      * this file item.
@@ -517,7 +484,6 @@ public class DiskFileItem
         return fieldName;
     }
 
-
     /**
      * Sets the field name used to reference this file item.
      *
@@ -531,7 +497,6 @@ public class DiskFileItem
         this.fieldName = fieldName;
     }
 
-
     /**
      * Determines whether or not a <code>FileItem</code> instance represents
      * a simple form field.
@@ -547,7 +512,6 @@ public class DiskFileItem
         return isFormField;
     }
 
-
     /**
      * Specifies whether or not a <code>FileItem</code> instance represents
      * a simple form field.
@@ -563,7 +527,6 @@ public class DiskFileItem
         isFormField = state;
     }
 
-
     /**
      * Returns an {@link java.io.OutputStream OutputStream} that can
      * be used for storing the contents of the file.
@@ -583,10 +546,8 @@ public class DiskFileItem
         return dfos;
     }
 
-
     // --------------------------------------------------------- Public methods
 
-
     /**
      * Returns the {@link java.io.File} object for the <code>FileItem</code>'s
      * data's temporary location on the disk. Note that for
@@ -601,13 +562,14 @@ public class DiskFileItem
      *         memory.
      */
     public File getStoreLocation() {
-        return dfos == null ? null : dfos.getFile();
+        if (dfos == null) {
+            return null;
+        }
+        return dfos.getFile();
     }
 
-
     // ------------------------------------------------------ Protected methods
 
-
     /**
      * Removes the file contents from the temporary storage.
      */
@@ -620,7 +582,6 @@ public class DiskFileItem
         }
     }
 
-
     /**
      * Creates and returns a {@link java.io.File File} representing a uniquely
      * named temporary file in the configured repository path. The lifetime of
@@ -637,17 +598,15 @@ public class DiskFileItem
             }
 
             String tempFileName =
-                "upload_" + UID + "_" + getUniqueId() + ".tmp";
+                    String.format("upload_%s_%s.tmp", UID, getUniqueId());
 
             tempFile = new File(tempDir, tempFileName);
         }
         return tempFile;
     }
 
-
     // -------------------------------------------------------- Private methods
 
-
     /**
      * Returns an identifier that is unique within the class loader used to
      * load this class, but does not have random-like apearance.
@@ -656,10 +615,7 @@ public class DiskFileItem
      */
     private static String getUniqueId() {
         final int limit = 100000000;
-        int current;
-        synchronized (DiskFileItem.class) {
-            current = counter++;
-        }
+        int current = COUNTER.getAndIncrement();
         String id = Integer.toString(current);
 
         // If you manage to get more than 100 million of ids, you'll
@@ -670,7 +626,6 @@ public class DiskFileItem
         return id;
     }
 
-
     /**
      * Returns a string representation of this object.
      *
@@ -678,21 +633,13 @@ public class DiskFileItem
      */
     @Override
     public String toString() {
-        return "name=" + this.getName()
-            + ", StoreLocation="
-            + String.valueOf(this.getStoreLocation())
-            + ", size="
-            + this.getSize()
-            + "bytes, "
-            + "isFormField=" + isFormField()
-            + ", FieldName="
-            + this.getFieldName();
+        return String.format("name=%s, StoreLocation=%s, size=%s bytes, isFormField=%s, FieldName=%s",
+                      getName(), getStoreLocation(), Long.valueOf(getSize()),
+                      Boolean.valueOf(isFormField()), getFieldName());
     }
 
-
     // -------------------------------------------------- Serialization methods
 
-
     /**
      * Writes the state of this object during serialization.
      *
@@ -757,4 +704,5 @@ public class DiskFileItem
     public void setHeaders(FileItemHeaders pHeaders) {
         headers = pHeaders;
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
index 79f19a2..294d3e7 100644
--- a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
+++ b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
@@ -22,7 +22,6 @@ import org.apache.tomcat.util.http.fileupload.FileCleaningTracker;
 import org.apache.tomcat.util.http.fileupload.FileItem;
 import org.apache.tomcat.util.http.fileupload.FileItemFactory;
 
-
 /**
  * <p>The default {@link org.apache.tomcat.util.http.fileupload.FileItemFactory}
  * implementation. This implementation creates
@@ -34,12 +33,23 @@ import org.apache.tomcat.util.http.fileupload.FileItemFactory;
  * created.</p>
  *
  * <p>If not otherwise configured, the default configuration values are as
- * follows:
+ * follows:</p>
  * <ul>
  *   <li>Size threshold is 10KB.</li>
  *   <li>Repository is the system default temp directory, as returned by
  *       <code>System.getProperty("java.io.tmpdir")</code>.</li>
  * </ul>
+ * <p>
+ * <b>NOTE</b>: Files are created in the system default temp directory with
+ * predictable names. This means that a local attacker with write access to that
+ * directory can perform a TOUTOC attack to replace any uploaded file with a
+ * file of the attackers choice. The implications of this will depend on how the
+ * uploaded file is used but could be significant. When using this
+ * implementation in an environment with local, untrusted users,
+ * {@link #setRepository(File)} MUST be used to configure a repository location
+ * that is not publicly writable. In a Servlet container the location identified
+ * by the ServletContext attribute <code>javax.servlet.context.tempdir</code>
+ * may be used.
  * </p>
  *
  * <p>Temporary files, which are created for file items, should be
@@ -56,38 +66,31 @@ import org.apache.tomcat.util.http.fileupload.FileItemFactory;
  * your web application ends. See the section on "Resource cleanup"
  * in the users guide of commons-fileupload.</p>
  *
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- *
  * @since FileUpload 1.1
  *
- * @version $Id: DiskFileItemFactory.java 1154575 2011-08-06 20:19:29Z markt $
+ * @version $Id: DiskFileItemFactory.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public class DiskFileItemFactory implements FileItemFactory {
 
     // ----------------------------------------------------- Manifest constants
 
-
     /**
      * The default threshold above which uploads will be stored on disk.
      */
     public static final int DEFAULT_SIZE_THRESHOLD = 10240;
 
-
     // ----------------------------------------------------- Instance Variables
 
-
     /**
      * The directory in which uploaded files will be stored, if stored on disk.
      */
     private File repository;
 
-
     /**
      * The threshold above which uploads will be stored on disk.
      */
     private int sizeThreshold = DEFAULT_SIZE_THRESHOLD;
 
-
     /**
      * <p>The instance of {@link FileCleaningTracker}, which is responsible
      * for deleting temporary files.</p>
@@ -97,7 +100,6 @@ public class DiskFileItemFactory implements FileItemFactory {
 
     // ----------------------------------------------------------- Constructors
 
-
     /**
      * Constructs an unconfigured instance of this class. The resulting factory
      * may be configured by calling the appropriate setter methods.
@@ -106,7 +108,6 @@ public class DiskFileItemFactory implements FileItemFactory {
         this(DEFAULT_SIZE_THRESHOLD, null);
     }
 
-
     /**
      * Constructs a preconfigured instance of this class.
      *
@@ -124,7 +125,6 @@ public class DiskFileItemFactory implements FileItemFactory {
 
     // ------------------------------------------------------------- Properties
 
-
     /**
      * Returns the directory used to temporarily store files that are larger
      * than the configured size threshold.
@@ -138,7 +138,6 @@ public class DiskFileItemFactory implements FileItemFactory {
         return repository;
     }
 
-
     /**
      * Sets the directory used to temporarily store files that are larger
      * than the configured size threshold.
@@ -152,7 +151,6 @@ public class DiskFileItemFactory implements FileItemFactory {
         this.repository = repository;
     }
 
-
     /**
      * Returns the size threshold beyond which files are written directly to
      * disk. The default value is 10240 bytes.
@@ -165,7 +163,6 @@ public class DiskFileItemFactory implements FileItemFactory {
         return sizeThreshold;
     }
 
-
     /**
      * Sets the size threshold beyond which files are written directly to disk.
      *
@@ -178,7 +175,6 @@ public class DiskFileItemFactory implements FileItemFactory {
         this.sizeThreshold = sizeThreshold;
     }
 
-
     // --------------------------------------------------------- Public Methods
 
     /**
@@ -202,15 +198,15 @@ public class DiskFileItemFactory implements FileItemFactory {
                 isFormField, fileName, sizeThreshold, repository);
         FileCleaningTracker tracker = getFileCleaningTracker();
         if (tracker != null) {
-            tracker.track(result.getTempFile(), this);
+            tracker.track(result.getTempFile(), result);
         }
         return result;
     }
 
-
     /**
      * Returns the tracker, which is responsible for deleting temporary
      * files.
+     *
      * @return An instance of {@link FileCleaningTracker}, or null
      *   (default), if temporary files aren't tracked.
      */
@@ -221,6 +217,7 @@ public class DiskFileItemFactory implements FileItemFactory {
     /**
      * Sets the tracker, which is responsible for deleting temporary
      * files.
+     *
      * @param pTracker An instance of {@link FileCleaningTracker},
      *   which will from now on track the created files, or null
      *   (default), to disable tracking.
@@ -228,4 +225,5 @@ public class DiskFileItemFactory implements FileItemFactory {
     public void setFileCleaningTracker(FileCleaningTracker pTracker) {
         fileCleaningTracker = pTracker;
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/disk/package-info.java b/java/org/apache/tomcat/util/http/fileupload/disk/package-info.java
new file mode 100644
index 0000000..69c5ae8
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/disk/package-info.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+/**
+ *    <p>
+ *      A disk-based implementation of the
+ *      {@link org.apache.commons.fileupload.FileItem FileItem}
+ *      interface. This implementation retains smaller items in memory, while
+ *      writing larger ones to disk. The threshold between these two is
+ *      configurable, as is the location of files that are written to disk.
+ *    </p>
+ *    <p>
+ *      In typical usage, an instance of
+ *      {@link org.apache.commons.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}
+ *      would be created, configured, and then passed to a
+ *      {@link org.apache.commons.fileupload.FileUpload FileUpload}
+ *      implementation such as
+ *      {@link org.apache.commons.fileupload.servlet.ServletFileUpload ServletFileUpload}
+ *      or
+ *      {@link org.apache.commons.fileupload.portlet.PortletFileUpload PortletFileUpload}.
+ *    </p>
+ *    <p>
+ *      The following code fragment demonstrates this usage.
+ *    </p>
+ * <pre>
+ *        DiskFileItemFactory factory = new DiskFileItemFactory();
+ *        // maximum size that will be stored in memory
+ *        factory.setSizeThreshold(4096);
+ *        // the location for saving data that is larger than getSizeThreshold()
+ *        factory.setRepository(new File("/tmp"));
+ *
+ *        ServletFileUpload upload = new ServletFileUpload(factory);
+ * </pre>
+ *    <p>
+ *      Please see the FileUpload
+ *      <a href="http://commons.apache.org/fileupload/using.html" target="_top">User Guide</a>
+ *      for further details and examples of how to use this package.
+ *    </p>
+ */
+package org.apache.tomcat.util.http.fileupload.disk;
diff --git a/java/org/apache/tomcat/util/http/fileupload/package-info.java b/java/org/apache/tomcat/util/http/fileupload/package-info.java
new file mode 100644
index 0000000..85796e4
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/package-info.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * <p><b>NOTE:</b> This code has been copied from commons-fileupload trunk
+ * revision 1458500 and commons-io 1.4 and package renamed to avoid clashes with
+ * any web apps that may wish to use these libraries.
+ * </p>
+ * <p>
+ * A component for handling HTML file uploads as specified by
+ * <a href="http://www.ietf.org/rfc/rfc1867.txt" target="_top">RFC 1867</a>.
+ * This component provides support for uploads within both servlets (JSR 53)
+ * and portlets (JSR 168).
+ * </p>
+ * <p>
+ * While this package provides the generic functionality for file uploads,
+ * these classes are not typically used directly. Instead, normal usage
+ * involves one of the provided extensions of
+ * {@link org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} such as
+ * {@link org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload ServletFileUpload}
+ * together with a factory for
+ * {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} instances,
+ * such as
+ * {@link org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}.
+ * </p>
+ * <p>
+ * The following is a brief example of typical usage in a servlet, storing
+ * the uploaded files on disk.
+ * </p>
+ * <pre>public void doPost(HttpServletRequest req, HttpServletResponse res) {
+ *   DiskFileItemFactory factory = new DiskFileItemFactory();
+ *   // maximum size that will be stored in memory
+ *   factory.setSizeThreshold(4096);
+ *   // the location for saving data that is larger than getSizeThreshold()
+ *   factory.setRepository(new File("/tmp"));
+ *
+ *   ServletFileUpload upload = new ServletFileUpload(factory);
+ *   // maximum size before a FileUploadException will be thrown
+ *   upload.setSizeMax(1000000);
+ *
+ *   List fileItems = upload.parseRequest(req);
+ *   // assume we know there are two files. The first file is a small
+ *   // text file, the second is unknown and is written to a file on
+ *   // the server
+ *   Iterator i = fileItems.iterator();
+ *   String comment = ((FileItem)i.next()).getString();
+ *   FileItem fi = (FileItem)i.next();
+ *   // filename on the client
+ *   String fileName = fi.getName();
+ *   // save comment and filename to database
+ *   ...
+ *   // write the file
+ *   fi.write(new File("/www/uploads/", fileName));
+ * }
+ * </pre>
+ * <p>
+ * In the example above, the first file is loaded into memory as a
+ * <code>String</code>. Before calling the <code>getString</code> method,
+ * the data may have been in memory or on disk depending on its size. The
+ * second file we assume it will be large and therefore never explicitly
+ * load it into memory, though if it is less than 4096 bytes it will be
+ * in memory before it is written to its final location. When writing to
+ * the final location, if the data is larger than the threshold, an attempt
+ * is made to rename the temporary file to the given location.  If it cannot
+ * be renamed, it is streamed to the new location.
+ * </p>
+ * <p>
+ * Please see the FileUpload
+ * <a href="http://commons.apache.org/fileupload/using.html" target="_top">User Guide</a>
+ * for further details and examples of how to use this package.
+ * </p>
+ */
+package org.apache.tomcat.util.http.fileupload;
diff --git a/java/org/apache/tomcat/util/http/fileupload/package.html b/java/org/apache/tomcat/util/http/fileupload/package.html
deleted file mode 100644
index eea80cb..0000000
--- a/java/org/apache/tomcat/util/http/fileupload/package.html
+++ /dev/null
@@ -1,94 +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.
--->
-<!-- $Id: package.html 981816 2010-08-03 10:44:58Z markt $ -->
-<html>
-  <head>
-    <title>
-      Overview of the org.apache.tomcat.util.http.fileupload component
-    </title>
-  </head>
-  <body>
-    <p><b>NOTE:</b> This code has been copied from commons-fileupload 1.2.1 and
-    commons-io 1.4 and package renamed to avoid clashes with any web apps that
-    may wish to use these libraries.
-    </p>
-    <p>
-      A component for handling HTML file uploads as specified by
-      <a href="http://www.ietf.org/rfc/rfc1867.txt" target="_top">RFC 1867</a>.
-      This component provides support for uploads within both servlets (JSR 53)
-      and portlets (JSR 168).
-    </p>
-    <p>
-      While this package provides the generic functionality for file uploads,
-      these classes are not typically used directly. Instead, normal usage
-      involves one of the provided extensions of
-      {@link org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} such as
-      {@link org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload ServletFileUpload}
-      together with a factory for 
-      {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} instances,
-      such as
-      {@link org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}.
-    </p>
-    <p>
-      The following is a brief example of typical usage in a servlet, storing
-      the uploaded files on disk.
-    </p>
-<pre>
-    public void doPost(HttpServletRequest req, HttpServletResponse res) {
-        DiskFileItemFactory factory = new DiskFileItemFactory();
-        // maximum size that will be stored in memory
-        factory.setSizeThreshold(4096);
-        // the location for saving data that is larger than getSizeThreshold()
-        factory.setRepository(new File("/tmp"));
-
-        ServletFileUpload upload = new ServletFileUpload(factory);
-        // maximum size before a FileUploadException will be thrown
-        upload.setSizeMax(1000000);
-
-        List fileItems = upload.parseRequest(req);
-        // assume we know there are two files. The first file is a small
-        // text file, the second is unknown and is written to a file on
-        // the server
-        Iterator i = fileItems.iterator();
-        String comment = ((FileItem)i.next()).getString();
-        FileItem fi = (FileItem)i.next();
-        // filename on the client
-        String fileName = fi.getName();
-        // save comment and filename to database
-        ...
-        // write the file
-        fi.write(new File("/www/uploads/", fileName));
-    }
-</pre>
-    <p>
-      In the example above, the first file is loaded into memory as a
-      <code>String</code>. Before calling the <code>getString</code> method,
-      the data may have been in memory or on disk depending on its size. The
-      second file we assume it will be large and therefore never explicitly
-      load it into memory, though if it is less than 4096 bytes it will be
-      in memory before it is written to its final location. When writing to
-      the final location, if the data is larger than the threshold, an attempt
-      is made to rename the temporary file to the given location.  If it cannot
-      be renamed, it is streamed to the new location.
-    </p>
-    <p>
-      Please see the FileUpload
-      <a href="http://commons.apache.org/fileupload/using.html" target="_top">User Guide</a>
-      for further details and examples of how to use this package.
-    </p>
-  </body>
-</html>
diff --git a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java
index bebec3e..6cb7cec 100644
--- a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java
+++ b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java
@@ -18,7 +18,7 @@ package org.apache.tomcat.util.http.fileupload.servlet;
 
 import java.io.IOException;
 import java.util.List;
-import java.util.Locale;
+import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -26,6 +26,7 @@ import org.apache.tomcat.util.http.fileupload.FileItem;
 import org.apache.tomcat.util.http.fileupload.FileItemFactory;
 import org.apache.tomcat.util.http.fileupload.FileItemIterator;
 import org.apache.tomcat.util.http.fileupload.FileUpload;
+import org.apache.tomcat.util.http.fileupload.FileUploadBase;
 import org.apache.tomcat.util.http.fileupload.FileUploadException;
 
 
@@ -35,27 +36,24 @@ import org.apache.tomcat.util.http.fileupload.FileUploadException;
  * <p>This class handles multiple files per single HTML widget, sent using
  * <code>multipart/mixed</code> encoding type, as specified by
  * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>.  Use {@link
- * #parseRequest(HttpServletRequest)} to acquire a list of {@link
- * org.apache.tomcat.util.http.fileupload.FileItem}s associated with a given HTML
- * widget.</p>
+ * #parseRequest(org.apache.tomcat.util.http.fileupload.RequestContext)} to
+ * acquire a list of {@link org.apache.tomcat.util.http.fileupload.FileItem}s
+ * associated with a given HTML widget.</p>
  *
  * <p>How the data for individual parts is stored is determined by the factory
  * used to create them; a given part may be in memory, on disk, or somewhere
  * else.</p>
  *
- * @author <a href="mailto:Rafal.Krzewski at e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:dlr at collab.net">Daniel Rall</a>
- * @author <a href="mailto:jvanzyl at apache.org">Jason van Zyl</a>
- * @author <a href="mailto:jmcnally at collab.net">John McNally</a>
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- * @author Sean C. Sullivan
- *
- * @version $Id: ServletFileUpload.java 981816 2010-08-03 10:44:58Z markt $
+ * @version $Id: ServletFileUpload.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public class ServletFileUpload extends FileUpload {
 
-    // ---------------------------------------------------------- Class methods
+    /**
+     * Constant for HTTP POST method.
+     */
+    private static final String POST_METHOD = "POST";
 
+    // ---------------------------------------------------------- Class methods
 
     /**
      * Utility method that determines whether the request contains multipart
@@ -68,23 +66,14 @@ public class ServletFileUpload extends FileUpload {
      */
     public static final boolean isMultipartContent(
             HttpServletRequest request) {
-        if (!"post".equals(request.getMethod().toLowerCase(Locale.ENGLISH))) {
-            return false;
-        }
-        String contentType = request.getContentType();
-        if (contentType == null) {
+        if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) {
             return false;
         }
-        if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
-            return true;
-        }
-        return false;
+        return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
     }
 
-
     // ----------------------------------------------------------- Constructors
 
-
     /**
      * Constructs an uninitialised instance of this class. A factory must be
      * configured, using <code>setFileItemFactory()</code>, before attempting
@@ -96,7 +85,6 @@ public class ServletFileUpload extends FileUpload {
         super();
     }
 
-
     /**
      * Constructs an instance of this class which uses the supplied factory to
      * create <code>FileItem</code> instances.
@@ -108,28 +96,26 @@ public class ServletFileUpload extends FileUpload {
         super(fileItemFactory);
     }
 
-
     // --------------------------------------------------------- Public methods
 
-
     /**
      * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
      * compliant <code>multipart/form-data</code> stream.
      *
      * @param request The servlet request to be parsed.
      *
-     * @return A list of <code>FileItem</code> instances parsed from the
-     *         request, in the order that they were transmitted.
+     * @return A map of <code>FileItem</code> instances parsed from the request.
      *
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
+     *
+     * @since 1.3
      */
-    public List<FileItem> parseRequest(HttpServletRequest request)
-    throws FileUploadException {
-        return parseRequest(new ServletRequestContext(request));
+    public Map<String, List<FileItem>> parseParameterMap(HttpServletRequest request)
+            throws FileUploadException {
+        return parseParameterMap(new ServletRequestContext(request));
     }
 
-
     /**
      * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
      * compliant <code>multipart/form-data</code> stream.
@@ -150,4 +136,5 @@ public class ServletFileUpload extends FileUpload {
     throws FileUploadException, IOException {
         return super.getItemIterator(new ServletRequestContext(request));
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java
index 8f084a3..3af49b8 100644
--- a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java
+++ b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java
@@ -21,28 +21,26 @@ import java.io.InputStream;
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.apache.tomcat.util.http.fileupload.RequestContext;
+import org.apache.tomcat.util.http.fileupload.FileUploadBase;
+import org.apache.tomcat.util.http.fileupload.UploadContext;
 
 
 /**
  * <p>Provides access to the request information needed for a request made to
  * an HTTP servlet.</p>
  *
- * @author <a href="mailto:martinc at apache.org">Martin Cooper</a>
- *
  * @since FileUpload 1.1
  *
- * @version $Id: ServletRequestContext.java 1154575 2011-08-06 20:19:29Z markt $
+ * @version $Id: ServletRequestContext.java 1456935 2013-03-15 12:47:29Z markt $
  */
-public class ServletRequestContext implements RequestContext {
+public class ServletRequestContext implements UploadContext {
 
     // ----------------------------------------------------- Instance Variables
 
     /**
      * The request for which the context is being provided.
      */
-    private HttpServletRequest request;
-
+    private final HttpServletRequest request;
 
     // ----------------------------------------------------------- Constructors
 
@@ -55,7 +53,6 @@ public class ServletRequestContext implements RequestContext {
         this.request = request;
     }
 
-
     // --------------------------------------------------------- Public Methods
 
     /**
@@ -82,10 +79,17 @@ public class ServletRequestContext implements RequestContext {
      * Retrieve the content length of the request.
      *
      * @return The content length of the request.
+     * @since 1.3
      */
     @Override
-    public int getContentLength() {
-        return request.getContentLength();
+    public long contentLength() {
+        long size;
+        try {
+            size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH));
+        } catch (NumberFormatException e) {
+            size = request.getContentLength();
+        }
+        return size;
     }
 
     /**
@@ -107,9 +111,9 @@ public class ServletRequestContext implements RequestContext {
      */
     @Override
     public String toString() {
-        return "ContentLength="
-            + this.getContentLength()
-            + ", ContentType="
-            + this.getContentType();
+        return String.format("ContentLength=%s, ContentType=%s",
+                      Long.valueOf(this.contentLength()),
+                      this.getContentType());
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/servlet/package-info.java b/java/org/apache/tomcat/util/http/fileupload/servlet/package-info.java
new file mode 100644
index 0000000..73c6f60
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/servlet/package-info.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/**
+ *    <p>
+ *      An implementation of
+ *      {@link org.apache.tomcat.util.http.fileupload.FileUpload FileUpload}
+ *      for use in servlets conforming to JSR 53. This implementation requires
+ *      only access to the servlet's current <code>HttpServletRequest</code>
+ *      instance, and a suitable
+ *      {@link org.apache.tomcat.util.http.fileupload.FileItemFactory FileItemFactory}
+ *      implementation, such as
+ *      {@link org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}.
+ *    </p>
+ *    <p>
+ *      The following code fragment demonstrates typical usage.
+ *    </p>
+ * <pre>
+ *        DiskFileItemFactory factory = new DiskFileItemFactory();
+ *        // Configure the factory here, if desired.
+ *        ServletFileUpload upload = new ServletFileUpload(factory);
+ *        // Configure the uploader here, if desired.
+ *        List fileItems = upload.parseRequest(request);
+ * </pre>
+ *    <p>
+ *      Please see the FileUpload
+ *      <a href="http://commons.apache.org/fileupload/using.html" target="_top">User Guide</a>
+ *      for further details and examples of how to use this package.
+ *    </p>
+ */
+package org.apache.tomcat.util.http.fileupload.servlet;
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java b/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java
index 2c18c47..9dec9f8 100644
--- a/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java
+++ b/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java
@@ -18,21 +18,26 @@ package org.apache.tomcat.util.http.fileupload.util;
 
 import java.io.IOException;
 
-
 /**
  * Interface of an object, which may be closed.
+ *
+ * @version $Id: Closeable.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public interface Closeable {
+
     /**
      * Closes the object.
+     *
      * @throws IOException An I/O error occurred.
      */
     void close() throws IOException;
 
     /**
      * Returns, whether the object is already closed.
+     *
      * @return True, if the object is closed, otherwise false.
      * @throws IOException An I/O error occurred.
      */
     boolean isClosed() throws IOException;
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
index f19a690..9ff33ea 100644
--- a/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
+++ b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
@@ -19,8 +19,8 @@ package org.apache.tomcat.util.http.fileupload.util;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -31,10 +31,15 @@ import org.apache.tomcat.util.http.fileupload.FileItemHeaders;
 /**
  * Default implementation of the {@link FileItemHeaders} interface.
  *
- * @author Michael C. Macaluso
- * @since 1.3
+ * @since 1.2.1
+ *
+ * @version $Id: FileItemHeadersImpl.java 1458566 2013-03-19 23:14:59Z markt $
  */
 public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
+
+    /**
+     * Serial version UID, being used, if serialized.
+     */
     private static final long serialVersionUID = -4455695752627032559L;
 
     /**
@@ -42,15 +47,11 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
      * <code>String</code> instances.
      */
     private final Map<String,List<String>> headerNameToValueListMap =
-        new HashMap<String,List<String>>();
+            new LinkedHashMap<String,List<String>>();
 
     /**
-     * List to preserve order of headers as added.  This would not be
-     * needed if a <code>LinkedHashMap</code> could be used, but don't
-     * want to depend on 1.4.
+     * {@inheritDoc}
      */
-    private final List<String> headerNameList = new ArrayList<String>();
-
     @Override
     public String getHeader(String name) {
         String nameLower = name.toLowerCase(Locale.ENGLISH);
@@ -61,17 +62,23 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
         return headerValueList.get(0);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Iterator<String> getHeaderNames() {
-        return headerNameList.iterator();
+        return headerNameToValueListMap.keySet().iterator();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Iterator<String> getHeaders(String name) {
         String nameLower = name.toLowerCase(Locale.ENGLISH);
         List<String> headerValueList = headerNameToValueListMap.get(nameLower);
         if (null == headerValueList) {
-            return Collections.<String>emptyList().iterator();
+            headerValueList = Collections.emptyList();
         }
         return headerValueList.iterator();
     }
@@ -88,8 +95,8 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
         if (null == headerValueList) {
             headerValueList = new ArrayList<String>();
             headerNameToValueListMap.put(nameLower, headerValueList);
-            headerNameList.add(nameLower);
         }
         headerValueList.add(value);
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java b/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java
index be6046a..6317ea8 100644
--- a/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java
@@ -20,21 +20,24 @@ import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
-
 /**
  * An input stream, which limits its data size. This stream is
  * used, if the content length is unknown.
+ *
+ * @version $Id: LimitedInputStream.java 1456935 2013-03-15 12:47:29Z markt $
  */
-public abstract class LimitedInputStream
-        extends FilterInputStream implements Closeable {
+public abstract class LimitedInputStream extends FilterInputStream implements Closeable {
+
     /**
      * The maximum size of an item, in bytes.
      */
-    private long sizeMax;
+    private final long sizeMax;
+
     /**
      * The current number of bytes.
      */
     private long count;
+
     /**
      * Whether this stream is already closed.
      */
@@ -42,6 +45,7 @@ public abstract class LimitedInputStream
 
     /**
      * Creates a new instance.
+     *
      * @param pIn The input stream, which shall be limited.
      * @param pSizeMax The limit; no more than this number of bytes
      *   shall be returned by the source stream.
@@ -54,6 +58,7 @@ public abstract class LimitedInputStream
     /**
      * Called to indicate, that the input streams limit has
      * been exceeded.
+     *
      * @param pSizeMax The input streams limit, in bytes.
      * @param pCount The actual number of bytes.
      * @throws IOException The called method is expected
@@ -62,8 +67,10 @@ public abstract class LimitedInputStream
     protected abstract void raiseError(long pSizeMax, long pCount)
             throws IOException;
 
-    /** Called to check, whether the input streams
+    /**
+     * Called to check, whether the input streams
      * limit is reached.
+     *
      * @throws IOException The given limit is exceeded.
      */
     private void checkLimit() throws IOException {
@@ -134,6 +141,7 @@ public abstract class LimitedInputStream
 
     /**
      * Returns, whether this stream is already closed.
+     *
      * @return True, if the stream is closed, otherwise false.
      * @throws IOException An I/O error occurred.
      */
@@ -156,4 +164,5 @@ public abstract class LimitedInputStream
         closed = true;
         super.close();
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/Streams.java b/java/org/apache/tomcat/util/http/fileupload/util/Streams.java
index 00b311c..04e1232 100644
--- a/java/org/apache/tomcat/util/http/fileupload/util/Streams.java
+++ b/java/org/apache/tomcat/util/http/fileupload/util/Streams.java
@@ -23,10 +23,13 @@ import java.io.OutputStream;
 
 import org.apache.tomcat.util.http.fileupload.InvalidFileNameException;
 
-
-/** Utility class for working with streams.
+/**
+ * Utility class for working with streams.
+ *
+ * @version $Id: Streams.java 1456935 2013-03-15 12:47:29Z markt $
  */
 public final class Streams {
+
     /**
      * Private constructor, to prevent instantiation.
      * This class has only static methods.
@@ -47,6 +50,7 @@ public final class Streams {
      * <pre>
      *   copy(pInputStream, pOutputStream, new byte[8192]);
      * </pre>
+     *
      * @param pInputStream The input stream, which is being read.
      * It is guaranteed, that {@link InputStream#close()} is called
      * on the stream.
@@ -70,6 +74,7 @@ public final class Streams {
     /**
      * Copies the contents of the given {@link InputStream}
      * to the given {@link OutputStream}.
+     *
      * @param pIn The input stream, which is being read.
      *   It is guaranteed, that {@link InputStream#close()} is called
      *   on the stream.
@@ -138,6 +143,7 @@ public final class Streams {
      * {@link org.apache.tomcat.util.http.fileupload.FileItemStream}'s
      * content into a string. The platform's default character encoding
      * is used for converting bytes into characters.
+     *
      * @param pStream The input stream to read.
      * @see #asString(InputStream, String)
      * @return The streams contents, as a string.
@@ -153,6 +159,7 @@ public final class Streams {
      * This convenience method allows to read a
      * {@link org.apache.tomcat.util.http.fileupload.FileItemStream}'s
      * content into a string, using the given character encoding.
+     *
      * @param pStream The input stream to read.
      * @param pEncoding The character encoding, typically "UTF-8".
      * @see #asString(InputStream)
@@ -171,6 +178,7 @@ public final class Streams {
      * that it doesn't contain any NUL characters. If the file name
      * is valid, it will be returned without any modifications. Otherwise,
      * an {@link InvalidFileNameException} is raised.
+     *
      * @param pFileName The file name to check
      * @return Unmodified file name, if valid.
      * @throws InvalidFileNameException The file name was found to be invalid.
@@ -195,4 +203,5 @@ public final class Streams {
         }
         return pFileName;
     }
+
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java
new file mode 100644
index 0000000..9d24063
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.util.mime;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.tomcat.util.codec.binary.Base64;
+
+/**
+ * Utility class to decode MIME texts.
+ *
+ * @since 1.3
+ */
+public final class MimeUtility {
+
+    /**
+     * The {@code US-ASCII} charset identifier constant.
+     */
+    private static final String US_ASCII_CHARSET = "US-ASCII";
+
+    /**
+     * The marker to indicate text is encoded with BASE64 algorithm.
+     */
+    private static final String BASE64_ENCODING_MARKER = "B";
+
+    /**
+     * The marker to indicate text is encoded with QuotedPrintable algorithm.
+     */
+    private static final String QUOTEDPRINTABLE_ENCODING_MARKER = "Q";
+
+    /**
+     * If the text contains any encoded tokens, those tokens will be marked with "=?".
+     */
+    private static final String ENCODED_TOKEN_MARKER = "=?";
+
+    /**
+     * If the text contains any encoded tokens, those tokens will terminate with "=?".
+     */
+    private static final String ENCODED_TOKEN_FINISHER = "?=";
+
+    /**
+     * The linear whitespace chars sequence.
+     */
+    private static final String LINEAR_WHITESPACE = " \t\r\n";
+
+    /**
+     * Mappings between MIME and Java charset.
+     */
+    private static final Map<String,String> MIME2JAVA =
+            new HashMap<String,String>();
+
+    static {
+        MIME2JAVA.put("iso-2022-cn", "ISO2022CN");
+        MIME2JAVA.put("iso-2022-kr", "ISO2022KR");
+        MIME2JAVA.put("utf-8", "UTF8");
+        MIME2JAVA.put("utf8", "UTF8");
+        MIME2JAVA.put("ja_jp.iso2022-7", "ISO2022JP");
+        MIME2JAVA.put("ja_jp.eucjp", "EUCJIS");
+        MIME2JAVA.put("euc-kr", "KSC5601");
+        MIME2JAVA.put("euckr", "KSC5601");
+        MIME2JAVA.put("us-ascii", "ISO-8859-1");
+        MIME2JAVA.put("x-us-ascii", "ISO-8859-1");
+    }
+
+    /**
+     * Hidden constructor, this class must not be instantiated.
+     */
+    private MimeUtility() {
+        // do nothing
+    }
+
+    /**
+     * Decode a string of text obtained from a mail header into
+     * its proper form.  The text generally will consist of a
+     * string of tokens, some of which may be encoded using
+     * base64 encoding.
+     *
+     * @param text   The text to decode.
+     *
+     * @return The decoded text string.
+     * @throws UnsupportedEncodingException if the detected encoding in the input text is not supported.
+     */
+    public static String decodeText(String text) throws UnsupportedEncodingException {
+        // if the text contains any encoded tokens, those tokens will be marked with "=?".  If the
+        // source string doesn't contain that sequent, no decoding is required.
+        if (text.indexOf(ENCODED_TOKEN_MARKER) < 0) {
+            return text;
+        }
+
+        int offset = 0;
+        int endOffset = text.length();
+
+        int startWhiteSpace = -1;
+        int endWhiteSpace = -1;
+
+        StringBuilder decodedText = new StringBuilder(text.length());
+
+        boolean previousTokenEncoded = false;
+
+        while (offset < endOffset) {
+            char ch = text.charAt(offset);
+
+            // is this a whitespace character?
+            if (LINEAR_WHITESPACE.indexOf(ch) != -1) { // whitespace found
+                startWhiteSpace = offset;
+                while (offset < endOffset) {
+                    // step over the white space characters.
+                    ch = text.charAt(offset);
+                    if (LINEAR_WHITESPACE.indexOf(ch) != -1) { // whitespace found
+                        offset++;
+                    } else {
+                        // record the location of the first non lwsp and drop down to process the
+                        // token characters.
+                        endWhiteSpace = offset;
+                        break;
+                    }
+                }
+            } else {
+                // we have a word token.  We need to scan over the word and then try to parse it.
+                int wordStart = offset;
+
+                while (offset < endOffset) {
+                    // step over the non white space characters.
+                    ch = text.charAt(offset);
+                    if (LINEAR_WHITESPACE.indexOf(ch) == -1) { // not white space
+                        offset++;
+                    } else {
+                        break;
+                    }
+
+                    //NB:  Trailing whitespace on these header strings will just be discarded.
+                }
+                // pull out the word token.
+                String word = text.substring(wordStart, offset);
+                // is the token encoded?  decode the word
+                if (word.startsWith(ENCODED_TOKEN_MARKER)) {
+                    try {
+                        // if this gives a parsing failure, treat it like a non-encoded word.
+                        String decodedWord = decodeWord(word);
+
+                        // are any whitespace characters significant?  Append 'em if we've got 'em.
+                        if (!previousTokenEncoded && startWhiteSpace != -1) {
+                            decodedText.append(text.substring(startWhiteSpace, endWhiteSpace));
+                            startWhiteSpace = -1;
+                        }
+                        // this is definitely a decoded token.
+                        previousTokenEncoded = true;
+                        // and add this to the text.
+                        decodedText.append(decodedWord);
+                        // we continue parsing from here...we allow parsing errors to fall through
+                        // and get handled as normal text.
+                        continue;
+
+                    } catch (ParseException e) {
+                        // just ignore it, skip to next word
+                    }
+                }
+                // this is a normal token, so it doesn't matter what the previous token was.  Add the white space
+                // if we have it.
+                if (startWhiteSpace != -1) {
+                    decodedText.append(text.substring(startWhiteSpace, endWhiteSpace));
+                    startWhiteSpace = -1;
+                }
+                // this is not a decoded token.
+                previousTokenEncoded = false;
+                decodedText.append(word);
+            }
+        }
+
+        return decodedText.toString();
+    }
+
+    /**
+     * Parse a string using the RFC 2047 rules for an "encoded-word"
+     * type.  This encoding has the syntax:
+     *
+     * encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
+     *
+     * @param word   The possibly encoded word value.
+     *
+     * @return The decoded word.
+     * @throws ParseException
+     * @throws UnsupportedEncodingException
+     */
+    private static String decodeWord(String word) throws ParseException, UnsupportedEncodingException {
+        // encoded words start with the characters "=?".  If this not an encoded word, we throw a
+        // ParseException for the caller.
+
+        if (!word.startsWith(ENCODED_TOKEN_MARKER)) {
+            throw new ParseException("Invalid RFC 2047 encoded-word: " + word);
+        }
+
+        int charsetPos = word.indexOf('?', 2);
+        if (charsetPos == -1) {
+            throw new ParseException("Missing charset in RFC 2047 encoded-word: " + word);
+        }
+
+        // pull out the character set information (this is the MIME name at this point).
+        String charset = word.substring(2, charsetPos).toLowerCase();
+
+        // now pull out the encoding token the same way.
+        int encodingPos = word.indexOf('?', charsetPos + 1);
+        if (encodingPos == -1) {
+            throw new ParseException("Missing encoding in RFC 2047 encoded-word: " + word);
+        }
+
+        String encoding = word.substring(charsetPos + 1, encodingPos);
+
+        // and finally the encoded text.
+        int encodedTextPos = word.indexOf(ENCODED_TOKEN_FINISHER, encodingPos + 1);
+        if (encodedTextPos == -1) {
+            throw new ParseException("Missing encoded text in RFC 2047 encoded-word: " + word);
+        }
+
+        String encodedText = word.substring(encodingPos + 1, encodedTextPos);
+
+        // seems a bit silly to encode a null string, but easy to deal with.
+        if (encodedText.length() == 0) {
+            return "";
+        }
+
+        try {
+            // the decoder writes directly to an output stream.
+            ByteArrayOutputStream out = new ByteArrayOutputStream(encodedText.length());
+
+            byte[] decodedData;
+            // Base64 encoded?
+            if (encoding.equals(BASE64_ENCODING_MARKER)) {
+                decodedData = Base64.decodeBase64(encodedText);
+            } else if (encoding.equals(QUOTEDPRINTABLE_ENCODING_MARKER)) { // maybe quoted printable.
+                byte[] encodedData = encodedText.getBytes(US_ASCII_CHARSET);
+                QuotedPrintableDecoder.decode(encodedData, out);
+                decodedData = out.toByteArray();
+            } else {
+                throw new UnsupportedEncodingException("Unknown RFC 2047 encoding: " + encoding);
+            }
+            // Convert decoded byte data into a string.
+            return new String(decodedData, javaCharset(charset));
+        } catch (IOException e) {
+            throw new UnsupportedEncodingException("Invalid RFC 2047 encoding");
+        }
+    }
+
+    /**
+     * Translate a MIME standard character set name into the Java
+     * equivalent.
+     *
+     * @param charset The MIME standard name.
+     *
+     * @return The Java equivalent for this name.
+     */
+    private static String javaCharset(String charset) {
+        // nothing in, nothing out.
+        if (charset == null) {
+            return null;
+        }
+
+        String mappedCharset = MIME2JAVA.get(charset.toLowerCase(Locale.ENGLISH));
+        // if there is no mapping, then the original name is used.  Many of the MIME character set
+        // names map directly back into Java.  The reverse isn't necessarily true.
+        if (mappedCharset == null) {
+            return charset;
+        }
+        return mappedCharset;
+    }
+
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java
new file mode 100644
index 0000000..304f49e
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.util.mime;
+
+/**
+ * @since 1.3
+ */
+final class ParseException extends Exception {
+
+    /**
+     * The UID to use when serializing this instance.
+     */
+    private static final long serialVersionUID = 5355281266579392077L;
+
+    /**
+     * Constructs a new exception with the specified detail message.
+     *
+     * @param message the detail message.
+     */
+    public ParseException(String message) {
+        super(message);
+    }
+
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java
new file mode 100644
index 0000000..e7e9e4e
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.util.mime;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @since 1.3
+ */
+final class QuotedPrintableDecoder {
+
+    /**
+     * The shift value required to create the upper nibble
+     * from the first of 2 byte values converted from ascii hex.
+     */
+    private static final int UPPER_NIBBLE_SHIFT = Byte.SIZE / 2;
+
+    /**
+     * Hidden constructor, this class must not be instantiated.
+     */
+    private QuotedPrintableDecoder() {
+        // do nothing
+    }
+
+    /**
+     * Decode the encoded byte data writing it to the given output stream.
+     *
+     * @param data   The array of byte data to decode.
+     * @param out    The output stream used to return the decoded data.
+     *
+     * @return the number of bytes produced.
+     * @exception IOException
+     */
+    public static int decode(byte[] data, OutputStream out) throws IOException {
+        int off = 0;
+        int length = data.length;
+        int endOffset = off + length;
+        int bytesWritten = 0;
+
+        while (off < endOffset) {
+            byte ch = data[off++];
+
+            // space characters were translated to '_' on encode, so we need to translate them back.
+            if (ch == '_') {
+                out.write(' ');
+            } else if (ch == '=') {
+                // we found an encoded character.  Reduce the 3 char sequence to one.
+                // but first, make sure we have two characters to work with.
+                if (off + 1 >= endOffset) {
+                    throw new IOException("Invalid quoted printable encoding; truncated escape sequence");
+                }
+
+                byte b1 = data[off++];
+                byte b2 = data[off++];
+
+                // we've found an encoded carriage return.  The next char needs to be a newline
+                if (b1 == '\r') {
+                    if (b2 != '\n') {
+                        throw new IOException("Invalid quoted printable encoding; CR must be followed by LF");
+                    }
+                    // this was a soft linebreak inserted by the encoding.  We just toss this away
+                    // on decode.
+                } else {
+                    // this is a hex pair we need to convert back to a single byte.
+                    int c1 = hexToBinary(b1);
+                    int c2 = hexToBinary(b2);
+                    out.write((c1 << UPPER_NIBBLE_SHIFT) | c2);
+                    // 3 bytes in, one byte out
+                    bytesWritten++;
+                }
+            } else {
+                // simple character, just write it out.
+                out.write(ch);
+                bytesWritten++;
+            }
+        }
+
+        return bytesWritten;
+    }
+
+    /**
+     * Convert a hex digit to the binary value it represents.
+     *
+     * @param b the ascii hex byte to convert (0-0, A-F, a-f)
+     * @return the int value of the hex byte, 0-15
+     * @throws IOException if the byte is not a valid hex digit.
+     */
+    private static int hexToBinary(final byte b) throws IOException {
+        // CHECKSTYLE IGNORE MagicNumber FOR NEXT 1 LINE
+        final int i = Character.digit((char) b, 16);
+        if (i == -1) {
+            throw new IOException("Invalid quoted printable encoding: not a valid hex digit: " + b);
+        }
+        return i;
+    }
+
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/package-info.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/package-info.java
new file mode 100644
index 0000000..5456e4e
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * MIME decoder implementation, imported and retailed from
+ * <a href="http://svn.apache.org/repos/asf/geronimo/specs/tags/geronimo-javamail_1.4_spec-1.4/">Apache Geronimo</a>.
+ */
+package org.apache.tomcat.util.http.fileupload.util.mime;
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/package-info.java b/java/org/apache/tomcat/util/http/fileupload/util/package-info.java
new file mode 100644
index 0000000..fda7c88
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/util/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains various IO related utility classes
+ * or methods, which are basically reusable and not necessarily
+ * restricted to the scope of a file upload.
+ */
+package org.apache.tomcat.util.http.fileupload.util;
diff --git a/java/org/apache/tomcat/util/http/parser/HttpParser.java b/java/org/apache/tomcat/util/http/parser/HttpParser.java
index 9e464ed..34f1fae 100644
--- a/java/org/apache/tomcat/util/http/parser/HttpParser.java
+++ b/java/org/apache/tomcat/util/http/parser/HttpParser.java
@@ -43,12 +43,12 @@ import java.util.Map;
  */
 public class HttpParser {
 
+    @SuppressWarnings("unused")  // Unused due to buggy client implementations
     private static final Integer FIELD_TYPE_TOKEN = Integer.valueOf(0);
     private static final Integer FIELD_TYPE_QUOTED_STRING = Integer.valueOf(1);
     private static final Integer FIELD_TYPE_TOKEN_OR_QUOTED_STRING = Integer.valueOf(2);
     private static final Integer FIELD_TYPE_LHEX = Integer.valueOf(3);
-    private static final Integer FIELD_TYPE_QUOTED_LHEX = Integer.valueOf(4);
-    private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(5);
+    private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(4);
 
     private static final Map<String,Integer> fieldTypes =
             new HashMap<String,Integer>();
@@ -58,16 +58,23 @@ public class HttpParser {
     private static final boolean isHex[] = new boolean[128];
 
     static {
-        // Digest field types
+        // Digest field types.
+        // Note: These are more relaxed than RFC2617. This adheres to the
+        //       recommendation of RFC2616 that servers are tolerant of buggy
+        //       clients when they can be so without ambiguity.
         fieldTypes.put("username", FIELD_TYPE_QUOTED_STRING);
         fieldTypes.put("realm", FIELD_TYPE_QUOTED_STRING);
         fieldTypes.put("nonce", FIELD_TYPE_QUOTED_STRING);
         fieldTypes.put("digest-uri", FIELD_TYPE_QUOTED_STRING);
-        fieldTypes.put("response", FIELD_TYPE_QUOTED_LHEX);
-        fieldTypes.put("algorithm", FIELD_TYPE_TOKEN);
+        // RFC2617 says response is <">32LHEX<">. 32LHEX will also be accepted
+        fieldTypes.put("response", FIELD_TYPE_LHEX);
+        // RFC2617 says algorithm is token. <">token<"> will also be accepted
+        fieldTypes.put("algorithm", FIELD_TYPE_QUOTED_TOKEN);
         fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING);
         fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING);
+        // RFC2617 says qop is token. <">token<"> will also be accepted
         fieldTypes.put("qop", FIELD_TYPE_QUOTED_TOKEN);
+        // RFC2617 says nc is 8LHEX. <">8LHEX<"> will also be accepted
         fieldTypes.put("nc", FIELD_TYPE_LHEX);
 
         // Setup the flag arrays
@@ -125,7 +132,7 @@ public class HttpParser {
                 return null;
             }
             String value = null;
-            Integer type = fieldTypes.get(field.toLowerCase(Locale.US));
+            Integer type = fieldTypes.get(field.toLowerCase(Locale.ENGLISH));
             if (type == null) {
                 // auth-param = token "=" ( token | quoted-string )
                 type = FIELD_TYPE_TOKEN_OR_QUOTED_STRING;
@@ -148,10 +155,6 @@ public class HttpParser {
                     value = readLhex(input);
                     break;
                 case 4:
-                    // FIELD_TYPE_QUOTED_LHEX
-                    value = readQuotedLhex(input);
-                    break;
-                case 5:
                     // FIELD_TYPE_QUOTED_TOKEN
                     value = readQuotedToken(input);
                     break;
@@ -209,9 +212,9 @@ public class HttpParser {
 
             if (skipConstant(input, "=") == SkipConstantResult.FOUND) {
                 String value = readTokenOrQuotedString(input, true);
-                parameters.put(attribute.toLowerCase(Locale.US), value);
+                parameters.put(attribute.toLowerCase(Locale.ENGLISH), value);
             } else {
-                parameters.put(attribute.toLowerCase(Locale.US), "");
+                parameters.put(attribute.toLowerCase(Locale.ENGLISH), "");
             }
 
             lookForSemiColon = skipConstant(input, ";");
@@ -264,6 +267,8 @@ public class HttpParser {
         int len = constant.length();
 
         int c = input.read();
+
+        // Skip lws
         while (c == 32 || c == 9) {
             c = input.read();
         }
@@ -360,8 +365,12 @@ public class HttpParser {
 
     private static String readTokenOrQuotedString(StringReader input,
             boolean returnQuoted) throws IOException {
+
+        // Use mark/reset as skip(-1) fails when reading the last character of
+        // the input
         input.mark(1);
         int c = input.read();
+        // Go back so first character is available to be read again
         input.reset();
 
         if (c == '"') {
@@ -372,9 +381,12 @@ public class HttpParser {
     }
 
     /**
+     * Token can be read unambiguously with or without surrounding quotes so
+     * this parsing method for token permits optional surrounding double quotes.
      * This is not defined in any RFC. It is a special case to handle data from
-     * buggy clients (known buggy clients include Microsoft IE 8 & 9, Apple
-     * Safari for OSX and iOS) that add quotes to values that should be tokens.
+     * buggy clients (known buggy clients for DIGEST auth include Microsoft IE 8
+     * & 9, Apple Safari for OSX and iOS) that add quotes to values that
+     * should be tokens.
      *
      * @return the token if one was found, null if data other than a token or
      *         quoted token was found or null if the end of data was reached
@@ -395,7 +407,7 @@ public class HttpParser {
 
         if (c == '"') {
             quoted = true;
-        } else if (c == -1) {
+        } else if (c == -1 || !isToken(c)) {
             return null;
         } else {
             result.append((char) c);
@@ -424,14 +436,24 @@ public class HttpParser {
     }
 
     /**
-     * Parses lower case hex but permits upper case hex to be used (converting
-     * it to lower case before returning).
+     * LHEX can be read unambiguously with or without surrounding quotes so this
+     * parsing method for LHEX permits optional surrounding double quotes. Some
+     * buggy clients (libwww-perl for DIGEST auth) are known to send quoted LHEX
+     * when the specification requires just LHEX.
+     *
+     * <p>
+     * LHEX are, literally, lower-case hexadecimal digits. This implementation
+     * allows for upper-case digits as well, converting the returned value to
+     * lower-case.
      *
-     * @return the lower case hex if present or <code>null</code> if data other
-     *         than lower case hex was found
+     * @return  the sequence of LHEX (minus any surrounding quotes) if any was
+     *          found, or <code>null</code> if data other LHEX was found
      */
-    private static String readLhex(StringReader input) throws IOException {
+    private static String readLhex(StringReader input)
+            throws IOException {
+
         StringBuilder result = new StringBuilder();
+        boolean quoted = false;
 
         int c = input.read();
 
@@ -440,32 +462,40 @@ public class HttpParser {
             c = input.read();
         }
 
+        if (c == '"') {
+            quoted = true;
+        } else if (c == -1 || !isHex(c)) {
+            return null;
+        } else {
+            if ('A' <= c && c <= 'F') {
+                c -= ('A' - 'a');
+            }
+            result.append((char) c);
+        }
+        c = input.read();
+
         while (c != -1 && isHex(c)) {
+            if ('A' <= c && c <= 'F') {
+                c -= ('A' - 'a');
+            }
             result.append((char) c);
             c = input.read();
         }
-        // Skip back so non-hex character is available for next read
-        input.skip(-1);
 
-        if (result.length() == 0) {
-            return null;
+        if (quoted) {
+            if (c != '"') {
+                return null;
+            }
         } else {
-            return result.toString().toLowerCase(Locale.US);
+            // Skip back so non-hex character is available for next read
+            input.skip(-1);
         }
-    }
 
-    private static String readQuotedLhex(StringReader input)
-            throws IOException {
-
-        if (skipConstant(input, "\"") != SkipConstantResult.FOUND) {
-            return null;
-        }
-        String result = readLhex(input);
-        if (skipConstant(input, "\"") == SkipConstantResult.NOT_FOUND) {
+        if (c != -1 && result.length() == 0) {
             return null;
+        } else {
+            return result.toString();
         }
-
-        return result;
     }
 
     private static enum SkipConstantResult {
diff --git a/java/org/apache/tomcat/util/http/parser/MediaType.java b/java/org/apache/tomcat/util/http/parser/MediaType.java
index dbee0f6..ce60a14 100644
--- a/java/org/apache/tomcat/util/http/parser/MediaType.java
+++ b/java/org/apache/tomcat/util/http/parser/MediaType.java
@@ -60,7 +60,7 @@ public class MediaType {
     }
 
     public String getParameterValue(String parameter) {
-        return parameters.get(parameter.toLowerCase(Locale.US));
+        return parameters.get(parameter.toLowerCase(Locale.ENGLISH));
     }
 
     @Override
diff --git a/java/org/apache/tomcat/util/modeler/ManagedBean.java b/java/org/apache/tomcat/util/modeler/ManagedBean.java
index b19e753..823baf6 100644
--- a/java/org/apache/tomcat/util/modeler/ManagedBean.java
+++ b/java/org/apache/tomcat/util/modeler/ManagedBean.java
@@ -42,7 +42,7 @@ import javax.management.ServiceNotFoundException;
  * descriptor.</p>
  *
  * @author Craig R. McClanahan
- * @version $Id: ManagedBean.java 1176157 2011-09-27 01:21:08Z kkolinko $
+ * @version $Id: ManagedBean.java 1457749 2013-03-18 13:10:33Z markt $
  */
 
 public class ManagedBean implements java.io.Serializable {
@@ -291,7 +291,7 @@ public class ManagedBean implements java.io.Serializable {
      * @param operation The new operation descriptor
      */
     public void addOperation(OperationInfo operation) {
-        operations.put(operation.getName(), operation);
+        operations.put(createOperationKey(operation), operation);
     }
 
 
@@ -581,7 +581,8 @@ public class ManagedBean implements java.io.Serializable {
 
         // Acquire the ModelMBeanOperationInfo information for
         // the requested operation
-        OperationInfo opInfo = operations.get(aname);
+        OperationInfo opInfo =
+                operations.get(createOperationKey(aname, signature));
         if (opInfo == null)
             throw new MBeanException(new ServiceNotFoundException(
                     "Cannot find operation " + aname),
@@ -622,4 +623,31 @@ public class ManagedBean implements java.io.Serializable {
     }
 
 
+    private String createOperationKey(OperationInfo operation) {
+        StringBuilder key = new StringBuilder(operation.getName());
+        key.append('(');
+        for (ParameterInfo parameterInfo: operation.getSignature()) {
+            key.append(parameterInfo.getType());
+            // Note: A trailing ',' does not matter in this case
+            key.append(',');
+        }
+        key.append(')');
+
+        return key.toString();
+    }
+
+
+    private String createOperationKey(String methodName,
+            String[] parameterTypes) {
+        StringBuilder key = new StringBuilder(methodName);
+        key.append('(');
+        for (String parameter: parameterTypes) {
+            key.append(parameter);
+            // Note: A trailing ',' does not matter in this case
+            key.append(',');
+        }
+        key.append(')');
+
+        return key.toString();
+    }
 }
diff --git a/java/org/apache/tomcat/util/net/AbstractEndpoint.java b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
index 53983e7..df078a5 100644
--- a/java/org/apache/tomcat/util/net/AbstractEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AbstractEndpoint.java
@@ -626,7 +626,9 @@ public abstract class AbstractEndpoint {
 
         for (int i = 0; i < count; i++) {
             acceptors[i] = createAcceptor();
-            Thread t = new Thread(acceptors[i], getName() + "-Acceptor-" + i);
+            String threadName = getName() + "-Acceptor-" + i;
+            acceptors[i].setThreadName(threadName);
+            Thread t = new Thread(acceptors[i], threadName);
             t.setPriority(getAcceptorThreadPriority());
             t.setDaemon(getDaemon());
             t.start();
diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java
index e9b4d3c..7f4f2e6 100644
--- a/java/org/apache/tomcat/util/net/AprEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AprEndpoint.java
@@ -327,6 +327,19 @@ public class AprEndpoint extends AbstractEndpoint {
     public void setSSLHonorCipherOrder(boolean SSLHonorCipherOrder) { this.SSLHonorCipherOrder = SSLHonorCipherOrder; }
     public boolean getSSLHonorCipherOrder() { return SSLHonorCipherOrder; }
 
+    /**
+     * Disables compression of the SSL stream. This thwarts CRIME attack
+     * and possibly improves performance by not compressing uncompressible
+     * content such as JPEG, etc.
+     */
+    protected boolean SSLDisableCompression = false;
+
+    /**
+     * Set to <code>true</code> to disable SSL compression. This thwarts CRIME
+     * attack.
+     */
+    public void setSSLDisableCompression(boolean SSLDisableCompression) { this.SSLDisableCompression = SSLDisableCompression; }
+    public boolean getSSLDisableCompression() { return SSLDisableCompression; }
 
     /**
      * Port in use.
@@ -554,6 +567,23 @@ public class AprEndpoint extends AbstractEndpoint {
                 }
             }
 
+            // Disable compression if requested
+            if (SSLDisableCompression) {
+                boolean disableCompressionSupported = false;
+                try {
+                    disableCompressionSupported = SSL.hasOp(SSL.SSL_OP_NO_COMPRESSION);
+                    if (disableCompressionSupported)
+                        SSLContext.setOptions(sslContext, SSL.SSL_OP_NO_COMPRESSION);
+                } catch (UnsatisfiedLinkError e) {
+                    // Ignore
+                }
+                if (!disableCompressionSupported) {
+                    // OpenSSL does not support ciphers ordering.
+                    log.warn(sm.getString("endpoint.warn.noDisableCompression",
+                                          SSL.versionString()));
+                }
+            }
+
             // List the ciphers that the client is permitted to negotiate
             SSLContext.setCipherSuite(sslContext, SSLCipherSuite);
             // Load Server key and certificate
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index feb076c..e350109 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -388,6 +388,9 @@ public class NioEndpoint extends AbstractEndpoint {
     public SSLContext getSSLContext() { return sslContext;}
     public void setSSLContext(SSLContext c) { sslContext = c;}
 
+    private String[] enabledCiphers;
+    private String[] enabledProtocols;
+
 
     /**
      * Port in use.
@@ -495,6 +498,9 @@ public class NioEndpoint extends AbstractEndpoint {
             if (sessionContext != null) {
                 sslUtil.configureSessionContext(sessionContext);
             }
+            // Determine which cipher suites and protocols to enable
+            enabledCiphers = sslUtil.getEnableableCiphers(sslContext);
+            enabledProtocols = sslUtil.getEnableableProtocols(sslContext);
         }
 
         if (oomParachute>0) reclaimParachute(true);
@@ -700,8 +706,8 @@ public class NioEndpoint extends AbstractEndpoint {
             engine.setWantClientAuth(true);
         }
         engine.setUseClientMode(false);
-        if ( getCiphersArray().length > 0 ) engine.setEnabledCipherSuites(getCiphersArray());
-        if ( getSslEnabledProtocolsArray().length > 0 ) engine.setEnabledProtocols(getSslEnabledProtocolsArray());
+        engine.setEnabledCipherSuites(enabledCiphers);
+        engine.setEnabledProtocols(enabledProtocols);
 
         return engine;
     }
diff --git a/java/org/apache/tomcat/util/net/SSLUtil.java b/java/org/apache/tomcat/util/net/SSLUtil.java
index 0644779..ab16ce0 100644
--- a/java/org/apache/tomcat/util/net/SSLUtil.java
+++ b/java/org/apache/tomcat/util/net/SSLUtil.java
@@ -30,4 +30,32 @@ public interface SSLUtil {
     public TrustManager[] getTrustManagers() throws Exception;
 
     public void configureSessionContext(SSLSessionContext sslSessionContext);
+
+    /**
+     * Determines the SSL cipher suites that can be enabled, based on the
+     * configuration of the endpoint and the ciphers supported by the SSL
+     * implementation.
+     *
+     * @param context An initialized context to obtain the supported ciphers from.
+     *
+     * @return Array of SSL cipher suites that may be enabled (which may be
+     *         empty if none of the specified ciphers are supported), or
+     *         the defaults for the underlying SSL implementation if 
+     *         the endpoint configuration does not specify any ciphers.
+     */
+    public String[] getEnableableCiphers(SSLContext context);
+
+    /**
+     * Determines the SSL protocol variants that can be enabled, based on the
+     * configuration of the endpoint and the ciphers supported by the SSL
+     * implementation.
+     *
+     * @param context An initialized context to obtain the supported protocols from.
+     *
+     * @return Array of SSL protocol variants that may be enabled (which may be
+     *         empty if none of the specified protocols are supported), or
+     *         the defaults for the underlying SSL implementation if 
+     *         the endpoint configuration does not specify any protocols.
+     */
+    public String[] getEnableableProtocols(SSLContext context);
 }
diff --git a/java/org/apache/tomcat/util/net/URL.java b/java/org/apache/tomcat/util/net/URL.java
index 3da32e8..31da8ed 100644
--- a/java/org/apache/tomcat/util/net/URL.java
+++ b/java/org/apache/tomcat/util/net/URL.java
@@ -42,7 +42,7 @@ import java.util.Locale;
  * package someplace.</p>
  *
  * @author Craig R. McClanahan
- * @version $Id: URL.java 1200170 2011-11-10 05:54:22Z kkolinko $
+ * @version $Id: URL.java 1448144 2013-02-20 13:01:47Z markt $
  */
 
 public final class URL implements Serializable {
@@ -185,7 +185,10 @@ public final class URL implements Serializable {
      *
      * @exception MalformedURLException is never thrown, but present for
      *  compatible APIs
+     *
+     * @deprecated  Unused. Will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     public URL(String protocol, String host, String file)
         throws MalformedURLException {
 
@@ -207,7 +210,10 @@ public final class URL implements Serializable {
      *
      * @exception MalformedURLException is never thrown, but present for
      *  compatible APIs
+     *
+     * @deprecated  Unused. Will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     public URL(String protocol, String host, int port, String file)
         throws MalformedURLException {
 
@@ -543,7 +549,9 @@ public final class URL implements Serializable {
     /**
      * Return a string representation of this URL.  This follow the rules in
      * RFC 2396, Section 5.2, Step 7.
+     * @deprecated  Unused. Will be removed in Tomcat 8.0.x
      */
+    @Deprecated
     public String toExternalForm() {
 
         StringBuilder sb = new StringBuilder();
diff --git a/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java b/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java
index 3a98775..c971fb1 100644
--- a/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java
+++ b/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java
@@ -40,9 +40,11 @@ import java.security.cert.CertificateFactory;
 import java.security.cert.CollectionCertStoreParameters;
 import java.security.cert.PKIXBuilderParameters;
 import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
-import java.util.Vector;
 
 import javax.net.ssl.CertPathTrustManagerParameters;
 import javax.net.ssl.KeyManager;
@@ -87,6 +89,9 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil {
 
     private static final boolean RFC_5746_SUPPORTED;
 
+    private static final String[] DEFAULT_SERVER_PROTOCOLS;
+    private static final String[] DEAFULT_SERVER_CIPHER_SUITES;
+
     // Defaults - made public where re-used
     private static final String defaultProtocol = "TLS";
     private static final String defaultKeystoreType = "JKS";
@@ -100,23 +105,40 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil {
     static {
         boolean result = false;
         SSLContext context;
+        String[] ciphers = null;
+        String[] protocols = null;
         try {
             context = SSLContext.getInstance("TLS");
             context.init(null, null, null);
             SSLServerSocketFactory ssf = context.getServerSocketFactory();
-            String ciphers[] = ssf.getSupportedCipherSuites();
-            for (String cipher : ciphers) {
+            String supportedCiphers[] = ssf.getSupportedCipherSuites();
+            for (String cipher : supportedCiphers) {
                 if ("TLS_EMPTY_RENEGOTIATION_INFO_SCSV".equals(cipher)) {
                     result = true;
                     break;
                 }
             }
+
+            // There is no API to obtain the default server protocols and cipher
+            // suites. Having inspected the OpenJDK code there the same results
+            // can be achieved via the standard API but there is no guarantee
+            // that every JVM implementation determines the defaults the same
+            // way. Therefore the defaults are determined by creating a server
+            // socket and requested the configured values.
+
+            SSLServerSocket socket = (SSLServerSocket) ssf.createServerSocket();
+            ciphers = socket.getEnabledCipherSuites();
+            protocols = socket.getEnabledProtocols();
         } catch (NoSuchAlgorithmException e) {
             // Assume no RFC 5746 support
         } catch (KeyManagementException e) {
             // Assume no RFC 5746 support
+        } catch (IOException e) {
+            // Unable to determine default ciphers/protocols so use none
         }
         RFC_5746_SUPPORTED = result;
+        DEAFULT_SERVER_CIPHER_SUITES = ciphers;
+        DEFAULT_SERVER_PROTOCOLS = protocols;
     }
 
 
@@ -124,6 +146,7 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil {
 
     protected SSLServerSocketFactory sslProxy = null;
     protected String[] enabledCiphers;
+    protected String[] enabledProtocols;
     protected boolean allowUnsafeLegacyRenegotiation = false;
 
     /**
@@ -199,84 +222,46 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil {
         }
     }
 
-    /*
-     * Determines the SSL cipher suites to be enabled.
-     *
-     * @param requestedCiphers Comma-separated list of requested ciphers
-     * @param supportedCiphers Array of supported ciphers
-     *
-     * @return Array of SSL cipher suites to be enabled, or null if none of the
-     * requested ciphers are supported
-     */
-    protected String[] getEnabledCiphers(String requestedCiphers,
-                                         String[] supportedCiphers) {
-
-        String[] result = null;
-
-        if (ALLOW_ALL_SUPPORTED_CIPHERS.equals(requestedCiphers)) {
-            return supportedCiphers;
-        }
-
-        if (requestedCiphers != null) {
-            Vector<String> vec = null;
-            String cipher = requestedCiphers;
-            int index = requestedCiphers.indexOf(',');
-            if (index != -1) {
-                int fromIndex = 0;
-                while (index != -1) {
-                    cipher =
-                        requestedCiphers.substring(fromIndex, index).trim();
-                    if (cipher.length() > 0) {
-                        /*
-                         * Check to see if the requested cipher is among the
-                         * supported ciphers, i.e., may be enabled
-                         */
-                        for (int i=0; supportedCiphers != null
-                                     && i<supportedCiphers.length; i++) {
-                            if (supportedCiphers[i].equals(cipher)) {
-                                if (vec == null) {
-                                    vec = new Vector<String>();
-                                }
-                                vec.addElement(cipher);
-                                break;
-                            }
-                        }
-                    }
-                    fromIndex = index+1;
-                    index = requestedCiphers.indexOf(',', fromIndex);
-                } // while
-                cipher = requestedCiphers.substring(fromIndex);
-            }
+    @Override
+    public String[] getEnableableCiphers(SSLContext context) {
+        String requestedCiphersStr = endpoint.getCiphers();
 
-            if (cipher != null) {
-                cipher = cipher.trim();
-                if (cipher.length() > 0) {
-                    /*
-                     * Check to see if the requested cipher is among the
-                     * supported ciphers, i.e., may be enabled
-                     */
-                    for (int i=0; supportedCiphers != null
-                                 && i<supportedCiphers.length; i++) {
-                        if (supportedCiphers[i].equals(cipher)) {
-                            if (vec == null) {
-                                vec = new Vector<String>();
-                            }
-                            vec.addElement(cipher);
-                            break;
-                        }
-                    }
-                }
+        if (ALLOW_ALL_SUPPORTED_CIPHERS.equals(requestedCiphersStr)) {
+            return context.getSupportedSSLParameters().getCipherSuites();
+        }
+        if ((requestedCiphersStr == null)
+                || (requestedCiphersStr.trim().length() == 0)) {
+            return DEAFULT_SERVER_CIPHER_SUITES;
+        }
+
+        List<String> requestedCiphers = new ArrayList<String>();
+        for (String rc : requestedCiphersStr.split(",")) {
+            final String cipher = rc.trim();
+            if (cipher.length() > 0) {
+                requestedCiphers.add(cipher);
             }
+        }
+        if (requestedCiphers.isEmpty()) {
+            return DEAFULT_SERVER_CIPHER_SUITES;
+        }
+        List<String> ciphers = new ArrayList<String>(requestedCiphers);
+        ciphers.retainAll(Arrays.asList(context.getSupportedSSLParameters()
+                .getCipherSuites()));
 
-            if (vec != null) {
-                result = new String[vec.size()];
-                vec.copyInto(result);
+        if (ciphers.isEmpty()) {
+            log.warn(sm.getString("jsse.requested_ciphers_not_supported",
+                    requestedCiphersStr));
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jsse.enableable_ciphers", ciphers));
+            if (ciphers.size() != requestedCiphers.size()) {
+                List<String> skipped = new ArrayList<String>(requestedCiphers);
+                skipped.removeAll(ciphers);
+                log.debug(sm.getString("jsse.unsupported_ciphers", skipped));
             }
-        } else {
-            result = sslProxy.getDefaultCipherSuites();
         }
 
-        return result;
+        return ciphers.toArray(new String[ciphers.size()]);
     }
 
     /*
@@ -459,9 +444,8 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil {
             sslProxy = context.getServerSocketFactory();
 
             // Determine which cipher suites to enable
-            String requestedCiphers = endpoint.getCiphers();
-            enabledCiphers = getEnabledCiphers(requestedCiphers,
-                    sslProxy.getSupportedCipherSuites());
+            enabledCiphers = getEnableableCiphers(context);
+            enabledProtocols = getEnableableProtocols(context);
 
             allowUnsafeLegacyRenegotiation = "true".equals(
                     endpoint.getAllowUnsafeLegacyRenegotiation());
@@ -709,60 +693,32 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil {
         return crls;
     }
 
-    /**
-     * Set the SSL protocol variants to be enabled.
-     * @param socket the SSLServerSocket.
-     * @param protocols the protocols to use.
-     */
-    protected void setEnabledProtocols(SSLServerSocket socket,
-            String []protocols){
-        if (protocols != null) {
-            socket.setEnabledProtocols(protocols);
-        }
-    }
-
-    /**
-     * Determines the SSL protocol variants to be enabled.
-     *
-     * @param socket The socket to get supported list from.
-     * @param requestedProtocols Array of requested protocol names all of which
-     *                           must be non-null and non-zero length
-     *
-     * @return Array of SSL protocol variants to be enabled, or null if none of
-     * the requested protocol variants are supported
-     */
-    protected String[] getEnabledProtocols(SSLServerSocket socket,
-                                           String[] requestedProtocols){
-        String[] supportedProtocols = socket.getSupportedProtocols();
-
-        String[] enabledProtocols = null;
-
-        if (requestedProtocols != null && requestedProtocols.length > 0) {
-            Vector<String> vec = null;
-            for (String protocol : requestedProtocols) {
-                /*
-                 * Check to see if the requested protocol is among the supported
-                 * protocols, i.e., may be enabled
-                 */
-                for (int i=0; supportedProtocols != null &&
-                        i < supportedProtocols.length; i++) {
-                    if (supportedProtocols[i].equals(protocol)) {
-                        if (vec == null) {
-                            vec = new Vector<String>();
-                        }
-                        vec.addElement(protocol);
-                        break;
-                    }
-                }
-            }
-
-            if (vec != null) {
-                enabledProtocols = new String[vec.size()];
-                vec.copyInto(enabledProtocols);
+    @Override
+    public String[] getEnableableProtocols(SSLContext context) {
+        String[] requestedProtocols = endpoint.getSslEnabledProtocolsArray();
+        if ((requestedProtocols == null) || (requestedProtocols.length == 0)) {
+            return DEFAULT_SERVER_PROTOCOLS;
+        }
+
+        List<String> protocols = new ArrayList<String>(
+                Arrays.asList(requestedProtocols));
+        protocols.retainAll(Arrays.asList(context.getSupportedSSLParameters()
+                .getProtocols()));
+
+        if (protocols.isEmpty()) {
+            log.warn(sm.getString("jsse.requested_protocols_not_supported",
+                    Arrays.asList(requestedProtocols)));
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jsse.enableable_protocols", protocols));
+            if (protocols.size() != requestedProtocols.length) {
+                List<String> skipped = new ArrayList<String>(
+                        Arrays.asList(requestedProtocols));
+                skipped.removeAll(protocols);
+                log.debug(sm.getString("jsse.unsupported_protocols", skipped));
             }
         }
-
-        return enabledProtocols;
+        return protocols.toArray(new String[protocols.size()]);
     }
 
     /**
@@ -787,14 +743,9 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil {
 
         SSLServerSocket socket = (SSLServerSocket) ssocket;
 
-        if (enabledCiphers != null) {
-            socket.setEnabledCipherSuites(enabledCiphers);
-        }
-
-        String[] requestedProtocols = endpoint.getSslEnabledProtocolsArray();
-        setEnabledProtocols(socket, getEnabledProtocols(socket,
-                                                         requestedProtocols));
-
+        socket.setEnabledCipherSuites(enabledCiphers);
+        socket.setEnabledProtocols(enabledProtocols);
+        
         // we don't know if client auth is needed -
         // after parsing the request we may re-handshake
         configureClientAuth(socket);
diff --git a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
index a01e0c9..f629c73 100644
--- a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
@@ -18,6 +18,12 @@ jsse.keystore_load_failed=Failed to load keystore type {0} with path {1} due to
 jsse.invalid_ssl_conf=SSL configuration is invalid due to {0}
 jsse.invalid_truststore_password=The provided trust store password could not be used to unlock and/or validate the trust store. Retrying to access the trust store with a null password which will skip validation.
 jsse.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager
+jsse.requested_ciphers_not_supported=None of the ciphers specified are supported by the SSL engine : {0}
+jsse.enableable_ciphers=Specified SSL ciphers that are supported and enableable are : {0}
+jsse.unsupported_ciphers=Some specified SSL ciphers are not supported by the SSL engine : {0}
+jsse.requested_protocols_not_supported=None of the SSL protocols specified are supported by the SSL engine : {0}
+jsse.enableable_protocols=Specified SSL protocols that are supported and enableable are : {0}
+jsse.unsupported_protocols=Some specified SSL protocols are not supported by the SSL engine : {0}
 jsseSupport.clientCertError=Error trying to obtain a certificate from the client
 jseeSupport.certTranslationError=Error translating certificate [{0}]
 jsseSupport.noCertWant=No client certificate sent for want
diff --git a/java/org/apache/tomcat/util/net/res/LocalStrings.properties b/java/org/apache/tomcat/util/net/res/LocalStrings.properties
index 56d9038..869f56b 100644
--- a/java/org/apache/tomcat/util/net/res/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/res/LocalStrings.properties
@@ -41,6 +41,7 @@ endpoint.process.fail=Error allocating socket processor
 endpoint.sendfile.error=Unexpected sendfile error
 endpoint.sendfile.addfail=Sendfile failure: [{0}] {1}
 endpoint.sendfile.nosupport=Disabling sendfile, since either the APR version or the system doesn't support it
+endpoint.warn.noDisableCompression='Disable compression' option is not supported by the SSL library {0}
 endpoint.warn.noInsecureReneg=Secure re-negotiation is not supported by the SSL library {0}
 endpoint.warn.noHonorCipherOrder='Honor cipher order' option is not supported by the SSL library {0}
 endpoint.warn.unlockAcceptorFailed=Acceptor thread [{0}] failed to unlock. Forcing hard socket shutdown.
diff --git a/java/org/apache/tomcat/util/scan/StandardJarScanner.java b/java/org/apache/tomcat/util/scan/StandardJarScanner.java
index 7efc51d..27ce670 100644
--- a/java/org/apache/tomcat/util/scan/StandardJarScanner.java
+++ b/java/org/apache/tomcat/util/scan/StandardJarScanner.java
@@ -109,6 +109,18 @@ public class StandardJarScanner implements JarScanner {
     }
 
     /**
+     * Controls the testing of the bootstrap classpath which consists of the
+     * runtime classes provided by the JVM and any installed system extensions.
+     */
+    private boolean scanBootstrapClassPath = false;
+    public boolean isScanBootstrapClassPath() {
+        return scanBootstrapClassPath;
+    }
+    public void setScanBootstrapClassPath(boolean scanBootstrapClassPath) {
+        this.scanBootstrapClassPath = scanBootstrapClassPath;
+    }
+
+    /**
      * Scan the provided ServletContext and classloader for JAR files. Each JAR
      * file found will be passed to the callback handler to be processed.
      *
@@ -176,15 +188,20 @@ public class StandardJarScanner implements JarScanner {
         }
 
         // Scan the classpath
-        if (scanClassPath) {
+        if (scanClassPath && classloader != null) {
             if (log.isTraceEnabled()) {
                 log.trace(sm.getString("jarScan.classloaderStart"));
             }
 
-            ClassLoader loader =
-                Thread.currentThread().getContextClassLoader();
+            ClassLoader loader = classloader;
+
+            ClassLoader stopLoader = null;
+            if (!scanBootstrapClassPath) {
+                // Stop when we reach the bootstrap class loader
+                stopLoader = ClassLoader.getSystemClassLoader().getParent();
+            }
 
-            while (loader != null) {
+            while (loader != null && loader != stopLoader) {
                 if (loader instanceof URLClassLoader) {
                     URL[] urls = ((URLClassLoader) loader).getURLs();
                     for (int i=0; i<urls.length; i++) {
diff --git a/modules/jdbc-pool/build.properties.default b/modules/jdbc-pool/build.properties.default
index a144e6b..dddb359 100644
--- a/modules/jdbc-pool/build.properties.default
+++ b/modules/jdbc-pool/build.properties.default
@@ -62,11 +62,11 @@ testdb.validationQuery=SELECT 1
 #testdb.driverClassName=org.apache.derby.jdbc.EmbeddedDriver
 #testdb.validationQuery=VALUES 1
 
-# ----- JUnit Unit Test Suite, version 3.7 or later -----
-junit.home=${base.path}/junit3.8.2
+# ----- JUnit Unit Test Suite, version 4.8 or later -----
+junit.home=${base.path}/junit4.8.2
 junit.lib=${junit.home}
-junit.jar=${junit.lib}/junit.jar
-junit.loc=http://downloads.sourceforge.net/junit/junit3.8.2.zip
+junit.jar=${junit.lib}/junit-4.8.2.jar
+junit.loc=http://cloud.github.com/downloads/KentBeck/junit/junit4.8.2.zip
 
 c3p0.home=${base.path}/c3p0-0.9.1.2
 c3p0.jar=${c3p0.home}/lib/c3p0-0.9.1.2.jar
diff --git a/modules/jdbc-pool/resources/MANIFEST.MF b/modules/jdbc-pool/resources/MANIFEST.MF
index 6470f3a..60dac2e 100644
--- a/modules/jdbc-pool/resources/MANIFEST.MF
+++ b/modules/jdbc-pool/resources/MANIFEST.MF
@@ -18,5 +18,6 @@ Import-Package:
   javax.management;version="0",
   javax.management.openmbean;version="0",
   javax.naming;version="0",
+  javax.naming.spi;version="0",
   javax.sql;version="0",
-  org.apache.juli.logging;version="[6.0.18, 7.0.0)"
+  org.apache.juli.logging;version="[6.0.18, 7.1.0)"
diff --git a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
index becd283..18ebbda 100644
--- a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
+++ b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
@@ -802,28 +802,33 @@ public class PoolProperties implements PoolConfiguration, Cloneable, Serializabl
         StringBuilder buf = new StringBuilder("ConnectionPool[");
         try {
             String[] fields = DataSourceFactory.ALL_PROPERTIES;
-            for (int i=0; i<fields.length; i++) {
+            for (String field: fields) {
                 final String[] prefix = new String[] {"get","is"};
                 for (int j=0; j<prefix.length; j++) {
 
-                    String name = prefix[j] + fields[i].substring(0, 1).toUpperCase(Locale.US) +
-                                  fields[i].substring(1);
+                    String name = prefix[j]
+                            + field.substring(0, 1).toUpperCase(Locale.ENGLISH)
+                            + field.substring(1);
                     Method m = null;
                     try {
                         m = getClass().getMethod(name);
                     }catch (NoSuchMethodException nm) {
                         continue;
                     }
-                    buf.append(fields[i]);
+                    buf.append(field);
                     buf.append("=");
-                    buf.append(m.invoke(this, new Object[0]));
+                    if (DataSourceFactory.PROP_PASSWORD.equals(field)) {
+                        buf.append("********");
+                    } else {
+                        buf.append(m.invoke(this, new Object[0]));
+                    }
                     buf.append("; ");
                     break;
                 }
             }
         }catch (Exception x) {
-            //shouldn;t happen
-            x.printStackTrace();
+            //shouldn't happen
+            log.debug("toString() call failed", x);
         }
         return buf.toString();
     }
diff --git a/res/maven/mvn.properties.default b/res/maven/mvn.properties.default
index 38b0abb..5fc1f39 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=7.0.35
+maven.asf.release.deploy.version=7.0.39
 
 #Where do we load the libraries from
 tomcat.lib.path=../../output/build/lib
diff --git a/res/maven/tomcat-embed-jasper.pom b/res/maven/tomcat-embed-jasper.pom
index 4ab7696..20f3e1e 100644
--- a/res/maven/tomcat-embed-jasper.pom
+++ b/res/maven/tomcat-embed-jasper.pom
@@ -39,7 +39,7 @@
     <dependency>
       <groupId>org.eclipse.jdt.core.compiler</groupId>
       <artifactId>ecj</artifactId>
-      <version>3.7.2</version>
+      <version>4.2.1</version>
     </dependency>
   </dependencies>
 </project>
diff --git a/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java b/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java
index f741dc9..647f893 100644
--- a/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java
+++ b/test/org/apache/catalina/authenticator/TestDigestAuthenticator.java
@@ -18,15 +18,21 @@ package org.apache.catalina.authenticator;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import org.junit.Assert;
 import org.junit.Test;
 
 import org.apache.catalina.Context;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.core.TesterContext;
 import org.apache.catalina.deploy.LoginConfig;
 import org.apache.catalina.deploy.SecurityCollection;
 import org.apache.catalina.deploy.SecurityConstraint;
@@ -53,6 +59,25 @@ public class TestDigestAuthenticator extends TomcatBaseTest {
     private static String NC2 = "00000002";
     private static String QOP = "auth";
 
+
+    @Test
+    public void bug54521() throws LifecycleException {
+        DigestAuthenticator digestAuthenticator = new DigestAuthenticator();
+        digestAuthenticator.setContainer(new TesterContext());
+        digestAuthenticator.start();
+        Request request = new TesterRequest();
+        final int count = 1000;
+
+        Set<String> nonces = new HashSet<String>();
+
+        for (int i = 0; i < count; i++) {
+            nonces.add(digestAuthenticator.generateNonce(request));
+        }
+
+        Assert.assertEquals(count,  nonces.size());
+    }
+
+
     @Test
     public void testAllValid() throws Exception {
         doTest(USER, PWD, CONTEXT_PATH + URI, false, true, REALM, true, true,
@@ -363,4 +388,13 @@ public class TestDigestAuthenticator extends TomcatBaseTest {
         return MD5Encoder.encode(
                 ConcurrentMessageDigest.digestMD5(input.getBytes()));
     }
+
+
+    private static class TesterRequest extends Request {
+
+        @Override
+        public String getRemoteAddr() {
+            return "127.0.0.1";
+        }
+    }
 }
diff --git a/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java b/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java
index fb8d7a3..1364e69 100644
--- a/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java
+++ b/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java
@@ -36,8 +36,9 @@ import org.apache.catalina.session.ManagerBase;
 import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
-import org.apache.catalina.util.Base64;
+import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.codec.binary.Base64;
 
 /**
  * Test BasicAuthenticator and NonLoginAuthenticator when a
@@ -197,18 +198,20 @@ public class TestNonLoginAndBasicAuthenticator extends TomcatBaseTest {
      * This is the same as testAcceptProtectedBasic (above), except
      * using excess white space after the authentication method.
      *
-     * The request is rejected with 401 SC_UNAUTHORIZED status.
+     * The access will be challenged with 401 SC_UNAUTHORIZED, and then be
+     * permitted once authenticated.
      *
-     * TODO: RFC2617 does not define the separation syntax between the
-     *       auth-scheme and basic-credentials tokens. Tomcat should tolerate
-     *       any reasonable amount of white space and return SC_OK.
+     * RFC2617 does not define the separation syntax between the auth-scheme and
+     * basic-credentials tokens. Tomcat tolerates any amount of white space
+     * (within the limits of HTTP header sizes) and returns SC_OK.
      */
     @Test
     public void testAuthMethodExtraSpace() throws Exception {
         doTestBasic(CONTEXT_PATH_LOGIN + URI_PROTECTED, NO_CREDENTIALS,
                 NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
         doTestBasic(CONTEXT_PATH_LOGIN + URI_PROTECTED, SPACED_BASE64,
-                NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
+                NO_COOKIES, HttpServletResponse.SC_OK);
+
     }
 
     /*
@@ -611,8 +614,9 @@ public class TestNonLoginAndBasicAuthenticator extends TomcatBaseTest {
             username = aUsername;
             password = aPassword;
             String userCredentials = username + ":" + password;
-            byte[] credentialsBytes = ByteChunk.convertToBytes(userCredentials);
-            String base64auth = Base64.encode(credentialsBytes);
+            byte[] credentialsBytes =
+                    userCredentials.getBytes(B2CConverter.ISO_8859_1);
+            String base64auth = Base64.encodeBase64String(credentialsBytes);
             credentials= method + " " + base64auth;
         }
 
diff --git a/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java b/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java
index 06ea775..cece327 100644
--- a/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java
+++ b/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java
@@ -34,8 +34,9 @@ import org.apache.catalina.deploy.SecurityConstraint;
 import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
-import org.apache.catalina.util.Base64;
+import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.codec.binary.Base64;
 
 /**
  * Test BasicAuthenticator and NonLoginAuthenticator when a
@@ -236,10 +237,11 @@ public class TestSSOnonLoginAndBasicAuthenticator extends TomcatBaseTest {
             return;
         }
 
-        // the second access attempt should be sucessful
+        // the second access attempt should be successful
         String credentials = user + ":" + pwd;
-        byte[] credentialsBytes = ByteChunk.convertToBytes(credentials);
-        String base64auth = Base64.encode(credentialsBytes);
+
+        String base64auth = Base64.encodeBase64String(
+                credentials.getBytes(B2CConverter.ISO_8859_1));
         String authLine = "Basic " + base64auth;
 
         List<String> auth = new ArrayList<String>();
diff --git a/test/org/apache/catalina/connector/TestCoyoteAdapter.java b/test/org/apache/catalina/connector/TestCoyoteAdapter.java
index 51b066c..39c6e1e 100644
--- a/test/org/apache/catalina/connector/TestCoyoteAdapter.java
+++ b/test/org/apache/catalina/connector/TestCoyoteAdapter.java
@@ -25,9 +25,7 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
+import org.junit.Assert;
 import org.junit.Test;
 
 import org.apache.catalina.Context;
@@ -89,7 +87,7 @@ public class TestCoyoteAdapter extends TomcatBaseTest {
         File foo = new File(docBase, "foo");
         addDeleteOnTearDown(foo);
         if (!foo.mkdirs() && !foo.isDirectory()) {
-            fail("Unable to create foo directory in docBase");
+            Assert.fail("Unable to create foo directory in docBase");
         }
 
         Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
@@ -122,12 +120,12 @@ public class TestCoyoteAdapter extends TomcatBaseTest {
         tomcat.start();
 
         ByteChunk res = getUrl("http://localhost:" + getPort() + path);
-        assertEquals(expected, res.toString());
+        Assert.assertEquals(expected, res.toString());
     }
 
     private void testPath(String path, String expected) throws Exception {
         ByteChunk res = getUrl("http://localhost:" + getPort() + path);
-        assertEquals(expected, res.toString());
+        Assert.assertEquals(expected, res.toString());
     }
 
     private static class PathParamServlet extends HttpServlet {
@@ -176,6 +174,80 @@ public class TestCoyoteAdapter extends TomcatBaseTest {
         tomcat.start();
 
         ByteChunk res = getUrl("http://localhost:" + getPort() + path);
-        assertEquals(expected, res.toString());
+        Assert.assertEquals(expected, res.toString());
+    }
+
+    @Test
+    public void testBug54602a() throws Exception {
+        // No UTF-8
+        doTestUriDecoding("/foo", "UTF-8", "/foo");
+    }
+
+    @Test
+    public void testBug54602b() throws Exception {
+        // Valid UTF-8
+        doTestUriDecoding("/foo%c4%87", "UTF-8", "/foo\u0107");
+    }
+
+    @Test
+    public void testBug54602c() throws Exception {
+        // Partial UTF-8
+        doTestUriDecoding("/foo%c4", "UTF-8", "/foo\uFFFD");
+    }
+
+    @Test
+    public void testBug54602d() throws Exception {
+        // Invalid UTF-8
+        doTestUriDecoding("/foo%ff", "UTF-8", "/foo\uFFFD");
+    }
+
+    @Test
+    public void testBug54602e() throws Exception {
+        // Invalid UTF-8
+        doTestUriDecoding("/foo%ed%a0%80", "UTF-8", "/foo\uFFFD\uFFFD\uFFFD");
+    }
+
+    private void doTestUriDecoding(String path, String encoding,
+            String expectedPathInfo) throws Exception{
+
+        // Setup Tomcat instance
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.getConnector().setURIEncoding(encoding);
+
+        // Must have a real docBase - just use temp
+        Context ctx =
+            tomcat.addContext("/", System.getProperty("java.io.tmpdir"));
+
+        PathInfoServlet servlet = new PathInfoServlet();
+        Tomcat.addServlet(ctx, "servlet", servlet);
+        ctx.addServletMapping("/*", "servlet");
+
+        tomcat.start();
+
+        int rc = getUrl("http://localhost:" + getPort() + path,
+                new ByteChunk(), null);
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+
+        Assert.assertEquals(expectedPathInfo, servlet.getPathInfo());
+    }
+
+    private static class PathInfoServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        private String pathInfo = null;
+
+        public String getPathInfo() {
+            return pathInfo;
+        }
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+
+            // Not thread safe
+            pathInfo = req.getPathInfo();
+        }
     }
 }
diff --git a/test/org/apache/catalina/connector/TestInputBuffer.java b/test/org/apache/catalina/connector/TestInputBuffer.java
new file mode 100644
index 0000000..2b21aa0
--- /dev/null
+++ b/test/org/apache/catalina/connector/TestInputBuffer.java
@@ -0,0 +1,115 @@
+/*
+ * 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.catalina.connector;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.TestUtf8;
+import org.apache.tomcat.util.buf.TestUtf8.Utf8TestCase;
+
+public class TestInputBuffer extends TomcatBaseTest {
+
+    @Test
+    public void testUtf8Body() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        Context root = tomcat.addContext("", TEMP_DIR);
+        Tomcat.addServlet(root, "Echo", new Utf8Echo());
+        root.addServletMapping("/test", "Echo");
+
+        tomcat.getConnector().setProperty("soTimeout", "300000");
+        tomcat.start();
+
+        for (Utf8TestCase testCase : TestUtf8.TEST_CASES) {
+            String expected = null;
+            if (testCase.invalidIndex == -1) {
+                expected = testCase.outputReplaced;
+            }
+            doUtf8BodyTest(testCase.description, testCase.input, expected);
+        }
+    }
+
+
+    private void doUtf8BodyTest(String description, int[] input,
+            String expected) throws Exception {
+
+        byte[] bytes = new byte[input.length];
+        for (int i = 0; i < input.length; i++) {
+            bytes[i] = (byte) input[i];
+        }
+
+        ByteChunk bc = new ByteChunk();
+        int rc = postUrl(bytes, "http://localhost:" + getPort() + "/test", bc,
+                null);
+
+        if (expected == null) {
+            Assert.assertEquals(description,
+                    HttpServletResponse.SC_INTERNAL_SERVER_ERROR, rc);
+        } else if (expected.length() == 0) {
+            Assert.assertNull(description, bc.toString());
+        } else {
+            bc.setCharset(B2CConverter.UTF_8);
+            Assert.assertEquals(description, expected, bc.toString());
+        }
+    }
+
+
+    private static class Utf8Echo extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            // Should use POST
+            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+        }
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            req.setCharacterEncoding("UTF-8");
+            Reader r = req.getReader();
+
+            resp.setCharacterEncoding("UTF-8");
+            resp.setContentType("text/plain");
+            Writer w = resp.getWriter();
+
+            // Copy one character at a time
+            int c = r.read();
+            while (c != -1) {
+                w.write(c);
+                c = r.read();
+            }
+            w.close();
+        }
+    }
+}
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java
index 3b50581..e875cfc 100644
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
@@ -60,7 +60,7 @@ import org.apache.tomcat.util.buf.ByteChunk;
 public class TestAsyncContextImpl extends TomcatBaseTest {
 
     // Time for a request to process (need to allow for threads to start etc.)
-    private static final long REQUEST_TIME = 1000;
+    private static final long REQUEST_TIME = 1500;
     // Timeout thread (where used) checks for timeout every second
     private static final long TIMEOUT_MARGIN = 1000;
     // Default timeout for these tests
diff --git a/test/org/apache/catalina/core/TesterContext.java b/test/org/apache/catalina/core/TesterContext.java
new file mode 100644
index 0000000..bc3c9f6
--- /dev/null
+++ b/test/org/apache/catalina/core/TesterContext.java
@@ -0,0 +1,1179 @@
+/*
+ * 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.catalina.core;
+
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.ObjectName;
+import javax.naming.directory.DirContext;
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.descriptor.JspConfigDescriptor;
+
+import org.apache.catalina.AccessLog;
+import org.apache.catalina.Authenticator;
+import org.apache.catalina.Cluster;
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerListener;
+import org.apache.catalina.Context;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.LifecycleState;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.ApplicationParameter;
+import org.apache.catalina.deploy.ErrorPage;
+import org.apache.catalina.deploy.FilterDef;
+import org.apache.catalina.deploy.FilterMap;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.util.CharsetMapper;
+import org.apache.juli.logging.Log;
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.util.http.mapper.Mapper;
+
+/**
+ * Minimal implementation for use in unit tests.
+ */
+public class TesterContext implements Context {
+
+    @Override
+    public Log getLogger() {
+        return null;
+    }
+
+    @Override
+    public ObjectName getObjectName() {
+        return null;
+    }
+
+    @Override
+    public Pipeline getPipeline() {
+        return null;
+    }
+
+    @Override
+    public Cluster getCluster() {
+        return null;
+    }
+
+    @Override
+    public void setCluster(Cluster cluster) {
+        // NO-OP
+    }
+
+    @Override
+    public int getBackgroundProcessorDelay() {
+        return 0;
+    }
+
+    @Override
+    public void setBackgroundProcessorDelay(int delay) {
+        // NO-OP
+    }
+
+    @Override
+    public String getName() {
+        return "/test";
+    }
+
+    @Override
+    public void setName(String name) {
+        // NO-OP
+    }
+
+    @Override
+    public Container getParent() {
+        return null;
+    }
+
+    @Override
+    public void setParent(Container container) {
+        // NO-OP
+    }
+
+    @Override
+    public ClassLoader getParentClassLoader() {
+        return null;
+    }
+
+    @Override
+    public void setParentClassLoader(ClassLoader parent) {
+        // NO-OP
+    }
+
+    @Override
+    public Realm getRealm() {
+        return null;
+    }
+
+    @Override
+    public void setRealm(Realm realm) {
+        // NO-OP
+    }
+
+    @Override
+    public void backgroundProcess() {
+        // NO-OP
+    }
+
+    @Override
+    public void addChild(Container child) {
+        // NO-OP
+    }
+
+    @Override
+    public void addContainerListener(ContainerListener listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        // NO-OP
+    }
+
+    @Override
+    public Container findChild(String name) {
+        return null;
+    }
+
+    @Override
+    public Container[] findChildren() {
+        return null;
+    }
+
+    @Override
+    public ContainerListener[] findContainerListeners() {
+        return null;
+    }
+
+    @Override
+    public void removeChild(Container child) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeContainerListener(ContainerListener listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void fireContainerEvent(String type, Object data) {
+        // NO-OP
+    }
+
+    @Override
+    public void logAccess(Request request, Response response, long time,
+            boolean useDefault) {
+        // NO-OP
+    }
+
+    @Override
+    public AccessLog getAccessLog() {
+        return null;
+    }
+
+    @Override
+    public int getStartStopThreads() {
+        return 0;
+    }
+
+    @Override
+    public void setStartStopThreads(int startStopThreads) {
+        // NO-OP
+    }
+
+    @Override
+    public void addLifecycleListener(LifecycleListener listener) {
+        // NO-OP
+    }
+
+    @Override
+    public LifecycleListener[] findLifecycleListeners() {
+        return null;
+    }
+
+    @Override
+    public void removeLifecycleListener(LifecycleListener listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void init() throws LifecycleException {
+        // NO-OP
+    }
+
+    @Override
+    public void start() throws LifecycleException {
+        // NO-OP
+    }
+
+    @Override
+    public void stop() throws LifecycleException {
+        // NO-OP
+    }
+
+    @Override
+    public void destroy() throws LifecycleException {
+        // NO-OP
+    }
+
+    @Override
+    public LifecycleState getState() {
+        return null;
+    }
+
+    @Override
+    public String getStateName() {
+        return null;
+    }
+
+    @Override
+    public boolean getAllowCasualMultipartParsing() {
+        return false;
+    }
+
+    @Override
+    public void setAllowCasualMultipartParsing(
+            boolean allowCasualMultipartParsing) {
+        // NO-OP
+    }
+
+    @Override
+    public Object[] getApplicationEventListeners() {
+        return null;
+    }
+
+    @Override
+    public void setApplicationEventListeners(Object[] listeners) {
+        // NO-OP
+    }
+
+    @Override
+    public Object[] getApplicationLifecycleListeners() {
+        return null;
+    }
+
+    @Override
+    public void setApplicationLifecycleListeners(Object[] listeners) {
+        // NO-OP
+    }
+
+    @Override
+    public String getCharset(Locale locale) {
+        return null;
+    }
+
+    @Override
+    public URL getConfigFile() {
+        return null;
+    }
+
+    @Override
+    public void setConfigFile(URL configFile) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getConfigured() {
+        return false;
+    }
+
+    @Override
+    public void setConfigured(boolean configured) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getCookies() {
+        return false;
+    }
+
+    @Override
+    public void setCookies(boolean cookies) {
+        // NO-OP
+    }
+
+    @Override
+    public String getSessionCookieName() {
+        return null;
+    }
+
+    @Override
+    public void setSessionCookieName(String sessionCookieName) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getUseHttpOnly() {
+        return false;
+    }
+
+    @Override
+    public void setUseHttpOnly(boolean useHttpOnly) {
+        // NO-OP
+    }
+
+    @Override
+    public String getSessionCookieDomain() {
+        return null;
+    }
+
+    @Override
+    public void setSessionCookieDomain(String sessionCookieDomain) {
+        // NO-OP
+    }
+
+    @Override
+    public String getSessionCookiePath() {
+        return null;
+    }
+
+    @Override
+    public void setSessionCookiePath(String sessionCookiePath) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getSessionCookiePathUsesTrailingSlash() {
+        return false;
+    }
+
+    @Override
+    public void setSessionCookiePathUsesTrailingSlash(
+            boolean sessionCookiePathUsesTrailingSlash) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getCrossContext() {
+        return false;
+    }
+
+    @Override
+    public String getAltDDName() {
+        return null;
+    }
+
+    @Override
+    public void setAltDDName(String altDDName) {
+        // NO-OP
+    }
+
+    @Override
+    public void setCrossContext(boolean crossContext) {
+        // NO-OP
+    }
+
+    @Override
+    public String getDisplayName() {
+        return null;
+    }
+
+    @Override
+    public void setDisplayName(String displayName) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getDistributable() {
+        return false;
+    }
+
+    @Override
+    public void setDistributable(boolean distributable) {
+        // NO-OP
+    }
+
+    @Override
+    public String getDocBase() {
+        return null;
+    }
+
+    @Override
+    public void setDocBase(String docBase) {
+        // NO-OP
+    }
+
+    @Override
+    public String getEncodedPath() {
+        return null;
+    }
+
+    @Override
+    public boolean getIgnoreAnnotations() {
+        return false;
+    }
+
+    @Override
+    public void setIgnoreAnnotations(boolean ignoreAnnotations) {
+        // NO-OP
+    }
+
+    @Override
+    public LoginConfig getLoginConfig() {
+        return null;
+    }
+
+    @Override
+    public void setLoginConfig(LoginConfig config) {
+        // NO-OP
+    }
+
+    @Override
+    public NamingResources getNamingResources() {
+        return null;
+    }
+
+    @Override
+    public void setNamingResources(NamingResources namingResources) {
+        // NO-OP
+    }
+
+    @Override
+    public String getPath() {
+        return null;
+    }
+
+    @Override
+    public void setPath(String path) {
+        // NO-OP
+    }
+
+    @Override
+    public String getPublicId() {
+        return null;
+    }
+
+    @Override
+    public void setPublicId(String publicId) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getReloadable() {
+        return false;
+    }
+
+    @Override
+    public void setReloadable(boolean reloadable) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getOverride() {
+        return false;
+    }
+
+    @Override
+    public void setOverride(boolean override) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getPrivileged() {
+        return false;
+    }
+
+    @Override
+    public void setPrivileged(boolean privileged) {
+        // NO-OP
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        return null;
+    }
+
+    @Override
+    public int getSessionTimeout() {
+        return 0;
+    }
+
+    @Override
+    public void setSessionTimeout(int timeout) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getSwallowAbortedUploads() {
+        return false;
+    }
+
+    @Override
+    public void setSwallowAbortedUploads(boolean swallowAbortedUploads) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getSwallowOutput() {
+        return false;
+    }
+
+    @Override
+    public void setSwallowOutput(boolean swallowOutput) {
+        // NO-OP
+    }
+
+    @Override
+    public String getWrapperClass() {
+        return null;
+    }
+
+    @Override
+    public void setWrapperClass(String wrapperClass) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getXmlNamespaceAware() {
+        return false;
+    }
+
+    @Override
+    public boolean getXmlValidation() {
+        return false;
+    }
+
+    @Override
+    public void setXmlValidation(boolean xmlValidation) {
+        // NO-OP
+    }
+
+    @Override
+    public void setXmlNamespaceAware(boolean xmlNamespaceAware) {
+        // NO-OP
+    }
+
+    @Override
+    public void setTldValidation(boolean tldValidation) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getTldValidation() {
+        return false;
+    }
+
+    @Override
+    public boolean getTldNamespaceAware() {
+        return false;
+    }
+
+    @Override
+    public void setTldNamespaceAware(boolean tldNamespaceAware) {
+        // NO-OP
+    }
+
+    @Override
+    public JarScanner getJarScanner() {
+        return null;
+    }
+
+    @Override
+    public void setJarScanner(JarScanner jarScanner) {
+        // NO-OP
+    }
+
+    @Override
+    public Authenticator getAuthenticator() {
+        return null;
+    }
+
+    @Override
+    public void setLogEffectiveWebXml(boolean logEffectiveWebXml) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getLogEffectiveWebXml() {
+        return false;
+    }
+
+    @Override
+    public void addApplicationListener(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void addApplicationParameter(ApplicationParameter parameter) {
+        // NO-OP
+    }
+
+    @Override
+    public void addConstraint(SecurityConstraint constraint) {
+        // NO-OP
+    }
+
+    @Override
+    public void addErrorPage(ErrorPage errorPage) {
+        // NO-OP
+    }
+
+    @Override
+    public void addFilterDef(FilterDef filterDef) {
+        // NO-OP
+    }
+
+    @Override
+    public void addFilterMap(FilterMap filterMap) {
+        // NO-OP
+    }
+
+    @Override
+    public void addFilterMapBefore(FilterMap filterMap) {
+        // NO-OP
+    }
+
+    @Override
+    public void addInstanceListener(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void addLocaleEncodingMappingParameter(String locale, String encoding) {
+        // NO-OP
+    }
+
+    @Override
+    public void addMimeMapping(String extension, String mimeType) {
+        // NO-OP
+    }
+
+    @Override
+    public void addParameter(String name, String value) {
+        // NO-OP
+    }
+
+    @Override
+    public void addRoleMapping(String role, String link) {
+        // NO-OP
+    }
+
+    @Override
+    public void addSecurityRole(String role) {
+        // NO-OP
+    }
+
+    @Override
+    public void addServletMapping(String pattern, String name) {
+        // NO-OP
+    }
+
+    @Override
+    public void addServletMapping(String pattern, String name,
+            boolean jspWildcard) {
+        // NO-OP
+    }
+
+    @Override
+    public void addWatchedResource(String name) {
+        // NO-OP
+    }
+
+    @Override
+    public void addWelcomeFile(String name) {
+        // NO-OP
+    }
+
+    @Override
+    public void addWrapperLifecycle(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void addWrapperListener(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public Wrapper createWrapper() {
+        return null;
+    }
+
+    @Override
+    public String[] findApplicationListeners() {
+        return null;
+    }
+
+    @Override
+    public ApplicationParameter[] findApplicationParameters() {
+        return null;
+    }
+
+    @Override
+    public SecurityConstraint[] findConstraints() {
+        return null;
+    }
+
+    @Override
+    public ErrorPage findErrorPage(int errorCode) {
+        return null;
+    }
+
+    @Override
+    public ErrorPage findErrorPage(String exceptionType) {
+        return null;
+    }
+
+    @Override
+    public ErrorPage[] findErrorPages() {
+        return null;
+    }
+
+    @Override
+    public FilterDef findFilterDef(String filterName) {
+        return null;
+    }
+
+    @Override
+    public FilterDef[] findFilterDefs() {
+        return null;
+    }
+
+    @Override
+    public FilterMap[] findFilterMaps() {
+        return null;
+    }
+
+    @Override
+    public String[] findInstanceListeners() {
+        return null;
+    }
+
+    @Override
+    public String findMimeMapping(String extension) {
+        return null;
+    }
+
+    @Override
+    public String[] findMimeMappings() {
+        return null;
+    }
+
+    @Override
+    public String findParameter(String name) {
+        return null;
+    }
+
+    @Override
+    public String[] findParameters() {
+        return null;
+    }
+
+    @Override
+    public String findRoleMapping(String role) {
+        return null;
+    }
+
+    @Override
+    public boolean findSecurityRole(String role) {
+        return false;
+    }
+
+    @Override
+    public String[] findSecurityRoles() {
+        return null;
+    }
+
+    @Override
+    public String findServletMapping(String pattern) {
+        return null;
+    }
+
+    @Override
+    public String[] findServletMappings() {
+        return null;
+    }
+
+    @Override
+    public String findStatusPage(int status) {
+        return null;
+    }
+
+    @Override
+    public int[] findStatusPages() {
+        return null;
+    }
+
+    @Override
+    public String[] findWatchedResources() {
+        return null;
+    }
+
+    @Override
+    public boolean findWelcomeFile(String name) {
+        return false;
+    }
+
+    @Override
+    public String[] findWelcomeFiles() {
+        return null;
+    }
+
+    @Override
+    public String[] findWrapperLifecycles() {
+        return null;
+    }
+
+    @Override
+    public String[] findWrapperListeners() {
+        return null;
+    }
+
+    @Override
+    public boolean fireRequestInitEvent(ServletRequest request) {
+        return false;
+    }
+
+    @Override
+    public boolean fireRequestDestroyEvent(ServletRequest request) {
+        return false;
+    }
+
+    @Override
+    public void reload() {
+        // NO-OP
+    }
+
+    @Override
+    public void removeApplicationListener(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeApplicationParameter(String name) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeConstraint(SecurityConstraint constraint) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeErrorPage(ErrorPage errorPage) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeFilterDef(FilterDef filterDef) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeFilterMap(FilterMap filterMap) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeInstanceListener(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeMimeMapping(String extension) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeParameter(String name) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeRoleMapping(String role) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeSecurityRole(String role) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeServletMapping(String pattern) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeWatchedResource(String name) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeWelcomeFile(String name) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeWrapperLifecycle(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public void removeWrapperListener(String listener) {
+        // NO-OP
+    }
+
+    @Override
+    public String getRealPath(String path) {
+        return null;
+    }
+
+    @Override
+    public int getEffectiveMajorVersion() {
+        return 0;
+    }
+
+    @Override
+    public void setEffectiveMajorVersion(int major) {
+        // NO-OP
+    }
+
+    @Override
+    public int getEffectiveMinorVersion() {
+        return 0;
+    }
+
+    @Override
+    public void setEffectiveMinorVersion(int minor) {
+        // NO-OP
+    }
+
+    @Override
+    public JspConfigDescriptor getJspConfigDescriptor() {
+        return null;
+    }
+
+    @Override
+    public void addServletContainerInitializer(ServletContainerInitializer sci,
+            Set<Class<?>> classes) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getPaused() {
+        return false;
+    }
+
+    @Override
+    public boolean isServlet22() {
+        return false;
+    }
+
+    @Override
+    public void setResourceOnlyServlets(String resourceOnlyServlets) {
+        // NO-OP
+    }
+
+    @Override
+    public String getResourceOnlyServlets() {
+        return null;
+    }
+
+    @Override
+    public boolean isResourceOnlyServlet(String servletName) {
+        return false;
+    }
+
+    @Override
+    public String getBaseName() {
+        return null;
+    }
+
+    @Override
+    public void setWebappVersion(String webappVersion) {
+        // NO-OP
+    }
+
+    @Override
+    public String getWebappVersion() {
+        return null;
+    }
+
+    @Override
+    public void setFireRequestListenersOnForwards(boolean enable) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getFireRequestListenersOnForwards() {
+        return false;
+    }
+
+    @Override
+    public void setPreemptiveAuthentication(boolean enable) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getPreemptiveAuthentication() {
+        return false;
+    }
+
+    @Override
+    public void setSendRedirectBody(boolean enable) {
+        // NO-OP
+    }
+
+    @Override
+    public boolean getSendRedirectBody() {
+        return false;
+    }
+
+    @Override
+    public Loader getLoader() {
+        return null;
+    }
+
+    @Override
+    public void setLoader(Loader loader) {
+        // NO-OP
+    }
+
+    @Override
+    public Manager getManager() {
+        return null;
+    }
+
+    @Override
+    public void setManager(Manager manager) {
+        // NO-OP
+    }
+
+    @Override
+    public void addPostConstructMethod(String clazz, String method) {
+        // NO-OP
+    }
+
+    @Override
+    public void addPreDestroyMethod(String clazz, String method) {
+        // NO-OP
+    }
+
+    @Override
+    public void removePostConstructMethod(String clazz) {
+        // NO-OP
+    }
+
+    @Override
+    public void removePreDestroyMethod(String clazz) {
+        // NO-OP
+    }
+
+    @Override
+    public String findPostConstructMethod(String clazz) {
+        return null;
+    }
+
+    @Override
+    public String findPreDestroyMethod(String clazz) {
+        return null;
+    }
+
+    @Override
+    public Map<String,String> findPostConstructMethods() {
+        return null;
+    }
+
+    @Override
+    public Map<String,String> findPreDestroyMethods() {
+        return null;
+    }
+
+    @Override
+    public String getInfo() {
+        return null;
+    }
+
+    @Override
+    @Deprecated
+    public Object getMappingObject() {
+        return null;
+    }
+
+    @Override
+    public DirContext getResources() {
+        return null;
+    }
+
+    @Override
+    public void setResources(DirContext resources) {
+        //NO-OP
+    }
+
+    @Override
+    @Deprecated
+    public void invoke(Request request, Response response) throws IOException,
+            ServletException {
+        // NO-OP
+    }
+
+    @Override
+    @Deprecated
+    public boolean getAvailable() {
+        return false;
+    }
+
+    @Override
+    @Deprecated
+    public CharsetMapper getCharsetMapper() {
+        return null;
+    }
+
+    @Override
+    @Deprecated
+    public void setCharsetMapper(CharsetMapper mapper) {
+        // NO-OP
+    }
+
+    @Override
+    public Mapper getMapper() {
+        return null;
+    }
+
+    @Override
+    public void addResourceJarUrl(URL url) {
+    }
+
+    @Override
+    public Set<String> addServletSecurity(
+            ApplicationServletRegistration registration,
+            ServletSecurityElement servletSecurityElement) {
+        return null;
+    }
+}
diff --git a/test/org/apache/catalina/startup/SimpleHttpClient.java b/test/org/apache/catalina/startup/SimpleHttpClient.java
index 3bea2df..a65e3cd 100644
--- a/test/org/apache/catalina/startup/SimpleHttpClient.java
+++ b/test/org/apache/catalina/startup/SimpleHttpClient.java
@@ -60,7 +60,7 @@ public abstract class SimpleHttpClient {
 
     protected static final String SESSION_COOKIE_NAME = "JSESSIONID";
     protected static final String SESSION_PARAMETER_NAME =
-            SESSION_COOKIE_NAME.toLowerCase(Locale.US);
+            SESSION_COOKIE_NAME.toLowerCase(Locale.ENGLISH);
 
     private static final String COOKIE_HEADER_PREFIX = "Set-Cookie: ";
     private static final String SESSION_COOKIE_HEADER_PREFIX =
diff --git a/test/org/apache/catalina/startup/TestContextConfig.java b/test/org/apache/catalina/startup/TestContextConfig.java
index 45a7ef6..91f4d71 100644
--- a/test/org/apache/catalina/startup/TestContextConfig.java
+++ b/test/org/apache/catalina/startup/TestContextConfig.java
@@ -126,6 +126,26 @@ public class TestContextConfig extends TomcatBaseTest {
         assertPageContains("/test/testServlet", "postConstruct1()");
     }
 
+    @Test
+    public void testBug54448and54450() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp-3.0-fragments");
+        Context context = tomcat.addWebapp(null, "/test",
+                appDir.getAbsolutePath());
+
+        Tomcat.addServlet(context, "TestServlet",
+                "org.apache.catalina.startup.TesterServletWithAnnotations");
+        context.addServletMapping("/testServlet", "TestServlet");
+
+        tomcat.enableNaming();
+
+        tomcat.start();
+
+        assertPageContains("/test/testServlet",
+                "envEntry1: 1 envEntry2: 2 envEntry3: 33 envEntry4: 4");
+    }
+
     private static class CustomDefaultServletSCI
             implements ServletContainerInitializer {
 
diff --git a/test/org/apache/catalina/startup/TesterServletWithAnnotations.java b/test/org/apache/catalina/startup/TesterServletWithAnnotations.java
new file mode 100644
index 0000000..7371322
--- /dev/null
+++ b/test/org/apache/catalina/startup/TesterServletWithAnnotations.java
@@ -0,0 +1,64 @@
+/*
+ * 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.catalina.startup;
+
+import java.io.IOException;
+
+import javax.annotation.Resource;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class TesterServletWithAnnotations extends HttpServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    @Resource(mappedName = "1")
+    private int envEntry1;
+
+    private int envEntry2;
+
+    private int envEntry3;
+
+    private int envEntry4;
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        resp.setContentType("text/plain");
+        resp.getWriter().print("envEntry1: " + envEntry1);
+        resp.getWriter().print(" envEntry2: " + envEntry2);
+        resp.getWriter().print(" envEntry3: " + envEntry3);
+        resp.getWriter().print(" envEntry4: " + envEntry4);
+    }
+
+    public void setEnvEntry2(int envEntry2) {
+        this.envEntry2 = envEntry2;
+    }
+
+    @Resource(mappedName = "3")
+    public void setEnvEntry3(int envEntry3) {
+        this.envEntry3 = envEntry3;
+    }
+
+    @Resource(mappedName = "4")
+    public void setEnvEntry4(int envEntry4) {
+        this.envEntry4 = envEntry4;
+    }
+}
\ No newline at end of file
diff --git a/test/org/apache/catalina/tribes/group/TestGroupChannelMemberArrival.java b/test/org/apache/catalina/tribes/group/TestGroupChannelMemberArrival.java
index d974ac4..3e5d022 100644
--- a/test/org/apache/catalina/tribes/group/TestGroupChannelMemberArrival.java
+++ b/test/org/apache/catalina/tribes/group/TestGroupChannelMemberArrival.java
@@ -71,7 +71,7 @@ public class TestGroupChannelMemberArrival {
         for (int i = 0; i < threads.length; i++) {
             threads[i].join();
         }
-        Thread.sleep(2000);
+        Thread.sleep(5000);
         System.out.println(System.currentTimeMillis()
                 + " All channels started.");
         for (int i = listeners.length - 1; i >= 0; i--) {
diff --git a/test/org/apache/catalina/util/TesterBase64Performance.java b/test/org/apache/catalina/util/TesterBase64Performance.java
new file mode 100644
index 0000000..ce11d78
--- /dev/null
+++ b/test/org/apache/catalina/util/TesterBase64Performance.java
@@ -0,0 +1,72 @@
+/*
+ * 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.catalina.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.junit.Test;
+
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+
+public class TesterBase64Performance {
+
+    private static final int SIZE = 10000000;
+
+    @SuppressWarnings("deprecation")
+    @Test
+    public void testDecode() throws Exception {
+
+        List<ByteChunk> inputs = new ArrayList<ByteChunk>(SIZE);
+
+        for (int i = 0; i < SIZE; i++) {
+            String decodedString = "abc" + Integer.valueOf(i) +
+                    ":abc" + Integer.valueOf(i);
+            byte[] decodedBytes =
+                    decodedString.getBytes(B2CConverter.ISO_8859_1);
+            String encodedString =
+                    DatatypeConverter.printBase64Binary(decodedBytes);
+            byte[] encodedBytes =
+                    encodedString.getBytes(B2CConverter.ISO_8859_1);
+
+            ByteChunk bc = new ByteChunk(encodedBytes.length);
+            bc.append(encodedBytes, 0, encodedBytes.length);
+
+            inputs.add(bc);
+        }
+
+        long startTomcat = System.currentTimeMillis();
+        for (ByteChunk bc : inputs) {
+            CharChunk cc = new CharChunk(bc.getLength());
+            Base64.decode(bc, cc);
+        }
+        long stopTomcat =  System.currentTimeMillis();
+        System.out.println("Tomcat: " + (stopTomcat - startTomcat) + " ms");
+
+        long startCodec = System.currentTimeMillis();
+        for (ByteChunk bc : inputs) {
+            org.apache.tomcat.util.codec.binary.Base64.decodeBase64(
+                    bc.getBuffer(), bc.getOffset(), bc.getLength());
+        }
+        long stopCodec =  System.currentTimeMillis();
+        System.out.println("Codec: " + (stopCodec - startCodec) + " ms");
+    }
+}
diff --git a/test/org/apache/catalina/valves/TestErrorReportValve.java b/test/org/apache/catalina/valves/TestErrorReportValve.java
index b163ad2..e104404 100644
--- a/test/org/apache/catalina/valves/TestErrorReportValve.java
+++ b/test/org/apache/catalina/valves/TestErrorReportValve.java
@@ -129,4 +129,44 @@ public class TestErrorReportValve extends TomcatBaseTest {
             }
         }
     }
+
+
+    /**
+     * Custom error/status codes should not result in a blank response.
+     */
+    @Test
+    public void testBug54536() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        // Must have a real docBase - just use temp
+        Context ctx =
+            tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+
+        Tomcat.addServlet(ctx, "bug54536", new Bug54536Servlet());
+        ctx.addServletMapping("/", "bug54536");
+
+        tomcat.start();
+
+        ByteChunk res = new ByteChunk();
+        int rc = getUrl("http://localhost:" + getPort(), res, null);
+
+        Assert.assertEquals(Bug54536Servlet.ERROR_STATUS, rc);
+        String body = res.toString();
+        Assert.assertNotNull(body);
+        Assert.assertTrue(body, body.contains(Bug54536Servlet.ERROR_MESSAGE));
+    }
+
+
+    private static final class Bug54536Servlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+        private static final int ERROR_STATUS = 999;
+        private static final String ERROR_MESSAGE = "The sky is falling";
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            resp.sendError(ERROR_STATUS, ERROR_MESSAGE);
+        }
+    }
 }
diff --git a/test/org/apache/catalina/websocket/TestUtf8.java b/test/org/apache/catalina/websocket/TestUtf8.java
deleted file mode 100644
index b3e47b0..0000000
--- a/test/org/apache/catalina/websocket/TestUtf8.java
+++ /dev/null
@@ -1,72 +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.catalina.websocket;
-
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-
-import static org.junit.Assert.fail;
-import org.junit.Test;
-
-import org.apache.tomcat.util.buf.B2CConverter;
-
-public class TestUtf8 {
-
-    // Invalid UTF-8
-    private static final byte[] SRC_BYTES =
-            new byte[] {-50, -70, -31,  -67, -71, -49, -125, -50, -68, -50,
-                        -75, -19, -96, -128, 101, 100,  105, 116, 101, 100};
-
-
-    @Test
-    public void testDecoder() throws Exception {
-        CharsetDecoder decoder = B2CConverter.UTF_8.newDecoder()
-                .onMalformedInput(CodingErrorAction.REPORT)
-                .onUnmappableCharacter(CodingErrorAction.REPORT);
-
-
-        ByteBuffer bb = ByteBuffer.wrap(SRC_BYTES);
-        CharBuffer cb = CharBuffer.allocate(bb.limit());
-
-        CoderResult cr = decoder.decode(bb, cb, true);
-        // if (!cr.isError()) {
-        if (cr.isError()) {
-            // This should fail but currently passes. Once this test fails, the
-            // JVM has been fixed and the commented out if statement above can
-            // be used.
-            fail();
-        }
-    }
-
-    @Test
-    public void testDecoder2() throws Exception {
-
-        CharsetDecoder decoder = new Utf8Decoder();
-
-        ByteBuffer bb = ByteBuffer.wrap(SRC_BYTES);
-        CharBuffer cb = CharBuffer.allocate(bb.limit());
-
-        CoderResult cr = decoder.decode(bb, cb, true);
-        // Confirm the custom decoder correctly reports an error
-        if (!cr.isError()) {
-            fail();
-        }
-    }
-}
diff --git a/test/org/apache/catalina/websocket/TestWebSocket.java b/test/org/apache/catalina/websocket/TestWebSocket.java
index a07db54..b24b69c 100644
--- a/test/org/apache/catalina/websocket/TestWebSocket.java
+++ b/test/org/apache/catalina/websocket/TestWebSocket.java
@@ -372,9 +372,10 @@ public class TestWebSocket extends TomcatBaseTest {
         private void sendMessage(String message, boolean finalFragment)
                 throws IOException {
             ByteChunk bc = new ByteChunk(8192);
-            C2BConverter c2b = new C2BConverter(bc, "UTF-8");
-            c2b.convert(message);
-            c2b.flushBuffer();
+            CharChunk cc = new CharChunk(8192);
+            C2BConverter c2b = new C2BConverter("UTF-8");
+            cc.append(message);
+            c2b.convert(cc, bc);
 
             int len = bc.getLength();
             assertTrue(len < 126);
@@ -427,7 +428,7 @@ public class TestWebSocket extends TomcatBaseTest {
             bc.setEnd(len);
 
             B2CConverter b2c = new B2CConverter("UTF-8");
-            b2c.convert(bc, cc, len);
+            b2c.convert(bc, cc, true);
 
             return cc.toString();
         }
diff --git a/test/org/apache/coyote/http11/TestInternalInputBuffer.java b/test/org/apache/coyote/http11/TestInternalInputBuffer.java
index b3d4766..6f0a853 100644
--- a/test/org/apache/coyote/http11/TestInternalInputBuffer.java
+++ b/test/org/apache/coyote/http11/TestInternalInputBuffer.java
@@ -27,12 +27,14 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 
 import org.apache.catalina.Context;
 import org.apache.catalina.startup.SimpleHttpClient;
+import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 
@@ -316,4 +318,101 @@ public class TestInternalInputBuffer extends TomcatBaseTest {
             }
         }
     }
+
+
+    /**
+     * Test case for new lines at the start of a request. RFC2616
+     * does not permit any, but Tomcat is tolerant of them if they are present.
+     */
+    @Test
+    public void testNewLines() {
+
+        NewLinesClient client = new NewLinesClient(10);
+
+        client.doRequest();
+        assertTrue(client.isResponse200());
+        assertTrue(client.isResponseBodyOK());
+    }
+
+
+    /**
+     * Test case for new lines at the start of a request. RFC2616
+     * does not permit any, but Tomcat is tolerant of them if they are present.
+     */
+    @Test
+    public void testNewLinesExcessive() {
+
+        NewLinesClient client = new NewLinesClient(10000);
+
+        // If the connection is closed fast enough, writing the request will
+        // fail and the response won't be read.
+        Exception e = client.doRequest();
+        if (e == null) {
+            assertTrue(client.isResponse400());
+        }
+        assertFalse(client.isResponseBodyOK());
+    }
+
+
+    private class NewLinesClient extends SimpleHttpClient {
+
+        private final String newLines;
+
+        private NewLinesClient(int count) {
+            StringBuilder sb = new StringBuilder(count * 2);
+            for (int i = 0; i < count; i++) {
+                sb.append(CRLF);
+            }
+            newLines = sb.toString();
+        }
+
+        private Exception doRequest() {
+
+            Tomcat tomcat = getTomcatInstance();
+
+            Context root = tomcat.addContext("", TEMP_DIR);
+            Tomcat.addServlet(root, "test", new TesterServlet());
+            root.addServletMapping("/test", "test");
+
+            try {
+                tomcat.start();
+                setPort(tomcat.getConnector().getLocalPort());
+
+                // Open connection
+                connect();
+
+                String[] request = new String[1];
+                request[0] =
+                    newLines +
+                    "GET http://localhost:8080/test HTTP/1.1" + CRLF +
+                    "X-Bug48839: abcd" + CRLF +
+                    "\tefgh" + CRLF +
+                    "Connection: close" + CRLF +
+                    CRLF;
+
+                setRequest(request);
+                processRequest(); // blocks until response has been read
+
+                // Close the connection
+                disconnect();
+            } catch (Exception e) {
+                return e;
+            }
+            return null;
+        }
+
+        @Override
+        public boolean isResponseBodyOK() {
+            if (getResponseBody() == null) {
+                return false;
+            }
+            if (!getResponseBody().contains("OK")) {
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+
 }
diff --git a/test/org/apache/el/util/Tester.java b/test/org/apache/el/util/Tester.java
old mode 100755
new mode 100644
diff --git a/test/org/apache/jasper/compiler/TestELInterpreterFactory.java b/test/org/apache/jasper/compiler/TestELInterpreterFactory.java
new file mode 100644
index 0000000..e1818c6
--- /dev/null
+++ b/test/org/apache/jasper/compiler/TestELInterpreterFactory.java
@@ -0,0 +1,88 @@
+/*
+ * 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.jasper.compiler;
+
+import java.io.File;
+
+import javax.servlet.ServletContext;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.compiler.ELInterpreterFactory.DefaultELInterpreter;
+
+public class TestELInterpreterFactory extends TomcatBaseTest {
+
+    public static class SimpleELInterpreter implements ELInterpreter {
+
+        @Override
+        public String interpreterCall(JspCompilationContext context,
+                boolean isTagFile, String expression, Class<?> expectedType,
+                String fnmapvar, boolean xmlEscape) {
+            return expression;
+        }
+    }
+
+    @Test
+    public void testBug54239() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp-3.0");
+        Context ctx = tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+        tomcat.start();
+
+        ServletContext context = ctx.getServletContext();
+
+        ELInterpreter interpreter =
+                ELInterpreterFactory.getELInterpreter(context);
+        Assert.assertNotNull(interpreter);
+        Assert.assertTrue(interpreter instanceof DefaultELInterpreter);
+
+        context.removeAttribute(ELInterpreter.class.getName());
+
+        context.setAttribute(ELInterpreter.class.getName(),
+                SimpleELInterpreter.class.getName());
+        interpreter = ELInterpreterFactory.getELInterpreter(context);
+        Assert.assertNotNull(interpreter);
+        Assert.assertTrue(interpreter instanceof SimpleELInterpreter);
+
+        context.removeAttribute(ELInterpreter.class.getName());
+
+        SimpleELInterpreter simpleInterpreter = new SimpleELInterpreter();
+        context.setAttribute(ELInterpreter.class.getName(), simpleInterpreter);
+        interpreter = ELInterpreterFactory.getELInterpreter(context);
+        Assert.assertNotNull(interpreter);
+        Assert.assertTrue(interpreter instanceof SimpleELInterpreter);
+        Assert.assertTrue(interpreter == simpleInterpreter);
+
+        context.removeAttribute(ELInterpreter.class.getName());
+
+
+        context.setInitParameter(ELInterpreter.class.getName(),
+                SimpleELInterpreter.class.getName());
+
+        interpreter = ELInterpreterFactory.getELInterpreter(context);
+        Assert.assertNotNull(interpreter);
+        Assert.assertTrue(interpreter instanceof SimpleELInterpreter);
+
+        context.removeAttribute(ELInterpreter.class.getName());
+    }
+}
diff --git a/test/org/apache/tomcat/util/buf/TestB2CConverter.java b/test/org/apache/tomcat/util/buf/TestB2CConverter.java
index ef35b2a..742bd83 100644
--- a/test/org/apache/tomcat/util/buf/TestB2CConverter.java
+++ b/test/org/apache/tomcat/util/buf/TestB2CConverter.java
@@ -16,6 +16,9 @@
  */
 package org.apache.tomcat.util.buf;
 
+import java.nio.charset.Charset;
+import java.nio.charset.MalformedInputException;
+
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -24,6 +27,10 @@ public class TestB2CConverter {
     private static final byte[] UTF16_MESSAGE =
             new byte[] {-2, -1, 0, 65, 0, 66, 0, 67};
 
+    private static final byte[] UTF8_INVALID = new byte[] {-8, -69, -73, -77};
+
+    private static final byte[] UTF8_PARTIAL = new byte[] {-50};
+
     @Test
     public void testSingleMessage() throws Exception {
         testMessages(1);
@@ -43,13 +50,12 @@ public class TestB2CConverter {
         B2CConverter conv = new B2CConverter("UTF-16");
 
         ByteChunk bc = new ByteChunk();
-        CharChunk cc = new CharChunk();
+        CharChunk cc = new CharChunk(32);
 
 
         for (int i = 0; i < msgCount; i++) {
             bc.append(UTF16_MESSAGE, 0, UTF16_MESSAGE.length);
-            // Note: The limit is the number of characters to read
-            conv.convert(bc, cc, 3);
+            conv.convert(bc, cc, true);
             Assert.assertEquals("ABC", cc.toString());
             bc.recycle();
             cc.recycle();
@@ -58,4 +64,86 @@ public class TestB2CConverter {
 
         System.out.println(cc);
     }
+
+    @Test
+    public void testLeftoverSize() {
+        float maxLeftover = 0;
+        String charsetName = "UNSET";
+        for (Charset charset : Charset.availableCharsets().values()) {
+            float leftover;
+            if (charset.name().toLowerCase().startsWith("x-")) {
+                // Non-standard charset that browsers won't be using
+                // Likely something used internally by the JRE
+                continue;
+            }
+            if (charset.name().equals("COMPOUND_TEXT")) {
+                // Java for-internal-use-only charset
+                // See:
+                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6392670
+                // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6381697
+                continue;
+            }
+            try {
+                leftover = charset.newEncoder().maxBytesPerChar();
+            } catch (UnsupportedOperationException uoe) {
+                // Skip it
+                continue;
+            }
+            if (leftover > maxLeftover) {
+                maxLeftover = leftover;
+                charsetName = charset.name();
+            }
+        }
+        Assert.assertTrue("Limit needs to be at least " + maxLeftover +
+                " (used in charset '" + charsetName + "')",
+                maxLeftover <= B2CConverter.LEFTOVER_SIZE);
+    }
+
+    // TODO Work-around bug in UTF8 decoder
+    //@Test(expected=MalformedInputException.class)
+    public void testBug54602a() throws Exception {
+        // Check invalid input is rejected straight away
+        B2CConverter conv = new B2CConverter("UTF-8");
+        ByteChunk bc = new ByteChunk();
+        CharChunk cc = new CharChunk();
+
+        bc.append(UTF8_INVALID, 0, UTF8_INVALID.length);
+        cc.allocate(bc.getLength(), -1);
+
+        conv.convert(bc, cc, false);
+    }
+
+    @Test(expected=MalformedInputException.class)
+    public void testBug54602b() throws Exception {
+        // Check partial input is rejected
+        B2CConverter conv = new B2CConverter("UTF-8");
+        ByteChunk bc = new ByteChunk();
+        CharChunk cc = new CharChunk();
+
+        bc.append(UTF8_PARTIAL, 0, UTF8_PARTIAL.length);
+        cc.allocate(bc.getLength(), -1);
+
+        conv.convert(bc, cc, true);
+    }
+
+    @Test
+    public void testBug54602c() throws Exception {
+        // Check partial input is rejected once it is known to be all available
+        B2CConverter conv = new B2CConverter("UTF-8");
+        ByteChunk bc = new ByteChunk();
+        CharChunk cc = new CharChunk();
+
+        bc.append(UTF8_PARTIAL, 0, UTF8_PARTIAL.length);
+        cc.allocate(bc.getLength(), -1);
+
+        conv.convert(bc, cc, false);
+
+        Exception e = null;
+        try {
+            conv.convert(bc, cc, true);
+        } catch (MalformedInputException mie) {
+            e = mie;
+        }
+        Assert.assertNotNull(e);
+    }
 }
diff --git a/test/org/apache/tomcat/util/buf/TestUEncoder.java b/test/org/apache/tomcat/util/buf/TestUEncoder.java
new file mode 100644
index 0000000..d77a7fc
--- /dev/null
+++ b/test/org/apache/tomcat/util/buf/TestUEncoder.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.tomcat.util.buf;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+/**
+ * Test cases for {@link UEncoder}.
+ */
+public class TestUEncoder {
+
+    @Test
+    public void testEncodeURL() throws IOException {
+        UEncoder urlEncoder = new UEncoder();
+
+        String s = "a/b/c/d+e.class";
+        assertTrue(urlEncoder.encodeURL(s, 0, s.length()).equals(
+                "a%2fb%2fc%2fd%2be.class"));
+        assertTrue(urlEncoder.encodeURL(s, 2, s.length() - 2).equals(
+                "b%2fc%2fd%2be.cla"));
+
+        urlEncoder.addSafeCharacter('+');
+        assertTrue(urlEncoder.encodeURL(s, 0, s.length()).equals(
+                "a%2fb%2fc%2fd+e.class"));
+
+        s = new String(new char[] { 0xD801, 0xDC01 });
+        assertTrue(urlEncoder.encodeURL(s, 0, s.length())
+                .equals("%f0%90%90%81"));
+    }
+}
diff --git a/test/org/apache/tomcat/util/buf/TestUtf8.java b/test/org/apache/tomcat/util/buf/TestUtf8.java
new file mode 100644
index 0000000..c26bbfb
--- /dev/null
+++ b/test/org/apache/tomcat/util/buf/TestUtf8.java
@@ -0,0 +1,482 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.buf;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * These tests have been written with reference to
+ * <a href="http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf">unicode 6.2,
+ * chapter 3, section 3.9</a>.
+ */
+public class TestUtf8 {
+
+    // Indicates that at invalid sequence is detected one character later than
+    // the earliest possible moment
+    private static final int ERROR_POS_PLUS1 = 1;
+    // Indicates that at invalid sequence is detected two characters later than
+    // the earliest possible moment
+    private static final int ERROR_POS_PLUS2 = 2;
+    // Indicates that at invalid sequence is detected four characters later
+    // than the earliest possible moment
+    private static final int ERROR_POS_PLUS4 = 4;
+    // Indicates that the trailing valid byte is included in replacement of the
+    // previous error
+    private static final int REPLACE_SWALLOWS_TRAILER = 8;
+    // Indicates that one replacement character is missing
+    private static final int REPLACE_MISSING1 = 16;
+    // Indicates that two replacement characters are missing
+    private static final int REPLACE_MISSING2 = 32;
+    // Indicates that three replacement characters are missing
+    private static final int REPLACE_MISSING4 = 64;
+
+    public static final List<Utf8TestCase> TEST_CASES =
+            new ArrayList<Utf8TestCase>();
+
+    static {
+        TEST_CASES.add(new Utf8TestCase(
+                "Zero length input",
+                new int[] {},
+                -1,
+                ""));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid one byte sequence",
+                new int[] {0x41},
+                -1,
+                "A"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid two byte sequence",
+                new int[] {0xC2, 0xA9},
+                -1,
+                "\u00A9"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid three byte sequence",
+                new int[] {0xE0, 0xA4, 0x87},
+                -1,
+                "\u0907"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid four byte sequence",
+                new int[] {0xF0, 0x90, 0x90, 0x80},
+                -1,
+                "\uD801\uDC00"));
+        // JVM decoder does not report error until all 4 bytes are available
+        TEST_CASES.add(new Utf8TestCase(
+                "Invalid code point - out of range",
+                new int[] {0x41, 0xF4, 0x90, 0x80, 0x80, 0x41},
+                2,
+                "A\uFFFD\uFFFD\uFFFD\uFFFDA").addForJvm(ERROR_POS_PLUS2));
+        // JVM decoder does not report error until all 2 bytes are available
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid sequence padded from one byte to two",
+                new int[] {0x41, 0xC0, 0xC1, 0x41},
+                1,
+                "A\uFFFD\uFFFDA").addForJvm(ERROR_POS_PLUS1));
+        // JVM decoder does not report error until all 3 bytes are available
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid sequence padded from one byte to three",
+                new int[] {0x41, 0xE0, 0x80, 0xC1, 0x41},
+                2,
+                "A\uFFFD\uFFFD\uFFFDA").addForJvm(ERROR_POS_PLUS1));
+        // JVM decoder does not report error until all 4 bytes are available
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid sequence padded from one byte to four",
+                new int[] {0x41, 0xF0, 0x80, 0x80, 0xC1, 0x41},
+                2,
+                "A\uFFFD\uFFFD\uFFFD\uFFFDA").addForJvm(ERROR_POS_PLUS2));
+        TEST_CASES.add(new Utf8TestCase(
+                "Invalid one byte 1111 1111",
+                new int[] {0x41, 0xFF, 0x41},
+                1,
+                "A\uFFFDA"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Invalid one byte 1111 0000",
+                new int[] {0x41, 0xF0, 0x41},
+                2,
+                "A\uFFFDA").addForJvm(REPLACE_SWALLOWS_TRAILER));
+        TEST_CASES.add(new Utf8TestCase(
+                "Invalid one byte 1110 0000",
+                new int[] {0x41, 0xE0, 0x41},
+                2,
+                "A\uFFFDA").addForJvm(REPLACE_SWALLOWS_TRAILER));
+        TEST_CASES.add(new Utf8TestCase(
+                "Invalid one byte 1100 0000",
+                new int[] {0x41, 0xC0, 0x41},
+                1,
+                "A\uFFFDA").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Invalid one byte 1000 000",
+                new int[] {0x41, 0x80, 0x41},
+                1,
+                "A\uFFFDA"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Invalid sequence from unicode 6.2 spec, table 3-8",
+                new int[] {0x61, 0xF1, 0x80, 0x80, 0xE1, 0x80, 0xC2, 0x62, 0x80,
+                        0x63, 0x80, 0xBF, 0x64},
+                4,
+                "a\uFFFD\uFFFD\uFFFDb\uFFFDc\uFFFD\uFFFDd"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid 4-byte sequence truncated to 3 bytes",
+                new int[] {0x61, 0xF0, 0x90, 0x90},
+                3,
+                "a\uFFFD"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid 4-byte sequence truncated to 2 bytes",
+                new int[] {0x61, 0xF0, 0x90},
+                2,
+                "a\uFFFD"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid 4-byte sequence truncated to 1 byte",
+                new int[] {0x61, 0xF0},
+                1,
+                "a\uFFFD"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid 4-byte sequence truncated to 3 bytes with trailer",
+                new int[] {0x61, 0xF0, 0x90, 0x90, 0x61},
+                4,
+                "a\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid 4-byte sequence truncated to 2 bytes with trailer",
+                new int[] {0x61, 0xF0, 0x90, 0x61},
+                3,
+                "a\uFFFDa").addForJvm(REPLACE_SWALLOWS_TRAILER));
+        TEST_CASES.add(new Utf8TestCase(
+                "Valid 4-byte sequence truncated to 1 byte with trailer",
+                new int[] {0x61, 0xF0, 0x61},
+                2,
+                "a\uFFFDa").addForJvm(REPLACE_SWALLOWS_TRAILER));
+        TEST_CASES.add(new Utf8TestCase(
+                "U+0000 zero-padded to two bytes",
+                new int[] {0x61, 0xC0, 0x80, 0x61},
+                1,
+                "a\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "U+007F zero-padded to two bytes",
+                new int[] {0x61, 0xC1, 0xBF, 0x61},
+                2,
+                "a\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Two bytes, all 1's",
+                new int[] {0x61, 0xFF, 0xFF, 0x61},
+                1,
+                "a\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Two bytes, 1110 first byte first nibble",
+                new int[] {0x61, 0xE0, 0x80, 0x61},
+                2,
+                "a\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Two bytes, 101x first byte first nibble",
+                new int[] {0x61, 0xA0, 0x80, 0x61},
+                1,
+                "a\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Two bytes, invalid second byte",
+                new int[] {0x61, 0xC2, 0x00, 0x61},
+                2,
+                "a\uFFFD\u0000a"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Two bytes, invalid second byte",
+                new int[] {0x61, 0xC2, 0xC0, 0x61},
+                2,
+                "a\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Three bytes, U+0000 zero-padded",
+                new int[] {0x61, 0xE0, 0x80, 0x80, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Three bytes, U+007F zero-padded",
+                new int[] {0x61, 0xE0, 0x81, 0xBF, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Three bytes, U+07FF zero-padded",
+                new int[] {0x61, 0xE0, 0x9F, 0xBF, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Three bytes, all 1's",
+                new int[] {0x61, 0xFF, 0xFF, 0xFF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Three bytes, invalid first byte",
+                new int[] {0x61, 0xF8, 0x80, 0x80, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        REPLACE_SWALLOWS_TRAILER).addForJvm(REPLACE_MISSING2));
+        TEST_CASES.add(new Utf8TestCase(
+                "Three bytes, invalid second byte",
+                new int[] {0x61, 0xE0, 0xC0, 0x80, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Three bytes, invalid third byte",
+                new int[] {0x61, 0xE1, 0x80, 0xC0, 0x61},
+                3,
+                "a\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, U+0000 zero-padded",
+                new int[] {0x61, 0xF0, 0x80, 0x80, 0x80, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS2));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, U+007F zero-padded",
+                new int[] {0x61, 0xF0, 0x80, 0x81, 0xBF, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS2));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, U+07FF zero-padded",
+                new int[] {0x61, 0xF0, 0x80, 0x9F, 0xBF, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS2));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, U+FFFF zero-padded",
+                new int[] {0x61, 0xF0, 0x8F, 0xBF, 0xBF, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS2));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, all 1's",
+                new int[] {0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, invalid first byte",
+                new int[] {0x61, 0xF8, 0x80, 0x80, 0x80, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(
+                        REPLACE_MISSING2).addForJvm(REPLACE_MISSING1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, invalid second byte",
+                new int[] {0x61, 0xF1, 0xC0, 0x80, 0x80, 0x61},
+                2,
+                "a\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS2));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, invalid third byte",
+                new int[] {0x61, 0xF1, 0x80, 0xC0, 0x80, 0x61},
+                3,
+                "a\uFFFD\uFFFD\uFFFDa").addForJvm(ERROR_POS_PLUS1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Four bytes, invalid fourth byte",
+                new int[] {0x61, 0xF1, 0x80, 0x80, 0xC0, 0x61},
+                4,
+                "a\uFFFD\uFFFDa"));
+        TEST_CASES.add(new Utf8TestCase(
+                "Five bytes, U+0000 zero padded",
+                new int[] {0x61, 0xF8, 0x80, 0x80, 0x80, 0x80, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4));
+        TEST_CASES.add(new Utf8TestCase(
+                "Five bytes, U+007F zero padded",
+                new int[] {0x61, 0xF8, 0x80, 0x80, 0x81, 0xBF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4));
+        TEST_CASES.add(new Utf8TestCase(
+                "Five bytes, U+07FF zero padded",
+                new int[] {0x61, 0xF8, 0x80, 0x80, 0x9F, 0xBF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4));
+        TEST_CASES.add(new Utf8TestCase(
+                "Five bytes, U+FFFF zero padded",
+                new int[] {0x61, 0xF8, 0x80, 0x8F, 0xBF, 0xBF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(REPLACE_MISSING4));
+        TEST_CASES.add(new Utf8TestCase(
+                "Six bytes, U+0000 zero padded",
+                new int[] {0x61, 0xFC, 0x80, 0x80, 0x80, 0x80, 0x80, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(
+                        ERROR_POS_PLUS1).addForJvm(
+                        REPLACE_MISSING4).addForJvm(REPLACE_MISSING1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Six bytes, U+007F zero padded",
+                new int[] {0x61, 0xFC, 0x80, 0x80, 0x80, 0x81, 0xBF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(
+                        ERROR_POS_PLUS1).addForJvm(
+                        REPLACE_MISSING4).addForJvm(REPLACE_MISSING1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Six bytes, U+07FF zero padded",
+                new int[] {0x61, 0xFC, 0x80, 0x80, 0x80, 0x9F, 0xBF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(
+                        ERROR_POS_PLUS1).addForJvm(
+                        REPLACE_MISSING4).addForJvm(REPLACE_MISSING1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Six bytes, U+FFFF zero padded",
+                new int[] {0x61, 0xFC, 0x80, 0x80, 0x8F, 0xBF, 0xBF, 0x61},
+                1,
+                "a\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFDa").addForJvm(
+                        ERROR_POS_PLUS4).addForJvm(
+                        ERROR_POS_PLUS1).addForJvm(
+                        REPLACE_MISSING4).addForJvm(REPLACE_MISSING1));
+        TEST_CASES.add(new Utf8TestCase(
+                "Original test case - derived from Autobahn?",
+                new int[] {0xCE, 0xBA, 0xE1, 0xDB, 0xB9, 0xCF, 0x83, 0xCE,
+                           0xBC, 0xCE, 0xB5, 0xED, 0x80, 0x65, 0x64, 0x69,
+                           0x74, 0x65, 0x64},
+                3,
+                "\u03BA\uFFFD\u06F9\u03C3\u03BC\u03B5\uFFFDedited").addForJvm(
+                        ERROR_POS_PLUS1));
+    }
+
+    @Test
+    public void testHarmonyDecoder() {
+        CharsetDecoder decoder = new Utf8Decoder();
+        for (Utf8TestCase testCase : TEST_CASES) {
+            doTest(decoder, testCase, 0);
+        }
+    }
+
+
+    @Test
+    public void testJvmDecoder() {
+        CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
+        for (Utf8TestCase testCase : TEST_CASES) {
+            doTest(decoder, testCase, testCase.flagsJvm);
+        }
+    }
+
+
+    private void doTest(CharsetDecoder decoder, Utf8TestCase testCase,
+            int flags) {
+
+        int len = testCase.input.length;
+        ByteBuffer bb = ByteBuffer.allocate(len);
+        CharBuffer cb = CharBuffer.allocate(len);
+
+        // Configure decoder to fail on an error
+        decoder.reset();
+        decoder.onMalformedInput(CodingErrorAction.REPORT);
+        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
+
+        // Add each byte one at a time. The decoder should fail as soon as
+        // an invalid sequence has been provided
+        for (int i = 0; i < len; i++) {
+            bb.put((byte) testCase.input[i]);
+            bb.flip();
+            CoderResult cr = decoder.decode(bb, cb, false);
+            if (cr.isError()) {
+                int expected =  testCase.invalidIndex;
+                if ((flags & ERROR_POS_PLUS1) != 0) {
+                    expected += 1;
+                }
+                if ((flags & ERROR_POS_PLUS2) != 0) {
+                    expected += 2;
+                }
+                if ((flags & ERROR_POS_PLUS4) != 0) {
+                    expected += 4;
+                }
+                Assert.assertEquals(testCase.description, expected, i);
+                break;
+            }
+            bb.compact();
+        }
+
+        // Configure decoder to replace on an error
+        decoder.reset();
+        decoder.onMalformedInput(CodingErrorAction.REPLACE);
+        decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+
+        // Add each byte one at a time.
+        bb.clear();
+        cb.clear();
+        for (int i = 0; i < len; i++) {
+            bb.put((byte) testCase.input[i]);
+            bb.flip();
+            CoderResult cr = decoder.decode(bb, cb, false);
+            if (cr.isError()) {
+                Assert.fail(testCase.description);
+            }
+            bb.compact();
+        }
+        // For incomplete sequences at the end of the input need to tell
+        // the decoder the input has ended
+        bb.flip();
+        CoderResult cr = decoder.decode(bb, cb, true);
+        if (cr.isError()) {
+            Assert.fail(testCase.description);
+        }
+        cb.flip();
+
+        String expected = testCase.outputReplaced;
+        if ((flags & REPLACE_SWALLOWS_TRAILER) != 0) {
+            expected = expected.substring(0, expected.length() - 1);
+        }
+
+        if ((flags & REPLACE_MISSING1) != 0) {
+            expected = expected.substring(0, 1) +
+                    expected.substring(2, expected.length());
+        }
+
+        if ((flags & REPLACE_MISSING2) != 0) {
+            expected = expected.substring(0, 1) +
+                    expected.substring(3, expected.length());
+        }
+
+        if ((flags & REPLACE_MISSING4) != 0) {
+            expected = expected.substring(0, 1) +
+                    expected.substring(5, expected.length());
+        }
+
+        Assert.assertEquals(testCase.description, expected, cb.toString());
+    }
+
+
+    /**
+     * Encapsulates a single UTF-8 test case
+     */
+    public static class Utf8TestCase {
+        public final String description;
+        public final int[] input;
+        public final int invalidIndex;
+        public final String outputReplaced;
+        public int flagsJvm = 0;
+
+        public Utf8TestCase(String description, int[] input, int invalidIndex,
+                String outputReplaced) {
+            this.description = description;
+            this.input = input;
+            this.invalidIndex = invalidIndex;
+            this.outputReplaced = outputReplaced;
+
+        }
+
+        public Utf8TestCase addForJvm(int flag) {
+            this.flagsJvm = this.flagsJvm | flag;
+            return this;
+        }
+    }
+}
diff --git a/test/org/apache/tomcat/util/http/mapper/TestMapper.java b/test/org/apache/tomcat/util/http/mapper/TestMapper.java
index 3bee69b..c146971 100644
--- a/test/org/apache/tomcat/util/http/mapper/TestMapper.java
+++ b/test/org/apache/tomcat/util/http/mapper/TestMapper.java
@@ -165,10 +165,10 @@ public class TestMapper extends LoggingBaseTest {
 
     @Test
     public void testPerformance() throws Exception {
-        // Takes ~1s on markt's laptop. If this takes more than 4s something
+        // Takes ~1s on markt's laptop. If this takes more than 5s something
         // probably needs looking at. If this fails repeatedly then we may need
         // to increase this limit.
-        final long maxTime = 4000;
+        final long maxTime = 5000;
         long time = testPerformanceImpl();
         if (time >= maxTime) {
             // Rerun to reject occasional failures, e.g. because of gc
diff --git a/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java b/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
index f300b8a..7edbc81 100644
--- a/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
+++ b/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
@@ -126,6 +126,39 @@ public class TestAuthorizationDigest {
     }
 
     @Test
+    public void testQuotedLhex() throws Exception {
+        String header = "Digest nc=\"09abcdef\"";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertEquals("09abcdef", result.get("nc"));
+    }
+
+    @Test
+    public void testQuotedLhexUppercase() throws Exception {
+        String header = "Digest nc=\"00ABCDEF\"";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertEquals("00abcdef", result.get("nc"));
+    }
+
+    @Test
+    public void testUnclosedQuotedLhex() throws Exception {
+        String header = "Digest nc=\"00000001";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+        Assert.assertNull(result);
+    }
+
+    @Test
     public void testUnclosedQuotedString1() throws Exception {
         String header = "Digest username=\"test";
 
@@ -226,6 +259,16 @@ public class TestAuthorizationDigest {
     }
 
     @Test
+    public void testWrongCharacterInToken2() throws Exception {
+        String header = "Digest qop=\u044f";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+        Assert.assertNull(result);
+    }
+
+    @Test
     public void testWrongCharacterInQuotedToken() throws Exception {
         String header = "Digest qop=\"\u044f\"";
 
@@ -244,4 +287,14 @@ public class TestAuthorizationDigest {
         Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
         Assert.assertNull(result);
     }
+
+    @Test
+    public void testWrongCharacterInQuotedHex() throws Exception {
+        String header = "Digest nc=\"\u044f\"";
+
+        StringReader input = new StringReader(header);
+
+        Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+        Assert.assertNull(result);
+    }
 }
diff --git a/test/org/apache/tomcat/util/net/localhost-cert.pem b/test/org/apache/tomcat/util/net/localhost-cert.pem
index 1994dfb..2e1d07e 100644
--- a/test/org/apache/tomcat/util/net/localhost-cert.pem
+++ b/test/org/apache/tomcat/util/net/localhost-cert.pem
@@ -1,35 +1,35 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 4096 (0x1000)
-        Signature Algorithm: sha1WithRSAEncryption
+        Serial Number: 4099 (0x1003)
+    Signature Algorithm: sha1WithRSAEncryption
         Issuer: C=US, CN=ca-test.tomcat.apache.org
         Validity
-            Not Before: Feb 28 23:10:55 2011 GMT
-            Not After : Feb 27 23:10:55 2013 GMT
+            Not Before: Feb 28 05:28:42 2013 GMT
+            Not After : Feb 28 05:28:42 2015 GMT
         Subject: C=US, CN=localhost
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
-            RSA Public Key: (2048 bit)
-                Modulus (2048 bit):
-                    00:b0:e3:8b:82:f8:b1:82:d9:b1:e8:e8:08:fd:3c:
-                    8a:14:d1:cd:a1:b7:d8:f8:58:93:46:54:c2:6b:b3:
-                    52:fe:ae:7f:a5:70:9e:6c:cf:1f:c7:fb:d7:c2:c2:
-                    5d:0f:18:c9:66:2a:c4:8a:57:ca:0e:4d:b0:0b:af:
-                    1b:26:e9:ad:dd:95:86:69:e4:ac:60:9d:b9:ae:65:
-                    aa:d4:9d:3b:02:19:31:60:df:c3:3e:a5:85:cd:49:
-                    01:12:84:36:4c:02:f5:9c:38:b2:20:bf:43:1d:5f:
-                    0c:ae:86:5a:67:24:65:74:77:fa:f4:cd:04:9f:8c:
-                    c0:f2:5e:4f:bf:db:da:ce:d2:db:a6:51:82:40:ce:
-                    62:0c:9b:5e:d3:10:7b:49:d5:7a:c9:8e:bf:4b:b8:
-                    e3:ac:30:ed:d8:b7:25:1c:c5:5c:0e:1e:57:7c:ad:
-                    60:44:ba:65:6d:45:26:e4:08:a2:1f:c9:3a:cf:7d:
-                    bc:e5:61:23:ea:3e:19:46:f0:16:f8:26:e5:32:c6:
-                    69:e5:ea:18:62:2e:05:65:93:49:23:45:11:c3:da:
-                    4c:3b:b4:c6:4a:72:ea:0b:e9:26:06:2c:69:4d:e7:
-                    b2:a5:3d:54:ae:7f:17:d3:63:8f:d8:36:5b:46:43:
-                    af:bc:c1:09:fc:98:e1:4f:be:74:68:a2:3e:d5:21:
-                    31:d3
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:e7:6f:79:3f:18:87:91:dd:27:98:34:24:79:58:
+                    47:f9:c2:69:2b:d8:5b:c0:e0:bb:4a:57:d6:00:b5:
+                    bb:6a:b0:66:84:5c:b8:f0:12:0a:27:27:32:9c:82:
+                    2a:2f:0f:69:77:a6:e9:0d:df:64:31:51:c0:41:1e:
+                    dc:d4:74:51:9c:a3:b8:51:13:58:73:ee:21:9c:f9:
+                    63:82:1b:c2:2c:49:c3:09:70:ff:a9:f3:af:a2:0c:
+                    0b:60:2f:6a:db:a5:01:45:3e:34:90:8e:67:69:eb:
+                    45:f3:34:29:85:db:39:8a:99:c2:0f:72:15:21:fd:
+                    54:35:a6:7b:a7:30:cb:1e:4d:3d:32:24:c6:4b:84:
+                    4f:5f:60:ff:64:5e:68:ca:d8:fa:de:98:7d:40:04:
+                    60:b7:ae:50:ec:c8:8c:ae:dd:94:81:41:18:5b:03:
+                    63:0f:2b:02:63:0a:95:6a:ed:7e:68:e6:b6:d5:56:
+                    e9:4e:60:ea:1d:95:58:33:be:a2:12:55:cb:7f:9c:
+                    c4:97:0b:db:c0:94:09:2a:b3:9f:e1:6b:78:0d:63:
+                    1a:41:d5:6b:db:d8:48:59:04:88:d1:11:d5:e7:45:
+                    28:0e:7c:1b:78:75:20:7d:ff:7f:e1:d6:ea:e4:c5:
+                    51:77:41:42:30:4b:ff:29:33:3d:89:58:94:69:5b:
+                    70:27
                 Exponent: 65537 (0x10001)
         X509v3 extensions:
             X509v3 Basic Constraints: 
@@ -37,43 +37,43 @@ Certificate:
             Netscape Comment: 
                 OpenSSL Generated Certificate
             X509v3 Subject Key Identifier: 
-                36:5C:54:F4:2E:91:6D:E7:BC:DD:94:C7:F8:D7:55:01:4A:F7:7D:CD
+                30:DB:AB:70:94:34:CA:FD:75:46:AB:CE:E2:4A:A9:9E:74:BC:69:BB
             X509v3 Authority Key Identifier: 
                 keyid:B0:3B:BC:C9:FA:28:5F:3E:04:1F:9B:6C:C7:8B:68:D8:01:B0:F8:3D
 
     Signature Algorithm: sha1WithRSAEncryption
-        30:d5:b3:07:2d:04:25:9b:f1:20:bb:91:49:dc:3d:bf:7e:1c:
-        2d:09:01:87:a0:30:2b:50:fe:3b:17:34:c6:1d:fa:51:c0:b3:
-        af:f5:62:a6:de:3a:bf:6c:f7:07:e6:80:26:08:d1:84:5b:a3:
-        5a:0c:6a:07:de:d6:26:1d:c1:89:ed:8a:15:1d:1a:36:0c:13:
-        db:ab:7c:43:35:0b:c2:c6:63:a6:43:81:ce:e5:52:28:cd:ee:
-        c7:0d:3c:8e:a1:07:3b:7c:48:ff:fe:b9:1d:04:51:18:27:d1:
-        fb:b4:1e:bf:36:f1:ef:a9:87:89:3b:b1:49:a9:70:62:5b:f0:
-        49:e7:27:3a:cc:91:6f:08:43:a4:de:28:f2:1c:69:90:09:5d:
-        bd:78:9f:25:ec:b6:4c:7a:ce:d4:3c:a1:d3:5c:3c:78:04:91:
-        b3:35:56:81:64:4c:61:7b:80:ae:42:34:e1:9a:a1:33:0e:23:
-        dc:76:bf:29:ca:6e:c1:ce:1a:f0:1b:a6:b5:ab:dc:be:19:e9:
-        9a:e3:6f:7d:ed:a1:e7:bf:f5:23:ad:60:ce:2b:79:49:4e:73:
-        7f:00:da:a6:95:af:f1:ae:e7:51:de:7f:35:70:60:5d:fb:61:
-        54:34:a9:22:7a:7e:76:49:70:9f:e7:ab:f1:38:a7:a1:53:87:
-        fb:61:b8:3f
+         ab:d3:e7:2b:35:d3:6d:9f:87:2a:64:58:f1:61:cb:56:a8:84:
+         22:79:ac:0d:68:1f:55:0d:dd:16:16:72:c4:a9:75:2a:0e:f8:
+         b1:73:68:c9:ee:43:d8:5c:fa:07:5d:3f:41:fb:14:17:be:64:
+         21:d8:1e:25:67:92:b2:c5:bb:43:1d:96:b6:d3:bd:1c:e1:a4:
+         c7:ee:e3:37:0b:92:14:56:ca:ad:a8:76:5b:80:c9:42:8c:89:
+         f1:42:6e:8c:fb:a1:d7:98:d5:6d:49:99:fe:b6:f6:c6:f3:cc:
+         8f:06:54:6e:02:f5:8f:4b:f1:86:ac:14:93:6c:74:25:26:44:
+         7a:5b:82:3c:57:d6:e5:14:6e:b7:29:53:e4:40:7a:2f:10:5d:
+         ff:28:7f:e5:e5:54:6c:38:fa:b9:27:97:2a:69:60:ba:4a:5a:
+         28:65:b1:81:e0:b7:a1:74:d6:e6:07:81:6d:b8:59:c3:45:bd:
+         7c:a8:17:67:1f:fc:52:1a:6c:90:87:4d:a1:98:51:8c:29:6a:
+         84:d9:0d:24:a8:86:6a:5e:6a:b7:f9:27:9b:52:37:96:b5:fd:
+         94:11:ca:c4:d9:6d:69:81:fa:96:34:63:3a:7c:49:2d:06:48:
+         ae:b1:14:59:12:29:8e:59:3d:03:99:42:90:e6:82:df:08:cf:
+         d7:77:ec:00
 -----BEGIN CERTIFICATE-----
-MIIDSTCCAjGgAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwMTELMAkGA1UEBhMCVVMx
-IjAgBgNVBAMTGWNhLXRlc3QudG9tY2F0LmFwYWNoZS5vcmcwHhcNMTEwMjI4MjMx
-MDU1WhcNMTMwMjI3MjMxMDU1WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAxMJbG9j
-YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsOOLgvixgtmx
-6OgI/TyKFNHNobfY+FiTRlTCa7NS/q5/pXCebM8fx/vXwsJdDxjJZirEilfKDk2w
-C68bJumt3ZWGaeSsYJ25rmWq1J07AhkxYN/DPqWFzUkBEoQ2TAL1nDiyIL9DHV8M
-roZaZyRldHf69M0En4zA8l5Pv9vaztLbplGCQM5iDJte0xB7SdV6yY6/S7jjrDDt
-2LclHMVcDh5XfK1gRLplbUUm5AiiH8k6z3285WEj6j4ZRvAW+CblMsZp5eoYYi4F
-ZZNJI0URw9pMO7TGSnLqC+kmBixpTeeypT1Urn8X02OP2DZbRkOvvMEJ/JjhT750
-aKI+1SEx0wIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVu
-U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUNlxU9C6Rbee83ZTH
-+NdVAUr3fc0wHwYDVR0jBBgwFoAUsDu8yfooXz4EH5tsx4to2AGw+D0wDQYJKoZI
-hvcNAQEFBQADggEBADDVswctBCWb8SC7kUncPb9+HC0JAYegMCtQ/jsXNMYd+lHA
-s6/1YqbeOr9s9wfmgCYI0YRbo1oMagfe1iYdwYntihUdGjYME9urfEM1C8LGY6ZD
-gc7lUijN7scNPI6hBzt8SP/+uR0EURgn0fu0Hr828e+ph4k7sUmpcGJb8EnnJzrM
-kW8IQ6TeKPIcaZAJXb14nyXstkx6ztQ8odNcPHgEkbM1VoFkTGF7gK5CNOGaoTMO
-I9x2vynKbsHOGvAbprWr3L4Z6Zrjb33toee/9SOtYM4reUlOc38A2qaVr/Gu51He
-fzVwYF37YVQ0qSJ6fnZJcJ/nq/E4p6FTh/thuD8=
+MIIDSTCCAjGgAwIBAgICEAMwDQYJKoZIhvcNAQEFBQAwMTELMAkGA1UEBhMCVVMx
+IjAgBgNVBAMTGWNhLXRlc3QudG9tY2F0LmFwYWNoZS5vcmcwHhcNMTMwMjI4MDUy
+ODQyWhcNMTUwMjI4MDUyODQyWjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAxMJbG9j
+YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5295PxiHkd0n
+mDQkeVhH+cJpK9hbwOC7SlfWALW7arBmhFy48BIKJycynIIqLw9pd6bpDd9kMVHA
+QR7c1HRRnKO4URNYc+4hnPljghvCLEnDCXD/qfOvogwLYC9q26UBRT40kI5naetF
+8zQphds5ipnCD3IVIf1UNaZ7pzDLHk09MiTGS4RPX2D/ZF5oytj63ph9QARgt65Q
+7MiMrt2UgUEYWwNjDysCYwqVau1+aOa21VbpTmDqHZVYM76iElXLf5zElwvbwJQJ
+KrOf4Wt4DWMaQdVr29hIWQSI0RHV50UoDnwbeHUgff9/4dbq5MVRd0FCMEv/KTM9
+iViUaVtwJwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVu
+U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUMNurcJQ0yv11RqvO
+4kqpnnS8abswHwYDVR0jBBgwFoAUsDu8yfooXz4EH5tsx4to2AGw+D0wDQYJKoZI
+hvcNAQEFBQADggEBAKvT5ys1022fhypkWPFhy1aohCJ5rA1oH1UN3RYWcsSpdSoO
++LFzaMnuQ9hc+gddP0H7FBe+ZCHYHiVnkrLFu0MdlrbTvRzhpMfu4zcLkhRWyq2o
+dluAyUKMifFCboz7odeY1W1Jmf629sbzzI8GVG4C9Y9L8YasFJNsdCUmRHpbgjxX
+1uUUbrcpU+RAei8QXf8of+XlVGw4+rknlyppYLpKWihlsYHgt6F01uYHgW24WcNF
+vXyoF2cf/FIabJCHTaGYUYwpaoTZDSSohmpearf5J5tSN5a1/ZQRysTZbWmB+pY0
+Yzp8SS0GSK6xFFkSKY5ZPQOZQpDmgt8Iz9d37AA=
 -----END CERTIFICATE-----
diff --git a/test/org/apache/tomcat/util/net/localhost-copy1.jks b/test/org/apache/tomcat/util/net/localhost-copy1.jks
index 256a64b..353cd81 100644
Binary files a/test/org/apache/tomcat/util/net/localhost-copy1.jks and b/test/org/apache/tomcat/util/net/localhost-copy1.jks differ
diff --git a/test/org/apache/tomcat/util/net/localhost-key.pem b/test/org/apache/tomcat/util/net/localhost-key.pem
index bc1c7e7..911476d 100644
--- a/test/org/apache/tomcat/util/net/localhost-key.pem
+++ b/test/org/apache/tomcat/util/net/localhost-key.pem
@@ -1,27 +1,28 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEAsOOLgvixgtmx6OgI/TyKFNHNobfY+FiTRlTCa7NS/q5/pXCe
-bM8fx/vXwsJdDxjJZirEilfKDk2wC68bJumt3ZWGaeSsYJ25rmWq1J07AhkxYN/D
-PqWFzUkBEoQ2TAL1nDiyIL9DHV8MroZaZyRldHf69M0En4zA8l5Pv9vaztLbplGC
-QM5iDJte0xB7SdV6yY6/S7jjrDDt2LclHMVcDh5XfK1gRLplbUUm5AiiH8k6z328
-5WEj6j4ZRvAW+CblMsZp5eoYYi4FZZNJI0URw9pMO7TGSnLqC+kmBixpTeeypT1U
-rn8X02OP2DZbRkOvvMEJ/JjhT750aKI+1SEx0wIDAQABAoIBACTERx1D//GIujgE
-8slgKftF2I4CnrCQCJyXxYmJTnjtYE7M58EKFDsHF8O9joYyyrnXrd5rfO4YK71h
-+izOaXsjNzsPctzqK8waCbYDsF4xSlguanC9CuCuifCFVpvaCZ8dEblIx/R06zfj
-aSsDH6tjvN/hNVLMeNZnz/+6/PH7/SP+HbDWGEi15yx1CSuqD3Dj/wIY7uhvlv/J
-DGDeYhjcSupjofBkk2guwHzV6qL7fLWyn7MPVS3iRHeX8yWxAWabiW7WVqpClAKE
-OTfP9h13yutQx10dhMzIYdxcXeyyfOVfI+mwyi8AN9FAwP11dN7w/0xqTMNErCox
-qW1C1YECgYEA6QKjfMGkmtpWsDKpu0I4wgnPh0VtuhQGaLy/f0IFn05BOZVD0LiF
-0jqyj1HtNkBSeX0Cz5GCG7DihX4seMjiYbHrOLTRrqIGxMLGJdMNUkmZZHCX7ZhT
-SXFTgbqF3gCSPL5avta2eyPKjrCJYDYwqpbvd2lc7YKPOfHyOgqyDnMCgYEAwldk
-xZUK3HR94/4GWS46TNIsv0IYLTbrzJKNFnbn0t1JVPR7aHUeI8cSrGa5mCHzn1wK
-JFwe7JzlgyLZvgblqbxgDw5x8/GrLNhR3ClxtROusAg7zgX2Pxl0Gk1pr8dBgoiU
-m3cZPKgvhagPQ6NKkP+ryzqJxXc8Pm51neZbFyECgYEA0Z91ExRmkIVivasmdXfS
-9gW7dNeqKmA/j9RWdxcfVb0iArrdQpXulj4GS9eJj2f4iqFDeRdPtLfCYhQr0BHx
-T7Cvi9loVjIf4r3TY03myyO5YtnEZJTIQOc6GBiEvD9JUGpz2wHxMwD1Br+dJzg5
-Og8FqijY2De/wIKAx2S94S8CgYEAlZ4gx/ipxvWsYhWUn532ZmQ87PYelNi+it2c
-31mlunKA3XXneJEKJjNCDhZ79kLVQ6/hYwLFEBbun5n6FtFKiPWs4oqVcmBxD3Ju
-+1ew4d6IU5/TIxb18LhQ6VsF7b0ykyNBfbsgY9F73KN5NPKHGsCrayfjH3JfoBT8
-WhcZs+ECgYBu7Y+hbGzMpHiuzyV/Niii5Iec2X+5H5rnM6S5h9I37aVnOp2Kl8bo
-Eg5krCCeR6/F+I8Qj3KSgu3af1pTliO4m7Dt0sm3SEJeGrb7xQF2m0mf4VJ7Bf/w
-H/H3Cuk63tsLedxWD0AYdlNbT7cA47bl15G8J+5qRQXZyuxUP1mZ9Q==
------END RSA PRIVATE KEY-----
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDnb3k/GIeR3SeY
+NCR5WEf5wmkr2FvA4LtKV9YAtbtqsGaEXLjwEgonJzKcgiovD2l3pukN32QxUcBB
+HtzUdFGco7hRE1hz7iGc+WOCG8IsScMJcP+p86+iDAtgL2rbpQFFPjSQjmdp60Xz
+NCmF2zmKmcIPchUh/VQ1pnunMMseTT0yJMZLhE9fYP9kXmjK2PremH1ABGC3rlDs
+yIyu3ZSBQRhbA2MPKwJjCpVq7X5o5rbVVulOYOodlVgzvqISVct/nMSXC9vAlAkq
+s5/ha3gNYxpB1Wvb2EhZBIjREdXnRSgOfBt4dSB9/3/h1urkxVF3QUIwS/8pMz2J
+WJRpW3AnAgMBAAECggEBALfaj6h3NSPEW7MHIT6gyjT4o5IoQ+O65C6QDrrrpCKC
+Vj6qZmSZACXQdt1sblSKWs+p8hSKNc8UUbWp7eZ9LWRRj5gg1TDrqRpJ6CoxIRUL
+1/wFH6WEqC8EgHj90lcBAzxdyWZZKoAzXpNxCdeDq3eW5Fpe17jzxdUFF9Be6816
+LbxTlrMisLp0u39v1GnE/vd2nemKUWY7uNSRRrtTi8mjAmXcnogxBmAyN7wjqVHt
+KKBYkyTRPCh8K6R+t/dqbZsv1k8fdS1/csXoiU2nJ86pdbSHOQ7aZMWXTZmAE5wb
+G4Oe9X61Hg5xgTDO/nEd8q2Sl6mMSx9L5IjdTm+WVRkCgYEA/CaXCzlUPUtVbkih
+bkDCQbYVarrRo90PskL2mgUQDUBgFOzSQXrJ6qEEYXy5PdOBhiaK3385wSXBX+nF
+7LOANzrgN9k+6Vt3fe20HrYltoc5e0lxvk4rdNSyrpe+E5bz8LtASlMBj2o6W6Md
+NkCAEKRp7wC2gb3MPeWhCpiJrLsCgYEA6vfthWHjL+yr6hFro/IsHnQdYSn4QPgn
++WrOg6gGwhS5ZqJLK5jB95RFvgGhNBxh8nMCP0VnJYmM1pQtzR/YE7PU7SlRyAd/
+DVkyO8NRQTzA6z/mPoeGx4dtTwaye10c7KZxmZCXq1tB4D6gTDJUQF5gt8tbx4C8
+1mul1xQ0aYUCgYAFovMzbAenCx0QxwzcwxPUljZqWVzAVfu412hdzwkp0quTLCwT
+DKSg2xKW/0vAxw6ZKhlmn5hx6d8lvrsO7IBMO8OxW+jdHI9SQFMLcLTtHJ67U8v4
+HhU4mlyYLIoyM+imE/l+79YUF6LQU5gek1iJhrNbhV+PDOgY5h4wd3J0awKBgBfF
+OSwzOO6SPNoTJRaS20/BY29+9XRtJm4fFgFPsE9WFWOCq6Qfcg//2gZc19gTvvzu
+EZ4hAUxU3AChQPjtbcigerv7YCCiUYIiMejF26SD5uhlsH9G6qWo17AU911vkAuI
+0xk7/XwCYWm0LDdJKCjS42n0krZeGbx/a2mUy7CZAoGAGXq2r3INg0xiZa8mSeJB
+MeZswgGKxN7MHlKKcpELEWg97ev4NvTq4T+PEl+1miRtlyzcFgMXKe3oBU0Ru7Qu
+O2u3kfLTOPGHmo+KpFNJHE8g+PwoOheNis2JZkd3T9fX7JRRYCiBeW4nMYzP2yGS
+nlaUqPewhh5/1fRCmF36TyU=
+-----END PRIVATE KEY-----
diff --git a/test/org/apache/tomcat/util/net/localhost.jks b/test/org/apache/tomcat/util/net/localhost.jks
index a9f4f10..3be335c 100644
Binary files a/test/org/apache/tomcat/util/net/localhost.jks and b/test/org/apache/tomcat/util/net/localhost.jks differ
diff --git a/test/org/apache/tomcat/util/net/user1.jks b/test/org/apache/tomcat/util/net/user1.jks
index cc420f5..0c084fc 100644
Binary files a/test/org/apache/tomcat/util/net/user1.jks and b/test/org/apache/tomcat/util/net/user1.jks differ
diff --git a/test/webapp-3.0-fragments/WEB-INF/web.xml b/test/webapp-3.0-fragments/WEB-INF/web.xml
index 9424b38..3344671 100644
--- a/test/webapp-3.0-fragments/WEB-INF/web.xml
+++ b/test/webapp-3.0-fragments/WEB-INF/web.xml
@@ -57,4 +57,23 @@
     <lifecycle-callback-class>org.apache.catalina.startup.TesterServletWithLifeCycleMethods</lifecycle-callback-class>
     <lifecycle-callback-method>preDestroy1</lifecycle-callback-method>
   </pre-destroy>
+
+  <env-entry>
+    <env-entry-name>envEntry2</env-entry-name>
+    <env-entry-type>java.lang.Integer</env-entry-type>
+    <env-entry-value>2</env-entry-value>
+    <injection-target>
+      <injection-target-class>org.apache.catalina.startup.TesterServletWithAnnotations</injection-target-class>
+      <injection-target-name>envEntry2</injection-target-name>
+    </injection-target>
+  </env-entry>
+  <env-entry>
+    <env-entry-name>envEntry3</env-entry-name>
+    <env-entry-type>java.lang.Integer</env-entry-type>
+    <env-entry-value>33</env-entry-value>
+    <injection-target>
+      <injection-target-class>org.apache.catalina.startup.TesterServletWithAnnotations</injection-target-class>
+      <injection-target-name>envEntry3</injection-target-name>
+    </injection-target>
+  </env-entry>
 </web-app>
\ No newline at end of file
diff --git a/webapps/docs/appdev/deployment.xml b/webapps/docs/appdev/deployment.xml
index e6a1681..b626aca 100644
--- a/webapps/docs/appdev/deployment.xml
+++ b/webapps/docs/appdev/deployment.xml
@@ -124,7 +124,7 @@ API Specification, version 2.3, which you should consult for more details.</p>
 <p>Like most servlet containers, Tomcat also supports mechanisms to install
 library JAR files (or unpacked classes) once, and make them visible to all
 installed web applications (without having to be included inside the web
-application itself.  The details of how Tomcat locates and shares such
+application itself).  The details of how Tomcat locates and shares such
 classes are described in the
 <a href="../class-loader-howto.html">Class Loader HOW-TO</a> documentation.
 The location commonly used within a Tomcat installation for shared code is
@@ -138,9 +138,6 @@ of pre-installed shared library files, including:</p>
 <ul>
 <li>The <em>Servlet 3.0</em> and <em>JSP 2.2</em> APIs that are fundamental
     to writing servlets and JavaServer Pages.<br/><br/></li>
-<li>An <em>XML Parser</em> compliant with the JAXP (version 1.2) APIs, so
-    your application can perform DOM-based or SAX-based processing of
-    XML documents.<br/><br/></li>
 </ul>
 
 </section>
@@ -177,10 +174,11 @@ the order defined by the DTD (see Section 13.3).</p>
 <section name="Tomcat Context Descriptor">
 
 <p>A /META-INF/context.xml file can be used to define Tomcat specific
-configuration options, such as loggers, data sources, session manager
+configuration options, such as an access log, data sources, session manager
 configuration and more. This XML file must contain one Context element, which
 will be considered as if it was the child of the Host element corresponding
-to the Host to which the  The Tomcat configuration documentation contains
+to the Host to which the web application is being deployed. The
+<a href="../config/index.html">Tomcat configuration documentation</a> contains
 information on the Context element.</p>
 
 </section>
diff --git a/webapps/docs/appdev/introduction.xml b/webapps/docs/appdev/introduction.xml
index 0048d61..6e37f6d 100644
--- a/webapps/docs/appdev/introduction.xml
+++ b/webapps/docs/appdev/introduction.xml
@@ -49,7 +49,7 @@ are included in the following subsections.</p>
 a text editor along with command line tools to develop and debug their
 applications.  As such, the recommendations are fairly generic -- but you
 should easily be able to apply them in either a Windows-based or Unix-based
-development environment.  If you are utilizing an Interactive Development
+development environment.  If you are utilizing an Integrated Development
 Environment (IDE) tool, you will need to adapt the advice given here to
 the details of your particular environment.</p>
 
@@ -62,35 +62,27 @@ the details of your particular environment.</p>
 information, documentation, and software that is useful in developing
 web applications with Tomcat.</p>
 <ul>
-<li><a href="http://java.sun.com/products/jsp/">http://java.sun.com/products/jsp/</a> -
-    <i>JavaServer Pages (JSP) Specification, Version 2.0</i>.  Describes
+<li><a href="http://jcp.org/aboutJava/communityprocess/mrel/jsr245/index.html">http://jcp.org/aboutJava/communityprocess/mrel/jsr245/</a> -
+    <i>JavaServer Pages (JSP) Specification, Version 2.2</i>.  Describes
     the programming environment provided by standard implementations
     of the JavaServer Pages (JSP) technology.  In conjunction with
     the Servlet API Specification (see below), this document describes
     what a portable API page is allowed to contain.  Specific
-    information on scripting (Chapter 6), tag extensions (Chapter 7),
+    information on scripting (Chapter 9), tag extensions (Chapter 7),
     and packaging JSP pages (Appendix A) is useful.  The Javadoc
     API Documentation is included in the specification, and with the
     Tomcat download.<br/><br/></li>
-<li><a href="http://java.sun.com/products/servlet/download.html">http://java.sun.com/products/servlet/download.html</a> -
+<li><a href="http://jcp.org/aboutJava/communityprocess/mrel/jsr315/index.html">http://jcp.org/aboutJava/communityprocess/mrel/jsr315/</a> -
     <i>Servlet API Specification, Version 3.0</i>.  Describes the
     programming environment that must be provided by all servlet
     containers conforming to this specification.  In particular, you
     will need this document to understand the web application
-    directory structure and deployment file (Chapter 9), methods of
-    mapping request URIs to servlets (Chapter 11), container managed
-    security (Chapter 12), and the syntax of the <code>web.xml</code>
-    Web Application Deployment Descriptor (Chapter 13).  The Javadoc
+    directory structure and deployment file (Chapter 10), methods of
+    mapping request URIs to servlets (Chapter 12), container managed
+    security (Chapter 13), and the syntax of the <code>web.xml</code>
+    Web Application Deployment Descriptor (Chapter 14).  The Javadoc
     API Documentation is included in the specification, and with the
     Tomcat download.<br/><br/></li>
-<li><a href="http://java.sun.com/j2ee/blueprints/">http://java.sun.com/j2ee/blueprints/</a> -
-    <i>Sun BluePrints (tm) Design Guidelines for J2EE</i>.  Comprehensive
-    advice and examples on application design for the Java2 Enterprise
-    Edition (J2EE) platform, which includes servlets and JSP pages.  The
-    chapters on servlet and JSP design are useful even when your application
-    does not require other J2EE platform components.
-    <br/><br/></li>
-<li><b>TODO</b> -- Add more entries here!</li>
 </ul>
 
 </section>
diff --git a/webapps/docs/architecture/overview.xml b/webapps/docs/architecture/overview.xml
index 504add1..62de4e0 100644
--- a/webapps/docs/architecture/overview.xml
+++ b/webapps/docs/architecture/overview.xml
@@ -63,7 +63,7 @@ implementation is simple and sufficient:
 An
 <a href="../config/engine.html">Engine</a> represents request processing
 pipeline for a specific Service.  As a Service may have multiple Connectors,
-the Engine received and processes all requests from these connectors, handing
+the Engine receives and processes all requests from these connectors, handing
 the response back to the appropriate connector for transmission to the client.
 The <a href="../api/org/apache/catalina/Engine.html">Engine interface</a>
 may be implemented to supply custom Engines, though this is uncommon.
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 243b5e9..fc29b69 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -24,17 +24,19 @@
   &project;
 
   <properties>
-    <author email="remm at apache.org">Remy Maucherat</author>
-    <author email="fhanik at apache.org">Filip Hanik</author>
-    <author email="rjung at apache.org">Rainer Jung</author>
-    <author email="kkolinko at apache.org">Konstantin Kolinko</author>
-    <author email="pero at apache.org">Peter Rossbach</author>
-    <author email="kfujino at apache.org">Keiichi Fujino</author>
-    <author email="timw at apache.org">Tim Whittington</author>   
-    <author email="mturk at apache.org">Mladen Turk</author>
-    <author email="schultz at apache.org">Christopher Schultz</author>
-    <author email="slaurent at apache.org">Sylvain Laurent</author>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="fhanik at apache.org">Filip Hanik</author>
+    <author email="rjung at apache.org">Rainer Jung</author>
+    <author email="kkolinko at apache.org">Konstantin Kolinko</author>
+    <author email="pero at apache.org">Peter Rossbach</author>
+    <author email="kfujino at apache.org">Keiichi Fujino</author>
+    <author email="timw at apache.org">Tim Whittington</author>   
+    <author email="mturk at apache.org">Mladen Turk</author>
+    <author email="schultz at apache.org">Christopher Schultz</author>
+    <author email="slaurent at apache.org">Sylvain Laurent</author>
+    <author email="violetagg at apache.org">Violeta Georgieva</author>
     <title>Changelog</title>
+    <no-comments />
   </properties>
 
 <body>
@@ -53,7 +55,438 @@
   They eventually become mixed with the numbered issues. (I.e., numbered
   issues to not "pop up" wrt. others).
 -->
-<section name="Tomcat 7.0.35 (markt)">
+<section name="Tomcat 7.0.39 (markt)">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Ensure a log message is generated when a web application fails to start
+        due to an error processing a ServletContainerInitializer. (markt)
+      </fix>
+      <fix>
+        Prevent NPE in JAR scanning when running in an environment where the
+        bootstrap class loader is not an ancestor of the web application class
+        loader such as OSGi environments. (violetagg)
+      </fix>
+      <fix>
+        Ensure that, if a call to UEncoder#encodeURL is made, all internal
+        structures are properly cleaned. (violetagg)
+      </fix>
+      <add>
+        <bug>54660</bug>: Enable the modification of an access log's
+        <code>fileDateFormat</code> attribute while the access log is in use.
+        The change will take effect when the next entry is made to the access
+        log. (markt)
+      </add>
+      <update>
+        Update Tomcat's internal copy of Commons FileUpload to FileUpload trunk,
+        revision 1458500 and the associated extract from Commons IO to 2.4.
+        (markt)
+      </update>
+      <fix>
+        <bug>54702</bug>: Prevent file descriptors leak and ensure that files
+        are closed when parsing web application deployment descriptors.
+        (violetagg)
+      </fix>
+      <fix>
+        <bug>54707</bug>: Further relax the parsing of DIGEST authentication
+        headers to allow for buggy clients that quote values that RFC2617 states
+        should not be quoted. (markt/kkolinko)
+      </fix>
+      <fix>
+        Enable support for MBeans with multiple operations with the same name
+        but different signatures. (markt)
+      </fix>
+      <scode>
+        Deprecate Tomcat's internal Base 64 encoder/decoder and switch to
+        using a package renamed copy of the Commons Codec implementation.
+        (markt)
+      </scode>
+      <fix>
+        Ensure that StandardJarScanner#scan will use the provided class loader
+        when scanning the class loader hierarchy. (violetagg)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>54690</bug>: Fix a regression caused by the previous fix for
+        <bug>54406</bug>. If no values are specified for sslEnabledProtocols or
+        ciphers use the default values for server sockets rather than the
+        default values for client sockets. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <update>
+        Correct Deployer, Manager and Context pages of Tomcat documentation.
+        (kkolinko)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="jdbc-pool">
+    <changelog>
+      <fix>
+        <bug>52318</bug>: Version for imported package
+        <code>org.apache.juli.logging</code> is extended to include also 7.0.x
+        versions. The fix is applicable only when running in OSGi environment.
+        Patch provided by Martin Lichtin. (violetagg)
+      </fix>
+      <fix>
+        <bug>54599</bug>: Do not print connection password in
+        <code>PoolProperties.toString()</code>. Based on a patch by
+        Daniel Mikusa. (kkolinko)
+      </fix>
+      <fix>
+        <bug>54684</bug>: Add <code>javax.naming.spi</code> to 
+        <code>Import-Package</code> header in MANIFEST.MF in order to resolve
+        <code>ClassNotFoundException</code> when running in OSGi environment.
+        (violetagg)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <fix>
+        Update to Apache Commons Daemon 1.0.14 to resolve <bug>54609</bug>
+        which meant that installation of Windows service could fail
+        producing incorrect service launch command. (mturk)
+      </fix>
+      <fix>
+        Ensure HEAD requests return the correct content length when the
+        requested resource uses a Writer. Patch by Nick Williams. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.38 (markt)" rtext="not released">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Ensure that the request start time (used by the access log valve to
+        calculate request processing time) is correctly recorded for the HTTP
+        NIO connector. In some cases the request processing time may have been
+        longer than that recorded. (markt)
+      </fix>
+      <update>
+        Add one more library from JDK 7 to the value of <code>jarsToSkip</code>
+        property in the <code>catalina.properties</code> file. (kkolinko)
+      </update>
+      <add>
+        <bug>53871</bug>: If annotation scanning results in a
+        <code>StackOverflowError</code> due to broken class dependencies, add
+        the class hierarchy that triggered the exception to the error message.
+        (markt)
+      </add>
+      <add>
+        Add a new option to the standard JarScanner implementation
+        (<code>scanBootstrapClassPath</code>) to control if the bootstrap
+        classpath is scanned or not. By default, it will not be scanned. (markt)
+      </add>
+      <update>
+        Provide more consolidated servlet MBean data in the webapp MBean.
+        (rjung)
+      </update>
+      <fix>
+        <bug>54584</bug>: Take account of the delegate attribute when building
+        the web application class path to pass to the JSP compiler. (markt)
+      </fix>
+      <fix>
+        Copy the updated and re-packaged UTF-8 decoder from Tomcat 8.0.x and use
+        this improved decoder for WebSocket connections. Remove the WebSocket
+        specific UTF-8 decoder. (markt)
+      </fix>
+      <fix>
+        <bug>54602</bug>: Recycle the byte to character converter used for URIs
+        between requests to ensure an error in one request does not trigger a
+        failure in the next request. (markt)
+      </fix>
+      <fix>
+        Use the newly added improved UTF-8 decoder for decoding UTF-8 encoded
+        URIs and UTF-8 encoded request bodies. Invalid UTF-8 URIs will not
+        cause an error but will make use of the replacement character when an
+        error is detected. This will allow web applications to handle the URI
+        which will most likely result in a 404 response. The fall-back to
+        decoding with ISO-8859-1 if UTF-8 decoding fails has been removed.
+        Invalid UTF-8 sequences in a request body will trigger an IOException.
+        The way the decoder is used has also been improved. The notable change
+        is that invalid sequences at the end of the input now trigger an error
+        rather than being silently swallowed. (markt)
+      </fix>
+      <fix>
+        <bug>54624</bug>: Ensure that the correct request body length is used
+        when swallowing a request body after FORM authentication prior to
+        restoring the original request preventing possible hanging when
+        restoring POST requests submitted over AJP. (markt)
+      </fix>
+      <fix>
+        <bug>54628</bug>: When writing binary WebSocket messages write from
+        start position in array rather than the start of the array. Patch
+        provided by blee. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <scode>
+        Refactor char encoding/decoding using NIO APIs. (remm)
+      </scode>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <fix>
+        <bug>54203</bug>: Complete the Javadoc for
+        <code>javax.servlet.http.Part</code>. (markt)
+      </fix>
+      <fix>
+        <bug>54638</bug>: Fix display of "Used" memory value for memory pools
+        on the status page in Manager web application when the page is rendered
+        as XML. (kkolinko)
+      </fix>
+      <fix>
+        Correct typos in configuration samples on SSL Configuration page
+        of Tomcat documentation. (kkolinko)
+      </fix>
+      <update>
+        Disable support for comments on Changelog page of Tomcat
+        documentation. (kkolinko)
+      </update>
+      <fix>
+        Fix several issues with <code>status.xsd</code> schema in Manager web
+        application, testing it against actual output of StatusTransformer
+        class. (kkolinko)
+      </fix>
+      <fix>
+        Clarify the documentation on how context paths may be configured for web
+        applications. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <update>
+        <bug>54601</bug>: Change <code>catalina.sh</code> to consistently use
+        <code>LOGGING_MANAGER</code> variable to configure logging,
+        instead of modifying <code>JAVA_OPTS</code> one. (kkolinko)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.37 (markt)" rtext="2013-02-18">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>54521</bug>: Ensure that concurrent requests that require a DIGEST
+        authentication challenge receive different nonce values. (markt)
+      </fix>
+      <fix>
+        <bug>54534</bug>: Ensure that, if a call to
+        <code>StandardWrapper#isSingleThreadModel()</code> triggers the loading
+        of a Servlet, the correct class loader is used. (markt)
+      </fix>
+      <fix>
+        <bug>54536</bug>: Ensure the default error page is displayed if a custom
+        HTTP status code is used when calling
+        <code>HttpServletResponse#sendError(int, String)</code>. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>54456</bug>: Ensure that if a client aborts a request when sending
+        a chunked request body that this is communicated correctly to the client
+        reading the request body. (markt)
+      </fix>
+      <update>
+        Update the native component of the APR/native connector to 1.1.27 and
+        make that version the recommended minimum version. (markt)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <add>
+        <bug>54239</bug>: Enable web applications to provide their own
+        Expression Language interpreter to enable them to optimise processing of
+        expressions. Based on a patch by Sheldon Shao. (markt)
+      </add>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <add>
+        <bug>54505</bug>: Create clearer links from the JNDI How-To to the
+        Tomcat specific options for configuring JNDI resources. (markt)
+      </add>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <update>
+        Update to Apache Commons Daemon 1.0.13. (markt)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.36 (markt)" rtext="not released">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Make additional allowances for buggy client implementations of HTTP
+        DIGEST authentication. This is a follow-on to <bug>54060</bug>. (markt)
+      </fix>
+      <fix>
+        <bug>54438</bug>: Fix a regression in the fix for <bug>52953</bug> that
+        triggered a NPE when digested passwords were used and an authentication
+        attempt was made for a user that did not exist in the realm. (markt)
+      </fix>
+      <fix>
+        <bug>54448</bug>: Correctly handle <code>@Resource</code> annotations on
+        primitives. Patch provided by Violeta Georgieva. (markt)
+      </fix>
+      <fix>
+        <bug>54450</bug>: Correctly handle resource injection when part of the
+        servlet properties uses <code>@Resource</code> and the other uses
+        <code>injection-target</code>. Patch provided by  Violeta Georgieva.
+        (markt)
+      </fix>
+      <fix>
+        <bug>54458</bug>: Include exception when logging errors in the
+        DataSourceRealm. Patch provided by  Violeta Georgieva. (markt)
+      </fix>
+      <fix>
+        <bug>54483</bug>: Correct one of the Spanish translations. Based on a
+        suggestion from adinamita. (markt)
+      </fix>
+      <fix>
+        Prevent the SSO deregister when web application is stopped or reloaded.
+        When StandardManager(pathname="") or DeltaManager stops normally, all
+        sessions in the context are expired.
+        In this case, because most sessions is not time-out, SSO deregister was
+        triggered. (kfujino)
+      </fix>
+      <fix>
+        Include the exception in the log message if the parsing of the
+        context.xml file fails. (markt/kkolinko)
+      </fix>
+      <fix>
+        <bug>54497</bug>: Make memory leak detection code more robust so a
+        failure in the leak detection code does not prevent the Context from
+        stopping unless the error is fatal to the JVM. (markt)
+      </fix>
+      <fix>
+        <bug>54507</bug>: Do not start the background thread that is used for
+        expiring sessions (amongst other things) until the web application is
+        fully started. Stop the background thread as soon as the web application
+        is stopped. (markt)
+      </fix>
+      <fix>
+        Allow WebSocket Ping/Pong messages to be sent between fragments of a
+        fragmented message. (markt)
+      </fix>
+      <fix>
+        <bug>54612</bug>: Check if the socket is closed before trying to write a
+        WebSocket message to it. Also, flush any partial buffered data before
+        closing the socket. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>54324</bug>: Allow APR connector to disable TLS compression
+        if OpenSSL supports it. (schultz)
+      </fix>
+      <fix>
+        <bug>54406</bug>: Fix NIO HTTPS connector to prune specified <code>
+        ciphers</code> and <code>sslEnableProtocols</code> options to those
+        supported by the SSL implementation, sharing logic with the BIO
+        connector. Modified ciphers and sslEnabledProtocols option pruning to
+        not silently revert to JVM defaults when none of the options specified
+        are supported - new behaviour is to warn and explicitly enable no
+        options. (timw)
+      </fix>
+      <fix>
+        Align NIO HTTP connector with other HTTP connectors and include leading
+        blank lines when determining the size of the HTTP headers. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>53869</bug>: Performance improvement for pages with lots of heavily
+        nested tags. Retain a reference to the root JSP context rather than
+        traversing the hierarchy on every call. Based on a patch suggested by
+        Sheldon Shao. (markt)
+      </fix>
+      <fix>
+        <bug>54440</bug>: Correct a regression caused by the changes for
+        <bug>54240</bug> that broke compilation of JSPs with JspC. Patch
+        provided by Sheldon Shao. (markt)
+      </fix>
+      <fix>
+        <bug>54466</bug>: Improve error message by including the name of the
+        file when the java file generated from a tag file cannot be compiled.
+        Based on a patch by Sheldon Shao. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Fix incorrect increment of <code>counterSend_EVT_SESSION_EXPIRED</code>
+        and <code>counterSend_EVT_CHANGE_SESSION_ID</code>. These values are not
+        incremented if no members active in cluster group. (kfujino)
+      </fix>
+      <fix>
+        <bug>54476</bug>: Correct error in Javadoc of GroupChannel send methods
+        to maker clear that the minimum length of the destination member array
+        is one, not two. (markt)
+      </fix>
+      <fix>
+        Prevent SSO deregister when node shutdown normally in cluster
+        environment. (kfujino)
+      </fix>
+      <fix>
+        Check cluster member before sending replicate message in
+        ClusterSingleSignOn. (kfujino)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Web applications">
+    <changelog>
+      <fix>
+        <bug>54461</bug>: Improve the documentation for the compiler attribute
+        in the Jasper how-to. (markt)
+      </fix>
+      <add>
+        Add Jespa to the list of third-party Windows authentication providers
+        and make external links in the documentation for those providers
+        <code>no-follow</code>. (markt)
+      </add>
+    </changelog>
+  </subsection>
+  <subsection name="Tribes">
+    <changelog>
+      <fix>
+        <bug>54496</bug>: Don't use a hard-coded class name in
+        <code>MemberImpl.toString()</code>. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Other">
+    <changelog>
+      <update>
+        Update to Apache Commons Daemon 1.0.12. (markt)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Tomcat 7.0.35 (markt)" rtext="2013-01-16">
   <subsection name="Catalina">
     <changelog>
       <fix>
diff --git a/webapps/docs/config/context.xml b/webapps/docs/config/context.xml
index 5a7d532..89f75f7 100644
--- a/webapps/docs/config/context.xml
+++ b/webapps/docs/config/context.xml
@@ -62,8 +62,10 @@
   by the web application deployment.</p>
 
   <p>You may define as many <strong>Context</strong> elements as you
-  wish.  Each such Context MUST have a unique context name. In
-  addition, a Context must be present with a context path equal to
+  wish.  Each such Context MUST have a unique context name within a virtual
+  host. The context path does not need to be unique (see <em>parallel
+  deployment</em> below). In addition, a Context must be present with a
+  context path equal to
   a zero-length string.  This Context becomes the <em>default</em>
   web application for this virtual host, and is used to process all
   requests that do not match any other Context's context path.</p>
@@ -88,31 +90,69 @@
   </subsection>
 
   <subsection name="Naming">
-  <p>When autoDeploy or deployOnStartup is used then there is a close
-  relationship between the <em>context name</em>, <em>context path</em>,
-  <em>context version</em> and the <em>base file name</em> used for the WAR
-  and/or directory that contains the web application when the WAR or directory
-  is located in the Host's appBase. When no version is specified, the rules
-  are:
+  <p>When <code>autoDeploy</code> or <code>deployOnStartup</code> operations
+  are performed by a Host, the web application is specified by a context XML
+  file in <a href="host.html">Host</a>'s <code>xmlBase</code>
+  directory or by a WAR file or a directory file in Host's
+  <code>appBase</code> directory.
+  In this case the context path is derived from the name of the file that
+  is being deployed. Consequently, the context path <strong>may not</strong>
+  be defined in a <code>META-INF/context.xml</code> embedded in
+  the application. There is, therefore, a close relationship between the
+  <em>context name</em>, <em>context path</em>, <em>context version</em> and
+  the <em>base file name</em> (the name minus <code>.war</code> or
+  <code>.xml</code> extension) of the file.</p>
+
+  <p>Let us assume that you want to deploy your application to respond to
+  requests to URIs starting with certain context path. According to the
+  Servlet specification, the context path may be an empty string, or a
+  string starting with '/'. The rules to define the names for this context
+  path are the following:</p>
+
   <ul>
-    <li>contextName = contextPath</li>
-    <li>If the contextPath is a zero length string, the base name is ROOT</li>
-    <li>If the contextPath is not a zero length string, the base name is the
-        contextPath with the leading '/' removed and any remaining '/'
-        characters in the path replaced with '#'.</li>
+    <li><em>context name</em> is equal to context path</li>
+    <li>If the context path is a zero length string, the <em>base name</em> is
+    <code>"ROOT"</code> (uppercase)</li>
+    <li>If the context path is not a zero length string, the <em>base
+    name</em> is the context path with the leading '/' removed and any
+    remaining '/' characters in the path replaced with '#'.</li>
   </ul>
-  When a version is specified, <code>##version</code> is added to the contextName and base
-  name. To help clarify these rules, some examples are given in the following
+
+  <p>When a version is specified, to deploy several applications for the
+  same context path, the above values are modified as follows:</p>
+
+  <ul>
+    <li><code>"##" + version</code> is added as a suffix to <em>context name</em>
+    and <em>base name</em>.</li>
+  </ul>
+
+  <p>To help clarify these rules, some examples are given in the following
   table.</p>
 
   <table class="detail-table">
-    <tr><th>Context Path</th><th>Context Version</th><th>Context Name</th><th>Base filename</th></tr>
+    <tr>
+      <th>Context Path</th>
+      <th>Context Version</th>
+      <th>Context Name</th>
+      <th>Base File Name</th>
+    </tr>
     <tr><td>/foo</td><td><i>None</i></td><td>/foo</td><td>foo</td></tr>
-    <tr><td>/foo/bar</td><td><i>None</i></td><td>/foo/bar</td><td>foo#bar</td></tr>
-    <tr><td><i>Empty String</i></td><td><i>None</i></td><td><i>Empty String</i></td><td>ROOT</td></tr>
+    <tr>
+      <td>/foo/bar</td><td><i>None</i></td><td>/foo/bar</td><td>foo#bar</td>
+    </tr>
+    <tr>
+      <td><i>Empty String</i></td>
+      <td><i>None</i></td>
+      <td><i>Empty String</i></td>
+      <td>ROOT</td>
+    </tr>
     <tr><td>/foo</td><td>42</td><td>/foo##42</td><td>foo##42</td></tr>
-    <tr><td>/foo/bar</td><td>42</td><td>/foo/bar##42</td><td>foo#bar##42</td></tr>
-    <tr><td><i>Empty String</i></td><td>42</td><td>##42</td><td>ROOT##42</td></tr>
+    <tr>
+      <td>/foo/bar</td><td>42</td><td>/foo/bar##42</td><td>foo#bar##42</td>
+    </tr>
+    <tr>
+      <td><i>Empty String</i></td><td>42</td><td>##42</td><td>ROOT##42</td>
+    </tr>
   </table>
 
   <p>The version component is treated as a <code>String</code> both for
@@ -134,7 +174,7 @@
   </p>
   <ul>
   <li>Disable autoDeploy and deployOnStartup and define all
-  <Strong>Context</Strong>s in server.xml</li>
+  <strong>Context</strong>s in server.xml</li>
   <li>Locate the WAR and/or directory outside of the Host's appBase and use
       a context.xml file with a docBase attribute to define it.</li>
   </ul>
@@ -175,11 +215,11 @@
   </p>
   <ul>
   <li>In the <code>$CATALINA_BASE/conf/context.xml</code> file:
-  the Context element information will be loaded by all webapps.</li>
+  the Context element information will be loaded by all web applications.</li>
   <li>In the
   <code>$CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default</code>
-  file: the Context element information will be loaded by all webapps of that
-  host.</li>
+  file: the Context element information will be loaded by all web applications
+  of that host.</li>
   </ul>
 
   <p>With the exception of server.xml, files that define <strong>Context
@@ -193,11 +233,10 @@
   <a href="host.html#User Web Applications">User Web Applications</a>
   for more information.</p>
 
-  <p>To define multiple <Strong>Context</Strong>s that use a single WAR file or
-  directory, use one of the options described above for creating a
-  <Strong>Context</Strong> that has a path that is not related to the base file
-  name and create multiple <Strong>Context</Strong> definitions.
-  </p>
+  <p>To define multiple contexts that use a single WAR file or directory,
+  use one of the options described in the <a href="#Naming">Naming</a>
+  section above for creating a <strong>Context</strong> that has a path
+  that is not related to the base file name.</p>
   </subsection>
 </section>
 
@@ -1091,6 +1130,8 @@
         This attribute is ignored if the <code>singleton</code> attribute is
         false. If not specificed, no default is defined and no close method will
         be called.</p>
+        <p>For Apache Commons DBCP and Apache Tomcat JDBC connection pools
+        you can use <code>closeMethod="close"</code>.</p>
       </attribute>
 
       <attribute name="description" required="false">
diff --git a/webapps/docs/config/globalresources.xml b/webapps/docs/config/globalresources.xml
index 382e45f..ad61678 100644
--- a/webapps/docs/config/globalresources.xml
+++ b/webapps/docs/config/globalresources.xml
@@ -195,6 +195,8 @@
         This attribute is ignored if the <code>singleton</code> attribute is
         false. If not specificed, no default is defined and no close method will
         be called.</p>
+        <p>For Apache Commons DBCP and Apache Tomcat JDBC connection pools
+        you can use <code>closeMethod="close"</code>.</p>
       </attribute>
 
       <attribute name="description" required="false">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index d332ba1..f181c00 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -454,7 +454,7 @@
     </attribute>
 
     <attribute name="restrictedUserAgents" required="false">
-      <p>The value is a regular expression (using <code>java.util.regex</code>) matching
+      <p>The value is a regular expression (using <code>java.util.regex</code>)
       matching the <code>user-agent</code> header of HTTP clients for which
       HTTP/1.1 or HTTP/1.0 keep alive should not be used, even if the clients
       advertise support for these features.
@@ -930,13 +930,15 @@
     </attribute>
 
     <attribute name="ciphers" required="false">
-      <p>The comma separated list of encryption ciphers that this socket is
-      allowed to use. By default, the default ciphers for the JVM will be used.
-      Note that this usually means that the weak export grade ciphers will be
-      included in the list of available ciphers. The ciphers are specified using
-      the JSSE cipher naming convention. The special value of <code>ALL</code>
-      will enable all supported ciphers. This will include many that are not
-      secure. <code>ALL</code> is intended for testing purposes only.</p>
+      <p>The comma separated list of encryption ciphers to support for HTTPS
+      connections. If specified, only the ciphers that are listed and supported
+      by the SSL implementation will be used. By default, the default ciphers
+      for the JVM will be used. Note that this usually means that the weak
+      export grade ciphers will be included in the list of available ciphers.
+      The ciphers are specified using the JSSE cipher naming convention. The
+      special value of <code>ALL</code> will enable all supported ciphers. This
+      will include many that are not secure. <code>ALL</code> is intended for
+      testing purposes only.</p>
     </attribute>
 
     <attribute name="clientAuth" required="false">
@@ -1019,9 +1021,10 @@
 
     <attribute name="sslEnabledProtocols" required="false">
       <p>The comma separated list of SSL protocols to support for HTTPS
-      connections. If specified, only the protocols listed will be supported. If
-      not specified, the JVM default is used. The permitted values may be
-      obtained from the JVM documentation for the allowed values for
+      connections. If specified, only the protocols that are listed and
+      supported by the SSL implementation will be enabled. If not specified,
+      the JVM default is used. The permitted values may be obtained from the
+      JVM documentation for the allowed values for 
       <code>SSLSocket.setEnabledProtocols()</code> e.g.
       <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html#jssenames">
       Oracle Java 6</a> and
@@ -1198,6 +1201,12 @@
       supported).</p>
     </attribute>
 
+    <attribute name="SSLDisableCompression" required="false">
+      <p>Disables compression if set to <code>true</code> and OpenSSL supports
+      disabling comprssion. Default is <code>false</code> which inherits the
+      default compression setting in OpenSSL.</p>
+    </attribute>
+
     <attribute name="SSLHonorCipherOrder" required="false">
       <p>Set to <code>true</code> to enforce the server's cipher order
       (from the <code>SSLCipherSuite</code> setting) instead of allowing
diff --git a/webapps/docs/config/jar-scanner.xml b/webapps/docs/config/jar-scanner.xml
index 3c75c32..e14263f 100644
--- a/webapps/docs/config/jar-scanner.xml
+++ b/webapps/docs/config/jar-scanner.xml
@@ -77,10 +77,12 @@
 
     <attributes>
 
-      <attribute name="scanClassPath" required="false">
-       <p>If true, the full web application classpath, including the shared and
-       common classloaders will be scanned for Jar files in addition to the
-       web application. The default is <code>true</code>.</p>
+      <attribute name="scanAllDirectories" required="false">
+       <p>If true, any directories found on the classpath will be checked to see
+       if are expanded Jar files. The default is <code>false</code>. Tomcat
+       determines if directory is an expanded JAR file by looking for a META-INF
+       sub-directory. Only if the META-INF sub-directory exists, is the
+       directory to be an expanded JAR file.</p>
       </attribute>
 
       <attribute name="scanAllFiles" required="false">
@@ -89,12 +91,17 @@
        <code>.jar</code>. The default is <code>false</code></p>
       </attribute>
 
-      <attribute name="scanAllDirectories" required="false">
-       <p>If true, any directories found on the classpath will be checked to see
-       if are expanded Jar files. The default is <code>false</code>. Tomcat
-       determines if directory is an expanded JAR file by looking for a META-INF
-       sub-directory. Only if the META-INF sub-directory exists, is the
-       directory to be an expanded JAR file.</p>
+      <attribute name="scanClassPath" required="false">
+       <p>If true, the full web application classpath, including the shared and
+       common classloaders and the system classpath (but not the bootstrap
+       classpath) will be scanned for Jar files in addition to the web
+       application. The default is <code>true</code>. </p>
+      </attribute>
+
+      <attribute name="scanBootstrapClassPath" required="false">
+       <p>If <code>scanClassPath</code> is true and this is true the bootstrap
+       classpath will also be scanned for Jar files. The default is
+       <code>false</code>.</p>
       </attribute>
 
     </attributes>
diff --git a/webapps/docs/deployer-howto.xml b/webapps/docs/deployer-howto.xml
index acf2431..439b3c7 100644
--- a/webapps/docs/deployer-howto.xml
+++ b/webapps/docs/deployer-howto.xml
@@ -45,17 +45,29 @@
         <ul>
                 <li>Statically; the web application is setup before Tomcat is started</li>
                 <li>
-                    Dynamically; in conjunction with the Tomcat Manager web application or
-                    manipulating already deployed web applications
+                    Dynamically; by directly manipulating already deployed web
+                    applications (relying on <em>auto-deployment</em>
+                    feature) or remotely by using the Tomcat Manager web
+                    application
                 </li>
         </ul>
         <p>
-            The Tomcat Manager is a tool that allows URL-based web application
-            deployment features. There is also a tool called the Client Deployer,
-            which is a command shell based script that interacts with the Tomcat
-            Manager but provides additional functionality such as compiling and
-            validating web applications as well as packaging web application into
-            web application resource (WAR) files.
+            The <a href="manager-howto.html">Tomcat Manager</a> is a web
+            application that can be used interactively (via HTML GUI) or
+            programmatically (via URL-based API) to deploy and manage web
+            applications.
+        </p>
+        <p>
+            There are a number of ways to perform deployment that rely on
+            the Manager web application. Apache Tomcat provides tasks
+            for Apache Ant build tool.
+            <a href="http://tomcat.apache.org/maven-plugin.html">Apache Tomcat Maven Plugin</a>
+            project provides integration with Apache Maven.
+            There is also a tool called the Client Deployer, which can be
+            used from a command line and provides additional functionality
+            such as compiling and validating web applications as well as
+            packaging web application into web application resource (WAR)
+            files.
         </p>
     </section>
 
@@ -65,7 +77,8 @@
             applications as this is provided out of the box by Tomcat. Nor is any
             installation required for deployment functions with the Tomcat Manager,
             although some configuration is required as detailed in the
-            Tomcat Manager manual. An installation is however required if you wish
+            <a href="manager-howto.html">Tomcat Manager manual</a>.
+            An installation is however required if you wish
             to use the Tomcat Client Deployer (TCD).
         </p>
         <p>
@@ -88,7 +101,7 @@
                 The TCD package need not be extracted into any existing Tomcat
                 installation, it can be extracted to any location.
             </li>
-            <li>Read Using the <a href="#Deploying using the Client Deployer Package">
+            <li>Read Using the <a href="#Deploying_using_the_Client_Deployer_Package">
             Tomcat Client Deployer</a></li>
         </ol>
     </section>
@@ -117,7 +130,7 @@
             The locations for Context Descriptors are:
         </p>
         <ol>
-                <li>$CATALINA_BASE/conf/[enginename]/[hostname]/context.xml</li>
+                <li>$CATALINA_BASE/conf/[enginename]/[hostname]/[webappname].xml</li>
                 <li>$CATALINA_BASE/webapps/[webappname]/META-INF/context.xml</li>
         </ol>
         <p>
@@ -158,10 +171,6 @@
             </li>
             <li>.WAR files will be deployed</li>
         </ol>
-        <p>
-            Note again that for each deployed web application, a
-            Context Descriptor will be created <i>unless one exists already</i>.
-        </p>
     </section>
 
     <section name="Deploying on a running Tomcat server">
@@ -276,8 +285,8 @@
                 <code>compile</code> (default): Compile and validate the web
                 application. This can be used standalone, and does not need a running
                 Tomcat server. The compiled application will only run on the associated
-                Tomcat 7.0.x server release, and is not guaranteed to work on another
-                Tomcat release, as the code generated by Jasper depends on its runtime
+                <em>Tomcat X.Y.Z</em> server release, and is not guaranteed to work
+                on another Tomcat release, as the code generated by Jasper depends on its runtime
                 component. It should also be noted that this target will also compile
                 automatically any Java source file located in the
                 <code>/WEB-INF/classes</code> folder of the web application.</li>
diff --git a/webapps/docs/jasper-howto.xml b/webapps/docs/jasper-howto.xml
index a9ab663..814190a 100644
--- a/webapps/docs/jasper-howto.xml
+++ b/webapps/docs/jasper-howto.xml
@@ -96,9 +96,14 @@ attribute is always set when Jasper is used within Tomcat. By default the
 classpath is created dynamically based on the current web application.</li>
 
 <li><strong>compiler</strong> - Which compiler Ant should use to compile JSP
-pages.  See the Ant documentation for more information. If the value is not set,
-then the default Eclipse JDT Java compiler will be used instead of using Ant.
-No default value.</li>
+pages. The valid values for this are the same as for the compiler attribute of
+Ant's
+<a href="http://ant.apache.org/manual/Tasks/javac.html#compilervalues">javac</a>
+task. If the value is not set, then the default Eclipse JDT Java compiler will
+be used instead of using Ant. There is no default value. If this attribute is
+set then <code>setenv.[sh|bat]</code> should be used to add
+<code>ant.jar</code>, <code>ant-launcher.jar</code> and <code>tools.jar</code>
+to the <code>CLASSPATH</code> environment variable.</li>
 
 <li><strong>compilerSourceVM</strong> - What JDK version are the source files
 compatible with? (Default value: <code>1.6</code>)</li>
@@ -202,9 +207,8 @@ tens of JARs. On fast servers, this will allow sub-second recompilation cycles
 for even large JSP  pages.</p>
 
 <p>Apache Ant, which was used in previous Tomcat releases, can be used instead
-of the new compiler by simply removing the <code>lib/ecj-*.jar</code> file,
-and placing the <code>ant.jar</code> and <code>ant-launcher.jar</code> files
-from the latest Ant distribution in the <code>lib</code> folder.</p>
+of the new compiler by configuring the compiler attribute as explained above.
+</p>
 
 </section>
 
@@ -376,6 +380,28 @@ depending on the application.</li>
 </p>
 </section>
 
+<section name="Optimisation">
+<p>
+There are a number of extension points provided within Jasper that enable the
+user to optimise the behaviour for their environment.
+</p>
+
+<p>
+The first of these extension points is the tag plug-in mechanism. This allows
+alternative implementations of tag handlers to be provided for a web application
+to use. Tag plug-ins are registered via a <code>tagPlugins.xml</code> file
+located under <code>WEB-INF</code>. A sample plug-in for the JSTL is included
+with Jasper. 
+</p>
+
+<p>
+The second extension point is the Expression Language interpreter. Alternative
+interpreters may be configured through the <code>ServletContext</code>. See the
+<code>ELInterpreterFactory</code> javadoc for details of how to configure an
+alternative EL interpreter. 
+</p>
+</section> 
+
 </body>
 
 </document>
diff --git a/webapps/docs/jndi-resources-howto.xml b/webapps/docs/jndi-resources-howto.xml
index 5a88092..82430ed 100644
--- a/webapps/docs/jndi-resources-howto.xml
+++ b/webapps/docs/jndi-resources-howto.xml
@@ -78,6 +78,18 @@ resources:</p>
 use to create the resource and that no further configuration information is
 required, Tomcat will use the information in <code>/WEB-INF/web.xml</code> to
 create the resource.</p>
+
+<p>Tomcat provides a number of Tomcat specific options for JNDI resources that
+cannot be specified in web.xml. These include <code>closeMethod</code> that
+enables faster cleaning-up of JNDI resources when a web application stops and
+<code>singleton</code> that controls whether or not a new instance of the
+resource is created for every JNDI lookup. To use these configuration options
+the resource must be specified in a web application's
+<a href="config/context.html"><code><Context></code></a> element or in the
+<a href="config/globalresources.html">
+<code><strong><GlobalNamingResources></strong></code></a> element of
+<code>$CATALINA_BASE/conf/server.xml</code>.</p>
+
 </section>
 
 <section name="context.xml configuration">
diff --git a/webapps/docs/manager-howto.xml b/webapps/docs/manager-howto.xml
index c8645df..e9ae8a1 100644
--- a/webapps/docs/manager-howto.xml
+++ b/webapps/docs/manager-howto.xml
@@ -71,8 +71,10 @@ Manager web application <code>Context</code> to a new host install the
 <code>$CATALINA_BASE/conf/[enginename]/[hostname]</code> folder. Here is an
 example:</p>
 <pre>
-<Context privileged="true"
-         docBase="/usr/local/kinetic/tomcat7/server/webapps/manager">
+<Context privileged="true" antiResourceLocking="false"
+         docBase="${catalina.home}/webapps/manager">
+  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
+         allow="127\.0\.0\.1" />
 </Context>
 </pre>
 
@@ -442,7 +444,8 @@ http://localhost:8080/manager/text/deploy?config=file:/path/context.xml
 configuration ".xml" file and a web application ".war" file located
 on the server.</p>
 <source>
-http://localhost:8080/manager/text/deploy?config=file:/path/context.xml&war=jar:file:/path/bar.war!/
+http://localhost:8080/manager/text/deploy
+ ?config=file:/path/context.xml&war=jar:file:/path/bar.war!/
 </source>
 
 
@@ -1272,9 +1275,9 @@ http://webserver/manager/jmxproxy/?qry=STUFF
     fetch the value of a specific MBean's attribute. The general form of
     the <code>get</code> command is:
 
-    <source>
-      http://webserver/manager/jmxproxy/?get=BEANNAME&att=MYATTRIBUTE&key=MYKEY
-    </source>
+<source>
+http://webserver/manager/jmxproxy/?get=BEANNAME&att=MYATTRIBUTE&key=MYKEY
+</source>
 
     You must provide the following parameters:
     <ol>
@@ -1287,15 +1290,16 @@ http://webserver/manager/jmxproxy/?qry=STUFF
     be shown. For example, let's say we wish to fetch the current heap memory
     data:
 
-    <source>
-      http://webserver/manager/jmxproxy/?get=java.lang:type=Memory&att=HeapMemoryUsage
-    </source>
+<source>
+http://webserver/manager/jmxproxy/?get=java.lang:type=Memory&att=HeapMemoryUsage
+</source>
 
     Or, if you only want the "used" key:
 
-    <source>
-      http://webserver/manager/jmxproxy/?get=java.lang:type=Memory&att=HeapMemoryUsage&key=used
-    </source>
+<source>
+http://webserver/manager/jmxproxy/
+ ?get=java.lang:type=Memory&att=HeapMemoryUsage&key=used
+</source>
   </subsection>
 
   <subsection name="JMX Set command">
@@ -1315,7 +1319,8 @@ http://webserver/manager/jmxproxy/?set=BEANNAME&att=MYATTRIBUTE&val=NEWV
     <code>ErrorReportValve</code>. The following will set debugging to 10.
 <source>
 http://localhost:8080/manager/jmxproxy/
-?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost&att=debug&val=10
+ ?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost
+ &att=debug&val=10
 </source>
     and my result is (YMMV):
 <source>
@@ -1323,14 +1328,15 @@ Result: ok
 </source>
 
     Here is what I see if I pass in a bad value. Here is the URL I used,
-    I try set debugging equal to 'cowbell':
+    I try set debugging equal to 'cow':
 <source>
 http://localhost:8080/manager/jmxproxy/
-?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost&att=debug&val=cowbell
+ ?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost
+ &att=debug&val=cow
 </source>
     When I try that, my result is
 <source>
-Error: java.lang.NumberFormatException: For input string: "cowbell"
+Error: java.lang.NumberFormatException: For input string: "cow"
 </source>
   </subsection>
 
@@ -1338,12 +1344,14 @@ Error: java.lang.NumberFormatException: For input string: "cowbell"
     <p>The <code>invoke</code> command enables methods to be called on MBeans. The
     general form of the command is:</p>
 <source>
-http://webserver/manager/jmxproxy/?invoke=BEANNAME&op=METHODNAME&ps=COMMASEPARATEDPARAMETERS
+http://webserver/manager/jmxproxy/
+ ?invoke=BEANNAME&op=METHODNAME&ps=COMMASEPARATEDPARAMETERS
 </source>
     <p>For example, to call the <code>findConnectors()</code> method of the
     <strong>Service</strong> use:</p>
 <source>
-http://localhost:8080/manager/jmxproxy/?invoke=Catalina%3Atype%3DService&op=findConnectors&ps=
+http://localhost:8080/manager/jmxproxy/
+ ?invoke=Catalina%3Atype%3DService&op=findConnectors&ps=
 </source>
   </subsection>
 
diff --git a/webapps/docs/realm-howto.xml b/webapps/docs/realm-howto.xml
index b662fbf..74d3a6d 100644
--- a/webapps/docs/realm-howto.xml
+++ b/webapps/docs/realm-howto.xml
@@ -1180,7 +1180,7 @@ UserDatabase Realm and a DataSource Realm.</p>
     synchronisation in this Realm.</p>
 
     <p>This Realm does not require modification to the underlying Realms or the
-    associated user storage mecahisms. It achieves this by recording all failed
+    associated user storage mechanisms. It achieves this by recording all failed
     logins, including those for users that do not exist. To prevent a DOS by
     deliberating making requests with invalid users (and hence causing this
     cache to grow) the size of the list of users that have failed authentication
diff --git a/webapps/docs/setup.xml b/webapps/docs/setup.xml
index 36fe493..484f015 100644
--- a/webapps/docs/setup.xml
+++ b/webapps/docs/setup.xml
@@ -35,12 +35,10 @@
 
   <section name="Introduction">
     <p>
-      This document introduces several ways to set up Tomcat for running
-      on different platforms.  Please note that some advanced setup issues
-      are not covered here: the full distribution (ZIP file or tarball)
-      includes a file called
-      RUNNING.txt which discusses these issues.  We encourage you to refer
-      to it if the information below does not answer some of your questions.
+      There are several ways to set up Tomcat for running on different
+      platforms. The main documentation for this is a file called
+      <a href="RUNNING.txt">RUNNING.txt</a>. We encourage you to refer to that
+      file if the information below does not answer some of your questions.
     </p>
   </section>
 
diff --git a/webapps/docs/ssl-howto.xml b/webapps/docs/ssl-howto.xml
index 54adb37..b90af1a 100644
--- a/webapps/docs/ssl-howto.xml
+++ b/webapps/docs/ssl-howto.xml
@@ -297,17 +297,17 @@ then it will use the APR SSL implementation, otherwise it will use the Java JSSE
   in the <b>protocol</b> attribute of the Connector.<br/>
   To define a Java (JSSE) connector, regardless of whether the APR library is loaded or not do:
 <source>
-<-- Define a blocking Java SSL Coyote HTTP/1.1 Connector on port 8443 -->
+<!-- Define a blocking Java SSL Coyote HTTP/1.1 Connector on port 8443 -->
 <Connector protocol="org.apache.coyote.http11.Http11Protocol"
            port="8443" .../>
 
-<-- Define a non-blocking Java SSL Coyote HTTP/1.1 Connector on port 8443 -->
+<!-- Define a non-blocking Java SSL Coyote HTTP/1.1 Connector on port 8443 -->
 <Connector protocol="org.apache.coyote.http11.Http11NioProtocol"
            port="8443" .../>
 </source>
 Alternatively, to specify an APR connector (the APR library must be available) use:
 <source>
-<-- Define a APR SSL Coyote HTTP/1.1 Connector on port 8443 -->
+<!-- Define a APR SSL Coyote HTTP/1.1 Connector on port 8443 -->
 <Connector protocol="org.apache.coyote.http11.Http11AprProtocol"
            port="8443" .../>
 </source>
@@ -347,14 +347,13 @@ file installed with Tomcat.  To configure an SSL connector that uses JSSE, you
 will need to remove the comments and edit it so it looks something like
 this:</p>
 <source>
-<-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
+<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
 <Connector
            protocol="HTTP/1.1"
            port="8443" maxThreads="200"
            scheme="https" secure="true" SSLEnabled="true"
            keystoreFile="${user.home}/.keystore" keystorePass="changeit"
            clientAuth="false" sslProtocol="TLS"/>
--->
 </source>
 <p>
   The example above will throw an error if you have the APR and the Tomcat
@@ -362,7 +361,7 @@ this:</p>
   The APR connector uses different attributes for many SSL settings,
   particularly keys and certificates. An example of an APR configuration is:
 <source>
-<-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
+<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
 <Connector
            protocol="HTTP/1.1"
            port="8443" maxThreads="200"
diff --git a/webapps/docs/tomcat-docs.xsl b/webapps/docs/tomcat-docs.xsl
index dd97e92..cae4b06 100644
--- a/webapps/docs/tomcat-docs.xsl
+++ b/webapps/docs/tomcat-docs.xsl
@@ -17,7 +17,7 @@
 -->
 <!-- Content Stylesheet for "tomcat-docs" Documentation -->
 
-<!-- $Id: tomcat-docs.xsl 1431211 2013-01-10 08:46:23Z kkolinko $ -->
+<!-- $Id: tomcat-docs.xsl 1451777 2013-03-01 23:38:03Z kkolinko $ -->
 
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="1.0">
@@ -173,6 +173,7 @@
 
       </tr>
 
+      <xsl:if test="not(properties/no-comments)">
       <tr class="noPrint">
 
         <td width="20%" valign="top" nowrap="nowrap" class="noPrint">
@@ -212,7 +213,7 @@
                       (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s);
                   }
                   else {
-                      d.write('<div id="comments_thread"><strong>Comments are disabled for this page at the moment.</strong><\/div>');
+                      d.write('<div id="comments_thread"><strong>Comments are disabled for this page at the moment.<\/strong><\/div>');
                   }
               })(window, document);
               //--><!]]]]>></xsl:text></script>
@@ -220,6 +221,7 @@
           </table>
         </td>
       </tr>
+      </xsl:if>
 
       <xsl:comment>FOOTER SEPARATOR</xsl:comment>
       <tr>
diff --git a/webapps/docs/web-socket-howto.xml b/webapps/docs/web-socket-howto.xml
index b57dd9b..4ee87e0 100644
--- a/webapps/docs/web-socket-howto.xml
+++ b/webapps/docs/web-socket-howto.xml
@@ -58,9 +58,9 @@
 
 <p>There are also several example applications that demonstrate how the
    WebSocket API can be used. You'll need to look at both the client side <a
-   href="http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/websocket/">
+   href="http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/websocket/">
    html</a> and the server side <a
-   href="http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/">
+   href="http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/examples/WEB-INF/classes/websocket/">
    code</a>.</p>
 
 <p>Do keep in mind that the API is fluid and is likely to change, possibly
diff --git a/webapps/docs/windows-auth-howto.xml b/webapps/docs/windows-auth-howto.xml
index ba61cba..cf7b453 100644
--- a/webapps/docs/windows-auth-howto.xml
+++ b/webapps/docs/windows-auth-howto.xml
@@ -51,8 +51,9 @@ sections.</p>
 </section>
 
 <section name="Built-in Tomcat support">
-<p><strong>This is a work in progress. There are a number of outstanding
-questions that require further testing.</strong> These include:
+<p><strong>This documentation is a work in progress. There are a number of
+outstanding questions around the edge cases that require further
+testing.</strong> These include:
 </p>
 <ul>
 <li>Does the domain name have to be in upper case?</li>
@@ -219,7 +220,8 @@ com.sun.security.jgss.krb5.accept {
 
   <subsection name="Waffle">
   <p>Full details of this solution can be found through the
-  <a href="http://waffle.codeplex.com/">Waffle site</a>. The key features are:</p>
+  <a href="http://waffle.codeplex.com/"  rel="nofollow">Waffle web site</a>. The
+  key features are:</p>
   <ul>
   <li>Drop-in solution</li>
   <li>Simple configuration (no JAAS or Kerberos keytab configuration required)
@@ -230,8 +232,8 @@ com.sun.security.jgss.krb5.accept {
 
   <subsection name="Spring Security - Kerberos Extension">
   <p>Full details of this solution can be found through the
-  <a href="http://static.springsource.org/spring-security/site/extensions/krb/index.html">
-  Kerberos extension site</a>. The key features are:</p>
+  <a href="http://static.springsource.org/spring-security/site/extensions/krb/index.html"
+  rel="nofollow"> Kerberos extension web site</a>. The key features are:</p>
   <ul>
   <li>Extension to Spring Security</li>
   <li>Requires a Kerberos keytab file to be generated</li>
@@ -241,13 +243,23 @@ com.sun.security.jgss.krb5.accept {
 
   <subsection name="SPNEGO project at SourceForge">
   <p>Full details of this solution can be found through the
-  <a href="http://spnego.sourceforge.net/index.html/">project site</a>. The key
-  features are:</p>
+  <a href="http://spnego.sourceforge.net/index.html/"  rel="nofollow">project
+  site</a>. The key features are:</p>
   <ul>
   <li>Uses Kerberos</li>
   <li>Pure Java solution</li>
   </ul>
   </subsection>
+
+  <subsection name="Jespa">
+  <p>Full details of this solution can be found through the
+  <a href="http://www.ioplex.com/" rel="nofollow">project web site</a>The key
+  features are:</p>
+  <ul>
+  <li>Pure Java solution</li>
+  <li>Advanced Active Directory integration</li>
+  </ul>
+  </subsection>
 </section>
 
 <section name="Reverse proxies">
@@ -270,12 +282,12 @@ com.sun.security.jgss.krb5.accept {
   <p>Apache httpd does not support Windows authentication out of the box but
   there are a number of third-party modules that can be used. These include:</p>
   <ol>
-  <li><a href="http://sourceforge.net/projects/mod-auth-sspi/">mod_auth_sspi</a>
-  for use on Windows platforms.</li>
-  <li><a href="http://adldap.sourceforge.net/wiki/doku.php?id=mod_auth_ntlm_winbind">
-  mod_auth_ntlm_winbind</a> for non-Windows platforms. Known to work with httpd
-  2.0.x on 32-bit platforms. Some users have reported stability issues with both
-  httpd 2.2.x builds and 64-bit Linux builds.</li>
+  <li><a href="http://sourceforge.net/projects/mod-auth-sspi/"
+  rel="nofollow">mod_auth_sspi</a> for use on Windows platforms.</li>
+  <li><a href="http://adldap.sourceforge.net/wiki/doku.php?id=mod_auth_ntlm_winbind"
+  rel="nofollow">mod_auth_ntlm_winbind</a> for non-Windows platforms. Known to
+  work with httpd 2.0.x on 32-bit platforms. Some users have reported stability
+  issues with both httpd 2.2.x builds and 64-bit Linux builds.</li>
   </ol>
   <p>There are three steps to configuring httpd to provide Windows
   authentication. They are:</p>
diff --git a/webapps/docs/windows-service-howto.xml b/webapps/docs/windows-service-howto.xml
index 9f44708..882c181 100644
--- a/webapps/docs/windows-service-howto.xml
+++ b/webapps/docs/windows-service-howto.xml
@@ -53,7 +53,7 @@
     </tr>
     <tr><th>//MS//</th>
         <td>Monitor service</td>
-        <td>Put the icon in the system try</td>
+        <td>Put the icon in the system tray</td>
     </tr>
     </table>
 </p>
diff --git a/webapps/manager/status.xsd b/webapps/manager/status.xsd
index 53db43b..5af979d 100644
--- a/webapps/manager/status.xsd
+++ b/webapps/manager/status.xsd
@@ -15,9 +15,15 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-<!-- edited with XMLSPY v5 rel. 4 U (http://www.xmlspy.com) by peter lin (consultant) -->
-<!--W3C Schema generated by XMLSPY v5 rel. 4 U (http://www.xmlspy.com)-->
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+    <xs:element name="status">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="jvm" type="jvm"/>
+                <xs:element name="connector" type="connector" minOccurs="1" maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
     <xs:complexType name="connector">
         <xs:sequence>
             <xs:element name="threadInfo" type="threadInfo"/>
@@ -29,6 +35,7 @@
     <xs:complexType name="jvm">
         <xs:sequence>
             <xs:element name="memory" type="memory"/>
+            <xs:element name="memorypool" type="memorypool" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
     </xs:complexType>
     <xs:complexType name="memory">
@@ -36,6 +43,14 @@
         <xs:attribute name="total" type="xs:long" use="required"/>
         <xs:attribute name="max" type="xs:long" use="required"/>
     </xs:complexType>
+    <xs:complexType name="memorypool">
+        <xs:attribute name="name" type="xs:string" use="required"/>
+        <xs:attribute name="type" type="xs:string" use="required"/>
+        <xs:attribute name="usageInit" type="xs:long" use="required"/>
+        <xs:attribute name="usageCommitted" type="xs:long" use="required"/>
+        <xs:attribute name="usageMax" type="xs:long" use="required"/>
+        <xs:attribute name="usageUsed" type="xs:long" use="required"/>
+    </xs:complexType>
     <xs:complexType name="requestInfo">
         <xs:attribute name="maxTime" type="xs:long" use="required"/>
         <xs:attribute name="processingTime" type="xs:int" use="required"/>
@@ -44,17 +59,8 @@
         <xs:attribute name="bytesReceived" type="xs:long" use="required"/>
         <xs:attribute name="bytesSent" type="xs:long" use="required"/>
     </xs:complexType>
-    <xs:element name="status">
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element name="jvm" type="jvm"/>
-                <xs:element name="connector" type="connector"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
     <xs:complexType name="threadInfo">
         <xs:attribute name="maxThreads" type="xs:int" use="required"/>
-        <xs:attribute name="minSpareThreads" type="xs:int" use="required"/>
         <xs:attribute name="currentThreadCount" type="xs:int" use="required"/>
         <xs:attribute name="currentThreadsBusy" type="xs:int" use="required"/>
     </xs:complexType>
@@ -72,7 +78,7 @@
     </xs:complexType>
     <xs:complexType name="workers">
         <xs:sequence>
-            <xs:element name="worker" type="worker"/>
+            <xs:element name="worker" type="worker" minOccurs="0" maxOccurs="unbounded"/>
         </xs:sequence>
     </xs:complexType>
 </xs:schema>
diff --git a/webapps/manager/xform.xsl b/webapps/manager/xform.xsl
index 7082ed3..b07fcb9 100644
--- a/webapps/manager/xform.xsl
+++ b/webapps/manager/xform.xsl
@@ -81,9 +81,8 @@
 
   <xsl:template match="threadInfo">
     <table><tr>
-             <td><b>threadInfo </b></td>
+             <td><b>threadInfo</b></td>
              <td><b>maxThreads:</b> <xsl:value-of select="@maxThreads"/></td>
-             <td><b>minSpareThreads:</b> <xsl:value-of select="@minSpareThreads"/></td>
              <td><b>currentThreadCount:</b> <xsl:value-of select="@currentThreadCount"/></td>
              <td><b>currentThreadsBusy:</b> <xsl:value-of select="@currentThreadsBusy"/></td>
            </tr>

-- 
tomcat7: Servlet and JSP engine



More information about the pkg-java-commits mailing list