Adam, I added your handler and associated to XmlRpcServer refactoring to CVS HEAD (thanks). I haven't yet looked at the auth changes.
I explicitly didn't add the automatic addition of the system.multicall handler to the XmlRpcServer class, as I don't think it currently adds any handler by default and am hoping to keep it that way. The multicall handler needs a reference to the XmlRpcServer to perform the multiple RPC calls; I assume this is why you set things up this way. Any ideas on avoiding this issue? - Dan Adam Megacz <[EMAIL PROTECTED]> writes: > 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; > } > + > } > + > -- Daniel Rall <[EMAIL PROTECTED]>
