* xmlrpcs.inc, xmlrpcs.inc: remove code that was left for compatibility with php...
authorggiunta <ggiunta@013ecfd8-0664-425d-a759-9c98391dc3f9>
Sat, 5 Sep 2009 15:14:26 +0000 (15:14 +0000)
committerggiunta <ggiunta@013ecfd8-0664-425d-a759-9c98391dc3f9>
Sat, 5 Sep 2009 15:14:26 +0000 (15:14 +0000)
* xmlrpcs.inc: catch exceptions thrown during execution of invoked methods; check for $_SERVER having been disabled via php.ini and log an error if so
* server.php, testsuite.php: add a new test and server method for exception catching in the server

git-svn-id: https://svn.code.sf.net/p/phpxmlrpc/code/trunk/xmlrpc@54 013ecfd8-0664-425d-a759-9c98391dc3f9

ChangeLog
demo/server/server.php
lib/xmlrpc.inc
lib/xmlrpcs.inc

index 1aedc15..c8a5050 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2009-09-05 - G. Giunta (giunta.gaetano@gmail.com)\r
+\r
+       * xmlrpcs.inc, xmlrpcs.inc: remove code that was left for compatibility\r
+       with php 4; use __METHOD__ constant for error messages instead of hardcoded\r
+       values\r
+\r
+       * xmlrpcs.inc: catch exceptions thrown during execution of invoked methods;\r
+       check for $_SERVER having been disabled via php.ini and log an error if so\r
+\r
+       * server.php, testsuite.php: add a new test and server method for exception\r
+       catching in the server\r
+\r
 2009-08-05 - G. Giunta (giunta.gaetano@gmail.com)\r
 \r
        * xmlrpc_wrappers.inc: improve compatibility with php 5.0 when registering\r
index 31f2225..bc8200e 100644 (file)
@@ -36,6 +36,14 @@ if ($_SERVER['REQUEST_METHOD'] != 'POST' && isset($_GET['showSource']))
                        return new xmlrpcresp(new xmlrpcval(1, 'boolean'));
                }
 
+           /**
+            * Method used to testcatching of exceptions in the server.
+            */
+           function exceptiongenerator($m)
+           {
+               throw new Exception("it's just a test", 1);
+           }
+
                /**
                * a PHP version of the state-number server. Send me an integer and i'll sell you a state
                * @param integer $s
@@ -693,6 +701,9 @@ mimetype, a string, is a standard MIME type, for example, text/plain.
                        "function" => array($o, "phpwarninggenerator")
                        //'function' => 'xmlrpc_server_methods_container::phpwarninggenerator'
                ),
+               "examples.raiseException" => array(
+                       "function" => array($o, "exceptiongenerator")
+               ),
                "examples.getallheaders" => array(
                        "function" => 'getallheaders_xmlrpc',
                        "signature" => $getallheaders_sig,
@@ -835,7 +846,8 @@ mimetype, a string, is a standard MIME type, for example, text/plain.
        // we do this to help the testsuite script: do not reproduce in production!
        if (isset($_GET['RESPONSE_ENCODING']))
                $s->response_charset_encoding = $_GET['RESPONSE_ENCODING'];
-
+       if (isset($_GET['EXCEPTION_HANDLING']))
+               $s->exception_handling = $_GET['EXCEPTION_HANDLING'];
        $s->service();
        // that should do all we need!
 ?>
\ No newline at end of file
index 4ac287a..74c2c25 100644 (file)
                                $credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";\r
                                if ($authtype != 1)\r
                                {\r
-                                       error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported with HTTP 1.0');\r
+                                       error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported with HTTP 1.0');\r
                                }\r
                        }\r
 \r
                                {\r
                                        if ($proxyauthtype != 1)\r
                                        {\r
-                                               error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported with HTTP 1.0');\r
+                                               error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported with HTTP 1.0');\r
                                        }\r
                                        $proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n";\r
                                }\r
                                }\r
                                else if ($authtype != 1)\r
                                {\r
-                                       error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported by the current PHP/curl install');\r
+                                       error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth is supported by the current PHP/curl install');\r
                                }\r
                        }\r
 \r
                                        }\r
                                        else if ($proxyauthtype != 1)\r
                                        {\r
-                                               error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported by the current PHP/curl install');\r
+                                               error_log('XML-RPC: '.__METHOD__.': warning. Only Basic auth to proxy is supported by the current PHP/curl install');\r
                                        }\r
                                }\r
                        }\r
                                curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2));\r
                        }\r
 \r
-                   foreach ($this->extracurlopts as $opt => $val)\r
-                   {\r
-                       curl_setopt($curl, $opt, $val);\r
-                   }\r
+                       foreach ($this->extracurlopts as $opt => $val)\r
+                       {\r
+                               curl_setopt($curl, $opt, $val);\r
+                       }\r
 \r
                        $result = curl_exec($curl);\r
 \r
@@ -2262,7 +2262,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                                        }\r
                                        else\r
                                        {\r
-                                               error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTPS via proxy error, tunnel connection possibly failed');\r
+                                               error_log('XML-RPC: '.__METHOD__.': HTTPS via proxy error, tunnel connection possibly failed');\r
                                                $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)');\r
                                                return $r;\r
                                        }\r
@@ -2283,7 +2283,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                                if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data))\r
                                {\r
                                        $errstr= substr($data, 0, strpos($data, "\n")-1);\r
-                                       error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTP error, got response: ' .$errstr);\r
+                                       error_log('XML-RPC: '.__METHOD__.': HTTP error, got response: ' .$errstr);\r
                                        $r=new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')');\r
                                        return $r;\r
                                }\r
@@ -2408,7 +2408,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                                        {\r
                                                if(!$data = decode_chunked($data))\r
                                                {\r
-                                                       error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to rebuild the chunked data received from server');\r
+                                                       error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to rebuild the chunked data received from server');\r
                                                        $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']);\r
                                                        return $r;\r
                                                }\r
@@ -2438,14 +2438,14 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                                                                }\r
                                                                else\r
                                                                {\r
-                                                                       error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to decode the deflated data received from server');\r
+                                                                       error_log('XML-RPC: '.__METHOD__.': errors occurred when trying to decode the deflated data received from server');\r
                                                                        $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']);\r
                                                                        return $r;\r
                                                                }\r
                                                        }\r
                                                        else\r
                                                        {\r
-                                                               error_log('XML-RPC: xmlrpcmsg::parseResponse: the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');\r
+                                                               error_log('XML-RPC: '.__METHOD__.': the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');\r
                                                                $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']);\r
                                                                return $r;\r
                                                        }\r
@@ -2453,7 +2453,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                                        }\r
                                } // end of 'if needed, de-chunk, re-inflate response'\r
 \r
-                               // real stupid hack to avoid PHP complaining about returning NULL by ref\r
+                               // real stupid hack to avoid PHP complaining about returning NULL by ref\r
                                $r = null;\r
                                $r =& $r;\r
                                return $r;\r
@@ -2477,7 +2477,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
 \r
                        if($data == '')\r
                        {\r
-                               error_log('XML-RPC: xmlrpcmsg::parseResponse: no response received from server.');\r
+                               error_log('XML-RPC: '.__METHOD__.': no response received from server.');\r
                                $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']);\r
                                return $r;\r
                        }\r
@@ -2522,17 +2522,10 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
 \r
                        // be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts)\r
                        // idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib\r
-                       $bd = false;\r
-                       // Poor man's version of strrpos for php 4...\r
-                       $pos = strpos($data, '</methodResponse>');\r
-                       while($pos || is_int($pos))\r
-                       {\r
-                               $bd = $pos+17;\r
-                               $pos = strpos($data, '</methodResponse>', $bd);\r
-                       }\r
-                       if($bd)\r
+                       $pos = strrpos($data, '</methodResponse>');\r
+                       if($pos !== false)\r
                        {\r
-                               $data = substr($data, 0, $bd);\r
+                               $data = substr($data, 0, $pos+17);\r
                        }\r
 \r
                        // if user wants back raw xml, give it to him\r
@@ -2563,7 +2556,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                        // makes the lib about 200% slower...\r
                        //if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))\r
                        {\r
-                               error_log('XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of received response: '.$resp_encoding);\r
+                               error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received response: '.$resp_encoding);\r
                                $resp_encoding = $GLOBALS['xmlrpc_defencoding'];\r
                        }\r
                        $parser = xml_parser_create($resp_encoding);\r
@@ -2738,7 +2731,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                                                $this->me['struct']=$val;\r
                                                break;\r
                                        default:\r
-                                               error_log("XML-RPC: xmlrpcval::xmlrpcval: not a known type ($type)");\r
+                                               error_log("XML-RPC: ".__METHOD__.": not a known type ($type)");\r
                                }\r
                                /*if($type=='')\r
                                {\r
@@ -2770,7 +2763,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                        $typeof=@$GLOBALS['xmlrpcTypes'][$type];\r
                        if($typeof!=1)\r
                        {\r
-                               error_log("XML-RPC: xmlrpcval::addScalar: not a scalar type ($type)");\r
+                               error_log("XML-RPC: ".__METHOD__.": not a scalar type ($type)");\r
                                return 0;\r
                        }\r
 \r
@@ -2792,10 +2785,10 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                        switch($this->mytype)\r
                        {\r
                                case 1:\r
-                                       error_log('XML-RPC: xmlrpcval::addScalar: scalar xmlrpcval can have only one value');\r
+                                       error_log('XML-RPC: '.__METHOD__.': scalar xmlrpcval can have only one value');\r
                                        return 0;\r
                                case 3:\r
-                                       error_log('XML-RPC: xmlrpcval::addScalar: cannot add anonymous scalar to struct xmlrpcval');\r
+                                       error_log('XML-RPC: '.__METHOD__.': cannot add anonymous scalar to struct xmlrpcval');\r
                                        return 0;\r
                                case 2:\r
                                        // we're adding a scalar value to an array here\r
@@ -2837,7 +2830,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                        }\r
                        else\r
                        {\r
-                               error_log('XML-RPC: xmlrpcval::addArray: already initialized as a [' . $this->kindOf() . ']');\r
+                               error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');\r
                                return 0;\r
                        }\r
                }\r
@@ -2866,7 +2859,7 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                        }\r
                        else\r
                        {\r
-                               error_log('XML-RPC: xmlrpcval::addStruct: already initialized as a [' . $this->kindOf() . ']');\r
+                               error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');\r
                                return 0;\r
                        }\r
                }\r
@@ -2939,8 +2932,8 @@ xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $cha
                                                        break;\r
                                                case $GLOBALS['xmlrpcDouble']:\r
                                                        // avoid using standard conversion of float to string because it is locale-dependent,\r
-                                                       // and also because the xmlrpc spec forbids exponential notation\r
-                                                       // sprintf('%F') would be most likely ok but it is only available since PHP 4.3.10 and PHP 5.0.3.\r
+                                                       // and also because the xmlrpc spec forbids exponential notation.\r
+                                                       // sprintf('%F') could be most likely ok but it fails eg. on 2e-14.\r
                                                        // The code below tries its best at keeping max precision while avoiding exp notation,\r
                                                        // but there is of course no limit in the number of decimal places to be used...\r
                                                        $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', ''))."</${typ}>";\r
index ea6ec13..2fafdae 100644 (file)
 \r
        $GLOBALS['_xmlrpcs_occurred_errors'] = '';\r
        $GLOBALS['_xmlrpcs_prev_ehandler'] = '';\r
+\r
        /**\r
        * Error handler used to track errors that occur during server-side execution of PHP code.\r
        * This allows to report back to the client whether an internal error has occurred or not\r
                        return;\r
 \r
                //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING)\r
-               if($errcode != 2048) // do not use E_STRICT by name, since on PHP 4 it will not be defined\r
+               if($errcode != E_STRICT)\r
                {\r
                        $GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n";\r
                }\r
                * valid strings are 'xmlrpcvals', 'phpvals' or 'epivals'\r
                */\r
                var $functions_parameters_type='xmlrpcvals';\r
-           /**\r
-           * Option used for fine-tuning the encoding the php values returned from\r
-           * functions registered in the dispatch map when the functions_parameters_types\r
-            member is set to 'phpvals'\r
-           * @see php_xmlrpc_encode for a list of values\r
-           */\r
-           var $phpvals_encoding_options = array( 'auto_dates' );\r
+               /**\r
+               * Option used for fine-tuning the encoding the php values returned from\r
+               * functions registered in the dispatch map when the functions_parameters_types\r
+               * member is set to 'phpvals'\r
+               * @see php_xmlrpc_encode for a list of values\r
+               */\r
+               var $phpvals_encoding_options = array( 'auto_dates' );\r
                /// 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\r
                var $debug = 1;\r
                /**\r
+               * Controls behaviour of server when invoked user function throws an exception:\r
+               * 0 = catch it and return an 'internal error' xmlrpc response (default)\r
+               * 1 = catch it and return an xmlrpc response with the error corresponding to the exception\r
+               * 2 = allow the exception to float to the upper layers\r
+               */\r
+               var $exception_handling = 0;\r
+               /**\r
                * When set to true, it will enable HTTP compression of the response, in case\r
                * the client has declared its support for compression in the request.\r
                */\r
                        }\r
                        else\r
                        {\r
-                               error_log('XML-RPC: xmlrpc_server::service: http headers already sent before response is fully generated. Check for php warning or error messages');\r
+                               error_log('XML-RPC: '.__METHOD__.': http headers already sent before response is fully generated. Check for php warning or error messages');\r
                        }\r
 \r
                        print $payload;\r
                        }\r
                        if ($sigdoc)\r
                        {\r
-                           $this->dmap[$methodname]['signature_docs'] = $sigdoc;\r
+                               $this->dmap[$methodname]['signature_docs'] = $sigdoc;\r
                        }\r
                }\r
 \r
                */\r
                function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression)\r
                {\r
-                       // Play nice to PHP 4.0.x: superglobals were not yet invented...\r
-                       if(!isset($_SERVER))\r
+                       // check if $_SERVER is populated: it might have been disabled via ini file\r
+                       // (this is true even when in CLI mode)\r
+                       if (count($_SERVER) == 0)\r
                        {\r
-                               $_SERVER = $GLOBALS['HTTP_SERVER_VARS'];\r
+                               error_log('XML-RPC: '.__METHOD__.': cannot parse request headers as $_SERVER is not populated');\r
                        }\r
 \r
                        if($this->debug > 1)\r
                                // makes the lib about 200% slower...\r
                                //if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))\r
                                {\r
-                                       error_log('XML-RPC: xmlrpc_server::parseRequest: invalid charset encoding of received request: '.$req_encoding);\r
+                                       error_log('XML-RPC: '.__METHOD__.': invalid charset encoding of received request: '.$req_encoding);\r
                                        $req_encoding = $GLOBALS['xmlrpc_defencoding'];\r
                                }\r
                                /// @BUG this will fail on PHP 5 if charset is not specified in the xml prologue,\r
                        else\r
                        {\r
                                xml_parser_free($parser);\r
-                           // small layering violation in favor of speed and memory usage:\r
-                           // we should allow the 'execute' method handle this, but in the\r
-                           // most common scenario (xmlrpcvals type server with some methods\r
-                           // registered as phpvals) that would mean a useless encode+decode pass\r
+                               // small layering violation in favor of speed and memory usage:\r
+                               // we should allow the 'execute' method handle this, but in the\r
+                               // most common scenario (xmlrpcvals type server with some methods\r
+                               // registered as phpvals) that would mean a useless encode+decode pass\r
                                if ($this->functions_parameters_type != 'xmlrpcvals' || (isset($this->dmap[$GLOBALS['_xh']['method']]['parameters_type']) && ($this->dmap[$GLOBALS['_xh']['method']]['parameters_type'] == 'phpvals')))\r
                                {\r
                                        if($this->debug > 1)\r
                        // verify that function to be invoked is in fact callable\r
                        if(!is_callable($func))\r
                        {\r
-                               error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler is not callable");\r
+                               error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler is not callable");\r
                                return new xmlrpcresp(\r
                                        0,\r
                                        $GLOBALS['xmlrpcerr']['server_error'],\r
                        {\r
                                $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler');\r
                        }\r
-                   // Allow mixed-convention servers\r
-                       if (is_object($m))\r
+                       try\r
                        {\r
-                               if($sysCall)\r
-                               {\r
-                                       $r = call_user_func($func, $this, $m);\r
-                               }\r
-                               else\r
-                               {\r
-                                       $r = call_user_func($func, $m);\r
-                               }\r
-                               if (!is_a($r, 'xmlrpcresp'))\r
+                               // Allow mixed-convention servers\r
+                               if (is_object($m))\r
                                {\r
-                                       error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler does not return an xmlrpcresp object");\r
-                                       if (is_a($r, 'xmlrpcval'))\r
+                                       if($sysCall)\r
                                        {\r
-                                               $r = new xmlrpcresp($r);\r
+                                               $r = call_user_func($func, $this, $m);\r
                                        }\r
                                        else\r
                                        {\r
-                                               $r = new xmlrpcresp(\r
-                                                       0,\r
-                                                       $GLOBALS['xmlrpcerr']['server_error'],\r
-                                                       $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object"\r
-                                               );\r
+                                               $r = call_user_func($func, $m);\r
+                                       }\r
+                                       if (!is_a($r, 'xmlrpcresp'))\r
+                                       {\r
+                                               error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler does not return an xmlrpcresp object");\r
+                                               if (is_a($r, 'xmlrpcval'))\r
+                                               {\r
+                                                       $r = new xmlrpcresp($r);\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       $r = new xmlrpcresp(\r
+                                                               0,\r
+                                                               $GLOBALS['xmlrpcerr']['server_error'],\r
+                                                               $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object"\r
+                                                       );\r
+                                               }\r
                                        }\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               // call a 'plain php' function\r
-                               if($sysCall)\r
-                               {\r
-                                       array_unshift($params, $this);\r
-                                       $r = call_user_func_array($func, $params);\r
                                }\r
                                else\r
                                {\r
-                                       // 3rd API convention for method-handling functions: EPI-style\r
-                                       if ($this->functions_parameters_type == 'epivals')\r
+                                       // call a 'plain php' function\r
+                                       if($sysCall)\r
+                                       {\r
+                                               array_unshift($params, $this);\r
+                                               $r = call_user_func_array($func, $params);\r
+                                       }\r
+                                       else\r
                                        {\r
-                                               $r = call_user_func_array($func, array($methName, $params, $this->user_data));\r
-                                               // mimic EPI behaviour: if we get an array that looks like an error, make it\r
-                                               // an eror response\r
-                                               if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r))\r
+                                               // 3rd API convention for method-handling functions: EPI-style\r
+                                               if ($this->functions_parameters_type == 'epivals')\r
                                                {\r
-                                                       $r = new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']);\r
+                                                       $r = call_user_func_array($func, array($methName, $params, $this->user_data));\r
+                                                       // mimic EPI behaviour: if we get an array that looks like an error, make it\r
+                                                       // an eror response\r
+                                                       if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r))\r
+                                                       {\r
+                                                               $r = new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']);\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               // functions using EPI api should NOT return resp objects,\r
+                                                               // so make sure we encode the return type correctly\r
+                                                               $r = new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api')));\r
+                                                       }\r
                                                }\r
                                                else\r
                                                {\r
-                                                       // functions using EPI api should NOT return resp objects,\r
-                                                       // so make sure we encode the return type correctly\r
-                                                       $r = new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api')));\r
+                                                       $r = call_user_func_array($func, $params);\r
                                                }\r
                                        }\r
-                                       else\r
+                                       // the return type can be either an xmlrpcresp object or a plain php value...\r
+                                       if (!is_a($r, 'xmlrpcresp'))\r
                                        {\r
-                                               $r = call_user_func_array($func, $params);\r
+                                               // what should we assume here about automatic encoding of datetimes\r
+                                               // and php classes instances???\r
+                                               $r = new xmlrpcresp(php_xmlrpc_encode($r, $this->phpvals_encoding_options));\r
                                        }\r
                                }\r
-                               // the return type can be either an xmlrpcresp object or a plain php value...\r
-                               if (!is_a($r, 'xmlrpcresp'))\r
+                       }\r
+                       catch(Exception $e)\r
+                       {\r
+                               // (barring errors in the lib) an uncatched exception happened\r
+                               // in the called function, we wrap it in a proper error-response\r
+                               switch($this->exception_handling)\r
                                {\r
-                                       // what should we assume here about automatic encoding of datetimes\r
-                                       // and php classes instances???\r
-                                       $r = new xmlrpcresp(php_xmlrpc_encode($r, $this->phpvals_encoding_options));\r
+                                       case 2:\r
+                                               throw $e;\r
+                                               break;\r
+                                       case 1:\r
+                                               $r = new xmlrpcresp(0, $e->getCode(), $e->getMessage());\r
+                                               break;\r
+                                       default:\r
+                                               $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_error'], $GLOBALS['xmlrpcstr']['server_error']);\r
                                }\r
                        }\r
                        if($this->debug > 2)\r