From f77b3cdaa95e804dfa21bd118dbb05363cd95048 Mon Sep 17 00:00:00 2001 From: gggeek Date: Mon, 19 Dec 2022 15:33:46 +0000 Subject: [PATCH] improve debugger support for php cli-webserver --- NEWS.md | 6 + debugger/action.php | 270 +++++++++++++++++++++------------------- debugger/controller.php | 10 +- 3 files changed, 155 insertions(+), 131 deletions(-) diff --git a/NEWS.md b/NEWS.md index e1c45eb3..96c70238 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +## XML-RPC for PHP version 4.xx.yy - unreleased + +* improved: avoid stalling the webserver when using the debugger with the php built-in webserver and testing the demo + server within the same install + + ## XML-RPC for PHP version 4.9.2 - 2022-12-18 * security fix: removed the possibility of an XSS attack in the debugger. diff --git a/debugger/action.php b/debugger/action.php index 89d58b8e..82d66980 100644 --- a/debugger/action.php +++ b/debugger/action.php @@ -94,153 +94,166 @@ include __DIR__ . '/common.php'; if ($action) { - // make sure the script waits long enough for the call to complete... - if ($timeout) { - set_time_limit($timeout + 10); + // avoid php hanging when using the builtin webserver and sending requests to itself + $skip = false; + if (php_sapi_name() === 'cli-server' && ((int)getenv('PHP_CLI_SERVER_WORKERS') < 2)) { + $localHost = explode(':', $_SERVER['HTTP_HOST']); + /// @todo support also case where port is null (on either side), and when there is a Proxy in the parameters, + /// and that proxy is us + if ($localHost[0] == $host && (@$localHost[1] == $port)) { + $actionname = '[ERROR: can not make call to self when running php-cli webserver without setting PHP_CLI_SERVER_WORKERS]'; + $skip = true; + } } - if ($wstype == 1) { - //@include 'jsonrpc.inc'; - if (!class_exists('\PhpXmlRpc\JsonRpc\Client')) { - die('Error: to debug the jsonrpc protocol the phpxmlrpc/jsonrpc package is needed'); + if (!$skip) { + // make sure the script waits long enough for the call to complete... + if ($timeout) { + set_time_limit($timeout + 10); } - $clientClass = '\PhpXmlRpc\JsonRpc\Client'; - $requestClass = '\PhpXmlRpc\JsonRpc\Request'; - $protoName = 'JSONRPC'; - } else { - $clientClass = '\PhpXmlRpc\Client'; - $requestClass = '\PhpXmlRpc\Request'; - $protoName = 'XMLRPC'; - } - if ($port != "") { - $client = new $clientClass($path, $host, $port); - $server = "$host:$port$path"; - } else { - $client = new $clientClass($path, $host); - $server = "$host$path"; - } - if ($protocol == 2 || $protocol == 3) { - $server = 'https://' . $server; - } else { - $server = 'http://' . $server; - } - if ($proxy != '') { - $pproxy = explode(':', $proxy); - if (count($pproxy) > 1) { - $pport = $pproxy[1]; + if ($wstype == 1) { + if (!class_exists('\PhpXmlRpc\JsonRpc\Client')) { + die('Error: to debug the jsonrpc protocol the phpxmlrpc/jsonrpc package is needed'); + } + $clientClass = '\PhpXmlRpc\JsonRpc\Client'; + $requestClass = '\PhpXmlRpc\JsonRpc\Request'; + $protoName = 'JSONRPC'; } else { - $pport = 8080; + $clientClass = '\PhpXmlRpc\Client'; + $requestClass = '\PhpXmlRpc\Request'; + $protoName = 'XMLRPC'; } - $client->setProxy($pproxy[0], $pport, $proxyuser, $proxypwd); - } - if ($protocol == 2 || $protocol == 3) { - $client->setSSLVerifyPeer($verifypeer); - $client->setSSLVerifyHost($verifyhost); - if ($cainfo) { - $client->setCaCertificate($cainfo); + if ($port != "") { + $client = new $clientClass($path, $host, $port); + $server = "$host:$port$path"; + } else { + $client = new $clientClass($path, $host); + $server = "$host$path"; } - if ($protocol == 3) { - $httpprotocol = 'h2'; + if ($protocol == 2 || $protocol == 3) { + $server = 'https://' . $server; } else { - $httpprotocol = 'https'; + $server = 'http://' . $server; + } + if ($proxy != '') { + $pproxy = explode(':', $proxy); + if (count($pproxy) > 1) { + $pport = $pproxy[1]; + } else { + $pport = 8080; + } + $client->setProxy($pproxy[0], $pport, $proxyuser, $proxypwd); } - } elseif ($protocol == 4) { - $httpprotocol = 'h2c'; - } elseif ($protocol == 1) { - $httpprotocol = 'http11'; - } else { - $httpprotocol = 'http'; - } - - if ($username) { - $client->setCredentials($username, $password, $authtype); - } - $client->setDebug($debug); + if ($protocol == 2 || $protocol == 3) { + $client->setSSLVerifyPeer($verifypeer); + $client->setSSLVerifyHost($verifyhost); + if ($cainfo) { + $client->setCaCertificate($cainfo); + } + if ($protocol == 3) { + $httpprotocol = 'h2'; + } else { + $httpprotocol = 'https'; + } + } elseif ($protocol == 4) { + $httpprotocol = 'h2c'; + } elseif ($protocol == 1) { + $httpprotocol = 'http11'; + } else { + $httpprotocol = 'http'; + } - switch ($requestcompression) { - case 0: - $client->request_compression = ''; - break; - case 1: - $client->request_compression = 'gzip'; - break; - case 2: - $client->request_compression = 'deflate'; - break; - } + if ($username) { + $client->setCredentials($username, $password, $authtype); + } - switch ($responsecompression) { - case 0: - $client->accepted_compression = ''; - break; - case 1: - $client->accepted_compression = array('gzip'); - break; - case 2: - $client->accepted_compression = array('deflate'); - break; - case 3: - $client->accepted_compression = array('gzip', 'deflate'); - break; - } + $client->setDebug($debug); + + switch ($requestcompression) { + case 0: + $client->request_compression = ''; + break; + case 1: + $client->request_compression = 'gzip'; + break; + case 2: + $client->request_compression = 'deflate'; + break; + } - $cookies = explode(',', $clientcookies); - foreach ($cookies as $cookie) { - if (strpos($cookie, '=')) { - $cookie = explode('=', $cookie); - $client->setCookie(trim($cookie[0]), trim(@$cookie[1])); + switch ($responsecompression) { + case 0: + $client->accepted_compression = ''; + break; + case 1: + $client->accepted_compression = array('gzip'); + break; + case 2: + $client->accepted_compression = array('deflate'); + break; + case 3: + $client->accepted_compression = array('gzip', 'deflate'); + break; } - } - $msg = array(); - switch ($action) { - // fall thru intentionally - case 'describe': - case 'wrap': - $msg[0] = new $requestClass('system.methodHelp', array(), $id); - $msg[0]->addparam(new PhpXmlRpc\Value($method)); - $msg[1] = new $requestClass('system.methodSignature', array(), (int)$id + 1); - $msg[1]->addparam(new PhpXmlRpc\Value($method)); - $actionname = 'Description of method "' . $method . '"'; - break; - case 'list': - $msg[0] = new $requestClass('system.listMethods', array(), $id); - $actionname = 'List of available methods'; - break; - case 'execute': - if (!payload_is_safe($payload)) { - die("Tsk tsk tsk, please stop it or I will have to call in the cops!"); + $cookies = explode(',', $clientcookies); + foreach ($cookies as $cookie) { + if (strpos($cookie, '=')) { + $cookie = explode('=', $cookie); + $client->setCookie(trim($cookie[0]), trim(@$cookie[1])); } - $msg[0] = new $requestClass($method, array(), $id); - // hack! build xml payload by hand - if ($wstype == 1) { - $msg[0]->payload = "{\n" . - '"method": "' . $method . "\",\n\"params\": [" . - $payload . - "\n],\n\"id\": "; - // fix: if user gave an empty string, use NULL, or we'll break json syntax - if ($id == "") { - $msg[0]->payload .= "null\n}"; - } else { - if (is_numeric($id) || $id == 'false' || $id == 'true' || $id == 'null') { - $msg[0]->payload .= "$id\n}"; + } + + $msg = array(); + switch ($action) { + // fall thru intentionally + case 'describe': + case 'wrap': + $msg[0] = new $requestClass('system.methodHelp', array(), $id); + $msg[0]->addparam(new PhpXmlRpc\Value($method)); + $msg[1] = new $requestClass('system.methodSignature', array(), (int)$id + 1); + $msg[1]->addparam(new PhpXmlRpc\Value($method)); + $actionname = 'Description of method "' . $method . '"'; + break; + case 'list': + $msg[0] = new $requestClass('system.listMethods', array(), $id); + $actionname = 'List of available methods'; + break; + case 'execute': + if (!payload_is_safe($payload)) { + die("Tsk tsk tsk, please stop it or I will have to call in the cops!"); + } + $msg[0] = new $requestClass($method, array(), $id); + // hack! build xml payload by hand + if ($wstype == 1) { + $msg[0]->payload = "{\n" . + '"method": "' . $method . "\",\n\"params\": [" . + $payload . + "\n],\n\"id\": "; + // fix: if user gave an empty string, use NULL, or we'll break json syntax + if ($id == "") { + $msg[0]->payload .= "null\n}"; } else { - $msg[0]->payload .= "\"$id\"\n}"; + if (is_numeric($id) || $id == 'false' || $id == 'true' || $id == 'null') { + $msg[0]->payload .= "$id\n}"; + } else { + $msg[0]->payload .= "\"$id\"\n}"; + } } + } else { + $msg[0]->payload = $msg[0]->xml_header($inputcharset) . + '' . $method . "\n" . + $payload . + "\n" . $msg[0]->xml_footer(); } - } else { - $msg[0]->payload = $msg[0]->xml_header($inputcharset) . - '' . $method . "\n" . - $payload . - "\n" . $msg[0]->xml_footer(); - } - $actionname = 'Execution of method ' . $method; - break; - default: // give a warning - $actionname = '[ERROR: unknown action] "' . $action . '"'; + $actionname = 'Execution of method ' . $method; + break; + default: // give a warning + $actionname = '[ERROR: unknown action] "' . $action . '"'; + } } // Before calling execute, echo out brief description of action taken + date and time ??? @@ -256,8 +269,7 @@ if ($action) { $resp = array(); $time = microtime(true); foreach ($msg as $message) { - // catch errors: for older xmlrpc libs, send does not return by ref - @$response = $client->send($message, $timeout, $httpprotocol); + $response = $client->send($message, $timeout, $httpprotocol); $resp[] = $response; if (!$response || $response->faultCode()) { break; diff --git a/debugger/controller.php b/debugger/controller.php index 88e3372d..021c9bb4 100644 --- a/debugger/controller.php +++ b/debugger/controller.php @@ -226,11 +226,17 @@ if (defined('JSXMLRPC_BASEURL')) { // use GET for ease of refresh, switch to POST when payload is too big to fit in url (in IE: 2048 bytes! see http://support.microsoft.com/kb/q208427/) function switchFormMethod() { - /// @todo use a more precise calculation, adding the rest of the fields to the actual generated url lenght + /// @todo use a more precise calculation, adding the rest of the fields to the actual generated url length - + /// retrieve first max url length for current browsers and webservers if (document.frmaction.methodpayload.value.length > 1536) { document.frmaction.action = 'action.php?usepost=true'; document.frmaction.method = 'post'; } + /*let form = document.forms[0]; + let formData = new FormData(form); + let search = new URLSearchParams(formData); + let queryString = search.toString(); + alert(queryString);alert(queryString.length);*/ } @@ -305,7 +311,7 @@ if (defined('JSXMLRPC_BASEURL')) { Timeout: - + -- 2.47.0