Author: markt Date: Tue Jun 28 23:26:11 2011 New Revision: 1140904 URL: http://svn.apache.org/viewvc?rev=1140904&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51400 Avoid jvm bottleneck on String/byte[] conversion triggered by a JVM bug. Based on patches by Dave Engberg and Konstantin Preißer.
Modified: tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/ByteChunk.java tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Modified: tomcat/tc6.0.x/trunk/STATUS.txt URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1140904&r1=1140903&r2=1140904&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Tue Jun 28 23:26:11 2011 @@ -140,13 +140,6 @@ PATCHES PROPOSED TO BACKPORT: +1: kkolinko, schultz -1: -* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=51400 - Avoid jvm bottleneck on String/byte[] conversion currently affecting a user - https://issues.apache.org/bugzilla/attachment.cgi?id=27219 - Based on patches by Dave Engberg and Konstantin Preißer - +1: markt, kkolinko, schultz - -1: - * Fix truncated cookies. Based on https://issues.jboss.org/browse/JBWEB-196 http://people.apache.org/~jfclere/patches/patch.110622.txt Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java?rev=1140904&r1=1140903&r2=1140904&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/connector/Request.java Tue Jun 28 23:26:11 2011 @@ -1516,15 +1516,12 @@ public class Request if (usingReader) return; - - // Ensure that the specified encoding is valid - byte buffer[] = new byte[1]; - buffer[0] = (byte) 'a'; - String dummy = new String(buffer, enc); + + // Confirm that the encoding name is valid + B2CConverter.getCharset(enc); // Save the validated encoding coyoteRequest.setCharacterEncoding(enc); - } Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java?rev=1140904&r1=1140903&r2=1140904&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java Tue Jun 28 23:26:11 2011 @@ -22,6 +22,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; /** Efficient conversion of bytes to character . * @@ -39,7 +43,36 @@ public class B2CConverter { private static org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( B2CConverter.class ); + + private static final Map<String, Charset> encodingToCharsetCache = + new HashMap<String, Charset>(); + static { + for (Charset charset: Charset.availableCharsets().values()) { + encodingToCharsetCache.put( + charset.name().toLowerCase(Locale.US), charset); + for (String alias : charset.aliases()) { + encodingToCharsetCache.put( + alias.toLowerCase(Locale.US), charset); + } + } + } + + public static Charset getCharset(String enc) + throws UnsupportedEncodingException { + + // Encoding names should all be ASCII + String lowerCaseEnc = enc.toLowerCase(Locale.US); + + Charset charset = encodingToCharsetCache.get(lowerCaseEnc); + + if (charset == null) { + // Pre-population of the cache means this must be invalid + throw new UnsupportedEncodingException(enc); + } + return charset; + } + private IntermediateInputStream iis; private ReadConvertor conv; private String encoding; @@ -114,7 +147,7 @@ public class B2CConverter { { // destroy the reader/iis iis=new IntermediateInputStream(); - conv=new ReadConvertor( iis, encoding ); + conv=new ReadConvertor( iis, getCharset(encoding) ); } private final int debug=0; @@ -192,10 +225,9 @@ final class ReadConvertor extends Input /** Create a converter. */ - public ReadConvertor( IntermediateInputStream in, String enc ) - throws UnsupportedEncodingException + public ReadConvertor( IntermediateInputStream in, Charset charset ) { - super( in, enc ); + super( in, charset ); } /** Overriden - will do nothing but reset internal state. Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/ByteChunk.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/ByteChunk.java?rev=1140904&r1=1140903&r2=1140904&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/ByteChunk.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/buf/ByteChunk.java Tue Jun 28 23:26:11 2011 @@ -19,6 +19,8 @@ package org.apache.tomcat.util.buf; import java.io.IOException; import java.io.Serializable; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; /* * In a server it is very important to be able to operate on @@ -95,7 +97,12 @@ public final class ByteChunk implements 8859_1, and this object is used mostly for servlets. */ public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; - + + /** Default Charset to use for interpreting byte[] as as String + */ + public static final Charset DEFAULT_CHARSET = + Charset.forName(DEFAULT_CHARACTER_ENCODING); + // byte[] private byte[] buff; @@ -493,8 +500,14 @@ public final class ByteChunk implements public String toStringInternal() { String strValue=null; try { - if( enc==null ) enc=DEFAULT_CHARACTER_ENCODING; - strValue = new String( buff, start, end-start, enc ); + Charset charset; + if (enc == null) { + charset = DEFAULT_CHARSET; + } else { + charset = B2CConverter.getCharset(enc); + } + strValue = charset.decode( + ByteBuffer.wrap(buff, start, end-start)).toString(); /* Does not improve the speed too much on most systems, it's safer to use the "clasical" new String(). Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1140904&r1=1140903&r2=1140904&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Tue Jun 28 23:26:11 2011 @@ -135,6 +135,11 @@ runtime exception (e.g. OOME) occurs while creating a new user for a MemoryUserDatabase via JMX. (markt) </fix> + <fix> + <bug>51400</bug>: Avoid jvm bottleneck on String/byte[] conversion + triggered by a JVM bug. Based on patches by Dave Engberg and Konstantin + Preißer. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org