From b6526ddc6f25d57fdfaefca13c839a48cdfa0b33 Mon Sep 17 00:00:00 2001 From: gggeek Date: Wed, 8 Feb 2023 12:57:58 +0000 Subject: [PATCH] make Client more strict in case of unsupported options and more verbose in case of failing to compress the request --- NEWS.md | 5 ++++ debugger/action.php | 2 +- doc/manual/phpxmlrpc_manual.adoc | 2 +- src/Client.php | 46 +++++++++++++++++++++++--------- src/PhpXmlRpc.php | 2 ++ 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/NEWS.md b/NEWS.md index e0ba37dc..6a8f7078 100644 --- a/NEWS.md +++ b/NEWS.md @@ -62,6 +62,9 @@ * fixed: made sure all debug output goes through the logger at response parsing time (there was one printf call left) +* fixed: `Client::send` will now return an error Response when it is requested to use an auth method that it does not + support, instead of logging an error message and continuing with another auth schema. The returned error code is 20 + * fixed: when calling `Client::multicall()` with `$client->return_type = 'xml'`, the code would be always falling back to non-multicall requests @@ -94,6 +97,8 @@ * new: method `PhpXmlRpc::setLogger()`, to simplify injecting a custom logger into all classes of the library in one step +* improved: the Client is more verbose in logging issues when trying to compress a Request for sending + * improved: the `Logger` class now sports methods adhering to Psr\Log\LoggerInterface * improved: limit the size of incoming data which will be used in error responses and logged error messages, making diff --git a/debugger/action.php b/debugger/action.php index 7b6534e5..cc870758 100644 --- a/debugger/action.php +++ b/debugger/action.php @@ -570,7 +570,7 @@ if ($action) { You will need to enable the CURL extension to use the HTTPS, HTTP 1.1 and HTTP/2 transports

\n"; + echo "

You will need to enable the cURL extension to use the HTTPS, HTTP 1.1 and HTTP/2 transports

\n"; } ?> diff --git a/doc/manual/phpxmlrpc_manual.adoc b/doc/manual/phpxmlrpc_manual.adoc index 76c8c78f..bd99da55 100644 --- a/doc/manual/phpxmlrpc_manual.adoc +++ b/doc/manual/phpxmlrpc_manual.adoc @@ -945,7 +945,7 @@ Standard errors returned by the library include: response to a request, but no response body follows the HTTP headers. `7` No SSL support compiled in:: This error is generated by the client when trying to send a request with HTTPS and the - CURL extension is not available to PHP. + cURL extension is not available to PHP. `8` CURL error:: This error is generated by the client when trying to send a request with HTTPS and the HTTPS communication fails. diff --git a/src/Client.php b/src/Client.php index 1113e927..f45c6a2e 100644 --- a/src/Client.php +++ b/src/Client.php @@ -905,20 +905,28 @@ class Client // Deflate request body and set appropriate request headers $encodingHdr = ''; - if (function_exists('gzdeflate') && ($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate')) { - if ($opts['request_compression'] == 'gzip') { + if ($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate') { + if ($opts['request_compression'] == 'gzip' && function_exists('gzencode')) { $a = @gzencode($payload); if ($a) { $payload = $a; $encodingHdr = "Content-Encoding: gzip\r\n"; + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzencode failure in compressing request'); } - } else { + } else if (function_exists('gzcompress')) { $a = @gzcompress($payload); if ($a) { $payload = $a; $encodingHdr = "Content-Encoding: deflate\r\n"; + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzcompress failure in compressing request'); } + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported by this PHP install'); } + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported'); } // thanks to Grant Rauscher @@ -926,8 +934,9 @@ class Client if ($opts['username'] != '') { $credentials = 'Authorization: Basic ' . base64_encode($opts['username'] . ':' . $opts['password']) . "\r\n"; if ($opts['authtype'] != 1) { - /// @todo make this a proper error, i.e. return a failure $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported with HTTP 1.0'); + return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['unsupported_option'], + PhpXmlRpc::$xmlrpcerr['unsupported_option'] . ': only Basic auth is supported with HTTP 1.0'); } } @@ -952,8 +961,9 @@ class Client $uri = 'http://' . $server . ':' . $port . $path; if ($opts['proxy_user'] != '') { if ($opts['proxy_authtype'] != 1) { - /// @todo make this a proper error, i.e. return a failure $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported with HTTP 1.0'); + return new static::$responseClass(0, PhpXmlRpc::$xmlrpcerr['unsupported_option'], + PhpXmlRpc::$xmlrpcerr['unsupported_option'] . ': only Basic auth to proxy is supported with HTTP 1.0'); } $proxyCredentials = 'Proxy-Authorization: Basic ' . base64_encode($opts['proxy_user'] . ':' . $opts['proxy_pass']) . "\r\n"; @@ -1166,6 +1176,8 @@ class Client * @param string $path * @param array $opts the keys/values match self::getOptions * @return \CurlHandle|resource|false + * + * @todo allow this method to either throw or return a Response, so that we can pass back to caller more info on errors */ protected function createCURLHandle($req, $method, $server, $port, $path, $opts) { @@ -1185,21 +1197,28 @@ class Client // Deflate request body and set appropriate request headers $encodingHdr = ''; - /// @todo test for existence of proper function, in case of polyfills - if (function_exists('gzdeflate') && ($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate')) { - if ($opts['request_compression'] == 'gzip') { + if (($opts['request_compression'] == 'gzip' || $opts['request_compression'] == 'deflate')) { + if ($opts['request_compression'] == 'gzip' && function_exists('gzencode')) { $a = @gzencode($payload); if ($a) { $payload = $a; $encodingHdr = 'Content-Encoding: gzip'; + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzencode failure in compressing request'); } - } else { + } else if (function_exists('gzcompress')) { $a = @gzcompress($payload); if ($a) { $payload = $a; $encodingHdr = 'Content-Encoding: deflate'; + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': gzcompress failure in compressing request'); } + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported by this PHP install'); } + } else { + $this->getLogger()->warning('XML-RPC: ' . __METHOD__ . ': desired request compression method is unsupported'); } if (!$opts['keepalive'] || !$this->xmlrpc_curl_handle) { @@ -1287,8 +1306,9 @@ class Client if (defined('CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE')) { curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); } else { - /// @todo make this a proper error, i.e. return a failure $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. HTTP2 is not supported by the current PHP/curl install'); + curl_close($curl); + return false; } break; case 'h2': @@ -1301,8 +1321,9 @@ class Client if (defined('CURLOPT_HTTPAUTH')) { curl_setopt($curl, CURLOPT_HTTPAUTH, $opts['authtype']); } elseif ($opts['authtype'] != 1) { - /// @todo make this a proper error, i.e. return a failure $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth is supported by the current PHP/curl install'); + curl_close($curl); + return false; } } @@ -1351,8 +1372,9 @@ class Client if (defined('CURLOPT_PROXYAUTH')) { curl_setopt($curl, CURLOPT_PROXYAUTH, $opts['proxy_authtype']); } elseif ($opts['proxy_authtype'] != 1) { - /// @todo make this a proper error, i.e. return a failure $this->getLogger()->error('XML-RPC: ' . __METHOD__ . ': warning. Only Basic auth to proxy is supported by the current PHP/curl install'); + curl_close($curl); + return false; } } } diff --git a/src/PhpXmlRpc.php b/src/PhpXmlRpc.php index fea0b123..4e8cd47f 100644 --- a/src/PhpXmlRpc.php +++ b/src/PhpXmlRpc.php @@ -36,6 +36,7 @@ class PhpXmlRpc 'multicall_noparams' => 13, // client 'multicall_notarray' => 14, // client 'no_http2' => 19, // client + 'unsupported_option' => 20, // client // the following 3 are meant to give greater insight than 'invalid_return'. They use the same code for BC, // but you can override their value in your own code 'invalid_xml' => 2, // client @@ -74,6 +75,7 @@ class PhpXmlRpc 'multicall_noparams' => 'Missing params', 'multicall_notarray' => 'params is not an array', 'no_http2' => 'No HTTP/2 support compiled in', + 'unsupported_option' => 'Some client option is not supported with the transport method currently in use', // the following 3 are meant to give greater insight than 'invalid_return'. They use the same string for BC, // but you can override their value in your own code 'invalid_xml' => 'Invalid response payload (you can use the setDebug method to allow analysis of the response)', -- 2.47.0