Author: markt Date: Thu Mar 21 15:05:54 2013 New Revision: 1459346 URL: http://svn.apache.org/r1459346 Log: Switch to Base64 encoder/decoder from Commons Codec. Performance testing shows it to be ~25-30x slower than Tomcat's implementation.
Added: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/ - copied from r1459218, tomcat/trunk/java/org/apache/tomcat/util/codec/ Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java tomcat/tc7.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Base64.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/Base64.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/fileupload/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java tomcat/tc7.0.x/trunk/test/org/apache/catalina/util/TesterBase64Performance.java tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1459218,1459223,1459289 Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/ant/AbstractCatalinaTask.java Thu Mar 21 15:05:54 2013 @@ -27,9 +27,8 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; -import javax.xml.bind.DatatypeConverter; - 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; @@ -202,7 +201,7 @@ public abstract class AbstractCatalinaTa // Set up an authorization header with our credentials String input = username + ":" + password; - String output = DatatypeConverter.printBase64Binary( + String output = Base64.encodeBase64String( input.getBytes(B2CConverter.ISO_8859_1)); hconn.setRequestProperty("Authorization", "Basic " + output); Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java Thu Mar 21 15:05:54 2013 @@ -24,7 +24,6 @@ import java.security.Principal; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.xml.bind.DatatypeConverter; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; @@ -33,6 +32,7 @@ import org.apache.juli.logging.LogFactor import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.codec.binary.Base64; @@ -136,10 +136,10 @@ public class BasicAuthenticator if (authorizationBC.startsWithIgnoreCase("basic ", 0)) { authorizationBC.setOffset(authorizationBC.getOffset() + 6); - // Use the StringCache as these will be the same between - // requests - String encoded = authorizationBC.toStringInternal(); - byte[] decoded = DatatypeConverter.parseBase64Binary(encoded); + byte[] decoded = Base64.decodeBase64( + authorizationBC.getBuffer(), + authorizationBC.getOffset(), + authorizationBC.getLength()); // Get username and password int colon = -1; Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java Thu Mar 21 15:05:54 2013 @@ -27,7 +27,6 @@ import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.servlet.http.HttpServletResponse; -import javax.xml.bind.DatatypeConverter; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; @@ -35,9 +34,9 @@ import org.apache.catalina.deploy.LoginC import org.apache.catalina.startup.Bootstrap; 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.MessageBytes; +import org.apache.tomcat.util.codec.binary.Base64; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; @@ -192,13 +191,9 @@ public class SpnegoAuthenticator extends authorizationBC.setOffset(authorizationBC.getOffset() + 10); - // Create the String directly as this will change on each request and we - // don't want to use the StringCache - String encoded = new String(authorizationBC.getBuffer(), + byte[] decoded = Base64.decodeBase64(authorizationBC.getBuffer(), authorizationBC.getOffset(), - authorizationBC.getLength(), B2CConverter.ISO_8859_1); - - byte[] decoded = DatatypeConverter.parseBase64Binary(encoded); + authorizationBC.getLength()); if (decoded.length == 0) { if (log.isDebugEnabled()) { @@ -286,7 +281,7 @@ public class SpnegoAuthenticator extends // Send response token on success and failure response.setHeader("WWW-Authenticate", "Negotiate " - + DatatypeConverter.printBase64Binary(outToken)); + + Base64.encodeBase64String(outToken)); if (principal != null) { register(request, response, principal, Constants.SPNEGO_METHOD, Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java Thu Mar 21 15:05:54 2013 @@ -51,9 +51,10 @@ import javax.naming.directory.DirContext import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; -import javax.xml.bind.DatatypeConverter; import org.apache.catalina.LifecycleException; +import org.apache.tomcat.util.buf.B2CConverter; +import org.apache.tomcat.util.codec.binary.Base64; import org.ietf.jgss.GSSCredential; /** @@ -1572,8 +1573,9 @@ public class JNDIRealm extends RealmBase password = password.substring(5); md.reset(); md.update(credentials.getBytes(Charset.defaultCharset())); + byte[] decoded = Base64.decodeBase64(md.digest()); String digestedPassword = - DatatypeConverter.printBase64Binary(md.digest()); + new String(decoded, B2CConverter.ISO_8859_1); validated = password.equals(digestedPassword); } } else if (password.startsWith("{SSHA}")) { @@ -1586,17 +1588,15 @@ public class JNDIRealm extends RealmBase md.update(credentials.getBytes(Charset.defaultCharset())); // Decode stored password. - byte[] decoded = - DatatypeConverter.parseBase64Binary(password); + byte[] decoded = Base64.decodeBase64(password); // Split decoded password into hash and salt. final int saltpos = 20; byte[] hash = new byte[saltpos]; System.arraycopy(decoded, 0, hash, 0, saltpos); - byte[] salt = new byte[decoded.length - saltpos]; - System.arraycopy(decoded, saltpos, salt, 0, salt.length); - md.update(salt); + md.update(decoded, saltpos, decoded.length - saltpos); + byte[] dp = md.digest(); validated = Arrays.equals(dp, hash); Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Base64.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Base64.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Base64.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Base64.java Thu Mar 21 15:05:54 2013 @@ -32,8 +32,7 @@ import org.apache.tomcat.util.buf.CharCh * @author Jeffrey Rodriguez * @version $Id$ * - * @deprecated Use {@link - * javax.xml.bind.DatatypeConverter#parseBase64Binary(String)}. + * @deprecated Use {@link org.apache.tomcat.util.codec.binary.Base64} * This class will be removed in Tomcat 8. */ @Deprecated Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/Base64.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/Base64.java?rev=1459346&r1=1459218&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/Base64.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/Base64.java Thu Mar 21 15:05:54 2013 @@ -693,7 +693,12 @@ public class Base64 extends BaseNCodec { * @return Array containing decoded data. */ public static byte[] decodeBase64(final byte[] base64Data) { - return new Base64().decode(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 Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java?rev=1459346&r1=1459218&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java Thu Mar 21 15:05:54 2013 @@ -377,12 +377,16 @@ public abstract class BaseNCodec impleme */ @Override public byte[] decode(final byte[] pArray) { - if (pArray == null || pArray.length == 0) { - return 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, 0, pArray.length, context); - decode(pArray, 0, EOF, context); // Notify decoder of EOF. + 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; Propchange: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/fileupload/ ------------------------------------------------------------------------------ Merged /tomcat/trunk/java/org/apache/tomcat/util/http/fileupload:r1459289 Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java Thu Mar 21 15:05:54 2013 @@ -23,7 +23,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; -import javax.xml.bind.DatatypeConverter; +import org.apache.tomcat.util.codec.binary.Base64; /** * Utility class to decode MIME texts. @@ -245,7 +245,7 @@ public final class MimeUtility { byte[] decodedData; // Base64 encoded? if (encoding.equals(BASE64_ENCODING_MARKER)) { - decodedData = DatatypeConverter.parseBase64Binary(encodedText); + 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); Modified: tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java (original) +++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java Thu Mar 21 15:05:54 2013 @@ -22,7 +22,6 @@ import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; -import javax.xml.bind.DatatypeConverter; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -37,7 +36,9 @@ import org.apache.catalina.session.Manag import org.apache.catalina.startup.TesterServlet; 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.codec.binary.Base64; /** * Test BasicAuthenticator and NonLoginAuthenticator when a @@ -613,9 +614,9 @@ public class TestNonLoginAndBasicAuthent username = aUsername; password = aPassword; String userCredentials = username + ":" + password; - byte[] credentialsBytes = ByteChunk.convertToBytes(userCredentials); - String base64auth = - DatatypeConverter.printBase64Binary(credentialsBytes); + byte[] credentialsBytes = + userCredentials.getBytes(B2CConverter.ISO_8859_1); + String base64auth = Base64.encodeBase64String(credentialsBytes); credentials= method + " " + base64auth; } Modified: tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java (original) +++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/authenticator/TestSSOnonLoginAndBasicAuthenticator.java Thu Mar 21 15:05:54 2013 @@ -21,8 +21,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.xml.bind.DatatypeConverter; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -36,7 +34,9 @@ import org.apache.catalina.deploy.Securi import org.apache.catalina.startup.TesterServlet; 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.codec.binary.Base64; /** * Test BasicAuthenticator and NonLoginAuthenticator when a @@ -237,11 +237,11 @@ public class TestSSOnonLoginAndBasicAuth 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 = - DatatypeConverter.printBase64Binary(credentialsBytes); + + String base64auth = Base64.encodeBase64String( + credentials.getBytes(B2CConverter.ISO_8859_1)); String authLine = "Basic " + base64auth; List<String> auth = new ArrayList<String>(); Modified: tomcat/tc7.0.x/trunk/test/org/apache/catalina/util/TesterBase64Performance.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/util/TesterBase64Performance.java?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/test/org/apache/catalina/util/TesterBase64Performance.java (original) +++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/util/TesterBase64Performance.java Thu Mar 21 15:05:54 2013 @@ -36,8 +36,6 @@ public class TesterBase64Performance { public void testDecode() throws Exception { List<ByteChunk> inputs = new ArrayList<ByteChunk>(SIZE); - List<ByteChunk> warmups = new ArrayList<ByteChunk>(SIZE); - List<String> results = new ArrayList<String>(SIZE); for (int i = 0; i < SIZE; i++) { String decodedString = "abc" + Integer.valueOf(i) + @@ -55,60 +53,20 @@ public class TesterBase64Performance { inputs.add(bc); } - - for (int i = 0; i < SIZE; i++) { - String decodedString = "zyx" + Integer.valueOf(i) + - ":zyx" + 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); - - warmups.add(bc); - } - - //Warm up - for (ByteChunk bc : warmups) { - CharChunk cc = new CharChunk(bc.getLength()); - Base64.decode(bc, cc); - results.add(cc.toString()); - } - results.clear(); - - for (ByteChunk bc : warmups) { - byte[] decodedBytes = - DatatypeConverter.parseBase64Binary(bc.toString()); - String decodedString = - new String(decodedBytes, B2CConverter.ISO_8859_1); - results.add(decodedString); - } - results.clear(); - long startTomcat = System.currentTimeMillis(); for (ByteChunk bc : inputs) { CharChunk cc = new CharChunk(bc.getLength()); Base64.decode(bc, cc); - results.add(cc.toString()); } long stopTomcat = System.currentTimeMillis(); System.out.println("Tomcat: " + (stopTomcat - startTomcat) + " ms"); - results.clear(); - - long startJre = System.currentTimeMillis(); + long startCodec = System.currentTimeMillis(); for (ByteChunk bc : inputs) { - byte[] decodedBytes = - DatatypeConverter.parseBase64Binary(bc.toString()); - String decodedString = - new String(decodedBytes, B2CConverter.ISO_8859_1); - results.add(decodedString); + org.apache.tomcat.util.codec.binary.Base64.decodeBase64( + bc.getBuffer(), bc.getOffset(), bc.getLength()); } - long stopJre = System.currentTimeMillis(); - System.out.println("JRE: " + (stopJre - startJre) + " ms"); + long stopCodec = System.currentTimeMillis(); + System.out.println("Codec: " + (stopCodec - startCodec) + " ms"); } } Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1459346&r1=1459345&r2=1459346&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Thu Mar 21 15:05:54 2013 @@ -98,7 +98,8 @@ </fix> <scode> Deprecate Tomcat's internal Base 64 encoder/decoder and switch to - using the JRE provided implementation. (markt) + using a package renamed copy of the Commons Codec implementation. + (markt) </scode> <fix> Ensure that StandardJarScanner#scan will use the provided class loader --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org