FileDocCategorySizeDatePackage
RequestUtil.javaAPI DocGlassfish v2 API21200Fri May 04 22:32:30 BST 2007org.apache.catalina.util

RequestUtil

public final class RequestUtil extends Object
General purpose request parsing and encoding utility methods.
author
Craig R. McClanahan
author
Tim Tye
version
$Revision: 1.5 $ $Date: 2007/05/05 05:32:30 $

Fields Summary
private static final String
SESSION_VERSION_SEPARATOR
private static SimpleDateFormat
format
The DateFormat to use for generating readable dates in cookies.
Constructors Summary
Methods Summary
public static java.lang.StringURLDecode(byte[] bytes, java.lang.String enc)
Decode and return the specified URL-encoded byte array.

param
bytes The url-encoded byte array
param
enc The encoding to use; if null, the default encoding is used
exception
IllegalArgumentException if a '%' character is not followed by a valid 2-digit hexadecimal number


        if (bytes == null)
            return (null);

        int len = bytes.length;
        int ix = 0;
        int ox = 0;
        while (ix < len) {
            byte b = bytes[ix++];     // Get byte to test
            if (b == '+") {
                b = (byte)' ";
            } else if (b == '%") {
                b = (byte) ((convertHexDigit(bytes[ix++]) << 4)
                            + convertHexDigit(bytes[ix++]));
            }
            bytes[ox++] = b;
        }
        if (enc != null) {
            try {
                return new String(bytes, 0, ox, enc);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return new String(bytes, 0, ox);

    
public static java.lang.StringURLDecode(org.apache.tomcat.util.buf.ByteChunk bc, boolean toString)
Decode (in place) the specified URL-encoded byte chunk, and optionally return the decoded result as a String

param
bc The URL-encoded byte chunk to be decoded in place
param
toString true if the decoded result is to be returned as a String, false otherwise
return
The decoded result in String form, if toString is true, or null otherwise
exception
IllegalArgumentException if a '%' character is not followed by a valid 2-digit hexadecimal number


        if (bc == null) {
            return (null);
        }

        byte[] bytes = bc.getBytes();
        if (bytes == null) {
            return (null);
        }

        int ix = bc.getStart();
        int end = bc.getEnd();
        int ox = ix;
        while (ix < end) {
            byte b = bytes[ix++];     // Get byte to test
            if (b == '+") {
                b = (byte)' ";
            } else if (b == '%") {
                b = (byte) ((convertHexDigit(bytes[ix++]) << 4)
                            + convertHexDigit(bytes[ix++]));
            }
            bytes[ox++] = b;
        }
        bc.setEnd(ox);
        if (toString) {
            return bc.toString();
        } else {
            return null;
        }
    
public static java.lang.StringURLDecode(java.lang.String str)
Decode and return the specified URL-encoded String. When the byte array is converted to a string, the system default character encoding is used... This may be different than some other servers.

param
str The url-encoded string
exception
IllegalArgumentException if a '%' character is not followed by a valid 2-digit hexadecimal number


        return URLDecode(str, null);

    
public static java.lang.StringURLDecode(java.lang.String str, java.lang.String enc)
Decode and return the specified URL-encoded String.

param
str The url-encoded string
param
enc The encoding to use; if null, the default encoding is used
exception
IllegalArgumentException if a '%' character is not followed by a valid 2-digit hexadecimal number


        if (str == null)
            return (null);

        // use the specified encoding to extract bytes out of the
        // given string so that the encoding is not lost. If an
        // encoding is not specified, let it use platform default
        byte[] bytes = null;
        try {
            if (enc == null) {
                bytes = str.getBytes();
            } else {
                bytes = str.getBytes(enc);
            }
        } catch (UnsupportedEncodingException uee) {}

        return URLDecode(bytes, enc);

    
public static java.lang.StringURLDecode(byte[] bytes)
Decode and return the specified URL-encoded byte array.

param
bytes The url-encoded byte array
exception
IllegalArgumentException if a '%' character is not followed by a valid 2-digit hexadecimal number

        return URLDecode(bytes, null);
    
private static byteconvertHexDigit(byte b)
Convert a byte character value to hexidecimal digit value.

param
b the character value byte

        if ((b >= '0") && (b <= '9")) return (byte)(b - '0");
        if ((b >= 'a") && (b <= 'f")) return (byte)(b - 'a" + 10);
        if ((b >= 'A") && (b <= 'F")) return (byte)(b - 'A" + 10);
        return 0;
    
public static java.lang.StringencodeCookie(javax.servlet.http.Cookie cookie)
Encode a cookie as per RFC 2109. The resulting string can be used as the value for a Set-Cookie header.

param
cookie The cookie to encode.
return
A string following RFC 2109.


     
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
    

        StringBuffer buf = new StringBuffer( cookie.getName() );
        buf.append("=");
        buf.append(cookie.getValue());

        if (cookie.getComment() != null) {
            buf.append("; Comment=\"");
            buf.append(cookie.getComment());
            buf.append("\"");
        }

        if (cookie.getDomain() != null) {
            buf.append("; Domain=\"");
            buf.append(cookie.getDomain());
            buf.append("\"");
        }

        long age = cookie.getMaxAge();
        if (cookie.getMaxAge() >= 0) {
            buf.append("; Max-Age=\"");
            buf.append(cookie.getMaxAge());
            buf.append("\"");
        }

        if (cookie.getPath() != null) {
            buf.append("; Path=\"");
            buf.append(cookie.getPath());
            buf.append("\"");
        }

        if (cookie.getSecure()) {
            buf.append("; Secure");
        }

        if (cookie.getVersion() > 0) {
            buf.append("; Version=\"");
            buf.append(cookie.getVersion());
            buf.append("\"");
        }

        return (buf.toString());
    
public static java.lang.Stringfilter(java.lang.String message)
Filter the specified message string for characters that are sensitive in HTML. This avoids potential attacks caused by including JavaScript codes in the request URL that is often reported in error messages.

param
message The message string to be filtered


        if (message == null)
            return (null);

        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuffer result = new StringBuffer(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<":
                result.append("<");
                break;
            case '>":
                result.append(">");
                break;
            case '&":
                result.append("&");
                break;
            case '"":
                result.append(""");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());

    
public static java.lang.StringmakeSessionVersionString(java.util.HashMap sessionVersions)
Gets the string representation of the given session version mappings.

param
sessionVersions The session version mappings
return
The string representation of the given session version mappings


        if (sessionVersions == null) {
            return null;
        }

        StringBuffer sb = new StringBuffer();
        Iterator<String> iter = sessionVersions.keySet().iterator();
        boolean first = true;
        while (iter.hasNext()) {
            if (first) {
                first = false;
            } else {
                sb.append(':");
            }
            String contextPath = iter.next();
            sb.append(contextPath);
            sb.append(SESSION_VERSION_SEPARATOR);
            sb.append(sessionVersions.get(contextPath));
        }

        return sb.toString();
    
public static java.lang.Stringnormalize(java.lang.String path)
Normalize a relative URI path that may have relative values ("/./", "/../", and so on ) it it. WARNING - This method is useful only for normalizing application-generated paths. It does not try to perform security checks for malicious input.

param
path Relative path to be normalized


        if (path == null)
            return null;

        // Create a place for the normalized path
        String normalized = path;

        if (normalized.equals("/."))
            return "/";

        // Add a leading "/" if necessary
        if (!normalized.startsWith("/"))
            normalized = "/" + normalized;

        // Resolve occurrences of "//" in the normalized path
        while (true) {
            int index = normalized.indexOf("//");
            if (index < 0)
                break;
            normalized = normalized.substring(0, index) +
                normalized.substring(index + 1);
        }

        // Resolve occurrences of "/./" in the normalized path
        while (true) {
            int index = normalized.indexOf("/./");
            if (index < 0)
                break;
            normalized = normalized.substring(0, index) +
                normalized.substring(index + 2);
        }

        // Resolve occurrences of "/../" in the normalized path
        while (true) {
            int index = normalized.indexOf("/../");
            if (index < 0)
                break;
            if (index == 0)
                return (null);  // Trying to go outside our context
            int index2 = normalized.lastIndexOf('/", index - 1);
            normalized = normalized.substring(0, index2) +
                normalized.substring(index + 3);
        }

        // Return the normalized path that we have completed
        return (normalized);

    
public static java.lang.StringparseCharacterEncoding(java.lang.String contentType)
Parse the character encoding from the specified content type header. If the content type is null, or there is no explicit character encoding, null is returned.

param
contentType a content type header


        if (contentType == null)
            return (null);
        int start = contentType.indexOf("charset=");
        if (start < 0)
            return (null);
        String encoding = contentType.substring(start + 8);
        int end = encoding.indexOf(';");
        if (end >= 0)
            encoding = encoding.substring(0, end);
        encoding = encoding.trim();
        if ((encoding.length() > 2) && (encoding.startsWith("\""))
            && (encoding.endsWith("\"")))
            encoding = encoding.substring(1, encoding.length() - 1);
        return (encoding.trim());

    
public static javax.servlet.http.Cookie[]parseCookieHeader(java.lang.String header)
Parse a cookie header into an array of cookies according to RFC 2109.

param
header Value of an HTTP "Cookie" header


        if ((header == null) || (header.length() < 1))
            return (new Cookie[0]);

        ArrayList cookies = new ArrayList();
        while (header.length() > 0) {
            int semicolon = header.indexOf(';");
            if (semicolon < 0)
                semicolon = header.length();
            if (semicolon == 0)
                break;
            String token = header.substring(0, semicolon);
            if (semicolon < header.length())
                header = header.substring(semicolon + 1);
            else
                header = "";
            try {
                int equals = token.indexOf('=");
                if (equals > 0) {
                    String name = token.substring(0, equals).trim();
                    String value = token.substring(equals+1).trim();
                    cookies.add(new Cookie(name, value));
                }
            } catch (Throwable e) {
                ;
            }
        }

        return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));

    
public static voidparseParameters(java.util.Map map, byte[] data, java.lang.String encoding)
Append request parameters from the specified String to the specified Map. It is presumed that the specified Map is not accessed from any other thread, so no synchronization is performed.

IMPLEMENTATION NOTE: URL decoding is performed individually on the parsed name and value elements, rather than on the entire query string ahead of time, to properly deal with the case where the name or value includes an encoded "=" or "&" character that would otherwise be interpreted as a delimiter. NOTE: byte array data is modified by this method. Caller beware.

param
map Map that accumulates the resulting parameters
param
data Input string containing request parameters
param
encoding Encoding to use for converting hex
exception
UnsupportedEncodingException if the data is malformed


        if (data != null && data.length > 0) {
            int    pos = 0;
            int    ix = 0;
            int    ox = 0;
            String key = null;
            String value = null;
            while (ix < data.length) {
                byte c = data[ix++];
                switch ((char) c) {
                case '&":
                    value = new String(data, 0, ox, encoding);
                    if (key != null) {
                        putMapEntry(map, key, value);
                        key = null;
                    }
                    ox = 0;
                    break;
                case '=":
                    if (key == null) {
                        key = new String(data, 0, ox, encoding);
                        ox = 0;
                    } else {
                        data[ox++] = c;
                    }                   
                    break;  
                case '+":
                    data[ox++] = (byte)' ";
                    break;
                case '%":
                    data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
                                    + convertHexDigit(data[ix++]));
                    break;
                default:
                    data[ox++] = c;
                }
            }
            //The last value does not end in '&'.  So save it now.
            if (key != null) {
                value = new String(data, 0, ox, encoding);
                putMapEntry(map, key, value);
            }
        }

    
public static voidparseParameters(java.util.Map map, java.lang.String data, java.lang.String encoding)
Append request parameters from the specified String to the specified Map. It is presumed that the specified Map is not accessed from any other thread, so no synchronization is performed.

IMPLEMENTATION NOTE: URL decoding is performed individually on the parsed name and value elements, rather than on the entire query string ahead of time, to properly deal with the case where the name or value includes an encoded "=" or "&" character that would otherwise be interpreted as a delimiter.

param
map Map that accumulates the resulting parameters
param
data Input string containing request parameters
param
urlParameters true if we're parsing parameters on the URL
exception
IllegalArgumentException if the data is malformed


        if ((data != null) && (data.length() > 0)) {

            // use the specified encoding to extract bytes out of the
            // given string so that the encoding is not lost. If an
            // encoding is not specified, let it use platform default
            byte[] bytes = null;
            try {
                if (encoding == null) {
                    bytes = data.getBytes();
                } else {
                    bytes = data.getBytes(encoding);
                }
            } catch (UnsupportedEncodingException uee) {
            }

            parseParameters(map, bytes, encoding);
        }

    
public static final java.util.HashMapparseSessionVersions(java.lang.String sessionVersion)
Parses the given session version string into its components.

param
sessionVersion The session version string to parse
return
The mappings from context paths to session version numbers that were parsed from the given session version string


        if (sessionVersion == null) {
            return null;
        }

        StringTokenizer st = new StringTokenizer(sessionVersion,
                                                 SESSION_VERSION_SEPARATOR);
        HashMap<String, String> result =
            new HashMap<String, String>(st.countTokens());
        while (st.hasMoreTokens()) {
            String contextPath = st.nextToken();
            if (st.hasMoreTokens()) {
                result.put(contextPath, st.nextToken());
            }
        }

        return result;
    
private static voidputMapEntry(java.util.Map map, java.lang.String name, java.lang.String value)
Put name value pair in map.

param
b the character value byte Put name and value pair in map. When name already exist, add value to array of values.

        String[] newValues = null;
        String[] oldValues = (String[]) map.get(name);
        if (oldValues == null) {
            newValues = new String[1];
            newValues[0] = value;
        } else {
            newValues = new String[oldValues.length + 1];
            System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
            newValues[oldValues.length] = value;
        }
        map.put(name, newValues);