* 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.
This commit is contained in:
hns 2005-10-25 14:36:19 +00:00
parent 8a30ebf693
commit b7f0aa4ee2
3 changed files with 75 additions and 40 deletions

View file

@ -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.
*/

View file

@ -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.
@ -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.
*
@ -462,6 +457,9 @@ public final class ResponseTrans implements Serializable {
* @param message the error message
*/
public void writeErrorReport(String appName, String message) {
if (reqtrans.isXmlRpc()) {
writeXmlRpcError(new RuntimeException(message));
} else {
write("<html><body><h3>");
write("Error in application ");
write(appName);
@ -469,6 +467,30 @@ public final class ResponseTrans implements Serializable {
write(message);
write("</body></html>");
}
}
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));
}
/**
* This has to be called after writing to this response has finished and before it is shipped back to the

View file

@ -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);
}