You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by kk...@apache.org on 2011/11/10 07:26:26 UTC
svn commit: r1200183 - in
/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http: ContentType.java
CookieSupport.java Cookies.java ServerCookie.java
Author: kkolinko
Date: Thu Nov 10 06:26:26 2011
New Revision: 1200183
URL: http://svn.apache.org/viewvc?rev=1200183&view=rev
Log:
Merged revision 1187753 from tomcat/trunk:
Clean-up. No functional change.
Part 9
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ContentType.java
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/CookieSupport.java
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java
Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ContentType.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ContentType.java?rev=1200183&r1=1200182&r2=1200183&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ContentType.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ContentType.java Thu Nov 10 06:26:26 2011
@@ -14,13 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.tomcat.util.http;
/**
* Useful methods for Content-Type processing
- *
+ *
* @author James Duncan Davidson [duncan@eng.sun.com]
* @author James Todd [gonzo@eng.sun.com]
* @author Jason Hunter [jch@eng.sun.com]
@@ -38,19 +37,23 @@ public class ContentType {
*/
public static String getCharsetFromContentType(String contentType) {
- if (contentType == null)
+ if (contentType == null) {
return (null);
+ }
int start = contentType.indexOf("charset=");
- if (start < 0)
+ if (start < 0) {
return (null);
+ }
String encoding = contentType.substring(start + 8);
int end = encoding.indexOf(';');
- if (end >= 0)
+ if (end >= 0) {
encoding = encoding.substring(0, end);
+ }
encoding = encoding.trim();
if ((encoding.length() > 2) && (encoding.startsWith("\""))
- && (encoding.endsWith("\"")))
+ && (encoding.endsWith("\""))) {
encoding = encoding.substring(1, encoding.length() - 1);
+ }
return (encoding.trim());
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/CookieSupport.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/CookieSupport.java?rev=1200183&r1=1200182&r2=1200183&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/CookieSupport.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/CookieSupport.java Thu Nov 10 06:26:26 2011
@@ -5,17 +5,15 @@
* 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;
@@ -44,7 +42,7 @@ public final class CookieSupport {
* inclusion of / depends on the value of {@link #FWD_SLASH_IS_SEPARATOR}.
*/
public static final boolean ALLOW_HTTP_SEPARATORS_IN_V0;
-
+
/**
* If set to false, we don't use the IE6/7 Max-Age/Expires work around.
* Default is usually true. If STRICT_SERVLET_COMPLIANCE==true then default
@@ -71,7 +69,7 @@ public final class CookieSupport {
*/
private static final char[] V0_SEPARATORS = {',', ';', ' ', '\t'};
private static final boolean[] V0_SEPARATOR_FLAGS = new boolean[128];
-
+
/**
* The list of separators that apply to version 1 cookies. This may or may
* not include '/' depending on the setting of
@@ -79,20 +77,20 @@ public final class CookieSupport {
*/
private static final char[] HTTP_SEPARATORS;
private static final boolean[] HTTP_SEPARATOR_FLAGS = new boolean[128];
-
+
static {
STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty(
"org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
"false")).booleanValue();
-
+
ALLOW_EQUALS_IN_VALUE = Boolean.valueOf(System.getProperty(
"org.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE",
"false")).booleanValue();
-
+
ALLOW_HTTP_SEPARATORS_IN_V0 = Boolean.valueOf(System.getProperty(
"org.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0",
"false")).booleanValue();
-
+
String alwaysAddExpires = System.getProperty(
"org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES");
if (alwaysAddExpires == null) {
@@ -101,7 +99,7 @@ public final class CookieSupport {
ALWAYS_ADD_EXPIRES =
Boolean.valueOf(alwaysAddExpires).booleanValue();
}
-
+
String fwdSlashIsSeparator = System.getProperty(
"org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
if (fwdSlashIsSeparator == null) {
@@ -110,24 +108,24 @@ public final class CookieSupport {
FWD_SLASH_IS_SEPARATOR =
Boolean.valueOf(fwdSlashIsSeparator).booleanValue();
}
-
+
ALLOW_NAME_ONLY = Boolean.valueOf(System.getProperty(
"org.apache.tomcat.util.http.ServerCookie.ALLOW_NAME_ONLY",
"false")).booleanValue();
-
+
/*
- Excluding the '/' char by default violates the RFC, but
+ Excluding the '/' char by default violates the RFC, but
it looks like a lot of people put '/'
- in unquoted values: '/': ; //47
- '\t':9 ' ':32 '\"':34 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60
+ in unquoted values: '/': ; //47
+ '\t':9 ' ':32 '\"':34 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60
'=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125
*/
if (CookieSupport.FWD_SLASH_IS_SEPARATOR) {
- HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',', '/',
+ HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',', '/',
':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' };
} else {
- HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',',
+ HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',',
':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' };
}
for (int i = 0; i < 128; i++) {
@@ -142,7 +140,7 @@ public final class CookieSupport {
}
}
-
+
// ----------------------------------------------------------------- Methods
/**
@@ -159,10 +157,12 @@ public final class CookieSupport {
return V0_SEPARATOR_FLAGS[c];
}
-
+
public static boolean isV0Token(String value) {
- if( value==null) return false;
-
+ if( value==null) {
+ return false;
+ }
+
int i = 0;
int len = value.length();
@@ -170,12 +170,13 @@ public final class CookieSupport {
i++;
len--;
}
-
+
for (; i < len; i++) {
char c = value.charAt(i);
- if (isV0Separator(c))
+ if (isV0Separator(c)) {
return true;
+ }
}
return false;
}
@@ -198,8 +199,10 @@ public final class CookieSupport {
}
public static boolean isHttpToken(String value) {
- if( value==null) return false;
-
+ if( value==null) {
+ return false;
+ }
+
int i = 0;
int len = value.length();
@@ -207,18 +210,21 @@ public final class CookieSupport {
i++;
len--;
}
-
+
for (; i < len; i++) {
char c = value.charAt(i);
- if (isHttpSeparator(c))
+ if (isHttpSeparator(c)) {
return true;
+ }
}
return false;
}
public static boolean alreadyQuoted (String value) {
- if (value==null || value.length() < 2) return false;
+ if (value==null || value.length() < 2) {
+ return false;
+ }
return (value.charAt(0)=='\"' && value.charAt(value.length()-1)=='\"');
}
Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java?rev=1200183&r1=1200182&r2=1200183&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java Thu Nov 10 06:26:26 2011
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.tomcat.util.http;
import java.io.PrintWriter;
@@ -36,9 +35,9 @@ public final class Cookies { // extends
private static final org.apache.juli.logging.Log log=
org.apache.juli.logging.LogFactory.getLog(Cookies.class );
-
+
// expected average number of cookies per request
- public static final int INITIAL_SIZE=4;
+ public static final int INITIAL_SIZE=4;
ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE];
int cookieCount=0;
boolean unprocessed=true;
@@ -61,8 +60,9 @@ public final class Cookies { // extends
*/
public void recycle() {
for( int i=0; i< cookieCount; i++ ) {
- if( scookies[i]!=null )
+ if( scookies[i]!=null ) {
scookies[i].recycle();
+ }
}
cookieCount=0;
unprocessed=true;
@@ -84,7 +84,7 @@ public final class Cookies { // extends
}
// -------------------- Indexed access --------------------
-
+
public ServerCookie getCookie( int idx ) {
if( unprocessed ) {
getCookieCount(); // will also update the cookies
@@ -112,7 +112,7 @@ public final class Cookies { // extends
System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount);
scookies=scookiesTmp;
}
-
+
ServerCookie c = scookies[cookieCount];
if( c==null ) {
c= new ServerCookie();
@@ -123,20 +123,24 @@ public final class Cookies { // extends
}
- // code from CookieTools
+ // code from CookieTools
/** Add all Cookie found in the headers of a request.
*/
public void processCookies( MimeHeaders headers ) {
if( headers==null )
+ {
return;// nothing to process
+ }
// process each "cookie" header
int pos=0;
while( pos>=0 ) {
// Cookie2: version ? not needed
pos=headers.findHeader( "Cookie", pos );
// no more cookie headers headers
- if( pos<0 ) break;
+ if( pos<0 ) {
+ break;
+ }
MessageBytes cookieValue=headers.getValue( pos );
if( cookieValue==null || cookieValue.isNull() ) {
@@ -151,8 +155,9 @@ public final class Cookies { // extends
e);
cookieValue.toBytes();
}
- if(log.isDebugEnabled())
+ if(log.isDebugEnabled()) {
log.debug("Cookies: Parsing b[]: " + cookieValue.toString());
+ }
ByteChunk bc=cookieValue.getByteChunk();
processCookieHeader( bc.getBytes(),
bc.getOffset(),
@@ -175,7 +180,7 @@ public final class Cookies { // extends
}
return true;
}
-
+
/**
* Returns true if the byte is a whitespace character as
@@ -186,7 +191,7 @@ public final class Cookies { // extends
// This switch statement is slightly slower
// for my vm than the if statement.
// Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-164)
- /*
+ /*
switch (c) {
case ' ':;
case '\t':;
@@ -198,10 +203,11 @@ public final class Cookies { // extends
return false;
}
*/
- if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f')
- return true;
- else
- return false;
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f') {
+ return true;
+ } else {
+ return false;
+ }
}
/**
@@ -219,7 +225,7 @@ public final class Cookies { // extends
int end = bc.getEnd();
int dest = src;
byte[] buffer = bc.getBuffer();
-
+
while (src < end) {
if (buffer[src] == '\\' && src < end && buffer[src+1] == '"') {
src++;
@@ -238,7 +244,9 @@ public final class Cookies { // extends
* JVK
*/
protected final void processCookieHeader(byte bytes[], int off, int len){
- if( len<=0 || bytes==null ) return;
+ if( len<=0 || bytes==null ) {
+ return;
+ }
int end=off+len;
int pos=off;
int nameStart=0;
@@ -255,15 +263,16 @@ public final class Cookies { // extends
isQuoted = false;
// Skip whitespace and non-token characters (separators)
- while (pos < end &&
+ while (pos < end &&
(CookieSupport.isHttpSeparator((char) bytes[pos]) &&
!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 ||
CookieSupport.isV0Separator((char) bytes[pos]) ||
- isWhiteSpace(bytes[pos])))
- {pos++; }
+ isWhiteSpace(bytes[pos])))
+ {pos++; }
- if (pos >= end)
+ if (pos >= end) {
return;
+ }
// Detect Special cookies
if (bytes[pos] == '$') {
@@ -271,27 +280,28 @@ public final class Cookies { // extends
pos++;
}
- // Get the cookie/attribute name. This must be a token
- valueEnd = valueStart = nameStart = pos;
+ // Get the cookie/attribute name. This must be a token
+ valueEnd = valueStart = nameStart = pos;
pos = nameEnd = getTokenEndPosition(bytes,pos,end,version,true);
// Skip whitespace
- while (pos < end && isWhiteSpace(bytes[pos])) {pos++; }
-
+ while (pos < end && isWhiteSpace(bytes[pos])) {pos++; }
+
// Check for an '=' -- This could also be a name-only
// cookie at the end of the cookie header, so if we
// are past the end of the header, but we have a name
// skip to the name-only part.
- if (pos < (end - 1) && bytes[pos] == '=') {
+ if (pos < (end - 1) && bytes[pos] == '=') {
// Skip whitespace
do {
pos++;
- } while (pos < end && isWhiteSpace(bytes[pos]));
+ } while (pos < end && isWhiteSpace(bytes[pos]));
- if (pos >= end)
+ if (pos >= end) {
return;
+ }
// Determine what type of value this is, quoted value,
// token, name-only with an '=', or other (bad)
@@ -299,18 +309,19 @@ public final class Cookies { // extends
case '"': // Quoted Value
isQuoted = true;
valueStart=pos + 1; // strip "
- // getQuotedValue returns the position before
+ // getQuotedValue returns the position before
// at the last quote. This must be dealt with
// when the bytes are copied into the cookie
- valueEnd=getQuotedValueEndPosition(bytes,
+ valueEnd=getQuotedValueEndPosition(bytes,
valueStart, end);
// We need pos to advance
- pos = valueEnd;
- // Handles cases where the quoted value is
- // unterminated and at the end of the header,
+ pos = valueEnd;
+ // Handles cases where the quoted value is
+ // unterminated and at the end of the header,
// e.g. [myname="value]
- if (pos >= end)
+ if (pos >= end) {
return;
+ }
break;
case ';':
case ',':
@@ -339,15 +350,15 @@ public final class Cookies { // extends
// not valid.
log.info("Cookies: Invalid cookie. " +
"Value not a token or quoted value");
- while (pos < end && bytes[pos] != ';' &&
- bytes[pos] != ',')
+ while (pos < end && bytes[pos] != ';' &&
+ bytes[pos] != ',')
{pos++; }
pos++;
- // Make sure no special avpairs can be attributed to
+ // Make sure no special avpairs can be attributed to
// the previous cookie by setting the current cookie
// to null
sc = null;
- continue;
+ continue;
}
}
} else {
@@ -356,30 +367,30 @@ public final class Cookies { // extends
pos = nameEnd;
}
-
+
// We should have an avpair or name-only cookie at this
// point. Perform some basic checks to make sure we are
// in a good state.
-
+
// Skip whitespace
while (pos < end && isWhiteSpace(bytes[pos])) {pos++; }
// Make sure that after the cookie we have a separator. This
// is only important if this is not the last cookie pair
- while (pos < end && bytes[pos] != ';' && bytes[pos] != ',') {
+ while (pos < end && bytes[pos] != ';' && bytes[pos] != ',') {
pos++;
}
-
+
pos++;
- // All checks passed. Add the cookie, start with the
+ // All checks passed. Add the cookie, start with the
// special avpairs first
if (isSpecial) {
isSpecial = false;
// $Version must be the first avpair in the cookie header
// (sc must be null)
- if (equals( "Version", bytes, nameStart, nameEnd) &&
+ if (equals( "Version", bytes, nameStart, nameEnd) &&
sc == null) {
// Set version
if( bytes[valueStart] =='1' && valueEnd == (valueStart+1)) {
@@ -388,8 +399,8 @@ public final class Cookies { // extends
// unknown version (Versioning is not very strict)
}
continue;
- }
-
+ }
+
// We need an active cookie for Path/Port/etc.
if (sc == null) {
continue;
@@ -401,22 +412,22 @@ public final class Cookies { // extends
valueStart,
valueEnd-valueStart);
continue;
- }
+ }
if (equals( "Path", bytes, nameStart, nameEnd)) {
sc.getPath().setBytes( bytes,
valueStart,
valueEnd-valueStart);
continue;
- }
+ }
// v2 cookie attributes - skip them
if (equals( "Port", bytes, nameStart, nameEnd)) {
continue;
- }
+ }
if (equals( "CommentURL", bytes, nameStart, nameEnd)) {
continue;
- }
+ }
// Unknown cookie, complain
log.info("Cookies: Unknown Special Cookie");
@@ -431,7 +442,7 @@ public final class Cookies { // extends
sc.setVersion( version );
sc.getName().setBytes( bytes, nameStart,
nameEnd-nameStart);
-
+
if (valueStart != -1) { // Normal AVPair
sc.getValue().setBytes( bytes, valueStart,
valueEnd-valueStart);
@@ -441,7 +452,7 @@ public final class Cookies { // extends
}
} else {
// Name Only
- sc.getValue().setString("");
+ sc.getValue().setString("");
}
continue;
}
@@ -466,13 +477,14 @@ public final class Cookies { // extends
CookieSupport.ALLOW_EQUALS_IN_VALUE)) {
pos++;
}
-
- if (pos > end)
+
+ if (pos > end) {
return end;
+ }
return pos;
}
- /**
+ /**
* Given a starting position after an initial quote character, this gets
* the position of the end quote. This escapes anything after a '\' char
* JVK RFC 2616
@@ -481,7 +493,7 @@ public final class Cookies { // extends
int pos = off;
while (pos < end) {
if (bytes[pos] == '"') {
- return pos;
+ return pos;
} else if (bytes[pos] == '\\' && pos < (end - 1)) {
pos+=2;
} else {
Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java?rev=1200183&r1=1200182&r2=1200183&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java Thu Nov 10 06:26:26 2011
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.tomcat.util.http;
import java.io.Serializable;
@@ -38,19 +37,19 @@ import org.apache.tomcat.util.buf.Messag
* and the facade will convert it to the external representation.
*/
public class ServerCookie implements Serializable {
-
+
private static final long serialVersionUID = 1L;
-
+
// Version 0 (Netscape) attributes
- private MessageBytes name=MessageBytes.newInstance();
- private MessageBytes value=MessageBytes.newInstance();
+ private final MessageBytes name=MessageBytes.newInstance();
+ private final MessageBytes value=MessageBytes.newInstance();
// Expires - Not stored explicitly. Generated from Max-Age (see V1)
- private MessageBytes path=MessageBytes.newInstance();
- private MessageBytes domain=MessageBytes.newInstance();
+ private final MessageBytes path=MessageBytes.newInstance();
+ private final MessageBytes domain=MessageBytes.newInstance();
private boolean secure;
-
+
// Version 1 (RFC2109) attributes
- private MessageBytes comment=MessageBytes.newInstance();
+ private final MessageBytes comment=MessageBytes.newInstance();
private int maxAge = -1;
private int version = 0;
@@ -150,10 +149,10 @@ public class ServerCookie implements Ser
return "Cookie " + getName() + "=" + getValue() + " ; "
+ getVersion() + " " + getPath() + " " + getDomain();
}
-
+
// -------------------- Cookie parsing tools
-
+
public static void appendCookieValue( StringBuffer headerBuf,
int version,
String name,
@@ -170,19 +169,19 @@ public class ServerCookie implements Ser
buf.append( name );
buf.append("=");
// Servlet implementation does not check anything else
-
+
/*
* The spec allows some latitude on when to send the version attribute
* with a Set-Cookie header. To be nice to clients, we'll make sure the
* version attribute is first. That means checking the various things
* that can cause us to switch to a v1 cookie first.
- *
+ *
* Note that by checking for tokens we will also throw an exception if a
* control character is encountered.
*/
// Start by using the version we were asked for
int newVersion = version;
-
+
// If it is v0, check if we need to switch
if (newVersion == 0 &&
(!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
@@ -192,7 +191,7 @@ public class ServerCookie implements Ser
// HTTP token in value - need to use v1
newVersion = 1;
}
-
+
if (newVersion == 0 && comment != null) {
// Using a comment makes it a v1 cookie
newVersion = 1;
@@ -230,7 +229,7 @@ public class ServerCookie implements Ser
maybeQuote(buf, comment);
}
}
-
+
// Add domain information, if present
if (domain!=null) {
buf.append("; Domain=");
@@ -249,13 +248,14 @@ public class ServerCookie implements Ser
// Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
buf.append ("; Expires=");
// To expire immediately we need to set the time in past
- if (maxAge == 0)
+ if (maxAge == 0) {
buf.append( ancientDate );
- else
+ } else {
OLD_COOKIE_FORMAT.get().format(
new Date(System.currentTimeMillis() +
maxAge*1000L),
buf, new FieldPosition(0));
+ }
}
}
@@ -269,7 +269,7 @@ public class ServerCookie implements Ser
if (isSecure) {
buf.append ("; Secure");
}
-
+
// HttpOnly
if (isHttpOnly) {
buf.append("; HttpOnly");
@@ -322,12 +322,15 @@ public class ServerCookie implements Ser
if (c == '\\' ) {
b.append(c);
//ignore the character after an escape, just append it
- if (++i>=endIndex) throw new IllegalArgumentException("Invalid escape character in cookie value.");
+ if (++i>=endIndex) {
+ throw new IllegalArgumentException("Invalid escape character in cookie value.");
+ }
b.append(s.charAt(i));
- } else if (c == '"')
+ } else if (c == '"') {
b.append('\\').append('"');
- else
+ } else {
b.append(c);
+ }
}
return b.toString();
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org