From ff6b1ae76dbd2380328ec814c966c449976963b4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 7 Sep 2024 23:18:26 +0200 Subject: [PATCH] Implement request #47317: SoapServer::__getLastResponse() Convenient for debugging. --- ext/soap/php_soap.h | 3 + ext/soap/soap.c | 24 +++++++ ext/soap/soap.stub.php | 2 + ext/soap/soap_arginfo.h | 7 +- .../tests/SoapServer/__getLastResponse.phpt | 65 +++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 ext/soap/tests/SoapServer/__getLastResponse.phpt diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index 715af76faf5fb..a78734aa7f17a 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -98,6 +98,9 @@ struct _soapService { int features; int send_errors; struct _soapHeader **soap_headers_ptr; + + bool trace; + zend_string *last_response_body; }; #define SOAP_CLASS 1 diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 401fbde9d82a9..5f0a661ecba51 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -983,6 +983,11 @@ PHP_METHOD(SoapServer, __construct) } } + if ((tmp = zend_hash_find(ht, ZSTR_KNOWN(ZEND_STR_TRACE))) != NULL && + (Z_TYPE_P(tmp) == IS_TRUE || + (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 1))) { + service->trace = true; + } } else if (!wsdl) { php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode"); } @@ -1644,6 +1649,12 @@ PHP_METHOD(SoapServer, handle) sapi_add_header(cont_len, strlen(cont_len), 1); } php_write(buf, size); + if (service->trace) { + if (service->last_response_body) { + zend_string_release_ex(service->last_response_body, false); + } + service->last_response_body = zend_string_init((const char *) buf, size, false); + } xmlFree(buf); } else { sapi_add_header("HTTP/1.1 202 Accepted", sizeof("HTTP/1.1 202 Accepted")-1, 1); @@ -1752,6 +1763,16 @@ PHP_METHOD(SoapServer, addSoapHeader) } /* }}} */ +PHP_METHOD(SoapServer, __getLastResponse) +{ + soapServicePtr service; + ZEND_PARSE_PARAMETERS_NONE(); + FETCH_THIS_SERVICE_NO_BAILOUT(service); + if (service->last_response_body) { + RETURN_STR_COPY(service->last_response_body); + } +} + static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader *hdr) /* {{{ */ { int soap_version; @@ -4533,6 +4554,9 @@ static void delete_service(soapServicePtr service) /* {{{ */ zend_hash_destroy(service->class_map); FREE_HASHTABLE(service->class_map); } + if (service->last_response_body) { + zend_string_release_ex(service->last_response_body, false); + } zval_ptr_dtor(&service->soap_object); efree(service); } diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index a387c3a2d7555..82f884e24b308 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -527,6 +527,8 @@ public function addFunction($functions): void {} /** @tentative-return-type */ public function handle(?string $request = null): void {} + + public function __getLastResponse(): ?string {} } class SoapClient diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index 4f6709094dd33..ca0d2d9644e84 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 66221c42416635403ee6d49c12884e94073b67f2 */ + * Stub hash: 7712aba90b16090fbe7c124c1e3f26b2cc3e2ab2 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true") @@ -84,6 +84,9 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapServer_handl ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, request, IS_STRING, 1, "null") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SoapServer___getLastResponse, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_SoapClient___construct arginfo_class_SoapServer___construct ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___call, 0, 2, IS_MIXED, 0) @@ -152,6 +155,7 @@ ZEND_METHOD(SoapServer, setObject); ZEND_METHOD(SoapServer, getFunctions); ZEND_METHOD(SoapServer, addFunction); ZEND_METHOD(SoapServer, handle); +ZEND_METHOD(SoapServer, __getLastResponse); ZEND_METHOD(SoapClient, __construct); ZEND_METHOD(SoapClient, __call); ZEND_METHOD(SoapClient, __soapCall); @@ -204,6 +208,7 @@ static const zend_function_entry class_SoapServer_methods[] = { ZEND_ME(SoapServer, getFunctions, arginfo_class_SoapServer_getFunctions, ZEND_ACC_PUBLIC) ZEND_ME(SoapServer, addFunction, arginfo_class_SoapServer_addFunction, ZEND_ACC_PUBLIC) ZEND_ME(SoapServer, handle, arginfo_class_SoapServer_handle, ZEND_ACC_PUBLIC) + ZEND_ME(SoapServer, __getLastResponse, arginfo_class_SoapServer___getLastResponse, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/soap/tests/SoapServer/__getLastResponse.phpt b/ext/soap/tests/SoapServer/__getLastResponse.phpt new file mode 100644 index 0000000000000..83c20d3c3a49c --- /dev/null +++ b/ext/soap/tests/SoapServer/__getLastResponse.phpt @@ -0,0 +1,65 @@ +--TEST-- +Request #47317 (SoapServer::__getLastResponse) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +server = new SoapServer($wsdl, $options); + $this->server->addFunction("f"); + } + + function __doRequest($request, $location, $action, $version, $one_way = 0): string { + ob_start(); + $this->server->handle($request); + $response = ob_get_contents(); + ob_end_clean(); + return $response; + } +} + +$client = new LocalSoapClient(__DIR__."/../classmap003.wsdl", ["trace" => false]); +$client->f(); +var_dump($client->__getLastResponse()); +var_dump($client->server->__getLastResponse()); +var_dump($client->__getLastResponse() === $client->server->__getLastResponse()); + +echo "---\n"; + +$client = new LocalSoapClient(__DIR__."/../classmap003.wsdl", ["trace" => true]); +var_dump($client->__getLastResponse()); +var_dump($client->server->__getLastResponse()); +var_dump($client->__getLastResponse() === $client->server->__getLastResponse()); + +echo "---\n"; + +$client->f(); +echo $client->__getLastResponse(), "\n"; +echo $client->server->__getLastResponse(), "\n"; +var_dump($client->__getLastResponse() === $client->server->__getLastResponse()); +?> +--EXPECT-- +NULL +NULL +bool(true) +--- +NULL +NULL +bool(true) +--- + + + + + + +bool(true)