Monday, November 08, 2010 at 12:02 AM.
system.verbs.builtins.betty.rpc.server
on server (xmlText, adrParamTable) { //called from the RPC2 responder on an incoming request <<Change notes: <<5/24/06; 8:15:45 AM by DW <<Handle multiple domains as described here... <<http://geeks.opml.org/2006/05/24#a865 <<01/31/02; 2:13:15 PM by JES <<Factored the security check by IP address to betty.rpc.checkClient, so the check can be used for both XML-RPC and SOAP. <<04/27/01; 7:58:15 PM by JES <<If a request doesn't have a <params> element, don't fault. Instead treat it as a call with no input parameters. <<Thu, 02 Dec 1999 at 5:17:37 PM by AR <<Disabled fldebug flag again. <<Wed, 04 Nov 1999 at 10:33:45 PM by AR <<If user.betty.prefs.flAllowByIpOnly is true, block XML-RPC requests from anyone except those IP addresses listed in user.betty.prefs.allowedIpAddresses <<Mon, 25 Oct 1999 at 11:07:19 PM by AR <<If user.betty.prefs.flKeepServerLog is true, we log all incoming requests to the rpcServer section of the daily log GDB. <<Mon, 14 Jun 1999 15:46:57 GMT by AR <<When walking the XML structure to extract the parameters, we now handle the case correctly when a parameter is a table and the next parameter is a scalar. <<If an RPC fault occurs, left angle brackets and ampersands in the error string are now properly encoded to ensure that the XML-RPC response is well-formed. <<Friday, July 17, 1998 at 12:57:38 PM by PBS <<XML header is now lowercase to conform to the XML spec. <<Turned off debugging; use a local table rather than a global table so the server is thread-safe. local (fldebug = false, flFault = false, securitylist = {}); betty.init (); if not defined (user.betty.prefs.flServerDomains) { user.betty.prefs.flServerDomains = false}; local (adrhandlerstable = @user.betty.rpcHandlers); if user.betty.prefs.flServerDomains { //5/24/06 by DW if defined (user.betty.domains) { if defined (adrparamtable^.host) { local (host = adrparamtable^.host); if host contains ":" { //remove the port designator host = string.nthfield (host, ":", 1)}; local (adrtable = @user.betty.domains.[host]); if defined (adrtable^) { adrhandlerstable = adrtable}}}}; local (flLog = user.betty.prefs.flKeepServerLog); local (xmlResponse = "", indentlevel = 1); on add (s) { xmlResponse = xmlResponse + string.filledString ("\t", indentlevel) + s + "\r\n"}; on addToRpcLog (errorNum = nil) { //AR 10/25/1999 local (adrHitTable = log.addToGuestDatabase ("rpcServer", adrParamTable^.client, true)); adrHitTable^.time = clock.now (); adrHitTable^.threads = Frontier.countThreads (); adrHitTable^.sizeIn = sizeof (adrParamTable^.requestBody); adrHitTable^.sizeOut = sizeof (xmlResponse); if errorNum != nil { adrHitTable^.faultCode= errorNum}; if procedureName != nil { adrHitTable^.methodName= procedureName}; if defined (adrParamTable^.host) { adrHitTable^.host = adrParamTable^.host}; if defined (adrParamTable^.requestHeaders.["User-Agent"]) { adrHitTable^.agent = adrParamTable^.requestHeaders.["User-Agent"]}; adrHitTable^.ticks = clock.ticks () - adrParamTable^.stats.requestProcessingStarted}; on rpcFault (errorstring, errornum) { flFault = true; add ("<fault>"); indentlevel++; add ("<value>"); indentlevel++; add ("<struct>"); indentlevel++; add ("<member>"); indentlevel++; add ("<name>faultCode</name>"); add ("<value>"); indentlevel++; add ("<int>" + errornum + "</int>"); add ("</value>"); indentlevel--; add ("</member>"); indentlevel--; bundle { //AR 6/14/1999: make sure errorstring is encoded errorstring = string.replaceAll (errorstring, "&", "&"); errorstring = string.replaceAll (errorstring, "<", "<")}; add ("<member>"); indentlevel++; add ("<name>faultString</name>"); add ("<value>"); indentlevel++; add ("<string>" + errorstring + "</string>"); add ("</value>"); indentlevel--; add ("</member>"); indentlevel--; add ("</struct>"); indentlevel--; add ("</value>"); indentlevel++; add ("</fault>"); indentlevel--; if flLog { try { addToRpcLog (errornum)}}}; local (procedureName, paramlist); bundle { //AR 11/04/1999: check for rpc request blocking if not betty.rpc.checkClient (adrParamTable) { //1/31/02 JES: factored for use for both XML-RPC and SOAP rpcFault ("Access not allowed from " + adrParamTable^.client + ".", betty.rpc.errorCodes.securityFault)}}; <<if defined (user.betty.prefs.flAllowByIpOnly) <<if user.betty.prefs.flAllowByIpOnly <<local (flBlocked = true) <<local (okIpList = user.betty.prefs.allowedIpAddresses) <<if typeOf (okIpList) == stringType <<It's a comma-delimited string: create a local list from that string. <<local (s = okIpList) <<okIpList = {} <<local (i) <<for i = 1 to string.countFields (s, ',') <<local (oneIpAddress = string.nthField (s, ',', i)) <<oneIpAddress = string.trimWhiteSpace (oneIpAddress) <<if oneIpAddress != "" <<okIpList = okIpList + oneIpAddress <<local (oneIp) <<for oneIp in okIpList <<if string.trimWhiteSpace (oneIp) != "" <<if adrParamTable^.client == oneIp <<flblocked = false <<break <<if flblocked <<rpcFault ("Access not allowed from " + adrParamTable^.client + ".", betty.rpc.errorCodes.securityFault) if (not flFault) { //get the procedure name and the paramlist on parseXML () { local (xtable); try { //parse the XML into a table xml.compile (xmlText, @xtable)} else { rpcFault (tryError, betty.rpc.errorcodes.xmlFormatError); return}; if fldebug { scratchpad.rpcTable = xtable}; try { //set the procedure name and fill the params list by walking the XML structure paramlist = {}; adrTable = @xtable; //PBS 7/17/98 local (adrcall = xml.getAddress (adrtable, "methodCall")); procedureName = xml.getValue (adrcall, "methodName"); local (adrparams, flParams = true); try { //04/27/2001 JES: if there's no <params> element, getting its address will fail adrparams = xml.getAddress (adrcall, "params")} else { //no params flParams = false}; if flParams { local (xmlparamlist = xml.getAddressList (adrparams, "param")); local (param, name, adrvalue, val); for param in xmlparamlist { adrvalue = xml.getAddress (param, "value"); if typeof (adrvalue^) == tabletype { xml.coercions.structToFrontierValue (@adrvalue^ [1], @val)} else { table.assign (@val, adrvalue^)}; //AR 6/14/1999 paramlist = paramlist + {val}}}} else { rpcFault (tryError, betty.rpc.errorcodes.illegalCallStructureError); return}; if fldebug { try {delete (@scratchpad.rpcParams)}; scratchpad.rpcParams = paramlist}}; parseXML ()}; if (not flFault) { //call the script, put result in xmlResponse on callrpcScript () { local (nomad, adrscript); try { //locate the script local (s = procedureName, name); nomad = adrhandlerstable; loop { if typeOf (nomad^) == tabletype { local (adr = @nomad^.["#security"]); if defined (adr^) { securitylist = securitylist + {adr}}}; if sizeof (s) == 0 { break}; name = string.nthField (s, '.', 1); nomad = @nomad^.[name]; if typeof (nomad^) == addresstype { nomad = nomad^}; s = string.delete (s, 1, sizeof (name) + 1)}; adrscript = nomad} else { rpcFault (tryError, betty.rpc.errorcodes.scriptAddressError); return}; try { //check in with the #security scripts local (adr); for adr in securitylist { callScript (string (adr), {}, adrParamTable)}} else { rpcFault (tryError, betty.rpc.errorcodes.securityFault); return}; local (scriptResponse); try { //call the script scriptResponse = callScript (string (adrscript), paramlist, adrParamTable)} else { rpcFault (tryError, betty.rpc.errorcodes.scriptError); return}; local (encodedString); try { //encode the response encodedString = xml.coercions.frontierValueToTaggedText (@scriptResponse, 1)} else { rpcFault (tryError, betty.rpc.errorcodes.encodingFailure); return}; try { //add the encoded string to the returned XML text add ("<params>"); indentlevel++; add ("<param>"); indentlevel++; add ("<value>" + encodedString + "</value>"); add ("</param>"); indentlevel--; add ("</params>"); indentlevel--} else { rpcFault (tryError, betty.rpc.errorcodes.addReturnedValueError); return}}; callrpcScript ()}; local (pre = "<?xml version=\"1.0\"?>\r\n<methodResponse>\r\n"); local (post = "\t</methodResponse>\r\n"); xmlResponse = pre + xmlResponse + post; if fldebug { table.assign (@scratchpad.xmlResponse, xmlResponse)}; if flLog and not flFault { //AR 10/25/1999: don't log twice try { addToRpcLog ()}}; return (xmlResponse)}
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.