From b7f0aa4ee2896f2311f3a55c0fc1628835e147a2 Mon Sep 17 00:00:00 2001 From: hns Date: Tue, 25 Oct 2005 14:36:19 +0000 Subject: [PATCH] * Fix NullPointerException in getAction() for 404 requests. * Move XML-RPC response and error encoding to ResponseTrans class. * Implement error response generation for new type XML-RPC requests. * Set req.method to "XMLRPC" for new type XML-RPC requests. --- src/helma/framework/RequestTrans.java | 33 +++++++----- src/helma/framework/ResponseTrans.java | 52 +++++++++++++------ .../framework/core/RequestEvaluator.java | 30 +++++++---- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/src/helma/framework/RequestTrans.java b/src/helma/framework/RequestTrans.java index 4acd46a5..617d1d1d 100644 --- a/src/helma/framework/RequestTrans.java +++ b/src/helma/framework/RequestTrans.java @@ -59,7 +59,7 @@ public class RequestTrans implements Serializable { private final Map values; // the HTTP request method - private final String method; + private String method; // timestamp of client-cached version, if present in request private long ifModifiedSince = -1; @@ -70,9 +70,6 @@ public class RequestTrans implements Serializable { // when was execution started on this request? private final long startTime; - // true if this might be an XML-RPC request - private boolean isXmlRpc; - // the name of the action being invoked private String action; private String httpUsername; @@ -101,9 +98,6 @@ public class RequestTrans implements Serializable { this.path = path; values = new SystemMap(); startTime = System.currentTimeMillis(); - if ("POST".equals(method) && "text/xml".equals(request.getContentType())) { - isXmlRpc = true; - } } /** @@ -111,17 +105,19 @@ public class RequestTrans implements Serializable { * * @return true if this might be an XML-RPC request. */ - public synchronized boolean isXmlRpc() { - return isXmlRpc; + public synchronized boolean checkXmlRpc() { + return "POST".equals(method) && "text/xml".equals(request.getContentType()); } /** - * Set the isXmlRpc flag + * Return true if this request is in fact handled as XML-RPC request. + * This implies that {@link #checkXmlRpc()} returns true and a matching + * XML-RPC action was found. * - * @param xmlrpc true if this is infact an XML-RPC request + * @return true if this request is handled as XML-RPC request. */ - public synchronized void setXmlRpc(boolean xmlrpc) { - isXmlRpc = xmlrpc; + public synchronized boolean isXmlRpc() { + return XMLRPC.equals(method); } /** @@ -195,10 +191,19 @@ public class RequestTrans implements Serializable { * Return the method of the request. This may either be a HTTP method or * one of the Helma pseudo methods defined in this class. */ - public String getMethod() { + public synchronized String getMethod() { return method; } + /** + * Set the method of this request. + * + * @param method the method. + */ + public synchronized void setMethod(String method) { + this.method = method; + } + /** * Return true if this object represents a HTTP GET Request. */ diff --git a/src/helma/framework/ResponseTrans.java b/src/helma/framework/ResponseTrans.java index 8691c3e6..6d19b904 100644 --- a/src/helma/framework/ResponseTrans.java +++ b/src/helma/framework/ResponseTrans.java @@ -25,6 +25,8 @@ import java.io.*; import java.security.*; import java.util.*; +import org.apache.xmlrpc.XmlRpcResponseProcessor; + /** * A Transmitter for a response to the servlet client. Objects of this * class are directly exposed to JavaScript as global property res. @@ -118,7 +120,7 @@ public final class ResponseTrans implements Serializable { // the res.meta map for meta response data private transient Map meta = new SystemMap(); - + // the request trans for this response private transient RequestTrans reqtrans; @@ -129,13 +131,6 @@ public final class ResponseTrans implements Serializable { Application app; - /** - * Creates a new ResponseTrans object. - */ - public ResponseTrans(Application app) { - this.app = app; - } - /** * Creates a new ResponseTrans object. * @@ -170,7 +165,7 @@ public final class ResponseTrans implements Serializable { public Map getMacroHandlers() { return handlers; } - + /** * Get the meta info map for this response transmitter. */ @@ -462,12 +457,39 @@ public final class ResponseTrans implements Serializable { * @param message the error message */ public void writeErrorReport(String appName, String message) { - write("

"); - write("Error in application "); - write(appName); - write("

"); - write(message); - write(""); + if (reqtrans.isXmlRpc()) { + writeXmlRpcError(new RuntimeException(message)); + } else { + write("

"); + write("Error in application "); + write(appName); + write("

"); + write(message); + write(""); + } + } + + public void writeXmlRpcResponse(Object result) { + try { + reset(); + contentType = "text/xml"; + if (charset == null) { + charset = "UTF-8"; + } + XmlRpcResponseProcessor xresproc = new XmlRpcResponseProcessor(); + writeBinary(xresproc.encodeResponse(result, charset)); + } catch (Exception x) { + writeXmlRpcError(x); + } + } + + public void writeXmlRpcError(Exception x) { + contentType = "text/xml"; + if (charset == null) { + charset = "UTF-8"; + } + XmlRpcResponseProcessor xresproc = new XmlRpcResponseProcessor(); + writeBinary(xresproc.encodeException(x, charset)); } /** diff --git a/src/helma/framework/core/RequestEvaluator.java b/src/helma/framework/core/RequestEvaluator.java index b0d03324..a825b761 100644 --- a/src/helma/framework/core/RequestEvaluator.java +++ b/src/helma/framework/core/RequestEvaluator.java @@ -25,7 +25,6 @@ import java.util.*; import org.apache.xmlrpc.XmlRpcRequestProcessor; import org.apache.xmlrpc.XmlRpcServerRequest; -import org.apache.xmlrpc.XmlRpcResponseProcessor; /** * This class does the work for incoming requests. It holds a transactor thread @@ -194,7 +193,7 @@ public final class RequestEvaluator implements Runnable { String errorAction = app.props.getProperty("error", "error"); - action = getAction(currentElement, errorAction, null); + action = getAction(currentElement, errorAction, req); if (action == null) { throw new RuntimeException(error); @@ -284,7 +283,7 @@ public final class RequestEvaluator implements Runnable { "notfound"); currentElement = root; - action = getAction(currentElement, notFoundAction, null); + action = getAction(currentElement, notFoundAction, req); if (action == null) { throw new FrameworkException(notfound.getMessage()); @@ -352,14 +351,11 @@ public final class RequestEvaluator implements Runnable { XmlRpcRequestProcessor xreqproc = new XmlRpcRequestProcessor(); XmlRpcServerRequest xreq = xreqproc.decodeRequest(req.getServletRequest() .getInputStream()); - System.err.println("ARGUMENTS: " + xreq.getParameters()); Vector args = xreq.getParameters(); args.add(0, xreq.getMethodName()); result = scriptingEngine.invoke(currentElement, action, args.toArray(), ScriptingEngine.ARGS_WRAP_XMLRPC); - res.reset(); - XmlRpcResponseProcessor xresproc = new XmlRpcResponseProcessor(); - res.writeBinary(xresproc.encodeResponse(result, "UTF-8")); + res.writeXmlRpcResponse(result); } else { scriptingEngine.invoke(currentElement, action, new Object[0], @@ -533,7 +529,8 @@ public final class RequestEvaluator implements Runnable { res.reset(); - // check if we tried to process the error already + // check if we tried to process the error already, + // or if this is an XML-RPC request if (error == null) { app.errorCount += 1; @@ -555,6 +552,15 @@ public final class RequestEvaluator implements Runnable { app.logError(txname + ": " + error, x); + if (req.isXmlRpc()) { + // if it's an XML-RPC exception immediately generate error response + if (!(x instanceof Exception)) { + // we need an exception to pass to XML-RPC responder + x = new Exception(x.toString(), x); + } + res.writeXmlRpcError((Exception) x); + done = true; + } } else { // error in error action. use traditional minimal error message res.writeErrorReport(app.getName(), error); @@ -983,13 +989,15 @@ public final class RequestEvaluator implements Runnable { // afterwards for GET, POST, HEAD requests int length = buffer.length(); - if (req.isXmlRpc()) { + if (req.checkXmlRpc()) { // append _methodname buffer.append("_xmlrpc"); - if (scriptingEngine.hasFunction(obj, buffer.toString())) + if (scriptingEngine.hasFunction(obj, buffer.toString())) { + // handle as XML-RPC request + req.setMethod(RequestTrans.XMLRPC); return buffer.toString(); + } // cut off method in case it has been appended - req.setXmlRpc(false); buffer.setLength(length); }