From c79e320a2d513194a0e7b65d26407a45ae4cbdd3 Mon Sep 17 00:00:00 2001 From: gggeek Date: Tue, 16 Dec 2014 01:01:58 +0000 Subject: [PATCH] WIP - more bugfixes and start of testsuite reimplementation --- composer.json | 2 +- src/Client.php | 12 +- src/Request.php | 1 - src/Response.php | 8 +- src/Server.php | 122 ++- src/Wrapper.php | 10 +- test/benchmark.php | 299 ------ test/parse_args.php | 128 --- test/testsuite.php | 1550 ----------------------------- tests/InvalidHostTest.php | 82 ++ tests/LocalhostTest.php | 627 ++++++++++++ tests/ParsingBugsTest.php | 502 ++++++++++ tests/benchmark.php | 307 ++++++ tests/parse_args.php | 143 +++ {test => tests}/verify_compat.php | 0 15 files changed, 1737 insertions(+), 2056 deletions(-) delete mode 100644 test/benchmark.php delete mode 100644 test/parse_args.php delete mode 100644 test/testsuite.php create mode 100644 tests/InvalidHostTest.php create mode 100644 tests/LocalhostTest.php create mode 100644 tests/ParsingBugsTest.php create mode 100644 tests/benchmark.php create mode 100644 tests/parse_args.php rename {test => tests}/verify_compat.php (100%) diff --git a/composer.json b/composer.json index db3c1498..30644908 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "ext-xml": "*" }, "require-dev": { - "phpunit/phpunit": "4.3.*" + "phpunit/phpunit": ">=4.0.0" }, "suggest": { "ext-curl": "Needed for HTTPS and HTTP 1.1 support, NTLM Auth etc...", diff --git a/src/Client.php b/src/Client.php index a31c7327..c12d4070 100644 --- a/src/Client.php +++ b/src/Client.php @@ -59,7 +59,7 @@ class Client /// Charset encoding to be used in serializing request. NULL = use ASCII public $request_charset_encoding = ''; /** - * Decides the content of xmlrpcresp objects returned by calls to send() + * Decides the content of Response objects returned by calls to send() * valid strings are 'xmlrpcvals', 'phpvals' or 'xml' */ public $return_type = 'xmlrpcvals'; @@ -324,7 +324,7 @@ class Client * @param mixed $msg The request object, or an array of requests for using multicall, or the complete xml representation of a request * @param integer $timeout Connection timeout, in seconds, If unspecified, a platform specific timeout will apply * @param string $method if left unspecified, the http protocol chosen during creation of the object will be used - * @return xmlrpcresp + * @return Response */ public function& send($msg, $timeout=0, $method='') { @@ -337,7 +337,7 @@ class Client if(is_array($msg)) { - // $msg is an array of xmlrpcmsg's + // $msg is an array of Requests $r = $this->multicall($msg, $timeout, $method); return $r; } @@ -348,7 +348,7 @@ class Client $msg = $n; } - // where msg is an xmlrpcmsg + // where msg is a Request $msg->debug=$this->debug; if($method == 'https') @@ -908,7 +908,7 @@ class Client * NB: trying to shoehorn extra functionality into existing syntax has resulted * in pretty much convoluted code... * - * @param array $msgs an array of xmlrpcmsg objects + * @param Request[] $msgs an array of Request objects * @param integer $timeout connection timeout (in seconds) * @param string $method the http protocol variant to be used * @param boolean fallback When true, upon receiving an error during multicall, multiple single calls will be attempted @@ -939,7 +939,7 @@ class Client } else { - if (is_a($results, 'xmlrpcresp')) + if (is_a($results, '\PhpXmlRpc\Response')) { $result = $results; } diff --git a/src/Request.php b/src/Request.php index 00db29cb..70519319 100644 --- a/src/Request.php +++ b/src/Request.php @@ -4,7 +4,6 @@ namespace PhpXmlRpc; use PhpXmlRpc\Helper\Http; use PhpXmlRpc\Helper\XMLParser; -use PhpXmlRpc\Helper\Encoder; class Request { diff --git a/src/Response.php b/src/Response.php index 65325477..fe945c13 100644 --- a/src/Response.php +++ b/src/Response.php @@ -26,7 +26,7 @@ class Response * * @todo add check that $val / $fcode / $fstr is of correct type??? * NB: as of now we do not do it, since it might be either an xmlrpcval or a plain - * php val, or a complete xml chunk, depending on usage of xmlrpc_client::send() inside which creator is called... + * php val, or a complete xml chunk, depending on usage of Client::send() inside which creator is called... */ function __construct($val, $fcode = 0, $fstr = '', $valtyp='') { @@ -85,7 +85,7 @@ class Response /** * Returns the value received by the server. - * @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured xmlrpc_client objects + * @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured Client objects */ public function value() { @@ -99,7 +99,7 @@ class Response * NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past) * are still present in the array. It is up to the user-defined code to decide * how to use the received cookies, and whether they have to be sent back with the next - * request to the server (using xmlrpc_client::setCookie) or not + * request to the server (using Client::setCookie) or not * @return array array of cookies received from the server */ public function cookies() @@ -150,7 +150,7 @@ Charset::instance()->encode_entities($this->errstr, PhpXmlRpc::$xmlrpc_internale else { /// @todo try to build something serializable? - die('cannot serialize xmlrpcresp objects whose content is native php values'); + die('cannot serialize xmlrpc response objects whose content is native php values'); } } else diff --git a/src/Server.php b/src/Server.php index 56fd6e80..7f42b164 100644 --- a/src/Server.php +++ b/src/Server.php @@ -4,58 +4,6 @@ namespace PhpXmlRpc; use PhpXmlRpc\Helper\XMLParser; use PhpXmlRpc\Helper\Charset; -use PhpXmlRpc\Helper\Encoder; - -/** -* 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 -* using an xmlrpc response object, instead of letting the client deal with the html junk -* that a PHP execution error on the server generally entails. -* -* NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors. -* -*/ -function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null) -{ - // obey the @ protocol - if (error_reporting() == 0) - return; - - //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING) - if($errcode != E_STRICT) - { - \PhpXmlRpc\Server::error_occurred($errstring); - } - // Try to avoid as much as possible disruption to the previous error handling - // mechanism in place - if($GLOBALS['_xmlrpcs_prev_ehandler'] == '') - { - // The previous error handler was the default: all we should do is log error - // to the default error log (if level high enough) - if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode)) - { - error_log($errstring); - } - } - else - { - // Pass control on to previous error handler, trying to avoid loops... - if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler') - { - // NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers - if(is_array($GLOBALS['_xmlrpcs_prev_ehandler'])) - { - // the following works both with static class methods and plain object methods as error handler - call_user_func_array($GLOBALS['_xmlrpcs_prev_ehandler'], array($errcode, $errstring, $filename, $lineno, $context)); - } - else - { - $GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context); - } - } - } -} - class Server { @@ -421,7 +369,7 @@ class Server /** * Parse http headers received along with xmlrpc request. If needed, inflate request - * @return mixed null on success or an xmlrpcresp + * @return mixed null on success or a Response */ protected function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression) { @@ -544,7 +492,7 @@ class Server * php function registered with the server * @param string $data the xml request * @param string $req_encoding (optional) the charset encoding of the xml request - * @return xmlrpcresp + * @return Response */ public function parseRequest($data, $req_encoding='') { @@ -658,10 +606,10 @@ class Server /** * Execute a method invoked by the client, checking parameters used - * @param mixed $m either an xmlrpcmsg obj or a method name + * @param mixed $m either a Request obj or a method name * @param array $params array with method parameters as php types (if m is method name only) * @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only) - * @return xmlrpcresp + * @return Response */ protected function execute($m, $params=null, $paramtypes=null) { @@ -728,7 +676,7 @@ class Server // processing of user function, and log them as part of response if($this->debug > 2) { - $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler'); + $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler(array('\PhpXmlRpc\Server', '_xmlrpcs_errorHandler')); } try { @@ -743,9 +691,9 @@ class Server { $r = call_user_func($func, $m); } - if (!is_a($r, 'xmlrpcresp')) + if (!is_a($r, 'PhpXmlRpc\Response')) { - error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler does not return an xmlrpcresp object"); + error_log("XML-RPC: ".__METHOD__.": function $func registered as method handler does not return an xmlrpc response object"); if (is_a($r, 'PhpXmlRpc\Value')) { $r = new Response($r); @@ -755,7 +703,7 @@ class Server $r = new Response( 0, PhpXmlRpc::$xmlrpcerr['server_error'], - PhpXmlRpc::$xmlrpcstr['server_error'] . ": function does not return xmlrpcresp object" + PhpXmlRpc::$xmlrpcstr['server_error'] . ": function does not return xmlrpc response object" ); } } @@ -792,8 +740,8 @@ class Server $r = call_user_func_array($func, $params); } } - // the return type can be either an xmlrpcresp object or a plain php value... - if (!is_a($r, 'xmlrpcresp')) + // the return type can be either a Response object or a plain php value... + if (!is_a($r, '\PhpXmlRpc\Response')) { // what should we assume here about automatic encoding of datetimes // and php classes instances??? @@ -1181,4 +1129,54 @@ class Server return new Response(new Value($result, 'array')); } + + /** + * 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 + * using an xmlrpc response object, instead of letting the client deal with the html junk + * that a PHP execution error on the server generally entails. + * + * NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors. + * + */ + public static function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null) + { + // obey the @ protocol + if (error_reporting() == 0) + return; + + //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING) + if($errcode != E_STRICT) + { + \PhpXmlRpc\Server::error_occurred($errstring); + } + // Try to avoid as much as possible disruption to the previous error handling + // mechanism in place + if($GLOBALS['_xmlrpcs_prev_ehandler'] == '') + { + // The previous error handler was the default: all we should do is log error + // to the default error log (if level high enough) + if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode)) + { + error_log($errstring); + } + } + else + { + // Pass control on to previous error handler, trying to avoid loops... + if($GLOBALS['_xmlrpcs_prev_ehandler'] != array('\PhpXmlRpc\Server', '_xmlrpcs_errorHandler')) + { + if(is_array($GLOBALS['_xmlrpcs_prev_ehandler'])) + { + // the following works both with static class methods and plain object methods as error handler + call_user_func_array($GLOBALS['_xmlrpcs_prev_ehandler'], array($errcode, $errstring, $filename, $lineno, $context)); + } + else + { + $GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context); + } + } + } + } + } diff --git a/src/Wrapper.php b/src/Wrapper.php index ff1bbba9..3b7addd2 100644 --- a/src/Wrapper.php +++ b/src/Wrapper.php @@ -122,7 +122,7 @@ class Wrapper * function prototype is not considered valid (to be fixed?) * * Note that since rel. 2.0RC3 the preferred method to have the server call 'standard' - * php functions (ie. functions not expecting a single xmlrpcmsg obj as parameter) + * php functions (ie. functions not expecting a single Request obj as parameter) * is by making use of the functions_parameters_type class member. * * @param string $funcname the name of the PHP user function to be exposed as xmlrpc method; array($obj, 'methodname') and array('class', 'methodname') are ok too @@ -518,7 +518,7 @@ class Wrapper /** * Given an xmlrpc client and a method name, register a php wrapper function * that will call it and return results using native php types for both - * params and results. The generated php function will return an xmlrpcresp + * params and results. The generated php function will return a Response * object for failed xmlrpc calls * * Known limitations: @@ -538,7 +538,7 @@ class Wrapper * An extra 'debug' param is appended to param list of xmlrpc method, useful * for debugging purposes. * - * @param xmlrpc_client $client an xmlrpc client set up correctly to communicate with target server + * @param Client $client an xmlrpc client set up correctly to communicate with target server * @param string $methodname the xmlrpc method to be mapped to a php function * @param array $extra_options array of options that specify conversion details. valid options include * integer signum the index of the method signature to use in mapping (if method exposes many sigs) @@ -548,7 +548,7 @@ class Wrapper * string return_source if true return php code w. function definition instead fo function name * bool encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects * bool decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers --- - * mixed return_on_fault a php value to be returned when the xmlrpc call fails/returns a fault response (by default the xmlrpcresp object is returned in this case). If a string is used, '%faultCode%' and '%faultString%' tokens will be substituted with actual error values + * mixed return_on_fault a php value to be returned when the xmlrpc call fails/returns a fault response (by default the Response object is returned in this case). If a string is used, '%faultCode%' and '%faultString%' tokens will be substituted with actual error values * bool debug set it to 1 or 2 to see debug results of querying server for method synopsis * @return string the name of the generated php function (or false) - OR AN ARRAY... */ @@ -688,7 +688,7 @@ class Wrapper * Similar to wrap_xmlrpc_method, but will generate a php class that wraps * all xmlrpc methods exposed by the remote server as own methods. * For more details see wrap_xmlrpc_method. - * @param xmlrpc_client $client the client obj all set to query the desired server + * @param Client $client the client obj all set to query the desired server * @param array $extra_options list of options for wrapped code * @return mixed false on error, the name of the created class if all ok or an array with code, class name and comments (if the appropriatevoption is set in extra_options) */ diff --git a/test/benchmark.php b/test/benchmark.php deleted file mode 100644 index 8c0f6941..00000000 --- a/test/benchmark.php +++ /dev/null @@ -1,299 +0,0 @@ - $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1); - $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2); - $keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'); - - $test_results=array(); - $xd = extension_loaded('xdebug') && ini_get('xdebug.profiler_enable'); - if ($xd) - $num_tests = 1; - else - $num_tests = 10; - - $title = 'XML-RPC Benchmark Tests'; - - if(isset($_SERVER['REQUEST_METHOD'])) - { - echo "\n\n\n$title\n\n\n

$title

\n
\n";
-    }
-    else
-    {
-        echo "$title\n\n";
-    }
-
-    if(isset($_SERVER['REQUEST_METHOD']))
-    {
-        echo "

Using lib version: $xmlrpcVersion on PHP version: ".phpversion()."

\n"; - if ($xd) echo "

XDEBUG profiling enabled: skipping remote tests. Trace file is: ".htmlspecialchars(xdebug_get_profiler_filename())."

\n"; - flush(); - ob_flush(); - } - else - { - echo "Using lib version: $xmlrpcVersion on PHP version: ".phpversion()."\n"; - if ($xd) echo "XDEBUG profiling enabled: skipping remote tests\nTrace file is: ".xdebug_get_profiler_filename()."\n"; - } - - // test 'old style' data encoding vs. 'automatic style' encoding - begin_test('Data encoding (large array)', 'manual encoding'); - for ($i = 0; $i < $num_tests; $i++) - { - $vals = array(); - for ($j = 0; $j < 10; $j++) - { - $valarray = array(); - foreach ($data[$j] as $key => $val) - { - $values = array(); - $values[] = new xmlrpcval($val[0], 'int'); - $values[] = new xmlrpcval($val[1], 'double'); - $values[] = new xmlrpcval($val[2], 'string'); - $values[] = new xmlrpcval($val[3], 'boolean'); - $values[] = new xmlrpcval($val[4], 'dateTime.iso8601'); - $values[] = new xmlrpcval($val[5], 'int'); - $values[] = new xmlrpcval($val[6], 'double'); - $values[] = new xmlrpcval($val[7], 'string'); - $values[] = new xmlrpcval($val[8], 'boolean'); - $values[] = new xmlrpcval($val[9], 'dateTime.iso8601'); - $valarray[$key] = new xmlrpcval($values, 'array'); - } - $vals[] = new xmlrpcval($valarray, 'struct'); - } - $value = new xmlrpcval($vals, 'array'); - $out = $value->serialize(); - } - end_test('Data encoding (large array)', 'manual encoding', $out); - - begin_test('Data encoding (large array)', 'automatic encoding'); - for ($i = 0; $i < $num_tests; $i++) - { - $value = php_xmlrpc_encode($data, array('auto_dates')); - $out = $value->serialize(); - } - end_test('Data encoding (large array)', 'automatic encoding', $out); - - if (function_exists('xmlrpc_set_type')) - { - begin_test('Data encoding (large array)', 'xmlrpc-epi encoding'); - for ($i = 0; $i < $num_tests; $i++) - { - for ($j = 0; $j < 10; $j++) - foreach ($keys as $k) - { - xmlrpc_set_type($data[$j][$k][4], 'datetime'); - xmlrpc_set_type($data[$j][$k][8], 'datetime'); - } - $out = xmlrpc_encode($data); - } - end_test('Data encoding (large array)', 'xmlrpc-epi encoding', $out); - } - - // test 'old style' data decoding vs. 'automatic style' decoding - $dummy = new xmlrpcmsg(''); - $out = new xmlrpcresp($value); - $in = ''."\n".$out->serialize(); - - begin_test('Data decoding (large array)', 'manual decoding'); - for ($i = 0; $i < $num_tests; $i++) - { - $response =& $dummy->ParseResponse($in, true); - $value = $response->value(); - $result = array(); - for ($k = 0; $k < $value->arraysize(); $k++) - { - $val1 = $value->arraymem($k); - $out = array(); - while (list($name, $val) = $val1->structeach()) - { - $out[$name] = array(); - for ($j = 0; $j < $val->arraysize(); $j++) - { - $data = $val->arraymem($j); - $out[$name][] = $data->scalarval(); - } - } // while - $result[] = $out; - } - } - end_test('Data decoding (large array)', 'manual decoding', $result); - - begin_test('Data decoding (large array)', 'automatic decoding'); - for ($i = 0; $i < $num_tests; $i++) - { - $response =& $dummy->ParseResponse($in, true, 'phpvals'); - $value = $response->value(); - } - end_test('Data decoding (large array)', 'automatic decoding', $value); - - if (function_exists('xmlrpc_decode')) - { - begin_test('Data decoding (large array)', 'xmlrpc-epi decoding'); - for ($i = 0; $i < $num_tests; $i++) - { - $response =& $dummy->ParseResponse($in, true, 'xml'); - $value = xmlrpc_decode($response->value()); - } - end_test('Data decoding (large array)', 'xmlrpc-epi decoding', $value); - } - - if (!$xd) { - - /// test multicall vs. many calls vs. keep-alives - $value = php_xmlrpc_encode($data1, array('auto_dates')); - $msg = new xmlrpcmsg('interopEchoTests.echoValue', array($value)); - $msgs=array(); - for ($i = 0; $i < 25; $i++) - $msgs[] = $msg; - $server = explode(':', $LOCALSERVER); - if(count($server) > 1) - { - $c = new xmlrpc_client($URI, $server[0], $server[1]); - } - else - { - $c = new xmlrpc_client($URI, $LOCALSERVER); - } - // do not interfere with http compression - $c->accepted_compression = array(); - //$c->debug=true; - - if (function_exists('gzinflate')) { - $c->accepted_compression = null; - } - begin_test('Repeated send (small array)', 'http 10'); - $response = array(); - for ($i = 0; $i < 25; $i++) - { - $resp =& $c->send($msg); - $response[] = $resp->value(); - } - end_test('Repeated send (small array)', 'http 10', $response); - - if (function_exists('curl_init')) - { - begin_test('Repeated send (small array)', 'http 11 w. keep-alive'); - $response = array(); - for ($i = 0; $i < 25; $i++) - { - $resp =& $c->send($msg, 10, 'http11'); - $response[] = $resp->value(); - } - end_test('Repeated send (small array)', 'http 11 w. keep-alive', $response); - - $c->keepalive = false; - begin_test('Repeated send (small array)', 'http 11'); - $response = array(); - for ($i = 0; $i < 25; $i++) - { - $resp =& $c->send($msg, 10, 'http11'); - $response[] = $resp->value(); - } - end_test('Repeated send (small array)', 'http 11', $response); - } - - begin_test('Repeated send (small array)', 'multicall'); - $response =& $c->send($msgs); - foreach ($response as $key =>& $val) - { - $val = $val->value(); - } - end_test('Repeated send (small array)', 'multicall', $response); - - if (function_exists('gzinflate')) - { - $c->accepted_compression = array('gzip'); - $c->request_compression = 'gzip'; - - begin_test('Repeated send (small array)', 'http 10 w. compression'); - $response = array(); - for ($i = 0; $i < 25; $i++) - { - $resp =& $c->send($msg); - $response[] = $resp->value(); - } - end_test('Repeated send (small array)', 'http 10 w. compression', $response); - - if (function_exists('curl_init')) - { - begin_test('Repeated send (small array)', 'http 11 w. keep-alive and compression'); - $response = array(); - for ($i = 0; $i < 25; $i++) - { - $resp =& $c->send($msg, 10, 'http11'); - $response[] = $resp->value(); - } - end_test('Repeated send (small array)', 'http 11 w. keep-alive and compression', $response); - - $c->keepalive = false; - begin_test('Repeated send (small array)', 'http 11 w. compression'); - $response = array(); - for ($i = 0; $i < 25; $i++) - { - $resp =& $c->send($msg, 10, 'http11'); - $response[] = $resp->value(); - } - end_test('Repeated send (small array)', 'http 11 w. compression', $response); - } - - begin_test('Repeated send (small array)', 'multicall w. compression'); - $response =& $c->send($msgs); - foreach ($response as $key =>& $val) - { - $val = $val->value(); - } - end_test('Repeated send (small array)', 'multicall w. compression', $response); - } - - } // end of 'if no xdebug profiling' - - function begin_test($test_name, $test_case) - { - global $test_results; - if (!isset($test_results[$test_name])) - $test_results[$test_name]=array(); - $test_results[$test_name][$test_case] = array(); - $test_results[$test_name][$test_case]['time'] = microtime(true); - } - - function end_test($test_name, $test_case, $test_result) - { - global $test_results; - $end = microtime(true); - if (!isset($test_results[$test_name][$test_case])) - trigger_error('ending test that was not sterted'); - $test_results[$test_name][$test_case]['time'] = $end - $test_results[$test_name][$test_case]['time']; - $test_results[$test_name][$test_case]['result'] = $test_result; - echo '.'; - flush(); - ob_flush(); - } - - - echo "\n"; - foreach($test_results as $test => $results) - { - echo "\nTEST: $test\n"; - foreach ($results as $case => $data) - echo " $case: {$data['time']} secs - Output data CRC: ".crc32(serialize($data['result']))."\n"; - } - - - if(isset($_SERVER['REQUEST_METHOD'])) - { - echo "\n
\n\n\n"; - } diff --git a/test/parse_args.php b/test/parse_args.php deleted file mode 100644 index f8e2f558..00000000 --- a/test/parse_args.php +++ /dev/null @@ -1,128 +0,0 @@ - 1) - { - $$param[0]=$param[1]; - } - } - } - } - elseif(!ini_get('register_globals')) - { - // play nice to 'safe' PHP installations with register globals OFF - // NB: we might as well consider using $_GET stuff later on... - extract($_GET); - extract($_POST); - } - - if(!isset($DEBUG)) - { - $DEBUG = 0; - } - else - { - $DEBUG = intval($DEBUG); - } - - if(!isset($LOCALSERVER)) - { - if(isset($HTTP_HOST)) - { - $LOCALSERVER = $HTTP_HOST; - } - elseif(isset($_SERVER['HTTP_HOST'])) - { - $LOCALSERVER = $_SERVER['HTTP_HOST']; - } - else - { - $LOCALSERVER = 'localhost'; - } - } - if(!isset($HTTPSSERVER)) - { - $HTTPSSERVER = 'xmlrpc.usefulinc.com'; - } - if(!isset($HTTPSURI)) - { - $HTTPSURI = '/server.php'; - } - if(!isset($HTTPSIGNOREPEER)) - { - $HTTPSIGNOREPEER = false; - } - if(!isset($PROXY)) - { - $PROXYSERVER = null; - } - else - { - $arr = explode(':',$PROXY); - $PROXYSERVER = $arr[0]; - if(count($arr) > 1) - { - $PROXYPORT = $arr[1]; - } - else - { - $PROXYPORT = 8080; - } - } - // used to silence testsuite warnings about proxy code not being tested - if(!isset($NOPROXY)) - { - $NOPROXY = false; - } - if(!isset($URI)) - { - // GUESTIMATE the url of local demo server - // play nice to php 3 and 4-5 in retrieving URL of server.php - /// @todo filter out query string from REQUEST_URI - if(isset($REQUEST_URI)) - { - $URI = str_replace('/test/testsuite.php', '/demo/server/server.php', $REQUEST_URI); - $URI = str_replace('/testsuite.php', '/server.php', $URI); - $URI = str_replace('/test/benchmark.php', '/demo/server/server.php', $URI); - $URI = str_replace('/benchmark.php', '/server.php', $URI); - } - elseif(isset($_SERVER['PHP_SELF']) && isset($_SERVER['REQUEST_METHOD'])) - { - $URI = str_replace('/test/testsuite.php', '/demo/server/server.php', $_SERVER['PHP_SELF']); - $URI = str_replace('/testsuite.php', '/server.php', $URI); - $URI = str_replace('/test/benchmark.php', '/demo/server/server.php', $URI); - $URI = str_replace('/benchmark.php', '/server.php', $URI); - } - else - { - $URI = '/demo/server/server.php'; - } - } - if($URI[0] != '/') - { - $URI = '/'.$URI; - } - if(!isset($LOCALPATH)) - { - $LOCALPATH = __DIR__; - } diff --git a/test/testsuite.php b/test/testsuite.php deleted file mode 100644 index 34069e20..00000000 --- a/test/testsuite.php +++ /dev/null @@ -1,1550 +0,0 @@ - 1) - { - $this->client=new xmlrpc_client($URI, $server[0], $server[1]); - } - else - { - $this->client=new xmlrpc_client($URI, $LOCALSERVER); - } - if($DEBUG) - { - $this->client->setDebug($DEBUG); - } - $this->client->request_compression = $this->request_compression; - $this->client->accepted_compression = $this->accepted_compression; - } - - function send($msg, $errrorcode=0, $return_response=false) - { - $r = $this->client->send($msg, $this->timeout, $this->method); - // for multicall, return directly array of responses - if(is_array($r)) - { - return $r; - } - $this->assertEquals($r->faultCode(), $errrorcode, 'Error '.$r->faultCode().' connecting to server: '.$r->faultString()); - if(!$r->faultCode()) - { - if($return_response) - return $r; - else - return $r->value(); - } - else - { - return null; - } - } - - function testString() - { - $sendstring="here are 3 \"entities\": < > & " . - "and here's a dollar sign: \$pretendvarname and a backslash too: " . chr(92) . - " - isn't that great? \\\"hackery\\\" at it's best " . - " also don't want to miss out on \$item[0]. ". - "The real weird stuff follows: CRLF here".chr(13).chr(10). - "a simple CR here".chr(13). - "a simple LF here".chr(10). - "and then LFCR".chr(10).chr(13). - "last but not least weird names: G".chr(252)."nter, El".chr(232)."ne, and an xml comment closing tag: -->"; - $f=new xmlrpcmsg('examples.stringecho', array( - new xmlrpcval($sendstring, 'string') - )); - $v=$this->send($f); - if($v) - { - // when sending/receiving non-US-ASCII encoded strings, XML says cr-lf can be normalized. - // so we relax our tests... - $l1 = strlen($sendstring); - $l2 = strlen($v->scalarval()); - if ($l1 == $l2) - $this->assertEquals($sendstring, $v->scalarval()); - else - $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendstring), $v->scalarval()); - } - } - - function testAddingDoubles() - { - // note that rounding errors mean we - // keep precision to sensible levels here ;-) - $a=12.13; $b=-23.98; - $f=new xmlrpcmsg('examples.addtwodouble',array( - new xmlrpcval($a, 'double'), - new xmlrpcval($b, 'double') - )); - $v=$this->send($f); - if($v) - { - $this->assertEquals($a+$b,$v->scalarval()); - } - } - - function testAdding() - { - $f=new xmlrpcmsg('examples.addtwo',array( - new xmlrpcval(12, 'int'), - new xmlrpcval(-23, 'int') - )); - $v=$this->send($f); - if($v) - { - $this->assertEquals(12-23, $v->scalarval()); - } - } - - function testInvalidNumber() - { - $f=new xmlrpcmsg('examples.addtwo',array( - new xmlrpcval('fred', 'int'), - new xmlrpcval("\"; exec('ls')", 'int') - )); - $v=$this->send($f); - /// @todo a fault condition should be generated here - /// by the server, which we pick up on - if($v) - { - $this->assertEquals(0, $v->scalarval()); - } - } - - function testBoolean() - { - $f=new xmlrpcmsg('examples.invertBooleans', array( - new xmlrpcval(array( - new xmlrpcval(true, 'boolean'), - new xmlrpcval(false, 'boolean'), - new xmlrpcval(1, 'boolean'), - new xmlrpcval(0, 'boolean'), - //new xmlrpcval('true', 'boolean'), - //new xmlrpcval('false', 'boolean') - ), - 'array' - ))); - $answer='0101'; - $v=$this->send($f); - if($v) - { - $sz=$v->arraysize(); - $got=''; - for($i=0; $i<$sz; $i++) - { - $b=$v->arraymem($i); - if($b->scalarval()) - { - $got.='1'; - } - else - { - $got.='0'; - } - } - $this->assertEquals($answer, $got); - } - } - - function testBase64() - { - $sendstring='Mary had a little lamb, -Whose fleece was white as snow, -And everywhere that Mary went -the lamb was sure to go. - -Mary had a little lamb -She tied it to a pylon -Ten thousand volts went down its back -And turned it into nylon'; - $f=new xmlrpcmsg('examples.decode64',array( - new xmlrpcval($sendstring, 'base64') - )); - $v=$this->send($f); - if($v) - { - if (strlen($sendstring) == strlen($v->scalarval())) - $this->assertEquals($sendstring, $v->scalarval()); - else - $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendstring), $v->scalarval()); - } - } - - function testDateTime() - { - $time = time(); - $t1 = new xmlrpcval($time, 'dateTime.iso8601'); - $t2 = new xmlrpcval(iso8601_encode($time), 'dateTime.iso8601'); - $this->assertEquals($t1->serialize(), $t2->serialize()); - if (class_exists('DateTime')) - { - $datetime = new DateTime(); - // skip this test for php 5.2. It is a bit harder there to build a DateTime from unix timestamp with proper TZ info - if(is_callable(array($datetime,'setTimestamp'))) - { - $t3 = new xmlrpcval($datetime->setTimestamp($time), 'dateTime.iso8601'); - $this->assertEquals($t1->serialize(), $t3->serialize()); - } - } - } - - function testCountEntities() - { - $sendstring = "h'fd>onc>>l>>rw&bpu>q>esend($f); - if($v) - { - $got = ''; - $expected = '37210'; - $expect_array = array('ctLeftAngleBrackets','ctRightAngleBrackets','ctAmpersands','ctApostrophes','ctQuotes'); - while(list(,$val) = each($expect_array)) - { - $b = $v->structmem($val); - $got .= $b->me['int']; - } - $this->assertEquals($expected, $got); - } - } - - function _multicall_msg($method, $params) - { - $struct['methodName'] = new xmlrpcval($method, 'string'); - $struct['params'] = new xmlrpcval($params, 'array'); - return new xmlrpcval($struct, 'struct'); - } - - function testServerMulticall() - { - // We manually construct a system.multicall() call to ensure - // that the server supports it. - - // NB: This test will NOT pass if server does not support system.multicall. - - // Based on http://xmlrpc-c.sourceforge.net/hacks/test_multicall.py - $good1 = $this->_multicall_msg( - 'system.methodHelp', - array(php_xmlrpc_encode('system.listMethods'))); - $bad = $this->_multicall_msg( - 'test.nosuch', - array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); - $recursive = $this->_multicall_msg( - 'system.multicall', - array(new xmlrpcval(array(), 'array'))); - $good2 = $this->_multicall_msg( - 'system.methodSignature', - array(php_xmlrpc_encode('system.listMethods'))); - $arg = new xmlrpcval( - array($good1, $bad, $recursive, $good2), - 'array' - ); - - $f = new xmlrpcmsg('system.multicall', array($arg)); - $v = $this->send($f); - if($v) - { - //$this->assertTrue($r->faultCode() == 0, "fault from system.multicall"); - $this->assertTrue($v->arraysize() == 4, "bad number of return values"); - - $r1 = $v->arraymem(0); - $this->assertTrue( - $r1->kindOf() == 'array' && $r1->arraysize() == 1, - "did not get array of size 1 from good1" - ); - - $r2 = $v->arraymem(1); - $this->assertTrue( - $r2->kindOf() == 'struct', - "no fault from bad" - ); - - $r3 = $v->arraymem(2); - $this->assertTrue( - $r3->kindOf() == 'struct', - "recursive system.multicall did not fail" - ); - - $r4 = $v->arraymem(3); - $this->assertTrue( - $r4->kindOf() == 'array' && $r4->arraysize() == 1, - "did not get array of size 1 from good2" - ); - } - } - - function testClientMulticall1() - { - // NB: This test will NOT pass if server does not support system.multicall. - - $this->client->no_multicall = false; - - $good1 = new xmlrpcmsg('system.methodHelp', - array(php_xmlrpc_encode('system.listMethods'))); - $bad = new xmlrpcmsg('test.nosuch', - array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); - $recursive = new xmlrpcmsg('system.multicall', - array(new xmlrpcval(array(), 'array'))); - $good2 = new xmlrpcmsg('system.methodSignature', - array(php_xmlrpc_encode('system.listMethods')) - ); - - $r = $this->send(array($good1, $bad, $recursive, $good2)); - if($r) - { - $this->assertTrue(count($r) == 4, "wrong number of return values"); - } - - $this->assertTrue($r[0]->faultCode() == 0, "fault from good1"); - if(!$r[0]->faultCode()) - { - $val = $r[0]->value(); - $this->assertTrue( - $val->kindOf() == 'scalar' && $val->scalartyp() == 'string', - "good1 did not return string" - ); - } - $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad"); - $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall"); - $this->assertTrue($r[3]->faultCode() == 0, "fault from good2"); - if(!$r[3]->faultCode()) - { - $val = $r[3]->value(); - $this->assertTrue($val->kindOf() == 'array', "good2 did not return array"); - } - // This is the only assert in this test which should fail - // if the test server does not support system.multicall. - $this->assertTrue($this->client->no_multicall == false, - "server does not support system.multicall" - ); - } - - function testClientMulticall2() - { - // NB: This test will NOT pass if server does not support system.multicall. - - $this->client->no_multicall = true; - - $good1 = new xmlrpcmsg('system.methodHelp', - array(php_xmlrpc_encode('system.listMethods'))); - $bad = new xmlrpcmsg('test.nosuch', - array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); - $recursive = new xmlrpcmsg('system.multicall', - array(new xmlrpcval(array(), 'array'))); - $good2 = new xmlrpcmsg('system.methodSignature', - array(php_xmlrpc_encode('system.listMethods')) - ); - - $r = $this->send(array($good1, $bad, $recursive, $good2)); - if($r) - { - $this->assertTrue(count($r) == 4, "wrong number of return values"); - } - - $this->assertTrue($r[0]->faultCode() == 0, "fault from good1"); - if(!$r[0]->faultCode()) - { - $val = $r[0]->value(); - $this->assertTrue( - $val->kindOf() == 'scalar' && $val->scalartyp() == 'string', - "good1 did not return string"); - } - $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad"); - $this->assertTrue($r[2]->faultCode() == 0, "fault from (non recursive) system.multicall"); - $this->assertTrue($r[3]->faultCode() == 0, "fault from good2"); - if(!$r[3]->faultCode()) - { - $val = $r[3]->value(); - $this->assertTrue($val->kindOf() == 'array', "good2 did not return array"); - } - } - - function testClientMulticall3() - { - // NB: This test will NOT pass if server does not support system.multicall. - - $this->client->return_type = 'phpvals'; - $this->client->no_multicall = false; - - $good1 = new xmlrpcmsg('system.methodHelp', - array(php_xmlrpc_encode('system.listMethods'))); - $bad = new xmlrpcmsg('test.nosuch', - array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); - $recursive = new xmlrpcmsg('system.multicall', - array(new xmlrpcval(array(), 'array'))); - $good2 = new xmlrpcmsg('system.methodSignature', - array(php_xmlrpc_encode('system.listMethods')) - ); - - $r = $this->send(array($good1, $bad, $recursive, $good2)); - if($r) - { - $this->assertTrue(count($r) == 4, "wrong number of return values"); - } - $this->assertTrue($r[0]->faultCode() == 0, "fault from good1"); - if(!$r[0]->faultCode()) - { - $val = $r[0]->value(); - $this->assertTrue( - is_string($val) , "good1 did not return string"); - } - $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad"); - $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall"); - $this->assertTrue($r[3]->faultCode() == 0, "fault from good2"); - if(!$r[3]->faultCode()) - { - $val = $r[3]->value(); - $this->assertTrue(is_array($val), "good2 did not return array"); - } - $this->client->return_type = 'xmlrpcvals'; - } - - function testCatchWarnings() - { - $f = new xmlrpcmsg('examples.generatePHPWarning', array( - new xmlrpcval('whatever', 'string') - )); - $v = $this->send($f); - if($v) - { - $this->assertEquals($v->scalarval(), true); - } - } - - function testCatchExceptions() - { - global $URI; - $f = new xmlrpcmsg('examples.raiseException', array( - new xmlrpcval('whatever', 'string') - )); - $v = $this->send($f, $GLOBALS['xmlrpcerr']['server_error']); - $this->client->path = $URI.'?EXCEPTION_HANDLING=1'; - $v = $this->send($f, 1); - $this->client->path = $URI.'?EXCEPTION_HANDLING=2'; - $v = $this->send($f, $GLOBALS['xmlrpcerr']['invalid_return']); - } - - function testZeroParams() - { - $f = new xmlrpcmsg('system.listMethods'); - $v = $this->send($f); - } - - function testCodeInjectionServerSide() - { - $f = new xmlrpcmsg('system.MethodHelp'); - $f->payload = "validator1.echoStructTest','')); echo('gotcha!'); die(); //"; - $v = $this->send($f); - //$v = $r->faultCode(); - if ($v) - { - $this->assertEquals(0, $v->structsize()); - } - } - - function testAutoRegisteredFunction() - { - $f=new xmlrpcmsg('examples.php.getStateName',array( - new xmlrpcval(23, 'int') - )); - $v=$this->send($f); - if($v) - { - $this->assertEquals('Michigan', $v->scalarval()); - } - else - { - $this->fail('Note: server can only auto register functions if running with PHP 5.0.3 and up'); - } - } - - function testAutoRegisteredClass() - { - $f=new xmlrpcmsg('examples.php2.getStateName',array( - new xmlrpcval(23, 'int') - )); - $v=$this->send($f); - if($v) - { - $this->assertEquals('Michigan', $v->scalarval()); - $f=new xmlrpcmsg('examples.php3.getStateName',array( - new xmlrpcval(23, 'int') - )); - $v=$this->send($f); - if($v) - { - $this->assertEquals('Michigan', $v->scalarval()); - } - } - else - { - $this->fail('Note: server can only auto register class methods if running with PHP 5.0.3 and up'); - } - } - - function testAutoRegisteredMethod() - { - // make a 'deep client copy' as the original one might have many properties set - $func=wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 1)); - if($func == '') - { - $this->fail('Registration of examples.getStateName failed'); - } - else - { - $v=$func(23); - // work around bug in current version of phpunit - if(is_object($v)) - { - $v = var_export($v, true); - } - $this->assertEquals('Michigan', $v); - } - } - - function testGetCookies() - { - // let server set to us some cookies we tell it - $cookies = array( - //'c1' => array(), - 'c2' => array('value' => 'c2'), - 'c3' => array('value' => 'c3', 'expires' => time()+60*60*24*30), - 'c4' => array('value' => 'c4', 'expires' => time()+60*60*24*30, 'path' => '/'), - 'c5' => array('value' => 'c5', 'expires' => time()+60*60*24*30, 'path' => '/', 'domain' => 'localhost'), - ); - $cookiesval = php_xmlrpc_encode($cookies); - $f=new xmlrpcmsg('examples.setcookies',array($cookiesval)); - $r=$this->send($f, 0, true); - if($r) - { - $v = $r->value(); - $this->assertEquals(1, $v->scalarval()); - // now check if we decoded the cookies as we had set them - $rcookies = $r->cookies(); - // remove extra cookies which might have been set by proxies - foreach($rcookies as $c => $v) - if(!in_array($c, array('c2', 'c3', 'c4', 'c5'))) - unset($rcookies[$c]); - foreach($cookies as $c => $v) - // format for date string in cookies: 'Mon, 31 Oct 2005 13:50:56 GMT' - // but PHP versions differ on that, some use 'Mon, 31-Oct-2005 13:50:56 GMT'... - if(isset($v['expires'])) - { - if (isset($rcookies[$c]['expires']) && strpos($rcookies[$c]['expires'], '-')) - { - $cookies[$c]['expires'] = gmdate('D, d\-M\-Y H:i:s \G\M\T' ,$cookies[$c]['expires']); - } - else - { - $cookies[$c]['expires'] = gmdate('D, d M Y H:i:s \G\M\T' ,$cookies[$c]['expires']); - } - } - $this->assertEquals($cookies, $rcookies); - } - } - - function testSetCookies() - { - // let server set to us some cookies we tell it - $cookies = array( - 'c0' => null, - 'c1' => 1, - 'c2' => '2 3', - 'c3' => '!@#$%^&*()_+|}{":?><,./\';[]\\=-' - ); - $f=new xmlrpcmsg('examples.getcookies',array()); - foreach ($cookies as $cookie => $val) - { - $this->client->setCookie($cookie, $val); - $cookies[$cookie] = (string) $cookies[$cookie]; - } - $r = $this->client->send($f, $this->timeout, $this->method); - $this->assertEquals($r->faultCode(), 0, 'Error '.$r->faultCode().' connecting to server: '.$r->faultString()); - if(!$r->faultCode()) - { - $v = $r->value(); - $v = php_xmlrpc_decode($v); - // on IIS and Apache getallheaders returns something slightly different... - $this->assertEquals($v, $cookies); - } - } - - function testSendTwiceSameMsg() - { - $f=new xmlrpcmsg('examples.stringecho', array( - new xmlrpcval('hello world', 'string') - )); - $v1 = $this->send($f); - $v2 = $this->send($f); - //$v = $r->faultCode(); - if ($v1 && $v2) - { - $this->assertEquals($v2, $v1); - } - } -} - -class LocalHostMultiTests extends LocalhostTests -{ - function _runtests() - { - global $failed_tests; - foreach(get_class_methods('LocalhostTests') as $meth) - { - if(strpos($meth, 'test') === 0 && $meth != 'testHttps' && $meth != 'testCatchExceptions') - { - if (!isset($failed_tests[$meth])) - { - $this->$meth(); - } - } - if ($this->_failed) - { - break; - } - } - } - - function testDeflate() - { - if(!function_exists('gzdeflate')) - { - $this->fail('Zlib missing: cannot test deflate functionality'); - return; - } - $this->client->accepted_compression = array('deflate'); - $this->client->request_compression = 'deflate'; - $this->_runtests(); - } - - function testGzip() - { - if(!function_exists('gzdeflate')) - { - $this->fail('Zlib missing: cannot test gzip functionality'); - return; - } - $this->client->accepted_compression = array('gzip'); - $this->client->request_compression = 'gzip'; - $this->_runtests(); - } - - function testKeepAlives() - { - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test http 1.1'); - return; - } - $this->method = 'http11'; - $this->client->keepalive = true; - $this->_runtests(); - } - - function testProxy() - { - global $PROXYSERVER, $PROXYPORT, $NOPROXY; - if ($PROXYSERVER) - { - $this->client->setProxy($PROXYSERVER, $PROXYPORT); - $this->_runtests(); - } - else - if (!$NOPROXY) - $this->fail('PROXY definition missing: cannot test proxy'); - } - - function testHttp11() - { - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test http 1.1'); - return; - } - $this->method = 'http11'; // not an error the double assignment! - $this->client->method = 'http11'; - //$this->client->verifyhost = 0; - //$this->client->verifypeer = 0; - $this->client->keepalive = false; - $this->_runtests(); - } - - function testHttp11Gzip() - { - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test http 1.1'); - return; - } - $this->method = 'http11'; // not an error the double assignment! - $this->client->method = 'http11'; - $this->client->keepalive = false; - $this->client->accepted_compression = array('gzip'); - $this->client->request_compression = 'gzip'; - $this->_runtests(); - } - - function testHttp11Deflate() - { - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test http 1.1'); - return; - } - $this->method = 'http11'; // not an error the double assignment! - $this->client->method = 'http11'; - $this->client->keepalive = false; - $this->client->accepted_compression = array('deflate'); - $this->client->request_compression = 'deflate'; - $this->_runtests(); - } - - function testHttp11Proxy() - { - global $PROXYSERVER, $PROXYPORT, $NOPROXY; - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test http 1.1 w. proxy'); - return; - } - else if ($PROXYSERVER == '') - { - if (!$NOPROXY) - $this->fail('PROXY definition missing: cannot test proxy w. http 1.1'); - return; - } - $this->method = 'http11'; // not an error the double assignment! - $this->client->method = 'http11'; - $this->client->setProxy($PROXYSERVER, $PROXYPORT); - //$this->client->verifyhost = 0; - //$this->client->verifypeer = 0; - $this->client->keepalive = false; - $this->_runtests(); - } - - function testHttps() - { - global $HTTPSSERVER, $HTTPSURI, $HTTPSIGNOREPEER; - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test https functionality'); - return; - } - $this->client->server = $HTTPSSERVER; - $this->method = 'https'; - $this->client->method = 'https'; - $this->client->path = $HTTPSURI; - $this->client->setSSLVerifyPeer( !$HTTPSIGNOREPEER ); - // silence warning with newish php versions - $this->client->setSSLVerifyHost(2); - $this->_runtests(); - } - - function testHttpsProxy() - { - global $HTTPSSERVER, $HTTPSURI, $PROXYSERVER, $PROXYPORT, $NOPROXY; - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test https functionality'); - return; - } - else if ($PROXYSERVER == '') - { - if (!$NOPROXY) - $this->fail('PROXY definition missing: cannot test proxy w. http 1.1'); - return; - } - $this->client->server = $HTTPSSERVER; - $this->method = 'https'; - $this->client->method = 'https'; - $this->client->setProxy($PROXYSERVER, $PROXYPORT); - $this->client->path = $HTTPSURI; - $this->_runtests(); - } - - function testUTF8Responses() - { - global $URI; - //$this->client->path = strpos($URI, '?') === null ? $URI.'?RESPONSE_ENCODING=UTF-8' : $URI.'&RESPONSE_ENCODING=UTF-8'; - $this->client->path = $URI.'?RESPONSE_ENCODING=UTF-8'; - $this->_runtests(); - } - - function testUTF8Requests() - { - $this->client->request_charset_encoding = 'UTF-8'; - $this->_runtests(); - } - - function testISOResponses() - { - global $URI; - //$this->client->path = strpos($URI, '?') === null ? $URI.'?RESPONSE_ENCODING=UTF-8' : $URI.'&RESPONSE_ENCODING=UTF-8'; - $this->client->path = $URI.'?RESPONSE_ENCODING=ISO-8859-1'; - $this->_runtests(); - } - - function testISORequests() - { - $this->client->request_charset_encoding = 'ISO-8859-1'; - $this->_runtests(); - } -} - -class ParsingBugsTests extends PHPUnit_Framework_TestCase -{ - function testMinusOneString() - { - $v=new xmlrpcval('-1'); - $u=new xmlrpcval('-1', 'string'); - $this->assertEquals($u->scalarval(), $v->scalarval()); - } - - function testUnicodeInMemberName(){ - $str = "G".chr(252)."nter, El".chr(232)."ne"; - $v = array($str => new xmlrpcval(1)); - $r = new xmlrpcresp(new xmlrpcval($v, 'struct')); - $r = $r->serialize(); - $m = new xmlrpcmsg('dummy'); - $r = $m->parseResponse($r); - $v = $r->value(); - $this->assertEquals($v->structmemexists($str), true); - } - - function testUnicodeInErrorString() - { - $response = utf8_encode( -' - - - - - - - - -faultCode -888 - - -faultString -���àüè - - - - -'); - $m=new xmlrpcmsg('dummy'); - $r=$m->parseResponse($response); - $v=$r->faultString(); - $this->assertEquals('���àüè', $v); - } - - function testValidNumbers() - { - $m=new xmlrpcmsg('dummy'); - $fp= -' - - - - - - -integer1 -01 - - -float1 -01.10 - - -integer2 -+1 - - -float2 -+1.10 - - -float3 --1.10e2 - - - - - -'; - $r=$m->parseResponse($fp); - $v=$r->value(); - $s=$v->structmem('integer1'); - $t=$v->structmem('float1'); - $u=$v->structmem('integer2'); - $w=$v->structmem('float2'); - $x=$v->structmem('float3'); - $this->assertEquals(1, $s->scalarval()); - $this->assertEquals(1.1, $t->scalarval()); - $this->assertEquals(1, $u->scalarval()); - $this->assertEquals(1.1, $w->scalarval()); - $this->assertEquals(-110.0, $x->scalarval()); - } - - function testAddScalarToStruct() - { - $v=new xmlrpcval(array('a' => 'b'), 'struct'); - // use @ operator in case error_log gets on screen - $r= @$v->addscalar('c'); - $this->assertEquals(0, $r); - } - - function testAddStructToStruct() - { - $v=new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct'); - $r=$v->addstruct(array('b' => new xmlrpcval('c'))); - $this->assertEquals(2, $v->structsize()); - $this->assertEquals(1, $r); - $r=$v->addstruct(array('b' => new xmlrpcval('b'))); - $this->assertEquals(2, $v->structsize()); - } - - function testAddArrayToArray() - { - $v=new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array'); - $r=$v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c'))); - $this->assertEquals(4, $v->arraysize()); - $this->assertEquals(1, $r); - } - - function testEncodeArray() - { - $r=range(1, 100); - $v = php_xmlrpc_encode($r); - $this->assertEquals('array', $v->kindof()); - } - - function testEncodeRecursive() - { - $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string')); - $this->assertEquals('scalar', $v->kindof()); - } - - function testBrokenRequests() - { - $s = new xmlrpc_server(); - // omitting the 'params' tag: not tolerated by the lib anymore -$f = ' - -system.methodHelp - -system.methodHelp - -'; - $r = $s->parserequest($f); - $this->assertEquals(15, $r->faultCode()); - // omitting a 'param' tag -$f = ' - -system.methodHelp - -system.methodHelp - -'; - $r = $s->parserequest($f); - $this->assertEquals(15, $r->faultCode()); - // omitting a 'value' tag -$f = ' - -system.methodHelp - -system.methodHelp - -'; - $r = $s->parserequest($f); - $this->assertEquals(15, $r->faultCode()); - } - - function testBrokenResponses() - { - $m=new xmlrpcmsg('dummy'); - //$m->debug = 1; - // omitting the 'params' tag: no more tolerated by the lib... -$f = ' - - -system.methodHelp - -'; - $r = $m->parseResponse($f); - $this->assertEquals(2, $r->faultCode()); - // omitting the 'param' tag: no more tolerated by the lib... -$f = ' - - -system.methodHelp - -'; - $r = $m->parseResponse($f); - $this->assertEquals(2, $r->faultCode()); - // omitting a 'value' tag: KO -$f = ' - - -system.methodHelp - -'; - $r = $m->parseResponse($f); - $this->assertEquals(2, $r->faultCode()); - } - - function testBuggyHttp() - { - $s = new xmlrpcmsg('dummy'); -$f = 'HTTP/1.1 100 Welcome to the jungle - -HTTP/1.0 200 OK -X-Content-Marx-Brothers: Harpo - Chico and Groucho -Content-Length: who knows? - - - - - -userid311127 -dateCreated20011126T09:17:52contenthello world. 2 newlines follow - - -and there they were.postid7414222 - - '; - $r = $s->parseResponse($f); - $v = $r->value(); - $s = $v->structmem('content'); - $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval()); - } - - function testStringBug() - { - $s = new xmlrpcmsg('dummy'); -$f = ' - - - - - - - - -success - -1 - - - -sessionID - -S300510007I - - - - - - - '; - $r = $s->parseResponse($f); - $v = $r->value(); - $s = $v->structmem('sessionID'); - $this->assertEquals('S300510007I', $s->scalarval()); - } - - function testWhiteSpace() - { - $s = new xmlrpcmsg('dummy'); -$f = 'userid311127 -dateCreated20011126T09:17:52contenthello world. 2 newlines follow - - -and there they were.postid7414222 -'; - $r = $s->parseResponse($f); - $v = $r->value(); - $s = $v->structmem('content'); - $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval()); - } - - function testDoubleDataInArrayTag() - { - $s = new xmlrpcmsg('dummy'); -$f = ' - - - -'; - $r = $s->parseResponse($f); - $v = $r->faultCode(); - $this->assertEquals(2, $v); -$f = ' -Hello world - - -'; - $r = $s->parseResponse($f); - $v = $r->faultCode(); - $this->assertEquals(2, $v); - } - - function testDoubleStuffInValueTag() - { - $s = new xmlrpcmsg('dummy'); -$f = ' -hello world - - -'; - $r = $s->parseResponse($f); - $v = $r->faultCode(); - $this->assertEquals(2, $v); -$f = ' -hello -world - -'; - $r = $s->parseResponse($f); - $v = $r->faultCode(); - $this->assertEquals(2, $v); -$f = ' -hello -hello>world - -'; - $r = $s->parseResponse($f); - $v = $r->faultCode(); - $this->assertEquals(2, $v); - } - - function testAutodecodeResponse() - { - $s = new xmlrpcmsg('dummy'); -$f = 'userid311127 -dateCreated20011126T09:17:52contenthello world. 2 newlines follow - - -and there they were.postid7414222 -'; - $r = $s->parseResponse($f, true, 'phpvals'); - $v = $r->value(); - $s = $v['content']; - $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s); - } - - function testNoDecodeResponse() - { - $s = new xmlrpcmsg('dummy'); -$f = 'userid311127 -dateCreated20011126T09:17:52contenthello world. 2 newlines follow - - -and there they were.postid7414222'; - $r = $s->parseResponse($f, true, 'xml'); - $v = $r->value(); - $this->assertEquals($f, $v); - } - - function testAutoCoDec() - { - $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00'); - $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1); - $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2); - //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'); - $v1 = php_xmlrpc_encode($data, array('auto_dates')); - $v2 = php_xmlrpc_decode_xml($v1->serialize()); - $this->assertEquals($v1, $v2); - $r1 = new xmlrpcresp($v1); - $r2 = php_xmlrpc_decode_xml($r1->serialize()); - $r2->serialize(); // needed to set internal member payload - $this->assertEquals($r1, $r2); - $m1 = new xmlrpcmsg('hello dolly', array($v1)); - $m2 = php_xmlrpc_decode_xml($m1->serialize()); - $m2->serialize(); // needed to set internal member payload - $this->assertEquals($m1, $m2); - } - - function testUTF8Request() - { - $sendstring='κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string! - $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8'; - $f = new xmlrpcval($sendstring, 'string'); - $v=$f->serialize(); - $this->assertEquals("κόσμε\n", $v); - $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1'; - } - - function testUTF8Response() - { - $s = new xmlrpcmsg('dummy'); -$f = "HTTP/1.1 200 OK\r\nContent-type: text/xml; charset=UTF-8\r\n\r\n".'userid311127 -dateCreated20011126T09:17:52content'.utf8_encode('������').'postid7414222 -'; - $r = $s->parseResponse($f, false, 'phpvals'); - $v = $r->value(); - $v = $v['content']; - $this->assertEquals("������", $v); -$f = 'userid311127 -dateCreated20011126T09:17:52content'.utf8_encode('������').'postid7414222 -'; - $r = $s->parseResponse($f, false, 'phpvals'); - $v = $r->value(); - $v = $v['content']; - $this->assertEquals("������", $v); - } - - function testUTF8IntString() - { - $v=new xmlrpcval(100, 'int'); - $s=$v->serialize('UTF-8'); - $this->assertequals("100\n", $s); - } - - function testStringInt() - { - $v=new xmlrpcval('hello world', 'int'); - $s=$v->serialize(); - $this->assertequals("0\n", $s); - } - - function testStructMemExists() - { - $v=php_xmlrpc_encode(array('hello' => 'world')); - $b=$v->structmemexists('hello'); - $this->assertequals(true, $b); - $b=$v->structmemexists('world'); - $this->assertequals(false, $b); - } - - function testNilvalue() - { - // default case: we do not accept nil values received - $v = new xmlrpcval('hello', 'null'); - $r = new xmlrpcresp($v); - $s = $r->serialize(); - $m = new xmlrpcmsg('dummy'); - $r = $m->parseresponse($s); - $this->assertequals(2, $r->faultCode()); - // enable reception of nil values - $GLOBALS['xmlrpc_null_extension'] = true; - $r = $m->parseresponse($s); - $v = $r->value(); - $this->assertequals('null', $v->scalartyp()); - // test with the apache version: EX:NIL - $GLOBALS['xmlrpc_null_apache_encoding'] = true; - // serialization - $v = new xmlrpcval('hello', 'null'); - $s = $v->serialize(); - $this->assertequals(1, preg_match( '##', $s )); - // deserialization - $r = new xmlrpcresp($v); - $s = $r->serialize(); - $r = $m->parseresponse($s); - $v = $r->value(); - $this->assertequals('null', $v->scalartyp()); - $GLOBALS['xmlrpc_null_extension'] = false; - $r = $m->parseresponse($s); - $this->assertequals(2, $r->faultCode()); - } - - function TestLocale() - { - $locale = setlocale(LC_NUMERIC, 0); - /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma... - if (setlocale(LC_NUMERIC,'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) - { - $v = new xmlrpcval(1.1, 'double'); - if (strpos($v->scalarval(), ',') == 1) - { - $r = $v->serialize(); - $this->assertequals(false, strpos($r, ',')); - } - setlocale(LC_NUMERIC, $locale); - } - } -} - -class InvalidHostTests extends PHPUnit_Framework_TestCase -{ - var $client = null; - - function setUp() - { - global $DEBUG,$LOCALSERVER; - $this->client=new xmlrpc_client('/NOTEXIST.php', $LOCALSERVER, 80); - if($DEBUG) - { - $this->client->setDebug($DEBUG); - } - } - - function test404() - { - $f = new xmlrpcmsg('examples.echo',array( - new xmlrpcval('hello', 'string') - )); - $r = $this->client->send($f, 5); - $this->assertEquals(5, $r->faultCode()); - } - - function testSrvNotFound() - { - $f = new xmlrpcmsg('examples.echo',array( - new xmlrpcval('hello', 'string') - )); - $this->client->server .= 'XXX'; - $r = $this->client->send($f, 5); - $this->assertEquals(5, $r->faultCode()); - } - - function testCurlKAErr() - { - global $LOCALSERVER, $URI; - if(!function_exists('curl_init')) - { - $this->fail('CURL missing: cannot test curl keepalive errors'); - return; - } - $f = new xmlrpcmsg('examples.stringecho',array( - new xmlrpcval('hello', 'string') - )); - // test 2 calls w. keepalive: 1st time connection ko, second time ok - $this->client->server .= 'XXX'; - $this->client->keepalive = true; - $r = $this->client->send($f, 5, 'http11'); - // in case we have a "universal dns resolver" getting in the way, we might get a 302 instead of a 404 - $this->assertTrue($r->faultCode() === 8 || $r->faultCode() == 5); - - // now test a successful connection - $server = explode(':', $LOCALSERVER); - if(count($server) > 1) - { - $this->client->port = $server[1]; - } - $this->client->server = $server[0]; - $this->client->path = $URI; - - $r = $this->client->send($f, 5, 'http11'); - $this->assertEquals(0, $r->faultCode()); - $ro = $r->value(); - is_object( $ro ) && $this->assertEquals('hello', $ro->scalarVal()); - } -} - - -$suite->addTest(new LocalhostTests('testString')); -$suite->addTest(new LocalhostTests('testAdding')); -$suite->addTest(new LocalhostTests('testAddingDoubles')); -$suite->addTest(new LocalhostTests('testInvalidNumber')); -$suite->addTest(new LocalhostTests('testBoolean')); -$suite->addTest(new LocalhostTests('testCountEntities')); -$suite->addTest(new LocalhostTests('testBase64')); -$suite->addTest(new LocalhostTests('testDateTime')); -$suite->addTest(new LocalhostTests('testServerMulticall')); -$suite->addTest(new LocalhostTests('testClientMulticall1')); -$suite->addTest(new LocalhostTests('testClientMulticall2')); -$suite->addTest(new LocalhostTests('testClientMulticall3')); -$suite->addTest(new LocalhostTests('testCatchWarnings')); -$suite->addTest(new LocalhostTests('testCatchExceptions')); -$suite->addTest(new LocalhostTests('testZeroParams')); -$suite->addTest(new LocalhostTests('testCodeInjectionServerSide')); -$suite->addTest(new LocalhostTests('testAutoRegisteredFunction')); -$suite->addTest(new LocalhostTests('testAutoRegisteredMethod')); -$suite->addTest(new LocalhostTests('testSetCookies')); -$suite->addTest(new LocalhostTests('testGetCookies')); -$suite->addTest(new LocalhostTests('testSendTwiceSameMsg')); - -$suite->addTest(new LocalhostMultiTests('testUTF8Requests')); -$suite->addTest(new LocalhostMultiTests('testUTF8Responses')); -$suite->addTest(new LocalhostMultiTests('testISORequests')); -$suite->addTest(new LocalhostMultiTests('testISOResponses')); -$suite->addTest(new LocalhostMultiTests('testGzip')); -$suite->addTest(new LocalhostMultiTests('testDeflate')); -$suite->addTest(new LocalhostMultiTests('testProxy')); -$suite->addTest(new LocalhostMultiTests('testHttp11')); -$suite->addTest(new LocalhostMultiTests('testHttp11Gzip')); -$suite->addTest(new LocalhostMultiTests('testHttp11Deflate')); -$suite->addTest(new LocalhostMultiTests('testKeepAlives')); -$suite->addTest(new LocalhostMultiTests('testHttp11Proxy')); -$suite->addTest(new LocalhostMultiTests('testHttps')); -$suite->addTest(new LocalhostMultiTests('testHttpsProxy')); - -$suite->addTest(new InvalidHostTests('test404')); -//$suite->addTest(new InvalidHostTests('testSrvNotFound')); -$suite->addTest(new InvalidHostTests('testCurlKAErr')); - -$suite->addTest(new ParsingBugsTests('testMinusOneString')); -$suite->addTest(new ParsingBugsTests('testUnicodeInMemberName')); -$suite->addTest(new ParsingBugsTests('testUnicodeInErrorString')); -$suite->addTest(new ParsingBugsTests('testValidNumbers')); -$suite->addTest(new ParsingBugsTests('testAddScalarToStruct')); -$suite->addTest(new ParsingBugsTests('testAddStructToStruct')); -$suite->addTest(new ParsingBugsTests('testAddArrayToArray')); -$suite->addTest(new ParsingBugsTests('testEncodeArray')); -$suite->addTest(new ParsingBugsTests('testEncodeRecursive')); -$suite->addTest(new ParsingBugsTests('testBrokenrequests')); -$suite->addTest(new ParsingBugsTests('testBrokenresponses')); -$suite->addTest(new ParsingBugsTests('testBuggyHttp')); -$suite->addTest(new ParsingBugsTests('testStringBug')); -$suite->addTest(new ParsingBugsTests('testWhiteSpace')); -$suite->addTest(new ParsingBugsTests('testAutodecodeResponse')); -$suite->addTest(new ParsingBugsTests('testNoDecodeResponse')); -$suite->addTest(new ParsingBugsTests('testAutoCoDec')); -$suite->addTest(new ParsingBugsTests('testUTF8Response')); -$suite->addTest(new ParsingBugsTests('testUTF8Request')); -$suite->addTest(new ParsingBugsTests('testUTF8IntString')); -$suite->addTest(new ParsingBugsTests('testStringInt')); -$suite->addTest(new ParsingBugsTests('testStructMemExists')); -$suite->addTest(new ParsingBugsTests('testDoubleDataInArrayTag')); -$suite->addTest(new ParsingBugsTests('testDoubleStuffInValueTag')); -$suite->addTest(new ParsingBugsTests('testNilValue')); -$suite->addTest(new ParsingBugsTests('testLocale')); - -$title = 'XML-RPC Unit Tests'; - -if(isset($only)) -{ - $suite = new PHPUnit_TestSuite($only); -} - -if(isset($_SERVER['REQUEST_METHOD'])) -{ - echo "\n\n\n$title\n\n\n

$title

\n"; -} -else -{ - echo "$title\n\n"; -} - -if(isset($_SERVER['REQUEST_METHOD'])) -{ - echo "

Using lib version: $xmlrpcVersion on PHP version: ".phpversion()."

\n"; - echo '

Running '.$suite->count().' tests (some of which are multiple) against servers: http://'.htmlspecialchars($LOCALSERVER.$URI).' and https://'.htmlspecialchars($HTTPSSERVER.$HTTPSURI)."\n ...

\n"; - flush(); - @ob_flush(); -} -else -{ - echo "Using lib version: $xmlrpcVersion on PHP version: ".phpversion()."\n"; - echo 'Running '.$suite->count().' tests (some of which are multiple) against servers: http://'.$LOCALSERVER.$URI.' and https://'.$HTTPSSERVER.$HTTPSURI."\n\n"; -} - -// do some basic timing measurement -list($micro, $sec) = explode(' ', microtime()); -$start_time = $sec + $micro; - -//$PHPUnit = new PHPUnit; -//$result = $PHPUnit->run($suite, ($DEBUG == 0 ? '.' : '
')); -$result = $suite->run(); - -list($micro, $sec) = explode(' ', microtime()); -$end_time = $sec + $micro; - -if(!isset($_SERVER['REQUEST_METHOD'])) -{ - echo $result->toString()."\n"; -} - -if(isset($_SERVER['REQUEST_METHOD'])) -{ - echo '

'.$result->failureCount()." test failures

\n"; - printf("Time spent: %.2f secs
\n", $end_time - $start_time); -} -else -{ - echo $result->failureCount()." test failures\n"; - printf("Time spent: %.2f secs\n", $end_time - $start_time); -} - -if($result->failureCount() && !$DEBUG) -{ - $target = strpos($_SERVER['PHP_SELF'], '?') ? $_SERVER['PHP_SELF'].'&DEBUG=1' : $_SERVER['PHP_SELF'].'?DEBUG=1'; - $t2 = strpos($_SERVER['PHP_SELF'], '?') ? $_SERVER['PHP_SELF'].'&DEBUG=2' : $_SERVER['PHP_SELF'].'?DEBUG=2'; - if(isset($_SERVER['REQUEST_METHOD'])) - { - echo '

Run testsuite with DEBUG=1 to have more detail about tests results. Or with DEBUG=2 for even more.

'."\n"; - } - else - { - echo "Run testsuite with DEBUG=1 (or 2) to have more detail about tests results\n"; - } -} - -if(isset($_SERVER['REQUEST_METHOD'])) -{ -?> -More options... - -toHTML()."\n\n\n"; -} -else -{ - exit($result->failureCount()); -} diff --git a/tests/InvalidHostTest.php b/tests/InvalidHostTest.php new file mode 100644 index 00000000..fb89b432 --- /dev/null +++ b/tests/InvalidHostTest.php @@ -0,0 +1,82 @@ +args = argParser::getArgs(); + + $this->client = new xmlrpc_client('/NOTEXIST.php', $this->args['LOCALSERVER'], 80); + if($this->args['DEBUG']) + { + $this->client->setDebug($this->args['DEBUG']); + } + } + + function test404() + { + $f = new xmlrpcmsg('examples.echo',array( + new xmlrpcval('hello', 'string') + )); + $r = $this->client->send($f, 5); + $this->assertEquals(5, $r->faultCode()); + } + + function testSrvNotFound() + { + $f = new xmlrpcmsg('examples.echo',array( + new xmlrpcval('hello', 'string') + )); + $this->client->server .= 'XXX'; + $r = $this->client->send($f, 5); + // make sure there's no freaking catchall DNS in effect + $dnsinfo = dns_get_record($this->client->server); + if($dnsinfo) + { + $this->markTestSkipped('Seems like there is a catchall DNS in effect: host ' . $this->client->server . ' found'); + } + else + { + $this->assertEquals(5, $r->faultCode()); + } + } + + function testCurlKAErr() + { + if(!function_exists('curl_init')) + { + $this->markTestSkipped('CURL missing: cannot test curl keepalive errors'); + return; + } + $f = new xmlrpcmsg('examples.stringecho',array( + new xmlrpcval('hello', 'string') + )); + // test 2 calls w. keepalive: 1st time connection ko, second time ok + $this->client->server .= 'XXX'; + $this->client->keepalive = true; + $r = $this->client->send($f, 5, 'http11'); + // in case we have a "universal dns resolver" getting in the way, we might get a 302 instead of a 404 + $this->assertTrue($r->faultCode() === 8 || $r->faultCode() == 5); + + // now test a successful connection + $server = explode(':', $this->args['LOCALSERVER']); + if(count($server) > 1) + { + $this->client->port = $server[1]; + } + $this->client->server = $server[0]; + $this->client->path = $this->args['URI']; + + $r = $this->client->send($f, 5, 'http11'); + $this->assertEquals(0, $r->faultCode()); + $ro = $r->value(); + is_object( $ro ) && $this->assertEquals('hello', $ro->scalarVal()); + } +} diff --git a/tests/LocalhostTest.php b/tests/LocalhostTest.php new file mode 100644 index 00000000..28025244 --- /dev/null +++ b/tests/LocalhostTest.php @@ -0,0 +1,627 @@ +args = argParser::getArgs(); + + $server = explode(':', $this->args['LOCALSERVER']); + if(count($server) > 1) + { + $this->client=new xmlrpc_client(['URI'], $server[0], $server[1]); + } + else + { + $this->client=new xmlrpc_client($this->args['URI'], $this->args['LOCALSERVER']); + } + if($this->args['DEBUG']) + { + $this->client->setDebug($this->args['DEBUG']); + } + $this->client->request_compression = $this->request_compression; + $this->client->accepted_compression = $this->accepted_compression; + } + + function send($msg, $errrorcode=0, $return_response=false) + { + $r = $this->client->send($msg, $this->timeout, $this->method); + // for multicall, return directly array of responses + if(is_array($r)) + { + return $r; + } + $this->assertEquals($r->faultCode(), $errrorcode, 'Error '.$r->faultCode().' connecting to server: '.$r->faultString()); + if(!$r->faultCode()) + { + if($return_response) + return $r; + else + return $r->value(); + } + else + { + return null; + } + } + + function testString() + { + $sendstring="here are 3 \"entities\": < > & " . + "and here's a dollar sign: \$pretendvarname and a backslash too: " . chr(92) . + " - isn't that great? \\\"hackery\\\" at it's best " . + " also don't want to miss out on \$item[0]. ". + "The real weird stuff follows: CRLF here".chr(13).chr(10). + "a simple CR here".chr(13). + "a simple LF here".chr(10). + "and then LFCR".chr(10).chr(13). + "last but not least weird names: G".chr(252)."nter, El".chr(232)."ne, and an xml comment closing tag: -->"; + $f=new xmlrpcmsg('examples.stringecho', array( + new xmlrpcval($sendstring, 'string') + )); + $v=$this->send($f); + if($v) + { + // when sending/receiving non-US-ASCII encoded strings, XML says cr-lf can be normalized. + // so we relax our tests... + $l1 = strlen($sendstring); + $l2 = strlen($v->scalarval()); + if ($l1 == $l2) + $this->assertEquals($sendstring, $v->scalarval()); + else + $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendstring), $v->scalarval()); + } + } + + function testAddingDoubles() + { + // note that rounding errors mean we + // keep precision to sensible levels here ;-) + $a=12.13; $b=-23.98; + $f=new xmlrpcmsg('examples.addtwodouble',array( + new xmlrpcval($a, 'double'), + new xmlrpcval($b, 'double') + )); + $v=$this->send($f); + if($v) + { + $this->assertEquals($a+$b,$v->scalarval()); + } + } + + function testAdding() + { + $f=new xmlrpcmsg('examples.addtwo',array( + new xmlrpcval(12, 'int'), + new xmlrpcval(-23, 'int') + )); + $v=$this->send($f); + if($v) + { + $this->assertEquals(12-23, $v->scalarval()); + } + } + + function testInvalidNumber() + { + $f=new xmlrpcmsg('examples.addtwo',array( + new xmlrpcval('fred', 'int'), + new xmlrpcval("\"; exec('ls')", 'int') + )); + $v=$this->send($f); + /// @todo a fault condition should be generated here + /// by the server, which we pick up on + if($v) + { + $this->assertEquals(0, $v->scalarval()); + } + } + + function testBoolean() + { + $f=new xmlrpcmsg('examples.invertBooleans', array( + new xmlrpcval(array( + new xmlrpcval(true, 'boolean'), + new xmlrpcval(false, 'boolean'), + new xmlrpcval(1, 'boolean'), + new xmlrpcval(0, 'boolean'), + //new xmlrpcval('true', 'boolean'), + //new xmlrpcval('false', 'boolean') + ), + 'array' + ))); + $answer='0101'; + $v=$this->send($f); + if($v) + { + $sz=$v->arraysize(); + $got=''; + for($i=0; $i<$sz; $i++) + { + $b=$v->arraymem($i); + if($b->scalarval()) + { + $got.='1'; + } + else + { + $got.='0'; + } + } + $this->assertEquals($answer, $got); + } + } + + function testBase64() + { + $sendstring='Mary had a little lamb, +Whose fleece was white as snow, +And everywhere that Mary went +the lamb was sure to go. + +Mary had a little lamb +She tied it to a pylon +Ten thousand volts went down its back +And turned it into nylon'; + $f=new xmlrpcmsg('examples.decode64',array( + new xmlrpcval($sendstring, 'base64') + )); + $v=$this->send($f); + if($v) + { + if (strlen($sendstring) == strlen($v->scalarval())) + $this->assertEquals($sendstring, $v->scalarval()); + else + $this->assertEquals(str_replace(array("\r\n", "\r"), array("\n", "\n"), $sendstring), $v->scalarval()); + } + } + + function testDateTime() + { + $time = time(); + $t1 = new xmlrpcval($time, 'dateTime.iso8601'); + $t2 = new xmlrpcval(iso8601_encode($time), 'dateTime.iso8601'); + $this->assertEquals($t1->serialize(), $t2->serialize()); + if (class_exists('DateTime')) + { + $datetime = new DateTime(); + // skip this test for php 5.2. It is a bit harder there to build a DateTime from unix timestamp with proper TZ info + if(is_callable(array($datetime,'setTimestamp'))) + { + $t3 = new xmlrpcval($datetime->setTimestamp($time), 'dateTime.iso8601'); + $this->assertEquals($t1->serialize(), $t3->serialize()); + } + } + } + + function testCountEntities() + { + $sendstring = "h'fd>onc>>l>>rw&bpu>q>esend($f); + if($v) + { + $got = ''; + $expected = '37210'; + $expect_array = array('ctLeftAngleBrackets','ctRightAngleBrackets','ctAmpersands','ctApostrophes','ctQuotes'); + while(list(,$val) = each($expect_array)) + { + $b = $v->structmem($val); + $got .= $b->me['int']; + } + $this->assertEquals($expected, $got); + } + } + + function _multicall_msg($method, $params) + { + $struct['methodName'] = new xmlrpcval($method, 'string'); + $struct['params'] = new xmlrpcval($params, 'array'); + return new xmlrpcval($struct, 'struct'); + } + + function testServerMulticall() + { + // We manually construct a system.multicall() call to ensure + // that the server supports it. + + // NB: This test will NOT pass if server does not support system.multicall. + + // Based on http://xmlrpc-c.sourceforge.net/hacks/test_multicall.py + $good1 = $this->_multicall_msg( + 'system.methodHelp', + array(php_xmlrpc_encode('system.listMethods'))); + $bad = $this->_multicall_msg( + 'test.nosuch', + array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); + $recursive = $this->_multicall_msg( + 'system.multicall', + array(new xmlrpcval(array(), 'array'))); + $good2 = $this->_multicall_msg( + 'system.methodSignature', + array(php_xmlrpc_encode('system.listMethods'))); + $arg = new xmlrpcval( + array($good1, $bad, $recursive, $good2), + 'array' + ); + + $f = new xmlrpcmsg('system.multicall', array($arg)); + $v = $this->send($f); + if($v) + { + //$this->assertTrue($r->faultCode() == 0, "fault from system.multicall"); + $this->assertTrue($v->arraysize() == 4, "bad number of return values"); + + $r1 = $v->arraymem(0); + $this->assertTrue( + $r1->kindOf() == 'array' && $r1->arraysize() == 1, + "did not get array of size 1 from good1" + ); + + $r2 = $v->arraymem(1); + $this->assertTrue( + $r2->kindOf() == 'struct', + "no fault from bad" + ); + + $r3 = $v->arraymem(2); + $this->assertTrue( + $r3->kindOf() == 'struct', + "recursive system.multicall did not fail" + ); + + $r4 = $v->arraymem(3); + $this->assertTrue( + $r4->kindOf() == 'array' && $r4->arraysize() == 1, + "did not get array of size 1 from good2" + ); + } + } + + function testClientMulticall1() + { + // NB: This test will NOT pass if server does not support system.multicall. + + $this->client->no_multicall = false; + + $good1 = new xmlrpcmsg('system.methodHelp', + array(php_xmlrpc_encode('system.listMethods'))); + $bad = new xmlrpcmsg('test.nosuch', + array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); + $recursive = new xmlrpcmsg('system.multicall', + array(new xmlrpcval(array(), 'array'))); + $good2 = new xmlrpcmsg('system.methodSignature', + array(php_xmlrpc_encode('system.listMethods')) + ); + + $r = $this->send(array($good1, $bad, $recursive, $good2)); + if($r) + { + $this->assertTrue(count($r) == 4, "wrong number of return values"); + } + + $this->assertTrue($r[0]->faultCode() == 0, "fault from good1"); + if(!$r[0]->faultCode()) + { + $val = $r[0]->value(); + $this->assertTrue( + $val->kindOf() == 'scalar' && $val->scalartyp() == 'string', + "good1 did not return string" + ); + } + $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad"); + $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall"); + $this->assertTrue($r[3]->faultCode() == 0, "fault from good2"); + if(!$r[3]->faultCode()) + { + $val = $r[3]->value(); + $this->assertTrue($val->kindOf() == 'array', "good2 did not return array"); + } + // This is the only assert in this test which should fail + // if the test server does not support system.multicall. + $this->assertTrue($this->client->no_multicall == false, + "server does not support system.multicall" + ); + } + + function testClientMulticall2() + { + // NB: This test will NOT pass if server does not support system.multicall. + + $this->client->no_multicall = true; + + $good1 = new xmlrpcmsg('system.methodHelp', + array(php_xmlrpc_encode('system.listMethods'))); + $bad = new xmlrpcmsg('test.nosuch', + array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); + $recursive = new xmlrpcmsg('system.multicall', + array(new xmlrpcval(array(), 'array'))); + $good2 = new xmlrpcmsg('system.methodSignature', + array(php_xmlrpc_encode('system.listMethods')) + ); + + $r = $this->send(array($good1, $bad, $recursive, $good2)); + if($r) + { + $this->assertTrue(count($r) == 4, "wrong number of return values"); + } + + $this->assertTrue($r[0]->faultCode() == 0, "fault from good1"); + if(!$r[0]->faultCode()) + { + $val = $r[0]->value(); + $this->assertTrue( + $val->kindOf() == 'scalar' && $val->scalartyp() == 'string', + "good1 did not return string"); + } + $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad"); + $this->assertTrue($r[2]->faultCode() == 0, "fault from (non recursive) system.multicall"); + $this->assertTrue($r[3]->faultCode() == 0, "fault from good2"); + if(!$r[3]->faultCode()) + { + $val = $r[3]->value(); + $this->assertTrue($val->kindOf() == 'array', "good2 did not return array"); + } + } + + function testClientMulticall3() + { + // NB: This test will NOT pass if server does not support system.multicall. + + $this->client->return_type = 'phpvals'; + $this->client->no_multicall = false; + + $good1 = new xmlrpcmsg('system.methodHelp', + array(php_xmlrpc_encode('system.listMethods'))); + $bad = new xmlrpcmsg('test.nosuch', + array(php_xmlrpc_encode(1), php_xmlrpc_encode(2))); + $recursive = new xmlrpcmsg('system.multicall', + array(new xmlrpcval(array(), 'array'))); + $good2 = new xmlrpcmsg('system.methodSignature', + array(php_xmlrpc_encode('system.listMethods')) + ); + + $r = $this->send(array($good1, $bad, $recursive, $good2)); + if($r) + { + $this->assertTrue(count($r) == 4, "wrong number of return values"); + } + $this->assertTrue($r[0]->faultCode() == 0, "fault from good1"); + if(!$r[0]->faultCode()) + { + $val = $r[0]->value(); + $this->assertTrue( + is_string($val) , "good1 did not return string"); + } + $this->assertTrue($r[1]->faultCode() != 0, "no fault from bad"); + $this->assertTrue($r[2]->faultCode() != 0, "no fault from recursive system.multicall"); + $this->assertTrue($r[3]->faultCode() == 0, "fault from good2"); + if(!$r[3]->faultCode()) + { + $val = $r[3]->value(); + $this->assertTrue(is_array($val), "good2 did not return array"); + } + $this->client->return_type = 'xmlrpcvals'; + } + + function testCatchWarnings() + { + $f = new xmlrpcmsg('examples.generatePHPWarning', array( + new xmlrpcval('whatever', 'string') + )); + $v = $this->send($f); + if($v) + { + $this->assertEquals($v->scalarval(), true); + } + } + + function testCatchExceptions() + { + $f = new xmlrpcmsg('examples.raiseException', array( + new xmlrpcval('whatever', 'string') + )); + $v = $this->send($f, $GLOBALS['xmlrpcerr']['server_error']); + $this->client->path = $this->args['URI'].'?EXCEPTION_HANDLING=1'; + $v = $this->send($f, 1); + $this->client->path = $this->args['URI'].'?EXCEPTION_HANDLING=2'; + $v = $this->send($f, $GLOBALS['xmlrpcerr']['invalid_return']); + } + + function testZeroParams() + { + $f = new xmlrpcmsg('system.listMethods'); + $v = $this->send($f); + } + + function testCodeInjectionServerSide() + { + $f = new xmlrpcmsg('system.MethodHelp'); + $f->payload = "validator1.echoStructTest','')); echo('gotcha!'); die(); //"; + $v = $this->send($f); + //$v = $r->faultCode(); + if ($v) + { + $this->assertEquals(0, $v->structsize()); + } + } + + function testAutoRegisteredFunction() + { + $f=new xmlrpcmsg('examples.php.getStateName',array( + new xmlrpcval(23, 'int') + )); + $v=$this->send($f); + if($v) + { + $this->assertEquals('Michigan', $v->scalarval()); + } + else + { + $this->fail('Note: server can only auto register functions if running with PHP 5.0.3 and up'); + } + } + + function testAutoRegisteredClass() + { + $f=new xmlrpcmsg('examples.php2.getStateName',array( + new xmlrpcval(23, 'int') + )); + $v=$this->send($f); + if($v) + { + $this->assertEquals('Michigan', $v->scalarval()); + $f=new xmlrpcmsg('examples.php3.getStateName',array( + new xmlrpcval(23, 'int') + )); + $v=$this->send($f); + if($v) + { + $this->assertEquals('Michigan', $v->scalarval()); + } + } + else + { + $this->fail('Note: server can only auto register class methods if running with PHP 5.0.3 and up'); + } + } + + function testAutoRegisteredMethod() + { + // make a 'deep client copy' as the original one might have many properties set + $func=wrap_xmlrpc_method($this->client, 'examples.getStateName', array('simple_client_copy' => 1)); + if($func == '') + { + $this->fail('Registration of examples.getStateName failed'); + } + else + { + $v=$func(23); + // work around bug in current version of phpunit + if(is_object($v)) + { + $v = var_export($v, true); + } + $this->assertEquals('Michigan', $v); + } + } + + function testGetCookies() + { + // let server set to us some cookies we tell it + $cookies = array( + //'c1' => array(), + 'c2' => array('value' => 'c2'), + 'c3' => array('value' => 'c3', 'expires' => time()+60*60*24*30), + 'c4' => array('value' => 'c4', 'expires' => time()+60*60*24*30, 'path' => '/'), + 'c5' => array('value' => 'c5', 'expires' => time()+60*60*24*30, 'path' => '/', 'domain' => 'localhost'), + ); + $cookiesval = php_xmlrpc_encode($cookies); + $f=new xmlrpcmsg('examples.setcookies',array($cookiesval)); + $r=$this->send($f, 0, true); + if($r) + { + $v = $r->value(); + $this->assertEquals(1, $v->scalarval()); + // now check if we decoded the cookies as we had set them + $rcookies = $r->cookies(); + // remove extra cookies which might have been set by proxies + foreach($rcookies as $c => $v) + if(!in_array($c, array('c2', 'c3', 'c4', 'c5'))) + unset($rcookies[$c]); + foreach($cookies as $c => $v) + // format for date string in cookies: 'Mon, 31 Oct 2005 13:50:56 GMT' + // but PHP versions differ on that, some use 'Mon, 31-Oct-2005 13:50:56 GMT'... + if(isset($v['expires'])) + { + if (isset($rcookies[$c]['expires']) && strpos($rcookies[$c]['expires'], '-')) + { + $cookies[$c]['expires'] = gmdate('D, d\-M\-Y H:i:s \G\M\T' ,$cookies[$c]['expires']); + } + else + { + $cookies[$c]['expires'] = gmdate('D, d M Y H:i:s \G\M\T' ,$cookies[$c]['expires']); + } + } + $this->assertEquals($cookies, $rcookies); + } + } + + function testSetCookies() + { + // let server set to us some cookies we tell it + $cookies = array( + 'c0' => null, + 'c1' => 1, + 'c2' => '2 3', + 'c3' => '!@#$%^&*()_+|}{":?><,./\';[]\\=-' + ); + $f=new xmlrpcmsg('examples.getcookies',array()); + foreach ($cookies as $cookie => $val) + { + $this->client->setCookie($cookie, $val); + $cookies[$cookie] = (string) $cookies[$cookie]; + } + $r = $this->client->send($f, $this->timeout, $this->method); + $this->assertEquals($r->faultCode(), 0, 'Error '.$r->faultCode().' connecting to server: '.$r->faultString()); + if(!$r->faultCode()) + { + $v = $r->value(); + $v = php_xmlrpc_decode($v); + // on IIS and Apache getallheaders returns something slightly different... + $this->assertEquals($v, $cookies); + } + } + + function testSendTwiceSameMsg() + { + $f=new xmlrpcmsg('examples.stringecho', array( + new xmlrpcval('hello world', 'string') + )); + $v1 = $this->send($f); + $v2 = $this->send($f); + //$v = $r->faultCode(); + if ($v1 && $v2) + { + $this->assertEquals($v2, $v1); + } + } +} \ No newline at end of file diff --git a/tests/ParsingBugsTest.php b/tests/ParsingBugsTest.php new file mode 100644 index 00000000..93626c71 --- /dev/null +++ b/tests/ParsingBugsTest.php @@ -0,0 +1,502 @@ +assertEquals($u->scalarval(), $v->scalarval()); + } + + function testUnicodeInMemberName(){ + $str = "G".chr(252)."nter, El".chr(232)."ne"; + $v = array($str => new xmlrpcval(1)); + $r = new xmlrpcresp(new xmlrpcval($v, 'struct')); + $r = $r->serialize(); + $m = new xmlrpcmsg('dummy'); + $r = $m->parseResponse($r); + $v = $r->value(); + $this->assertEquals($v->structmemexists($str), true); + } + + function testUnicodeInErrorString() + { + $response = utf8_encode( + ' + + + + + + + + +faultCode +888 + + +faultString +'.chr(224).chr(252).chr(232).'àüè + + + + +'); + $m = new xmlrpcmsg('dummy'); + $r = $m->parseResponse($response); + $v = $r->faultString(); + $this->assertEquals(chr(224).chr(252).chr(232).chr(224).chr(252).chr(232), $v); + } + + function testValidNumbers() + { + $m = new xmlrpcmsg('dummy'); + $fp= + ' + + + + + + +integer1 +01 + + +float1 +01.10 + + +integer2 ++1 + + +float2 ++1.10 + + +float3 +-1.10e2 + + + + + +'; + $r=$m->parseResponse($fp); + $v=$r->value(); + $s=$v->structmem('integer1'); + $t=$v->structmem('float1'); + $u=$v->structmem('integer2'); + $w=$v->structmem('float2'); + $x=$v->structmem('float3'); + $this->assertEquals(1, $s->scalarval()); + $this->assertEquals(1.1, $t->scalarval()); + $this->assertEquals(1, $u->scalarval()); + $this->assertEquals(1.1, $w->scalarval()); + $this->assertEquals(-110.0, $x->scalarval()); + } + + function testAddScalarToStruct() + { + $v = new xmlrpcval(array('a' => 'b'), 'struct'); + // use @ operator in case error_log gets on screen + $r = @$v->addscalar('c'); + $this->assertEquals(0, $r); + } + + function testAddStructToStruct() + { + $v = new xmlrpcval(array('a' => new xmlrpcval('b')), 'struct'); + $r = $v->addstruct(array('b' => new xmlrpcval('c'))); + $this->assertEquals(2, $v->structsize()); + $this->assertEquals(1, $r); + $r = $v->addstruct(array('b' => new xmlrpcval('b'))); + $this->assertEquals(2, $v->structsize()); + } + + function testAddArrayToArray() + { + $v = new xmlrpcval(array(new xmlrpcval('a'), new xmlrpcval('b')), 'array'); + $r = $v->addarray(array(new xmlrpcval('b'), new xmlrpcval('c'))); + $this->assertEquals(4, $v->arraysize()); + $this->assertEquals(1, $r); + } + + function testEncodeArray() + { + $r = range(1, 100); + $v = php_xmlrpc_encode($r); + $this->assertEquals('array', $v->kindof()); + } + + function testEncodeRecursive() + { + $v = php_xmlrpc_encode(php_xmlrpc_encode('a simple string')); + $this->assertEquals('scalar', $v->kindof()); + } + + function testBrokenRequests() + { + $s = new xmlrpc_server(); + // omitting the 'params' tag: not tolerated by the lib anymore + $f = ' + +system.methodHelp + +system.methodHelp + +'; + $r = $s->parserequest($f); + $this->assertEquals(15, $r->faultCode()); + // omitting a 'param' tag + $f = ' + +system.methodHelp + +system.methodHelp + +'; + $r = $s->parserequest($f); + $this->assertEquals(15, $r->faultCode()); + // omitting a 'value' tag + $f = ' + +system.methodHelp + +system.methodHelp + +'; + $r = $s->parserequest($f); + $this->assertEquals(15, $r->faultCode()); + } + + function testBrokenResponses() + { + $m = new xmlrpcmsg('dummy'); + //$m->debug = 1; + // omitting the 'params' tag: no more tolerated by the lib... + $f = ' + + +system.methodHelp + +'; + $r = $m->parseResponse($f); + $this->assertEquals(2, $r->faultCode()); + // omitting the 'param' tag: no more tolerated by the lib... + $f = ' + + +system.methodHelp + +'; + $r = $m->parseResponse($f); + $this->assertEquals(2, $r->faultCode()); + // omitting a 'value' tag: KO + $f = ' + + +system.methodHelp + +'; + $r = $m->parseResponse($f); + $this->assertEquals(2, $r->faultCode()); + } + + function testBuggyHttp() + { + $s = new xmlrpcmsg('dummy'); + $f = 'HTTP/1.1 100 Welcome to the jungle + +HTTP/1.0 200 OK +X-Content-Marx-Brothers: Harpo + Chico and Groucho +Content-Length: who knows? + + + + + +userid311127 +dateCreated20011126T09:17:52contenthello world. 2 newlines follow + + +and there they were.postid7414222 + + '; + $r = $s->parseResponse($f); + $v = $r->value(); + $s = $v->structmem('content'); + $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval()); + } + + function testStringBug() + { + $s = new xmlrpcmsg('dummy'); + $f = ' + + + + + + + + +success + +1 + + + +sessionID + +S300510007I + + + + + + + '; + $r = $s->parseResponse($f); + $v = $r->value(); + $s = $v->structmem('sessionID'); + $this->assertEquals('S300510007I', $s->scalarval()); + } + + function testWhiteSpace() + { + $s = new xmlrpcmsg('dummy'); + $f = 'userid311127 +dateCreated20011126T09:17:52contenthello world. 2 newlines follow + + +and there they were.postid7414222 +'; + $r = $s->parseResponse($f); + $v = $r->value(); + $s = $v->structmem('content'); + $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s->scalarval()); + } + + function testDoubleDataInArrayTag() + { + $s = new xmlrpcmsg('dummy'); + $f = ' + + + +'; + $r = $s->parseResponse($f); + $v = $r->faultCode(); + $this->assertEquals(2, $v); + $f = ' +Hello world + + +'; + $r = $s->parseResponse($f); + $v = $r->faultCode(); + $this->assertEquals(2, $v); + } + + function testDoubleStuffInValueTag() + { + $s = new xmlrpcmsg('dummy'); + $f = ' +hello world + + +'; + $r = $s->parseResponse($f); + $v = $r->faultCode(); + $this->assertEquals(2, $v); + $f = ' +hello +world + +'; + $r = $s->parseResponse($f); + $v = $r->faultCode(); + $this->assertEquals(2, $v); + $f = ' +hello +hello>world + +'; + $r = $s->parseResponse($f); + $v = $r->faultCode(); + $this->assertEquals(2, $v); + } + + function testAutodecodeResponse() + { + $s = new xmlrpcmsg('dummy'); + $f = 'userid311127 +dateCreated20011126T09:17:52contenthello world. 2 newlines follow + + +and there they were.postid7414222 +'; + $r = $s->parseResponse($f, true, 'phpvals'); + $v = $r->value(); + $s = $v['content']; + $this->assertEquals("hello world. 2 newlines follow\n\n\nand there they were.", $s); + } + + function testNoDecodeResponse() + { + $s = new xmlrpcmsg('dummy'); + $f = 'userid311127 +dateCreated20011126T09:17:52contenthello world. 2 newlines follow + + +and there they were.postid7414222'; + $r = $s->parseResponse($f, true, 'xml'); + $v = $r->value(); + $this->assertEquals($f, $v); + } + + function testAutoCoDec() + { + $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00'); + $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1); + $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2); + //$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'); + $v1 = php_xmlrpc_encode($data, array('auto_dates')); + $v2 = php_xmlrpc_decode_xml($v1->serialize()); + $this->assertEquals($v1, $v2); + $r1 = new PhpXmlRpc\Response($v1); + $r2 = php_xmlrpc_decode_xml($r1->serialize()); + $r2->serialize(); // needed to set internal member payload + $this->assertEquals($r1, $r2); + $m1 = new PhpXmlRpc\Request('hello dolly', array($v1)); + $m2 = php_xmlrpc_decode_xml($m1->serialize()); + $m2->serialize(); // needed to set internal member payload + $this->assertEquals($m1, $m2); + } + + function testUTF8Request() + { + $sendstring='κόσμε'; // Greek word 'kosme'. NB: NOT a valid ISO8859 string! + $GLOBALS['xmlrpc_internalencoding'] = 'UTF-8'; + \PhpXmlRpc\PhpXmlRpc::importGlobals(); + $f = new xmlrpcval($sendstring, 'string'); + $v = $f->serialize(); + $this->assertEquals("κόσμε\n", $v); + $GLOBALS['xmlrpc_internalencoding'] = 'ISO-8859-1'; + \PhpXmlRpc\PhpXmlRpc::importGlobals(); + } + + function testUTF8Response() + { + $s = new xmlrpcmsg('dummy'); + $f = "HTTP/1.1 200 OK\r\nContent-type: text/xml; charset=UTF-8\r\n\r\n".'userid311127 +dateCreated20011126T09:17:52content'.utf8_encode('àüèàüè').'postid7414222 +'; + $r = $s->parseResponse($f, false, 'phpvals'); + $v = $r->value(); + $v = $v['content']; + $this->assertEquals("àüèàüè", $v); + $f = 'userid311127 +dateCreated20011126T09:17:52content'.utf8_encode('àüèàüè').'postid7414222 +'; + $r = $s->parseResponse($f, false, 'phpvals'); + $v = $r->value(); + $v = $v['content']; + $this->assertEquals("àüèàüè", $v); + } + + function testUTF8IntString() + { + $v = new xmlrpcval(100, 'int'); + $s = $v->serialize('UTF-8'); + $this->assertequals("100\n", $s); + } + + function testStringInt() + { + $v = new xmlrpcval('hello world', 'int'); + $s = $v->serialize(); + $this->assertequals("0\n", $s); + } + + function testStructMemExists() + { + $v = php_xmlrpc_encode(array('hello' => 'world')); + $b = $v->structmemexists('hello'); + $this->assertequals(true, $b); + $b = $v->structmemexists('world'); + $this->assertequals(false, $b); + } + + function testNilvalue() + { + // default case: we do not accept nil values received + $v = new xmlrpcval('hello', 'null'); + $r = new xmlrpcresp($v); + $s = $r->serialize(); + $m = new xmlrpcmsg('dummy'); + $r = $m->parseresponse($s); + $this->assertequals(2, $r->faultCode()); + // enable reception of nil values + $GLOBALS['xmlrpc_null_extension'] = true; + \PhpXmlRpc\PhpXmlRpc::importGlobals(); + $r = $m->parseresponse($s); + $v = $r->value(); + $this->assertequals('null', $v->scalartyp()); + // test with the apache version: EX:NIL + $GLOBALS['xmlrpc_null_apache_encoding'] = true; + \PhpXmlRpc\PhpXmlRpc::importGlobals(); + // serialization + $v = new xmlrpcval('hello', 'null'); + $s = $v->serialize(); + $this->assertequals(1, preg_match( '##', $s )); + // deserialization + $r = new xmlrpcresp($v); + $s = $r->serialize(); + $r = $m->parseresponse($s); + $v = $r->value(); + $this->assertequals('null', $v->scalartyp()); + $GLOBALS['xmlrpc_null_extension'] = false; + \PhpXmlRpc\PhpXmlRpc::importGlobals(); + $r = $m->parseresponse($s); + $this->assertequals(2, $r->faultCode()); + } + + function TestLocale() + { + $locale = setlocale(LC_NUMERIC, 0); + /// @todo on php 5.3/win setting locale to german does not seem to set decimal separator to comma... + if (setlocale(LC_NUMERIC,'deu', 'de_DE@euro', 'de_DE', 'de', 'ge') !== false) + { + $v = new xmlrpcval(1.1, 'double'); + if (strpos($v->scalarval(), ',') == 1) + { + $r = $v->serialize(); + $this->assertequals(false, strpos($r, ',')); + setlocale(LC_NUMERIC, $locale); + } + else + { + setlocale(LC_NUMERIC, $locale); + $this->markTestSkipped('did not find a locale which sets decimal separator to comma'); + } + } + else + { + $this->markTestSkipped('did not find a locale which sets decimal separator to comma'); + } + } +} diff --git a/tests/benchmark.php b/tests/benchmark.php new file mode 100644 index 00000000..a762e5f7 --- /dev/null +++ b/tests/benchmark.php @@ -0,0 +1,307 @@ + $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1); +$data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2); +$keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'); + +// Begin execution + +$test_results=array(); +$is_web = isset($_SERVER['REQUEST_METHOD']); +$xd = extension_loaded('xdebug') && ini_get('xdebug.profiler_enable'); +if ($xd) + $num_tests = 1; +else + $num_tests = 10; + +$title = 'XML-RPC Benchmark Tests'; + +if($is_web) +{ + echo "\n\n\n$title\n\n\n

$title

\n
\n";
+}
+else
+{
+    echo "$title\n\n";
+}
+
+if($is_web)
+{
+    echo "

Using lib version: $xmlrpcVersion on PHP version: ".phpversion()."

\n"; + if ($xd) echo "

XDEBUG profiling enabled: skipping remote tests. Trace file is: ".htmlspecialchars(xdebug_get_profiler_filename())."

\n"; + flush(); + ob_flush(); +} +else +{ + echo "Using lib version: $xmlrpcVersion on PHP version: ".phpversion()."\n"; + if ($xd) echo "XDEBUG profiling enabled: skipping remote tests\nTrace file is: ".xdebug_get_profiler_filename()."\n"; +} + +// test 'old style' data encoding vs. 'automatic style' encoding +begin_test('Data encoding (large array)', 'manual encoding'); +for ($i = 0; $i < $num_tests; $i++) +{ + $vals = array(); + for ($j = 0; $j < 10; $j++) + { + $valarray = array(); + foreach ($data[$j] as $key => $val) + { + $values = array(); + $values[] = new xmlrpcval($val[0], 'int'); + $values[] = new xmlrpcval($val[1], 'double'); + $values[] = new xmlrpcval($val[2], 'string'); + $values[] = new xmlrpcval($val[3], 'boolean'); + $values[] = new xmlrpcval($val[4], 'dateTime.iso8601'); + $values[] = new xmlrpcval($val[5], 'int'); + $values[] = new xmlrpcval($val[6], 'double'); + $values[] = new xmlrpcval($val[7], 'string'); + $values[] = new xmlrpcval($val[8], 'boolean'); + $values[] = new xmlrpcval($val[9], 'dateTime.iso8601'); + $valarray[$key] = new xmlrpcval($values, 'array'); + } + $vals[] = new xmlrpcval($valarray, 'struct'); + } + $value = new xmlrpcval($vals, 'array'); + $out = $value->serialize(); +} +end_test('Data encoding (large array)', 'manual encoding', $out); + +begin_test('Data encoding (large array)', 'automatic encoding'); +for ($i = 0; $i < $num_tests; $i++) +{ + $value = php_xmlrpc_encode($data, array('auto_dates')); + $out = $value->serialize(); +} +end_test('Data encoding (large array)', 'automatic encoding', $out); + +if (function_exists('xmlrpc_set_type')) +{ + begin_test('Data encoding (large array)', 'xmlrpc-epi encoding'); + for ($i = 0; $i < $num_tests; $i++) + { + for ($j = 0; $j < 10; $j++) + foreach ($keys as $k) + { + xmlrpc_set_type($data[$j][$k][4], 'datetime'); + xmlrpc_set_type($data[$j][$k][8], 'datetime'); + } + $out = xmlrpc_encode($data); + } + end_test('Data encoding (large array)', 'xmlrpc-epi encoding', $out); +} + +// test 'old style' data decoding vs. 'automatic style' decoding +$dummy = new xmlrpcmsg(''); +$out = new xmlrpcresp($value); +$in = ''."\n".$out->serialize(); + +begin_test('Data decoding (large array)', 'manual decoding'); +for ($i = 0; $i < $num_tests; $i++) +{ + $response = $dummy->ParseResponse($in, true); + $value = $response->value(); + $result = array(); + for ($k = 0; $k < $value->arraysize(); $k++) + { + $val1 = $value->arraymem($k); + $out = array(); + while (list($name, $val) = $val1->structeach()) + { + $out[$name] = array(); + for ($j = 0; $j < $val->arraysize(); $j++) + { + $data = $val->arraymem($j); + $out[$name][] = $data->scalarval(); + } + } // while + $result[] = $out; + } +} +end_test('Data decoding (large array)', 'manual decoding', $result); + +begin_test('Data decoding (large array)', 'automatic decoding'); +for ($i = 0; $i < $num_tests; $i++) +{ + $response = $dummy->ParseResponse($in, true, 'phpvals'); + $value = $response->value(); +} +end_test('Data decoding (large array)', 'automatic decoding', $value); + +if (function_exists('xmlrpc_decode')) +{ + begin_test('Data decoding (large array)', 'xmlrpc-epi decoding'); + for ($i = 0; $i < $num_tests; $i++) + { + $response = $dummy->ParseResponse($in, true, 'xml'); + $value = xmlrpc_decode($response->value()); + } + end_test('Data decoding (large array)', 'xmlrpc-epi decoding', $value); +} + +if (!$xd) +{ + + /// test multicall vs. many calls vs. keep-alives + $value = php_xmlrpc_encode($data1, array('auto_dates')); + $msg = new xmlrpcmsg('interopEchoTests.echoValue', array($value)); + $msgs=array(); + for ($i = 0; $i < 25; $i++) + $msgs[] = $msg; + $server = explode(':', $args['LOCALSERVER']); + if(count($server) > 1) + { + $c = new xmlrpc_client($args['URI'], $server[0], $server[1]); + } + else + { + $c = new xmlrpc_client($args['URI'], $args['LOCALSERVER']); + } + // do not interfere with http compression + $c->accepted_compression = array(); + //$c->debug=true; + + if (function_exists('gzinflate')) { + $c->accepted_compression = null; + } + begin_test('Repeated send (small array)', 'http 10'); + $response = array(); + for ($i = 0; $i < 25; $i++) + { + $resp = $c->send($msg); + $response[] = $resp->value(); + } + end_test('Repeated send (small array)', 'http 10', $response); + + if (function_exists('curl_init')) + { + begin_test('Repeated send (small array)', 'http 11 w. keep-alive'); + $response = array(); + for ($i = 0; $i < 25; $i++) + { + $resp = $c->send($msg, 10, 'http11'); + $response[] = $resp->value(); + } + end_test('Repeated send (small array)', 'http 11 w. keep-alive', $response); + + $c->keepalive = false; + begin_test('Repeated send (small array)', 'http 11'); + $response = array(); + for ($i = 0; $i < 25; $i++) + { + $resp = $c->send($msg, 10, 'http11'); + $response[] = $resp->value(); + } + end_test('Repeated send (small array)', 'http 11', $response); + } + + begin_test('Repeated send (small array)', 'multicall'); + $response = $c->send($msgs); + foreach ($response as $key =>& $val) + { + $val = $val->value(); + } + end_test('Repeated send (small array)', 'multicall', $response); + + if (function_exists('gzinflate')) + { + $c->accepted_compression = array('gzip'); + $c->request_compression = 'gzip'; + + begin_test('Repeated send (small array)', 'http 10 w. compression'); + $response = array(); + for ($i = 0; $i < 25; $i++) + { + $resp = $c->send($msg); + $response[] = $resp->value(); + } + end_test('Repeated send (small array)', 'http 10 w. compression', $response); + + if (function_exists('curl_init')) + { + begin_test('Repeated send (small array)', 'http 11 w. keep-alive and compression'); + $response = array(); + for ($i = 0; $i < 25; $i++) + { + $resp = $c->send($msg, 10, 'http11'); + $response[] = $resp->value(); + } + end_test('Repeated send (small array)', 'http 11 w. keep-alive and compression', $response); + + $c->keepalive = false; + begin_test('Repeated send (small array)', 'http 11 w. compression'); + $response = array(); + for ($i = 0; $i < 25; $i++) + { + $resp = $c->send($msg, 10, 'http11'); + $response[] = $resp->value(); + } + end_test('Repeated send (small array)', 'http 11 w. compression', $response); + } + + begin_test('Repeated send (small array)', 'multicall w. compression'); + $response = $c->send($msgs); + foreach ($response as $key =>& $val) + { + $val = $val->value(); + } + end_test('Repeated send (small array)', 'multicall w. compression', $response); + } + +} // end of 'if no xdebug profiling' + + +echo "\n"; +foreach($test_results as $test => $results) +{ + echo "\nTEST: $test\n"; + foreach ($results as $case => $data) + echo " $case: {$data['time']} secs - Output data CRC: ".crc32(serialize($data['result']))."\n"; +} + + +if($is_web) +{ + echo "\n
\n\n\n"; +} diff --git a/tests/parse_args.php b/tests/parse_args.php new file mode 100644 index 00000000..18b6bc37 --- /dev/null +++ b/tests/parse_args.php @@ -0,0 +1,143 @@ + 0, + 'LOCALSERVER' => 'localhost', + 'HTTPSSERVER' => 'gggeek.ssl.altervista.org', + 'HTTPSURI' => '/sw/xmlrpc/demo/server/server.php', + 'HTTPSIGNOREPEER' => false, + 'PROXYSERVER' => null, + 'NOPROXY' => false, + 'LOCALPATH' => __DIR__ + ); + + // check for command line vs web page input params + if(!isset($_SERVER['REQUEST_METHOD'])) + { + if(isset($argv)) + { + foreach($argv as $param) + { + $param = explode('=', $param); + if(count($param) > 1) + { + $pname = strtoupper(ltrim($param[0], '-')); + $$pname=$param[1]; + } + } + } + } + else + { + // NB: we might as well consider using $_GET stuff later on... + extract($_GET); + extract($_POST); + } + + if(isset($DEBUG)) + { + $args['DEBUG'] = intval($DEBUG); + } + if(isset($LOCALSERVER)) + { + $args['LOCALSERVER'] = $LOCALSERVER; + } + else + { + if(isset($HTTP_HOST)) + { + $args['LOCALSERVER'] = $HTTP_HOST; + } + elseif(isset($_SERVER['HTTP_HOST'])) + { + $args['LOCALSERVER'] = $_SERVER['HTTP_HOST']; + } + } + if(isset($HTTPSSERVER)) + { + $args['HTTPSSERVER'] = $HTTPSSERVER; + } + if(isset($HTTPSURI)) + { + $args['HTTPSURI'] = $HTTPSURI; + } + if(isset($HTTPSIGNOREPEER)) + { + $args['HTTPSIGNOREPEER'] = bool($HTTPSIGNOREPEER); + } + if(isset($PROXY)) + { + $arr = explode(':', $PROXY); + $args['PROXYSERVER'] = $arr[0]; + if(count($arr) > 1) + { + $args['PROXYPORT'] = $arr[1]; + } + else + { + $args['PROXYPORT'] = 8080; + } + } + // used to silence testsuite warnings about proxy code not being tested + if(isset($NOPROXY)) + { + $args['NOPROXY'] = true; + } + if(!isset($URI)) + { + // GUESTIMATE the url of local demo server + // play nice to php 3 and 4-5 in retrieving URL of server.php + /// @todo filter out query string from REQUEST_URI + if(isset($REQUEST_URI)) + { + $URI = str_replace('/tests/testsuite.php', '/demo/server/server.php', $REQUEST_URI); + $URI = str_replace('/testsuite.php', '/server.php', $URI); + $URI = str_replace('/tests/benchmark.php', '/demo/server/server.php', $URI); + $URI = str_replace('/benchmark.php', '/server.php', $URI); + } + elseif(isset($_SERVER['PHP_SELF']) && isset($_SERVER['REQUEST_METHOD'])) + { + $URI = str_replace('/tests/testsuite.php', '/demo/server/server.php', $_SERVER['PHP_SELF']); + $URI = str_replace('/testsuite.php', '/server.php', $URI); + $URI = str_replace('/tests/benchmark.php', '/demo/server/server.php', $URI); + $URI = str_replace('/benchmark.php', '/server.php', $URI); + } + else + { + $URI = '/demo/server/server.php'; + } + } + if($URI[0] != '/') + { + $URI = '/'.$URI; + } + $args['URI'] = $URI; + if(isset($LOCALPATH)) + { + $args['LOCALPATH'] =$LOCALPATH; + } + + return $args; + } + +} \ No newline at end of file diff --git a/test/verify_compat.php b/tests/verify_compat.php similarity index 100% rename from test/verify_compat.php rename to tests/verify_compat.php -- 2.47.0