UrlEncoded fix from Jürg Lehni to use JDK 1.4 methods if available and

switch back to JDK 1.3 methods otherwise. Methods renamed to encode()
and decode(), respectively.
This commit is contained in:
hns 2004-09-15 11:15:44 +00:00
parent fad94431e0
commit 71aeea336e
5 changed files with 97 additions and 34 deletions

View file

@ -1070,7 +1070,7 @@ public final class Application implements IPathElement, Runnable {
composeHref(elem, b, 0); composeHref(elem, b, 0);
if (actionName != null) { if (actionName != null) {
b.append(UrlEncoded.smartEncode(actionName, charset)); b.append(UrlEncoded.encode(actionName, charset));
} }
return b.toString(); return b.toString();
@ -1098,7 +1098,7 @@ public final class Application implements IPathElement, Runnable {
// append ourselves // append ourselves
String ename = getElementName(elem); String ename = getElementName(elem);
if (ename != null) { if (ename != null) {
b.append(UrlEncoded.smartEncode(ename, charset)); b.append(UrlEncoded.encode(ename, charset));
b.append("/"); b.append("/");
} }
} }

View file

@ -123,12 +123,12 @@ public class RequestPath {
} }
for (int i=start; i<ids.size(); i++) { for (int i=start; i<ids.size(); i++) {
buffer.append(UrlEncoded.smartEncode(ids.get(i).toString(), app.charset)); buffer.append(UrlEncoded.encode(ids.get(i).toString(), app.charset));
buffer.append("/"); buffer.append("/");
} }
if (action != null) { if (action != null) {
buffer.append(UrlEncoded.smartEncode(action, app.charset)); buffer.append(UrlEncoded.encode(action, app.charset));
} }
return buffer.toString(); return buffer.toString();

View file

@ -657,7 +657,7 @@ public final class Skin {
break; break;
case ENCODE_URL: case ENCODE_URL:
buffer.append(UrlEncoded.smartEncode(text, app.charset)); buffer.append(UrlEncoded.encode(text, app.charset));
break; break;

View file

@ -737,7 +737,7 @@ public abstract class AbstractServletClient extends HttpServlet {
pathbuffer.append('/'); pathbuffer.append('/');
} }
pathbuffer.append(UrlEncoded.smartDecode(token, defaultEncoding)); pathbuffer.append(UrlEncoded.decode(token, defaultEncoding));
} }
// append trailing "/" if it is contained in original URI // append trailing "/" if it is contained in original URI

View file

@ -16,43 +16,84 @@
package helma.util; package helma.util;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.net.URLCodec;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.BitSet; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;
/** /**
* A subclass of Jakarta Commons Codec URLCodec that offers * A proxy to java.net.URLEncoder which only encodes when there is actual work
* lazy encode/decode methods that only returns a new String * to do. This is necessary because URLEncoder is quite inefficient (e.g. it
* if actual work had to be done for encoding/decoding. * preallocates buffers and stuff), and we call it often with short string that
* This is because URLCodec is a bit inefficient (e.g. it * don't need encoding.
* preallocates buffers and stuff for each call to encode/decode),
* and we call it often with short strings that don't need encoding.
*/ */
public final class UrlEncoded extends URLCodec { public final class UrlEncoded {
// Java 1.4 encode method to use instead of deprecated 1.3 version.
private static Method encode = null;
private static Method decode = null;
// Initialize the encode and decode variables with the 1.4 methods if
// available.
// this code was adapted from org.apache.struts.utils.RequestUtils and
// org.apache.velocity.tools.view.tools.LinkTool
static {
try {
// get version of encode method with two String args
Class[] args = new Class[] { String.class, String.class };
encode = URLEncoder.class.getMethod("encode", args);
decode = URLDecoder.class.getMethod("decode", args);
} catch (NoSuchMethodException e) {
System.err.println("UrlEncoded: Can't find JDK 1.4 encode and decode methods. Using JDK 1.3 versions.");
}
}
/** /**
* URL-encode a string using the given encoding, or return it * URL-encodes a string using the given encoding, or return it unchanged if
* unchanged if no encoding was necessary. * no encoding was necessary.
* This method uses the new URLEncoder.encode() method from java 1.4 if
* available, otherwise the old deprecated version is used. Reflection is
* used to find the appropriate method; if the reflection operations throw
* exceptions other than UnsupportedEncodingException, it returns the url
* encoded with the old URLEncoder.encode() method.
* *
* @param str The string to be URL-encoded * @param str The string to be URL-encoded
* @param encoding the encoding to use * @param encoding the encoding to use
* @return the URL-encoded string, or str if no encoding necessary * @return the URL-encoded string, or str if no encoding necessary
*/ */
public static String smartEncode(String str, String encoding) public static String encode(String str, String encoding)
throws UnsupportedEncodingException { throws UnsupportedEncodingException {
int l = str.length(); int l = str.length();
boolean needsSpaceEncoding = false; boolean needsSpaceEncoding = false;
BitSet urlsafe = WWW_FORM_URL;
System.out.println(str);
for (int i = 0; i < l; i++) { for (int i = 0; i < l; i++) {
char c = str.charAt(i); char c = str.charAt(i);
if (c == ' ') { if (c == ' ') {
needsSpaceEncoding = true; needsSpaceEncoding = true;
} else if (!urlsafe.get(c)) { } else if (!(((c >= 'a') && (c <= 'z'))
return new URLCodec().encode(str, encoding); || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')))) {
if (encode != null) {
try {
return (String) encode.invoke(null, new Object[] { str,
encoding });
} catch (IllegalAccessException e) {
// don't keep trying if we get one of these
encode = null;
System.err.println("UrlEncoded: Can't access JDK 1.4 encode method ("
+ e + "). Using deprecated version from now on.");
} catch (InvocationTargetException e) {
// this can only be a UnsupportedEncodingException:
Throwable ex = e.getTargetException();
if (ex instanceof UnsupportedEncodingException)
throw (UnsupportedEncodingException) ex;
}
}
return URLEncoder.encode(str);
} }
} }
@ -64,19 +105,41 @@ public final class UrlEncoded extends URLCodec {
} }
/** /**
* URL-decode a string using the given encoding, * URL-decode a string using the given encoding, or return it unchanged if
* or return it unchanged if no encoding was necessary. * no encoding was necessary.
* This method uses the new URLDecoder.decode() method from java 1.4 if
* available, otherwise the old deprecated version is used. Reflection is
* used to find the appropriate method; if the reflection operations throw
* exceptions other than UnsupportedEncodingException, it returns the url
* decoded with the old URLDecoder.decode() method.
* *
* @param str The string to be URL-decoded * @param str The string to be URL-decoded
* @param encoding the encoding to use * @param encoding the encoding to use
* @return the URL-decoded string, or str if no decoding necessary * @return the URL-decoded string, or str if no decoding necessary
*/ */
public static String smartDecode(String str, String encoding) public static String decode(String str, String encoding)
throws DecoderException, UnsupportedEncodingException { throws UnsupportedEncodingException {
if ((str.indexOf('+') == -1) && (str.indexOf('%') == -1)) { if ((str.indexOf('+') == -1) && (str.indexOf('%') == -1)) {
return str; return str;
} else { } else {
return new URLCodec().decode(str, encoding); if (decode != null) {
try {
return (String) decode.invoke(null, new Object[] { str,
encoding });
} catch (IllegalAccessException e) {
// don't keep trying if we get one of these
decode = null;
System.err.println("UrlEncoded: Can't access JDK 1.4 decode method ("
+ e + "). Using deprecated version from now on.");
} catch (InvocationTargetException e) {
// this can only be a UnsupportedEncodingException:
Throwable ex = e.getTargetException();
if (ex instanceof UnsupportedEncodingException)
throw (UnsupportedEncodingException) ex;
}
}
return URLDecoder.decode(str);
} }
} }