Providing XML-RPC Services
Often, while writing applications, it's desirable to make functionality available to external clients. Numerous options exist, however XML-RPC is a relatively popular, cross-platform method for calling remote functionality. Pike includes a ready-to-go XML-RPC client, however, a little more work is required to provide XML-RPC services to clients. It's something I've needed often enough that I've developed some standard code that I always employ and it's worked quite well for me.XML-RPC consists of procedure calls and responses encoded in a standard XML format. These messages are sent over standard HTTP connections, which is convenient, as we can use a lot of what we've learned from our earlier Simple Web Server experiments. We'll extend that embedded web server to make methods in an object available via XML-RPC.Getting StartedWe like to get up and running quickly, so let's reuse some existing code. We'll take the code from the Simple Web Server article, and extend it by overriding handle_request(). The replacement function simply calls the parse() function, and traps any errors. By doing this, we can make sure that the remote client always receives a response, even if it's not proper XML-RPC: void handle_request(Protocols.HTTP.Server.Request request) { mapping response = ([]); if(catch(response = parse(request))) { response = (["error": 500, "type": "text/html", "data": "an unknown error has occurred."]); } request->response_and_finish(response); } mapping m; int off = search(request->raw, "rnrn"); if(off<=0) error("invalid request format.n"); object X; if(catch(X=Protocols.XMLRPC.decode_call(request->raw[(off+4) ..]))) { error("Error decoding the XML-RPC Call. Are you not speaking XML-RPC?n"); } if(this && this[X->method_name] && functionp(this[X->method_name])) { mixed response; mixed err=catch( response=call_function(this[X->method_name], @(X->params + ({request}) ))); if(err) { m=([ "data": Protocols.XMLRPC.encode_response_fault(1, err[0]), "type": "text/xml" ]); } else m=([ "data": Protocols.XMLRPC.encode_response( ({response}) ), "type": "text/xml" ]); } else { m=([ "data": Protocols.XMLRPC.encode_response_fault(1, "Method " + X->method_name + " not present.n"), "type": "text/xml" ]); } return (m); #!/usr/local/bin/pikeconstant default_port = 8908;Protocols.HTTP.Server.Port port;int main(int argc, array(string) argv) { int my_port = default_port; if(argc>1) my_port=(int)argv[1]; port = Protocols.HTTP.Server.Port(handle_request, my_port); return -1; }void handle_request(Protocols.HTTP.Server.Request request) { write(sprintf("Got request: %On", request)); mapping response = ([]); if(catch(response = parse(request))) { response = (["error": 500, "type": "text/html", "data": "an unknown error has occurred."]); } request->response_and_finish(response); }mixed parse(object request) { mapping m; int off = search(request->raw, "rnrn"); if(off<=0) error("invalid request format.n"); object X; if(catch(X=Protocols.XMLRPC.decode_call(request->raw[(off+4) ..]))) { error("Error decoding the XMLRPC Call. Are you not speaking XMLRPC?n"); } if(this && this[X->method_name] && functionp(this[X->method_name])) { mixed response; mixed err=catch( response=call_function(this[X->method_name], @(X->params + ({request}) ))); if(err) { m=([ "data": Protocols.XMLRPC.encode_response_fault(1, err[0]), "type": "text/xml" ]); } else m=([ "data": Protocols.XMLRPC.encode_response( ({response}) ), "type": "text/xml" ]); } else { m=([ "data": Protocols.XMLRPC.encode_response_fault(1, "Method " + X->method_name + " not present.n"), "type": "text/xml" ]); } return (m);} Powered by PikeWiki2 |
|||
gotpike.org | Copyright © 2004 - 2009 | Pike is a trademark of Department of Computer and Information Science, Linköping University |