Skip to content

ext/soap: Various refactorings #14579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 94 additions & 56 deletions ext/soap/soap.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,41 +703,61 @@ PHP_METHOD(SoapFault, __construct)
/* {{{ SoapFault constructor */
PHP_METHOD(SoapFault, __toString)
{
zval *faultcode, *faultstring, *file, *line, trace, rv1, rv2, rv3, rv4;
zend_string *str;
zval *this_ptr;
zend_string *faultcode_val, *faultstring_val, *file_val;
zend_long line_val;
zval *line, rv1, rv2, rv3, rv4, rv5;

if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}

this_ptr = ZEND_THIS;
faultcode = zend_read_property(soap_fault_class_entry, Z_OBJ_P(this_ptr), "faultcode", sizeof("faultcode")-1, 1, &rv1);
faultstring = zend_read_property(soap_fault_class_entry, Z_OBJ_P(this_ptr), "faultstring", sizeof("faultstring")-1, 1, &rv2);
file = zend_read_property_ex(soap_fault_class_entry, Z_OBJ_P(this_ptr), ZSTR_KNOWN(ZEND_STR_FILE), /* silent */ true, &rv3);
line = zend_read_property_ex(soap_fault_class_entry, Z_OBJ_P(this_ptr), ZSTR_KNOWN(ZEND_STR_LINE), /* silent */ true, &rv4);
zval *this_ptr = ZEND_THIS;

zend_call_method_with_0_params(
Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), NULL, "gettraceasstring", &trace);
/* SoapFault uses typed properties */
const zval *faultcode = zend_read_property(soap_fault_class_entry, Z_OBJ_P(this_ptr), "faultcode", sizeof("faultcode")-1, /* silent */ true, &rv1);
const zend_string *faultcode_val;
if (EXPECTED(Z_TYPE_P(faultcode) == IS_STRING)) {
faultcode_val = Z_STR_P(faultcode);
} else {
ZEND_ASSERT(Z_TYPE_P(faultcode) == IS_NULL);
faultcode_val = zend_empty_string;
}

faultcode_val = zval_get_string(faultcode);
faultstring_val = zval_get_string(faultstring);
file_val = zval_get_string(file);
line_val = zval_get_long(line);
convert_to_string(&trace);
const zval *faultstring = zend_read_property(soap_fault_class_entry, Z_OBJ_P(this_ptr), "faultstring", sizeof("faultstring")-1, /* silent */ true, &rv2);
const zend_string *faultstring_val;
if (EXPECTED(Z_TYPE_P(faultstring) == IS_STRING)) {
faultstring_val = Z_STR_P(faultstring);
} else {
ZEND_ASSERT(Z_TYPE_P(faultstring) == IS_NULL);
faultstring_val = zend_empty_string;
}

/* Exception uses typed properties */
const zval *file = zend_read_property_ex(soap_fault_class_entry, Z_OBJ_P(this_ptr), ZSTR_KNOWN(ZEND_STR_FILE), /* silent */ true, &rv3);
ZEND_ASSERT(Z_TYPE_P(file) == IS_STRING);
const zend_string *file_val = Z_STR_P(file);

str = strpprintf(0, "SoapFault exception: [%s] %s in %s:" ZEND_LONG_FMT "\nStack trace:\n%s",
ZSTR_VAL(faultcode_val), ZSTR_VAL(faultstring_val), ZSTR_VAL(file_val), line_val,
Z_STRLEN(trace) ? Z_STRVAL(trace) : "#0 {main}\n");
line = zend_read_property_ex(soap_fault_class_entry, Z_OBJ_P(this_ptr), ZSTR_KNOWN(ZEND_STR_LINE), /* silent */ true, &rv4);
ZEND_ASSERT(Z_TYPE_P(line) == IS_LONG);
zend_long line_val = Z_LVAL_P(line);

/* Grab private $trace property from base Exception class */
zval *trace = zend_read_property_ex(zend_ce_exception, Z_OBJ_P(this_ptr), ZSTR_KNOWN(ZEND_STR_TRACE), /* silent */ true, &rv5);
ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
zend_string *trace_str = zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true);

size_t max_length = ZSTR_LEN(faultcode_val)
+ ZSTR_LEN(faultstring_val)
+ ZSTR_LEN(file_val)
+ ZSTR_LEN(trace_str)
+ sizeof("9223372036854775807")
+ sizeof("SoapFault exception: [] in :\nStack trace:\n");
zend_string *str = strpprintf(max_length,
"SoapFault exception: [%s] %s in %s:" ZEND_LONG_FMT "\nStack trace:\n%s",
ZSTR_VAL(faultcode_val), ZSTR_VAL(faultstring_val), ZSTR_VAL(file_val), line_val, ZSTR_VAL(trace_str)
);

zend_string_release_ex(file_val, 0);
zend_string_release_ex(faultstring_val, 0);
zend_string_release_ex(faultcode_val, 0);
zval_ptr_dtor(&trace);
zend_string_release(trace_str);

RETVAL_STR(str);
RETURN_NEW_STR(str);
}
/* }}} */

Expand Down Expand Up @@ -900,8 +920,6 @@ PHP_METHOD(SoapServer, __construct)
RETURN_THROWS();
}

SOAP_SERVER_BEGIN_CODE();

service = emalloc(sizeof(soapService));
memset(service, 0, sizeof(soapService));
service->send_errors = 1;
Expand All @@ -914,18 +932,19 @@ PHP_METHOD(SoapServer, __construct)

if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
if (Z_TYPE_P(tmp) == IS_LONG &&
(Z_LVAL_P(tmp) == SOAP_1_1 || Z_LVAL_P(tmp) == SOAP_1_2)) {
(Z_LVAL_P(tmp) == SOAP_1_1 || Z_LVAL_P(tmp) == SOAP_1_2)) {
version = Z_LVAL_P(tmp);
} else {
php_error_docref(NULL, E_ERROR, "'soap_version' option must be SOAP_1_1 or SOAP_1_2");
zend_argument_value_error(2, "\"soap_version\" option must be SOAP_1_1 or SOAP_1_2");
goto error;
}
}

if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL && Z_TYPE_P(tmp) == IS_STRING) {
service->uri = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
} else if (!wsdl) {
php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
zend_argument_value_error(2, "must provide \"uri\" option as it is required in nonWSDL mode");
goto error;
}

if ((tmp = zend_hash_str_find(ht, "actor", sizeof("actor")-1)) != NULL &&
Expand All @@ -939,7 +958,8 @@ PHP_METHOD(SoapServer, __construct)

encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
if (encoding == NULL) {
php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
zend_argument_value_error(2, "provided \"encoding\" option \"%s\" is invalid", Z_STRVAL_P(tmp));
goto error;
} else {
service->encoding = encoding;
}
Expand Down Expand Up @@ -977,16 +997,27 @@ PHP_METHOD(SoapServer, __construct)
}

} else if (!wsdl) {
php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
zend_argument_value_error(2, "must provide \"uri\" option as it is required in nonWSDL mode");
goto error;
}

service->version = version;
service->type = SOAP_FUNCTIONS;
service->soap_functions.functions_all = FALSE;
service->soap_functions.ft = zend_new_array(0);

if (typemap_ht) {
service->typemap = soap_create_typemap(service->sdl, typemap_ht);
if (UNEXPECTED(service->typemap == NULL)) {
goto error;
}
}

if (wsdl) {
SOAP_SERVER_BEGIN_CODE();
service->sdl = get_sdl(ZEND_THIS, ZSTR_VAL(wsdl), cache_wsdl);
SOAP_SERVER_END_CODE();

if (service->uri == NULL) {
if (service->sdl->target_ns) {
service->uri = estrdup(service->sdl->target_ns);
Expand All @@ -997,14 +1028,13 @@ PHP_METHOD(SoapServer, __construct)
}
}

if (typemap_ht) {
service->typemap = soap_create_typemap(service->sdl, typemap_ht);
}

soap_server_object *server_obj = soap_server_object_fetch(Z_OBJ_P(ZEND_THIS));
server_obj->service = service;
return;

SOAP_SERVER_END_CODE();
error:
efree(service);
RETURN_THROWS();
}
/* }}} */

Expand Down Expand Up @@ -1951,8 +1981,6 @@ PHP_METHOD(SoapClient, __construct)
RETURN_THROWS();
}

SOAP_CLIENT_BEGIN_CODE();

cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;

if (options != NULL) {
Expand All @@ -1965,7 +1993,8 @@ PHP_METHOD(SoapClient, __construct)
Z_TYPE_P(tmp) == IS_STRING) {
ZVAL_STR_COPY(Z_CLIENT_URI_P(this_ptr), Z_STR_P(tmp));
} else {
php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
zend_argument_value_error(2, "must provide \"uri\" option as it is required in nonWSDL mode");
RETURN_THROWS();
}

if ((tmp = zend_hash_str_find(ht, "style", sizeof("style")-1)) != NULL &&
Expand Down Expand Up @@ -1993,7 +2022,8 @@ PHP_METHOD(SoapClient, __construct)
Z_TYPE_P(tmp) == IS_STRING) {
ZVAL_STR_COPY(Z_CLIENT_LOCATION_P(this_ptr), Z_STR_P(tmp));
} else if (!wsdl) {
php_error_docref(NULL, E_ERROR, "'location' option is required in nonWSDL mode");
zend_argument_value_error(2, "must provide \"location\" option as it is required in nonWSDL mode");
RETURN_THROWS();
}

if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
Expand Down Expand Up @@ -2072,7 +2102,8 @@ PHP_METHOD(SoapClient, __construct)

encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
if (encoding == NULL) {
php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
zend_argument_value_error(2, "provided \"encoding\" option \"%s\" is invalid", Z_STRVAL_P(tmp));
RETURN_THROWS();
} else {
xmlCharEncCloseFunc(encoding);
ZVAL_STR_COPY(Z_CLIENT_ENCODING_P(this_ptr), Z_STR_P(tmp));
Expand Down Expand Up @@ -2128,19 +2159,32 @@ PHP_METHOD(SoapClient, __construct)
"The \"ssl_method\" option is deprecated. "
"Use \"ssl\" stream context options instead");
}
} else if (!wsdl) {
php_error_docref(NULL, E_ERROR, "'location' and 'uri' options are required in nonWSDL mode");
}

if (options == NULL && wsdl == NULL) {
zend_argument_value_error(2, "must provide \"uri\" and \"location\" options as they are required in nonWSDL mode");
RETURN_THROWS();
}

ZVAL_LONG(Z_CLIENT_SOAP_VERSION_P(this_ptr), soap_version);

if (typemap_ht) {
HashTable *typemap = soap_create_typemap(sdl, typemap_ht);
if (UNEXPECTED(typemap == NULL)) {
RETURN_THROWS();
}
ZVAL_ARR(Z_CLIENT_TYPEMAP_P(this_ptr), typemap);
}

if (wsdl) {
int old_soap_version;

old_soap_version = SOAP_GLOBAL(soap_version);
SOAP_GLOBAL(soap_version) = soap_version;

SOAP_CLIENT_BEGIN_CODE();
sdl = get_sdl(this_ptr, ZSTR_VAL(wsdl), cache_wsdl);
SOAP_CLIENT_END_CODE();

zval *sdl_zval = Z_CLIENT_SDL_P(this_ptr);
if (Z_TYPE_P(sdl_zval) == IS_OBJECT) {
Expand All @@ -2153,14 +2197,6 @@ PHP_METHOD(SoapClient, __construct)

SOAP_GLOBAL(soap_version) = old_soap_version;
}

if (typemap_ht) {
HashTable *typemap = soap_create_typemap(sdl, typemap_ht);
if (typemap) {
ZVAL_ARR(Z_CLIENT_TYPEMAP_P(this_ptr), typemap);
}
}
SOAP_CLIENT_END_CODE();
}
/* }}} */

Expand Down Expand Up @@ -2597,7 +2633,8 @@ PHP_METHOD(SoapClient, __soapCall)
} else if (Z_TYPE_P(headers) == IS_ARRAY) {
soap_headers = Z_ARRVAL_P(headers);
if (!verify_soap_headers_array(soap_headers)) {
php_error_docref(NULL, E_ERROR, "Invalid SOAP header");
zend_argument_type_error(4, "must be on array of SoapHeader objects");
RETURN_THROWS();
}
free_soap_headers = false;
} else if (Z_TYPE_P(headers) == IS_OBJECT && instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry)) {
Expand Down Expand Up @@ -2808,7 +2845,8 @@ PHP_METHOD(SoapClient, __setSoapHeaders)
convert_to_null(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr));
} else if (Z_TYPE_P(headers) == IS_ARRAY) {
if (!verify_soap_headers_array(Z_ARRVAL_P(headers))) {
php_error_docref(NULL, E_ERROR, "Invalid SOAP header");
zend_argument_type_error(1, "must be on array of SoapHeader objects");
RETURN_THROWS();
}
zval_ptr_dtor(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr));
ZVAL_COPY(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr), headers);
Expand Down
4 changes: 2 additions & 2 deletions ext/soap/tests/SoapClient/invalid-encoding-option.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ try {

?>
--EXPECT--
SoapFault: SoapClient::__construct(): Invalid 'encoding' option - 'non-sense'
SoapFault: SoapClient::__construct(): Invalid 'encoding' option - 'non-sense'
ValueError: SoapClient::__construct(): Argument #2 ($options) provided "encoding" option "non-sense" is invalid
ValueError: SoapClient::__construct(): Argument #2 ($options) provided "encoding" option "non-sense" is invalid
12 changes: 6 additions & 6 deletions ext/soap/tests/SoapClient/missing-options-non-wsdl-mode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ try {
?>
--EXPECT--
$options not provided
SoapFault: SoapClient::__construct(): 'location' and 'uri' options are required in nonWSDL mode
SoapFault: SoapClient::__construct(): 'location' and 'uri' options are required in nonWSDL mode
ValueError: SoapClient::__construct(): Argument #2 ($options) must provide "uri" and "location" options as they are required in nonWSDL mode
ValueError: SoapClient::__construct(): Argument #2 ($options) must provide "uri" and "location" options as they are required in nonWSDL mode
Empty $options array
SoapFault: SoapClient::__construct(): 'uri' option is required in nonWSDL mode
SoapFault: SoapClient::__construct(): 'uri' option is required in nonWSDL mode
ValueError: SoapClient::__construct(): Argument #2 ($options) must provide "uri" option as it is required in nonWSDL mode
ValueError: SoapClient::__construct(): Argument #2 ($options) must provide "uri" option as it is required in nonWSDL mode
$options array only sets "uri" option
SoapFault: SoapClient::__construct(): 'location' option is required in nonWSDL mode
SoapFault: SoapClient::__construct(): 'location' option is required in nonWSDL mode
ValueError: SoapClient::__construct(): Argument #2 ($options) must provide "location" option as it is required in nonWSDL mode
ValueError: SoapClient::__construct(): Argument #2 ($options) must provide "location" option as it is required in nonWSDL mode
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ try {
}

?>
--EXPECTF--
Fatal error: SoapClient::__setSoapHeaders(): Invalid SOAP header in %s on line %d
--EXPECT--
TypeError: SoapClient::__setSoapHeaders(): Argument #1 ($headers) must be on array of SoapHeader objects
4 changes: 2 additions & 2 deletions ext/soap/tests/SoapClient/soapCall-invalid-headers.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ try {
}

?>
--EXPECTF--
Fatal error: SoapClient::__soapCall(): Invalid SOAP header in %s on line %d
--EXPECT--
TypeError: SoapClient::__soapCall(): Argument #4 ($inputHeaders) must be on array of SoapHeader objects
4 changes: 2 additions & 2 deletions ext/soap/tests/SoapServer/invalid-encoding-option.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ try {

?>
--EXPECT--
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>SoapServer::__construct(): Invalid 'encoding' option - 'non-sense'</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
ValueError: SoapServer::__construct(): Argument #2 ($options) provided "encoding" option "non-sense" is invalid
ValueError: SoapServer::__construct(): Argument #2 ($options) provided "encoding" option "non-sense" is invalid
4 changes: 2 additions & 2 deletions ext/soap/tests/SoapServer/invalid-soap_version-option.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ try {

?>
--EXPECT--
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>SoapServer::__construct(): 'soap_version' option must be SOAP_1_1 or SOAP_1_2</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
ValueError: SoapServer::__construct(): Argument #2 ($options) "soap_version" option must be SOAP_1_1 or SOAP_1_2
ValueError: SoapServer::__construct(): Argument #2 ($options) "soap_version" option must be SOAP_1_1 or SOAP_1_2
20 changes: 5 additions & 15 deletions ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,11 @@ try {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

echo "\$options array only sets \"uri\" option\n";
$options = ['uri' => 'https://example.com'];
try {
$client = new SoapServer(null, $options);
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
try {
$client = new ExtendedSoapServer(null, $options);
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

?>
--EXPECT--
$options not provided
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>SoapServer::__construct(): 'uri' option is required in nonWSDL mode</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
ValueError: SoapServer::__construct(): Argument #2 ($options) must provide "uri" option as it is required in nonWSDL mode
ValueError: SoapServer::__construct(): Argument #2 ($options) must provide "uri" option as it is required in nonWSDL mode
Empty $options array
ValueError: SoapServer::__construct(): Argument #2 ($options) must provide "uri" option as it is required in nonWSDL mode
ValueError: SoapServer::__construct(): Argument #2 ($options) must provide "uri" option as it is required in nonWSDL mode
Loading