In some of my Web Service methods I need to report server errors using services_error() calls.
This calls soap_server_server_error($message) which returns a NuSOAP nusoap_fault() object
which, if you call serialize() on it, results in a perfect XML representation of the SOAP-ENV:Fault

Unfortunately this fault object is not handled well by soap_call_wrapper(). It tries to map the object into an array. and then map the array to XML and send this to the client as a legitimate SOAP result. Sadly this ends even less well because the generated XML is invalid.

<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<return xsi:type="SOAP-ENC:Array">
<item><title/><value/></item>
...
<item>
 <title xsi:type="xsd:string">typemap</title>
 <value><http://www.w3.org/2001/XMLSchema>         <----- What the hell?
   <string xsi:type="xsd:string">string</string>
   <boolean xsi:type="xsd:string">boolean</boolean>
   <float xsi:type="xsd:string">double</float>
   <double xsi:type="xsd:string">double</double>
   <decimal xsi:type="xsd:string">double</decimal>
   <duration xsi:type="xsd:string"></duration>
   <dateTime xsi:type="xsd:string">string</dateTime>
...

At the moment I can't see how to break out of soap_call_wrapper() and avoid the resultant array wrapping.

Comments

doobs’s picture

Sorry, that was easier than I expected. Just modify soap_call_wrapper() as below:

  if (gettype($ret) != 'object') {
    return $ret;
  }
  // new bit below
  if (get_class($ret) == 'soap_fault') {
    return $ret;
  }

  // I've found that input is not a problem as nusoap deals well with the arguments, even if they

But now my ZSI python client complains that the SOAPFault is wrong:

<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"                                    
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"                      
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"                                    
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"                           
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">                     
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode xsi:type="xsd:string">SERVER</faultcode>
<faultactor xsi:type="xsd:string"></faultactor>
<faultstring xsi:type="xsd:string">No log record for dataset name 10tdk013</faultstring>
<detail xsi:type="xsd:string"></detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope> 

ZSI.EvaluateException: Type mismatch (http://www.w3.org/2001/XMLSchema namespace) 
(got string wanted QName)
[Element trace: /SOAP-ENV:Envelope/SOAP-ENV:Body/SOAP-ENV:Fault/faultcode]
doobs’s picture

I found a way forward that ZSI seems to be happy with. I had to add QName to the nusoap_base class in nusoap.php (and/or class.nusoap_base.php) - this was a one line change.

        /**
        * XML Schema types in an array of uri => (array of xml type => php type)
        * is this legacy yet?
        * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
        * @var      array
        * @access   public
        */
        var $typemap = array(
        'http://www.w3.org/2001/XMLSchema' => array(
                'QName'=>'string',            //   <--------------------- add this line!
           'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',

Then soap_server_server_error() needed a bit of a rewrite to convince soap_fault() to serialize both the faultcode and the detail (which caused additional ZSI problems) in an acceptible manner for ZSI.

/**
 * Implementation of hook_server_error()
 */
function soap_server_server_error($message) {
  global $soap_server;
  $xsdns = &$soap_server->XMLSchemaVersion;
  $faultcode = new soapval('faultcode', 'QName', 'SOAP-ENV:SERVER','', $xsdns );
  $details = new soapval('div', 'div', '','' , $xsdns );
  $detail = new soapval('detail', 'detail', $details,'' , '' );
  $err =  new soap_fault($faultcode, '', $message,$detail);
  return $err;
}

Now the response looks like this:

<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode xsi:type="xsd:QName">SOAP-ENV:SERVER</faultcode>
<faultactor xsi:type="xsd:string"></faultactor>
<faultstring xsi:type="xsd:string">No log record for dataset name 10tdk013</faultstring>
<detail><div xsi:type="xsd:string"></div></detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>