X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fxmlrpcs.inc;h=97035e4fac336e2990e9314e31206f56151555eb;hb=201aebdd998a8812360237fdc99cb941973057e5;hp=8111e1c03eb3597a28c1ad38cc62acfae97224c1;hpb=fce41d1c5ca142dccfe3a9b51edcc13acdc4a7ba;p=plcapi.git diff --git a/lib/xmlrpcs.inc b/lib/xmlrpcs.inc index 8111e1c..97035e4 100644 --- a/lib/xmlrpcs.inc +++ b/lib/xmlrpcs.inc @@ -365,6 +365,7 @@ $GLOBALS['_xmlrpcs_occurred_errors'] = ''; $GLOBALS['_xmlrpcs_prev_ehandler'] = ''; + /** * Error handler used to track errors that occur during server-side execution of PHP code. * This allows to report back to the client whether an internal error has occurred or not @@ -381,7 +382,7 @@ return; //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING) - if($errcode != 2048) // do not use E_STRICT by name, since on PHP 4 it will not be defined + if($errcode != E_STRICT) { $GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n"; } @@ -432,17 +433,34 @@ class xmlrpc_server { - /// array defining php functions exposed as xmlrpc methods by this server + /** + * Array defining php functions exposed as xmlrpc methods by this server + * @access private + */ var $dmap=array(); /** - * Defines how functions in dmap will be invokde: either using an xmlrpc msg object + * Defines how functions in dmap will be invoked: either using an xmlrpc msg object * or plain php values. * valid strings are 'xmlrpcvals', 'phpvals' or 'epivals' */ var $functions_parameters_type='xmlrpcvals'; + /** + * Option used for fine-tuning the encoding the php values returned from + * functions registered in the dispatch map when the functions_parameters_types + * member is set to 'phpvals' + * @see php_xmlrpc_encode for a list of values + */ + var $phpvals_encoding_options = array( 'auto_dates' ); /// controls wether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3 var $debug = 1; /** + * Controls behaviour of server when invoked user function throws an exception: + * 0 = catch it and return an 'internal error' xmlrpc response (default) + * 1 = catch it and return an xmlrpc response with the error corresponding to the exception + * 2 = allow the exception to float to the upper layers + */ + var $exception_handling = 0; + /** * When set to true, it will enable HTTP compression of the response, in case * the client has declared its support for compression in the request. */ @@ -466,9 +484,14 @@ * NB: pretty dangerous if you accept every charset and do not have mbstring enabled) */ var $response_charset_encoding = ''; - /// storage for internal debug info + /** + * Storage for internal debug info + * @access private + */ var $debug_info = ''; - /// extra data passed at runtime to method handling functions. Used only by EPI layer + /** + * Extra data passed at runtime to method handling functions. Used only by EPI layer + */ var $user_data = null; /** @@ -565,15 +588,7 @@ if ($data === null) { // workaround for a known bug in php ver. 5.2.2 that broke $HTTP_RAW_POST_DATA - $ver = phpversion(); - if ($ver[0] >= 5) - { - $data = file_get_contents('php://input'); - } - else - { - $data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : ''; - } + $data = file_get_contents('php://input'); } $raw_data = $data; @@ -659,7 +674,7 @@ } else { - error_log('XML-RPC: xmlrpc_server::service: http headers already sent before response is fully generated. Check for php warning or error messages'); + error_log('XML-RPC: '.__METHOD__.': http headers already sent before response is fully generated. Check for php warning or error messages'); } print $payload; @@ -689,7 +704,7 @@ } if ($sigdoc) { - $this->dmap[$methodname]['signature_docs'] = $sigdoc; + $this->dmap[$methodname]['signature_docs'] = $sigdoc; } } @@ -731,7 +746,7 @@ } else { - $pt= $in[$n] == 'i4' ? 'int' : $in[$n]; // dispatch maps never use i4... + $pt= $in[$n] == 'i4' ? 'int' : strtolower($in[$n]); // dispatch maps never use i4... } // param index is $n+1, as first member of sig is return type @@ -767,10 +782,11 @@ */ function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression) { - // Play nice to PHP 4.0.x: superglobals were not yet invented... - if(!isset($_SERVER)) + // check if $_SERVER is populated: it might have been disabled via ini file + // (this is true even when in CLI mode) + if (count($_SERVER) == 0) { - $_SERVER = $GLOBALS['HTTP_SERVER_VARS']; + error_log('XML-RPC: '.__METHOD__.': cannot parse request headers as $_SERVER is not populated'); } if($this->debug > 1) @@ -919,7 +935,7 @@ // makes the lib about 200% slower... //if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII'))) { - error_log('XML-RPC: xmlrpc_server::parseRequest: invalid charset encoding of received request: '.$req_encoding); + error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received request: '.$req_encoding); $req_encoding = $GLOBALS['xmlrpc_defencoding']; } /// @BUG this will fail on PHP 5 if charset is not specified in the xml prologue, @@ -974,7 +990,11 @@ else { xml_parser_free($parser); - if ($this->functions_parameters_type != 'xmlrpcvals') + // small layering violation in favor of speed and memory usage: + // we should allow the 'execute' method handle this, but in the + // most common scenario (xmlrpcvals type server with some methods + // registered as phpvals) that would mean a useless encode+decode pass + if ($this->functions_parameters_type != 'xmlrpcvals' || (isset($this->dmap[$GLOBALS['_xh']['method']]['parameters_type']) && ($this->dmap[$GLOBALS['_xh']['method']]['parameters_type'] == 'phpvals'))) { if($this->debug > 1) { @@ -1063,7 +1083,7 @@ // verify that function to be invoked is in fact callable if(!is_callable($func)) { - error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler is not callable"); + error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler is not callable"); return new xmlrpcresp( 0, $GLOBALS['xmlrpcerr']['server_error'], @@ -1077,71 +1097,91 @@ { $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler'); } - if (is_object($m)) + try { - if($sysCall) - { - $r = call_user_func($func, $this, $m); - } - else - { - $r = call_user_func($func, $m); - } - if (!is_a($r, 'xmlrpcresp')) + // Allow mixed-convention servers + if (is_object($m)) { - error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler does not return an xmlrpcresp object"); - if (is_a($r, 'xmlrpcval')) + if($sysCall) { - $r = new xmlrpcresp($r); + $r = call_user_func($func, $this, $m); } else { - $r = new xmlrpcresp( - 0, - $GLOBALS['xmlrpcerr']['server_error'], - $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object" - ); + $r = call_user_func($func, $m); + } + if (!is_a($r, 'xmlrpcresp')) + { + error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler does not return an xmlrpcresp object"); + if (is_a($r, 'xmlrpcval')) + { + $r = new xmlrpcresp($r); + } + else + { + $r = new xmlrpcresp( + 0, + $GLOBALS['xmlrpcerr']['server_error'], + $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object" + ); + } } - } - } - else - { - // call a 'plain php' function - if($sysCall) - { - array_unshift($params, $this); - $r = call_user_func_array($func, $params); } else { - // 3rd API convention for method-handling functions: EPI-style - if ($this->functions_parameters_type == 'epivals') + // call a 'plain php' function + if($sysCall) { - $r = call_user_func_array($func, array($methName, $params, $this->user_data)); - // mimic EPI behaviour: if we get an array that looks like an error, make it - // an eror response - if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r)) + array_unshift($params, $this); + $r = call_user_func_array($func, $params); + } + else + { + // 3rd API convention for method-handling functions: EPI-style + if ($this->functions_parameters_type == 'epivals') { - $r = new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']); + $r = call_user_func_array($func, array($methName, $params, $this->user_data)); + // mimic EPI behaviour: if we get an array that looks like an error, make it + // an eror response + if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r)) + { + $r = new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']); + } + else + { + // functions using EPI api should NOT return resp objects, + // so make sure we encode the return type correctly + $r = new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api'))); + } } else { - // functions using EPI api should NOT return resp objects, - // so make sure we encode the return type correctly - $r = new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api'))); + $r = call_user_func_array($func, $params); } } - else + // the return type can be either an xmlrpcresp object or a plain php value... + if (!is_a($r, 'xmlrpcresp')) { - $r = call_user_func_array($func, $params); + // what should we assume here about automatic encoding of datetimes + // and php classes instances??? + $r = new xmlrpcresp(php_xmlrpc_encode($r, $this->phpvals_encoding_options)); } } - // the return type can be either an xmlrpcresp object or a plain php value... - if (!is_a($r, 'xmlrpcresp')) + } + catch(Exception $e) + { + // (barring errors in the lib) an uncatched exception happened + // in the called function, we wrap it in a proper error-response + switch($this->exception_handling) { - // what should we assume here about automatic encoding of datetimes - // and php classes instances??? - $r = new xmlrpcresp(php_xmlrpc_encode($r, array('auto_dates'))); + case 2: + throw $e; + break; + case 1: + $r = new xmlrpcresp(0, $e->getCode(), $e->getMessage()); + break; + default: + $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_error'], $GLOBALS['xmlrpcstr']['server_error']); } } if($this->debug > 2)