Switch to Jakarta Commons Codec for URL en/decoding to provide
encoding-sensitivity on JDK 1.3. Use application charset for URL encoding and decoding. UnsupportedEncodingException is propagated.
This commit is contained in:
parent
e3eed21f50
commit
b8dd92a125
10 changed files with 108 additions and 63 deletions
|
@ -602,7 +602,7 @@ public final class Application implements IPathElement, Runnable {
|
||||||
try {
|
try {
|
||||||
res.close(charset);
|
res.close(charset);
|
||||||
} catch (UnsupportedEncodingException uee) {
|
} catch (UnsupportedEncodingException uee) {
|
||||||
logEvent("Unsupported response encoding: " + uee.getMessage());
|
logError("Unsupported response encoding", uee);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.waitForClose();
|
res.waitForClose();
|
||||||
|
@ -692,9 +692,9 @@ public final class Application implements IPathElement, Runnable {
|
||||||
String rootFactory = classMapping.getProperty("root.factory.class");
|
String rootFactory = classMapping.getProperty("root.factory.class");
|
||||||
Class c = typemgr.getClassLoader().loadClass(rootFactory);
|
Class c = typemgr.getClassLoader().loadClass(rootFactory);
|
||||||
Method m = c.getMethod(classMapping.getProperty("root.factory.method"),
|
Method m = c.getMethod(classMapping.getProperty("root.factory.method"),
|
||||||
null);
|
(Class[]) null);
|
||||||
|
|
||||||
rootObject = m.invoke(c, null);
|
rootObject = m.invoke(c, (Object[]) null);
|
||||||
} else {
|
} else {
|
||||||
String rootClass = classMapping.getProperty("root");
|
String rootClass = classMapping.getProperty("root");
|
||||||
Class c = typemgr.getClassLoader().loadClass(rootClass);
|
Class c = typemgr.getClassLoader().loadClass(rootClass);
|
||||||
|
@ -1056,26 +1056,28 @@ public final class Application implements IPathElement, Runnable {
|
||||||
/**
|
/**
|
||||||
* Return the href to the root of this application.
|
* Return the href to the root of this application.
|
||||||
*/
|
*/
|
||||||
public String getRootHref() {
|
public String getRootHref() throws UnsupportedEncodingException {
|
||||||
return getNodeHref(getDataRoot(), null);
|
return getNodeHref(getDataRoot(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a path to be used in a URL pointing to the given element and action
|
* Return a path to be used in a URL pointing to the given element and action
|
||||||
*/
|
*/
|
||||||
public String getNodeHref(Object elem, String actionName) {
|
public String getNodeHref(Object elem, String actionName)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
StringBuffer b = new StringBuffer(baseURI);
|
StringBuffer b = new StringBuffer(baseURI);
|
||||||
|
|
||||||
composeHref(elem, b, 0);
|
composeHref(elem, b, 0);
|
||||||
|
|
||||||
if (actionName != null) {
|
if (actionName != null) {
|
||||||
b.append(UrlEncoded.encode(actionName));
|
b.append(UrlEncoded.smartEncode(actionName, charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void composeHref(Object elem, StringBuffer b, int pathCount) {
|
private final void composeHref(Object elem, StringBuffer b, int pathCount)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
if ((elem == null) || (pathCount > 50)) {
|
if ((elem == null) || (pathCount > 50)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1096,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.encode(ename));
|
b.append(UrlEncoded.smartEncode(ename, charset));
|
||||||
b.append("/");
|
b.append("/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package helma.framework.core;
|
package helma.framework.core;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
import helma.util.UrlEncoded;
|
import helma.util.UrlEncoded;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +108,7 @@ public class RequestPath {
|
||||||
/**
|
/**
|
||||||
* Returns the string representation of this path usable for links.
|
* Returns the string representation of this path usable for links.
|
||||||
*/
|
*/
|
||||||
public String href(String action) {
|
public String href(String action) throws UnsupportedEncodingException {
|
||||||
StringBuffer buffer = new StringBuffer(app.getBaseURI());
|
StringBuffer buffer = new StringBuffer(app.getBaseURI());
|
||||||
|
|
||||||
int start = 1;
|
int start = 1;
|
||||||
|
@ -121,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.encode(ids.get(i).toString()));
|
buffer.append(UrlEncoded.smartEncode(ids.get(i).toString(), app.charset));
|
||||||
buffer.append("/");
|
buffer.append("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
buffer.append(UrlEncoded.encode(action));
|
buffer.append(UrlEncoded.smartEncode(action, app.charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
|
|
|
@ -23,6 +23,7 @@ import helma.util.SystemMap;
|
||||||
import helma.util.WrappedMap;
|
import helma.util.WrappedMap;
|
||||||
import helma.util.UrlEncoded;
|
import helma.util.UrlEncoded;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents a Helma skin, i.e. a template created from containing Macro tags
|
* This represents a Helma skin, i.e. a template created from containing Macro tags
|
||||||
|
@ -119,7 +120,7 @@ public final class Skin {
|
||||||
* Render this skin
|
* Render this skin
|
||||||
*/
|
*/
|
||||||
public void render(RequestEvaluator reval, Object thisObject, Map paramObject)
|
public void render(RequestEvaluator reval, Object thisObject, Map paramObject)
|
||||||
throws RedirectException {
|
throws RedirectException, UnsupportedEncodingException {
|
||||||
// check for endless skin recursion
|
// check for endless skin recursion
|
||||||
if (++reval.skinDepth > 50) {
|
if (++reval.skinDepth > 50) {
|
||||||
throw new RuntimeException("Recursive skin invocation suspected");
|
throw new RuntimeException("Recursive skin invocation suspected");
|
||||||
|
@ -369,7 +370,8 @@ public final class Skin {
|
||||||
* Render the macro given a handler object
|
* Render the macro given a handler object
|
||||||
*/
|
*/
|
||||||
public void render(RequestEvaluator reval, Object thisObject, Map paramObject,
|
public void render(RequestEvaluator reval, Object thisObject, Map paramObject,
|
||||||
Map handlerCache) throws RedirectException {
|
Map handlerCache)
|
||||||
|
throws RedirectException, UnsupportedEncodingException {
|
||||||
if ((sandbox != null) && !sandbox.contains(fullName)) {
|
if ((sandbox != null) && !sandbox.contains(fullName)) {
|
||||||
//String h = (handler == null) ? "global" : handler;
|
//String h = (handler == null) ? "global" : handler;
|
||||||
|
|
||||||
|
@ -547,7 +549,8 @@ public final class Skin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderFromResponse(RequestEvaluator reval) {
|
private void renderFromResponse(RequestEvaluator reval)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
Object value = null;
|
Object value = null;
|
||||||
|
|
||||||
if ("message".equals(name)) {
|
if ("message".equals(name)) {
|
||||||
|
@ -563,7 +566,8 @@ public final class Skin {
|
||||||
writeResponse(value, reval.res.getBuffer(), true);
|
writeResponse(value, reval.res.getBuffer(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderFromRequest(RequestEvaluator reval) {
|
private void renderFromRequest(RequestEvaluator reval)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
if (reval.req == null) {
|
if (reval.req == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -573,7 +577,8 @@ public final class Skin {
|
||||||
writeResponse(value, reval.res.getBuffer(), true);
|
writeResponse(value, reval.res.getBuffer(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderFromSession(RequestEvaluator reval) {
|
private void renderFromSession(RequestEvaluator reval)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
if (reval.session == null) {
|
if (reval.session == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -583,7 +588,8 @@ public final class Skin {
|
||||||
writeResponse(value, reval.res.getBuffer(), true);
|
writeResponse(value, reval.res.getBuffer(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderFromParam(RequestEvaluator reval, Map paramObject) {
|
private void renderFromParam(RequestEvaluator reval, Map paramObject)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
if (paramObject == null) {
|
if (paramObject == null) {
|
||||||
reval.res.write("[HopMacro error: Skin requires a parameter object]");
|
reval.res.write("[HopMacro error: Skin requires a parameter object]");
|
||||||
} else {
|
} else {
|
||||||
|
@ -596,7 +602,8 @@ public final class Skin {
|
||||||
/**
|
/**
|
||||||
* Utility method for writing text out to the response object.
|
* Utility method for writing text out to the response object.
|
||||||
*/
|
*/
|
||||||
void writeResponse(Object value, StringBuffer buffer, boolean useDefault) {
|
void writeResponse(Object value, StringBuffer buffer, boolean useDefault)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
String text;
|
String text;
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
@ -650,7 +657,7 @@ public final class Skin {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ENCODE_URL:
|
case ENCODE_URL:
|
||||||
buffer.append(UrlEncoded.encode(text));
|
buffer.append(UrlEncoded.smartEncode(text, app.charset));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,8 @@ public class GlobalObject extends ImporterTopLevel {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public boolean renderSkin(Object skinobj, Object paramobj) {
|
public boolean renderSkin(Object skinobj, Object paramobj)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -122,7 +123,8 @@ public class GlobalObject extends ImporterTopLevel {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public String renderSkinAsString(Object skinobj, Object paramobj) {
|
public String renderSkinAsString(Object skinobj, Object paramobj)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -247,7 +248,8 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public boolean jsFunction_renderSkin(Object skinobj, Object paramobj) {
|
public boolean jsFunction_renderSkin(Object skinobj, Object paramobj)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -280,7 +282,8 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public String jsFunction_renderSkinAsString(Object skinobj, Object paramobj) {
|
public String jsFunction_renderSkinAsString(Object skinobj, Object paramobj)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -315,7 +318,7 @@ public class HopObject extends ScriptableObject implements Wrapper {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public Object jsFunction_href(Object action) {
|
public Object jsFunction_href(Object action) throws UnsupportedEncodingException {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.mozilla.javascript.*;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -68,7 +69,8 @@ public class JavaObject extends NativeJavaObject {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public boolean renderSkin(Object skinobj, Object paramobj) {
|
public boolean renderSkin(Object skinobj, Object paramobj)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -101,7 +103,8 @@ public class JavaObject extends NativeJavaObject {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public String renderSkinAsString(Object skinobj, Object paramobj) {
|
public String renderSkinAsString(Object skinobj, Object paramobj)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
Context cx = Context.getCurrentContext();
|
Context cx = Context.getCurrentContext();
|
||||||
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
RequestEvaluator reval = (RequestEvaluator) cx.getThreadLocal("reval");
|
||||||
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
RhinoEngine engine = (RhinoEngine) cx.getThreadLocal("engine");
|
||||||
|
@ -136,7 +139,7 @@ public class JavaObject extends NativeJavaObject {
|
||||||
*
|
*
|
||||||
* @return ...
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public Object href(Object action) {
|
public Object href(Object action) throws UnsupportedEncodingException {
|
||||||
if (javaObject == null) {
|
if (javaObject == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ package helma.scripting.rhino;
|
||||||
import helma.framework.core.RequestPath;
|
import helma.framework.core.RequestPath;
|
||||||
import org.mozilla.javascript.*;
|
import org.mozilla.javascript.*;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class wraps around instances of helma.framework.core.RequestPath and
|
* This class wraps around instances of helma.framework.core.RequestPath and
|
||||||
* exposes them in an array-like fashion to the JavaScript runtime.
|
* exposes them in an array-like fashion to the JavaScript runtime.
|
||||||
|
@ -119,7 +121,7 @@ public class PathWrapper extends ScriptableObject {
|
||||||
/**
|
/**
|
||||||
* Returns the wrapped path rendered as URL path.
|
* Returns the wrapped path rendered as URL path.
|
||||||
*/
|
*/
|
||||||
public String href(Object action) {
|
public String href(Object action) throws UnsupportedEncodingException {
|
||||||
if (action != null && action != Undefined.instance) {
|
if (action != null && action != Undefined.instance) {
|
||||||
return path.href(action.toString());
|
return path.href(action.toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -660,8 +660,8 @@ public final class RhinoCore {
|
||||||
return esn;
|
return esn;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String postProcessHref(Object obj, String protoName, String basicHref) {
|
protected String postProcessHref(Object obj, String protoName, String basicHref)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
// check if the app.properties specify a href-function to post-process the
|
// check if the app.properties specify a href-function to post-process the
|
||||||
// basic href.
|
// basic href.
|
||||||
String hrefFunction = app.getProperty("hrefFunction", null);
|
String hrefFunction = app.getProperty("hrefFunction", null);
|
||||||
|
|
|
@ -27,6 +27,8 @@ import java.util.*;
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.*;
|
import javax.servlet.http.*;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an abstract Hop servlet adapter. This class communicates with hop applications
|
* This is an abstract Hop servlet adapter. This class communicates with hop applications
|
||||||
* via RMI. Subclasses are either one servlet per app, or one servlet that handles multiple apps
|
* via RMI. Subclasses are either one servlet per app, or one servlet that handles multiple apps
|
||||||
|
@ -49,7 +51,7 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
String cookieDomain;
|
String cookieDomain;
|
||||||
|
|
||||||
// default encoding for requests
|
// default encoding for requests
|
||||||
String defaultEncoding;
|
String defaultEncoding = "ISO8859_1";
|
||||||
|
|
||||||
// allow caching of responses
|
// allow caching of responses
|
||||||
boolean caching;
|
boolean caching;
|
||||||
|
@ -80,7 +82,12 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get default encoding
|
// get default encoding
|
||||||
defaultEncoding = init.getInitParameter("charset");
|
String encoding = init.getInitParameter("charset");
|
||||||
|
|
||||||
|
if (encoding != null) {
|
||||||
|
defaultEncoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
debug = ("true".equalsIgnoreCase(init.getInitParameter("debug")));
|
debug = ("true".equalsIgnoreCase(init.getInitParameter("debug")));
|
||||||
caching = !("false".equalsIgnoreCase(init.getInitParameter("caching")));
|
caching = !("false".equalsIgnoreCase(init.getInitParameter("caching")));
|
||||||
}
|
}
|
||||||
|
@ -125,7 +132,7 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
|
|
||||||
if (encoding == null) {
|
if (encoding == null) {
|
||||||
// no encoding from request, use standard one
|
// no encoding from request, use standard one
|
||||||
encoding = defaultEncoding != null ? defaultEncoding : "ISO-8859-1";
|
encoding = defaultEncoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read and set http parameters
|
// read and set http parameters
|
||||||
|
@ -346,15 +353,6 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
res.setDateHeader("Last-Modified", System.currentTimeMillis());
|
res.setDateHeader("Last-Modified", System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we don't know which charset to use for parsing HTTP params,
|
|
||||||
// take the one from the response. This usually works because
|
|
||||||
// browsers send parameters in the same encoding as the page
|
|
||||||
// containing the form has. Problem is we can do this only per servlet,
|
|
||||||
// not per session or even per page, which would produce too much overhead
|
|
||||||
if (defaultEncoding == null) {
|
|
||||||
defaultEncoding = hopres.charset;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.setContentLength(hopres.getContentLength());
|
res.setContentLength(hopres.getContentLength());
|
||||||
res.setContentType(hopres.getContentType());
|
res.setContentType(hopres.getContentType());
|
||||||
|
|
||||||
|
@ -711,7 +709,8 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getPathInfo(HttpServletRequest req) {
|
String getPathInfo(HttpServletRequest req)
|
||||||
|
throws DecoderException, UnsupportedEncodingException {
|
||||||
StringTokenizer t = new StringTokenizer(req.getContextPath(), "/");
|
StringTokenizer t = new StringTokenizer(req.getContextPath(), "/");
|
||||||
int prefixTokens = t.countTokens();
|
int prefixTokens = t.countTokens();
|
||||||
|
|
||||||
|
@ -735,11 +734,7 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
pathbuffer.append('/');
|
pathbuffer.append('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((token.indexOf('+') == -1) && (token.indexOf('%') == -1)) {
|
pathbuffer.append(UrlEncoded.smartDecode(token, defaultEncoding));
|
||||||
pathbuffer.append(token);
|
|
||||||
} else {
|
|
||||||
pathbuffer.append(URLDecoder.decode(token));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// append trailing "/" if it is contained in original URI
|
// append trailing "/" if it is contained in original URI
|
||||||
|
|
|
@ -16,35 +16,46 @@
|
||||||
|
|
||||||
package helma.util;
|
package helma.util;
|
||||||
|
|
||||||
import java.net.URLEncoder;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import org.apache.commons.codec.net.URLCodec;
|
||||||
|
import org.apache.commons.codec.DecoderException;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A proxy to java.net.URLEncoder which only encodes when
|
* A subclass of Jakarta Commons Codec URLCodec that offers
|
||||||
* there is actual work to do. This is necessary because
|
* lazy encode/decode methods that only returns a new String
|
||||||
* URLEncoder is quite inefficient (e.g. it preallocates
|
* if actual work had to be done for encoding/decoding.
|
||||||
* buffers and stuff), and we call it often with
|
* This is because URLCodec is a bit inefficient (e.g. it
|
||||||
* short string that 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 {
|
public final class UrlEncoded extends URLCodec {
|
||||||
|
|
||||||
|
public static final String defaultEncoding = "ISO8859_1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* URL-encode a string using the given encoding, or return it
|
||||||
|
* unchanged if no encoding was necessary.
|
||||||
*
|
*
|
||||||
*
|
* @param str The string to be URL-encoded
|
||||||
* @param str ...
|
* @param encoding the encoding to use
|
||||||
*
|
* @return the URL-encoded string, or str if no encoding necessary
|
||||||
* @return ...
|
|
||||||
*/
|
*/
|
||||||
public static String encode(String str) {
|
public static String smartEncode(String str, String encoding)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
int l = str.length();
|
int l = str.length();
|
||||||
boolean needsSpaceEncoding = false;
|
boolean needsSpaceEncoding = false;
|
||||||
|
BitSet urlsafe = WWW_FORM_URL;
|
||||||
|
|
||||||
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 (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ||
|
} else if (!urlsafe.get(c)) {
|
||||||
((c >= '0') && (c <= '9')))) {
|
URLCodec codec = new URLCodec();
|
||||||
return URLEncoder.encode(str);
|
return codec.encode(str, encoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,4 +65,22 @@ public final class UrlEncoded {
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL-decode a string using the given encoding,
|
||||||
|
* or return it unchanged if no encoding was necessary.
|
||||||
|
*
|
||||||
|
* @param str The string to be URL-decoded
|
||||||
|
* @param encoding the encoding to use
|
||||||
|
* @return the URL-decoded string, or str if no decoding necessary
|
||||||
|
*/
|
||||||
|
public static String smartDecode(String str, String encoding)
|
||||||
|
throws DecoderException, UnsupportedEncodingException {
|
||||||
|
if ((str.indexOf('+') == -1) && (str.indexOf('%') == -1)) {
|
||||||
|
return str;
|
||||||
|
} else {
|
||||||
|
return new URLCodec().decode(str, encoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue