Here's the patch for system.multicall(), plus a new file it adds (SystemMethods.java). This patch also includes my last patch for HTTP Basic authentication.
- a ______________________________________________________________________________ org/apache/xmlrpc/SystemMethods.java package org.apache.xmlrpc; /* * The Apache Software License, Version 1.1 * * * Copyright(c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation(http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "XML-RPC" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ import org.apache.xmlrpc.*; import java.util.*; /** Implements the XML-RPC standard system.* methods */ public class SystemMethods { XmlRpcServer serv = null; SystemMethods(XmlRpcServer serv) { this.serv = serv; } public Vector multicall(Vector in) { Vector ret = new Vector(); for(int i=0; i<in.size(); i++) { try { Hashtable call = (Hashtable)in.elementAt(i); String methodName = (String)call.get("methodName"); Vector params = (Vector)call.get("params"); Object handler = serv.getHandler(methodName); Vector v = new Vector(); v.addElement(serv.invokeHandler(handler, methodName, params, null, null)); ret.addElement(v); } catch (Exception x) { String message = x.toString(); int code = x instanceof XmlRpcException ? ((XmlRpcException) x).code : 0; Hashtable h = new Hashtable(); h.put("faultString", message); h.put("faultCode", new Integer(code)); ret.addElement(h); } } return ret; } } ______________________________________________________________________________ patch Index: src/java/org/apache/xmlrpc/WebServer.java =================================================================== RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/WebServer.java,v retrieving revision 1.13 diff -u -r1.13 WebServer.java --- src/java/org/apache/xmlrpc/WebServer.java 13 Aug 2002 22:27:16 -0000 1.13 +++ src/java/org/apache/xmlrpc/WebServer.java 14 Aug 2002 04:24:39 -0000 @@ -94,6 +94,7 @@ protected static final byte[] conclose = "Connection: close\r\n".getBytes(); protected static final byte[] ok = " 200 OK\r\n".getBytes(); protected static final byte[] server = "Server: Apache XML-RPC 1.0\r\n".getBytes(); + protected static final byte[] www_authenticate = "WWW-Authenticate: Basic +realm=XMLRPC\r\n".getBytes(); private static final String HTTP_11 = "HTTP/1.1"; private static final String STAR = "*"; @@ -584,29 +585,40 @@ { ServerInputStream sin = new ServerInputStream(input, contentLength); - byte result[] = xmlrpc.execute(sin, user, password); - output.write(httpversion.getBytes()); - output.write(ok); - output.write(server); - if (keepalive) - { - output.write(conkeep); - } - else - { - output.write (conclose); + try { + byte result[] = xmlrpc.execute(sin, user, password); + output.write(httpversion.getBytes()); + output.write(ok); + output.write(server); + if (keepalive) + { + output.write(conkeep); + } + else + { + output.write (conclose); + } + output.write(ctype); + output.write(clength); + output.write(Integer.toString(result.length) + .getBytes()); + output.write(doubleNewline); + output.write(result); + } catch (XmlRpcServer.AuthenticationRequiredException are) { + output.write("HTTP/1.0".getBytes()); + output.write(" 401 Unauthorized\r\n".getBytes()); + output.write(server); + output.write(www_authenticate); + output.write("\r\n".getBytes()); + output.write(("Method " + method + + " requires a username and +password").getBytes()); + keepalive = false; } - output.write(ctype); - output.write(clength); - output.write(Integer.toString(result.length) - .getBytes()); - output.write(doubleNewline); - output.write(result); output.flush(); } else { - output.write(httpversion.getBytes()); + output.write("HTTP/1.0".getBytes()); output.write(" 400 Bad Request\r\n".getBytes()); output.write(server); output.write("\r\n".getBytes()); Index: src/java/org/apache/xmlrpc/XmlRpcServer.java =================================================================== RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v retrieving revision 1.28 diff -u -r1.28 XmlRpcServer.java --- src/java/org/apache/xmlrpc/XmlRpcServer.java 9 Aug 2002 09:14:24 -0000 1.28 +++ src/java/org/apache/xmlrpc/XmlRpcServer.java 14 Aug 2002 04:24:41 -0000 @@ -93,6 +93,7 @@ handlers = new Hashtable(); pool = new Stack(); workers = 0; + addHandler("system", new SystemMethods(this)); } /** @@ -136,6 +137,7 @@ * since this is all packed into the response. */ public byte[] execute(InputStream is) + throws AuthenticationRequiredException { return execute(is, null, null); } @@ -146,6 +148,7 @@ * use the credentials to authenticate the user. */ public byte[] execute(InputStream is, String user, String password) + throws AuthenticationRequiredException { Worker worker = getWorker(); byte[] retval = worker.execute(is, user, password); @@ -179,6 +182,61 @@ } } + /** find the handler for a given method */ + Object getHandler(String methodName) throws Exception { + Object handler = null; + String handlerName = null; + int dot = methodName.lastIndexOf('.'); + if (dot > -1) + { + handlerName = methodName.substring(0, dot); + handler = handlers.get(handlerName); + if (handler != null) + { + methodName = methodName.substring(dot + 1); + } + } + + if (handler == null) + { + handler = handlers.get("$default"); + } + + if (handler == null) + { + if (dot > -1) + { + throw new Exception("RPC handler object \"" + + handlerName + "\" not found and no +default " + + "handler registered."); + } + else + { + throw new Exception("RPC handler object not found for \"" + + methodName + + "\": no default handler registered."); + } + } + + return handler; + } + + Object invokeHandler(Object handler, String methodName, + Vector inParams, String user, String password) + throws Exception { + if (handler instanceof AuthenticatedXmlRpcHandler) + { + if (user == null) throw new +XmlRpcServer.AuthenticationRequiredException(); + return ((AuthenticatedXmlRpcHandler) handler) + .execute(methodName, inParams, user, password); + } + else + { + return ((XmlRpcHandler) handler).execute(methodName, inParams); + } + } + + /** * Performs streaming, parsing, and handler execution. * Implementation is not thread-safe. @@ -202,6 +260,7 @@ * Given a request for the server, generates a response. */ public byte[] execute(InputStream is, String user, String password) + throws AuthenticationRequiredException { try { @@ -223,10 +282,10 @@ * @param password * @return */ - private byte[] executeInternal(InputStream is, String user, - String password) + byte[] executeInternal(InputStream is, String user, + String password) throws AuthenticationRequiredException { - byte[] result; + byte[] result = null; long now = 0; if (XmlRpc.debug) @@ -246,63 +305,20 @@ { throw new Exception(errorMsg); } - Object handler = null; - - String handlerName = null; - int dot = methodName.lastIndexOf('.'); - if (dot > -1) - { - handlerName = methodName.substring(0, dot); - handler = handlers.get(handlerName); - if (handler != null) - { - methodName = methodName.substring(dot + 1); - } - } - - if (handler == null) - { - handler = handlers.get("$default"); - } - if (handler == null) - { - if (dot > -1) - { - throw new Exception("RPC handler object \"" - + handlerName + "\" not found and no default " - + "handler registered."); - } - else - { - throw new Exception("RPC handler object not found for \"" - + methodName - + "\": no default handler registered."); - } - } + Object handler = getHandler(methodName); + Object outParam = invokeHandler(handler, methodName, inParams, user, +password); - Object outParam; - if (handler instanceof AuthenticatedXmlRpcHandler) - { - outParam =((AuthenticatedXmlRpcHandler) handler) - .execute(methodName, inParams, user, password); - } - else - { - outParam =((XmlRpcHandler) handler) - .execute(methodName, inParams); - } if (XmlRpc.debug) { System.out.println("outparam = " + outParam); } - writer = new XmlWriter(buffer, encoding); - writeResponse(outParam, writer); - writer.flush(); - result = buffer.toByteArray(); } catch(Exception x) { + if (x instanceof XmlRpcServer.AuthenticationRequiredException) + throw (XmlRpcServer.AuthenticationRequiredException)x; + if (XmlRpc.debug) { x.printStackTrace(); @@ -427,6 +443,11 @@ writer.endElement("methodResponse"); } } // end of inner class Worker + + public static class AuthenticationRequiredException extends IOException { + AuthenticationRequiredException() { } + } + } // XmlRpcServer /** @@ -555,4 +576,6 @@ } return returnValue; } + } +