Implement request #47317: SoapServer::__getLastResponse()

Convenient for debugging.

Closes GH-15792.
This commit is contained in:
Niels Dossche 2024-09-07 23:18:26 +02:00
parent 5048a0650a
commit 8bcfc8cc13
No known key found for this signature in database
GPG Key ID: B8A8AD166DF0E2E5
7 changed files with 106 additions and 1 deletions

1
NEWS
View File

@ -53,6 +53,7 @@ PHP NEWS
- SOAP:
. Fixed bug #61525 (SOAP functions require at least one space after HTTP
header colon). (nielsdos)
. Implement request #47317 (SoapServer::__getLastResponse()). (nielsdos)
- Standard:
. Fixed bug GH-15552 (Signed integer overflow in ext/standard/scanf.c). (cmb)

View File

@ -845,6 +845,11 @@ PHP 8.4 UPGRADE NOTES
. Added seek() method to SplObjectStorage, now it implements
SeekableIterator.
- SOAP:
. Added SoapServer::__getLastResponse(). This only tracks the last response
if the trace option is set to true in the SoapServer constructor's $options
argument.
- Standard:
. Added the http_get_last_response_headers() and
http_clear_last_response_headers() that allows retrieving the same content

View File

@ -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

View File

@ -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);
}

View File

@ -527,6 +527,8 @@ namespace {
/** @tentative-return-type */
public function handle(?string $request = null): void {}
public function __getLastResponse(): ?string {}
}
class SoapClient

View File

@ -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
};

View File

@ -0,0 +1,65 @@
--TEST--
Request #47317 (SoapServer::__getLastResponse)
--EXTENSIONS--
soap
--INI--
soap.wsdl_cache_enabled=0
--FILE--
<?php
function f() {
}
class LocalSoapClient extends SoapClient {
public $server;
function __construct($wsdl, $options) {
parent::__construct($wsdl, $options);
$this->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)
---
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:ab" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:fResponse><fReturn xsi:nil="true" xsi:type="ns1:A"/></ns1:fResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:ab" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:fResponse><fReturn xsi:nil="true" xsi:type="ns1:A"/></ns1:fResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
bool(true)