Skip to content
Browse files

MDL-32949 return exception errorcode from the REST/SOAP/XMLRPC servers

  • Loading branch information...
1 parent 71d7bc3 commit 506df9acbfc75f7e03927cb92601ed0caef75499 @mouneyrac mouneyrac committed May 15, 2012
Showing with 101 additions and 6 deletions.
  1. +3 −0 webservice/rest/locallib.php
  2. +85 −5 webservice/soap/locallib.php
  3. +13 −1 webservice/xmlrpc/locallib.php
View
3 webservice/rest/locallib.php
@@ -140,6 +140,7 @@ protected function generate_error($ex) {
if ($this->restformat == 'json') {
$errorobject = new stdClass;
$errorobject->exception = get_class($ex);
+ $errorobject->errorcode = $ex->errorcode;
$errorobject->message = $ex->getMessage();
if (debugging() and isset($ex->debuginfo)) {
$errorobject->debuginfo = $ex->debuginfo;
@@ -148,6 +149,8 @@ protected function generate_error($ex) {
} else {
$error = '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
$error .= '<EXCEPTION class="'.get_class($ex).'">'."\n";
+ $error .= '<ERRORCODE>' . htmlspecialchars($ex->errorcode, ENT_COMPAT, 'UTF-8')
+ . '</ERRORCODE>' . "\n";
$error .= '<MESSAGE>'.htmlspecialchars($ex->getMessage(), ENT_COMPAT, 'UTF-8').'</MESSAGE>'."\n";
if (debugging() and isset($ex->debuginfo)) {
$error .= '<DEBUGINFO>'.htmlspecialchars($ex->debuginfo, ENT_COMPAT, 'UTF-8').'</DEBUGINFO>'."\n";
View
90 webservice/soap/locallib.php
@@ -41,8 +41,7 @@ class moodle_zend_soap_server extends Zend_Soap_Server {
*
* Note that the arguments are the reverse of those used by SoapFault.
*
- * Moodle note: the difference with the Zend server is that we throw a SoapFault exception
- * with the debuginfo integrated in the exception message when DEBUG >= NORMAL
+ * Moodle note: basically we return the faultactor (errorcode) and faultdetails (debuginfo)
*
* If an exception is passed as the first argument, its message and code
* will be used to create the fault object if it has been registered via
@@ -55,15 +54,96 @@ class moodle_zend_soap_server extends Zend_Soap_Server {
*/
public function fault($fault = null, $code = "Receiver")
{
- //intercept any exceptions with debug info and transform it in Moodle exception
+
+ //run the zend code that clean/create a soapfault
+ $soapfault = parent::fault($fault, $code);
+
+ //intercept any exceptions and add the errorcode and debuginfo (optional)
+ $actor = null;
+ $details = null;
if ($fault instanceof Exception) {
//add the debuginfo to the exception message if debuginfo must be returned
+ $actor = $fault->errorcode;
if (debugging() and isset($fault->debuginfo)) {
- $fault = new SoapFault('Receiver', $fault->getMessage() . ' | DEBUG INFO: ' . $fault->debuginfo);
+ $details = $fault->debuginfo;
}
}
- return parent::fault($fault, $code);
+ return new SoapFault($soapfault->faultcode,
+ $soapfault->getMessage() . ' | ERRORCODE: ' . $fault->errorcode,
+ $actor, $details);
+ }
+
+ /**
+ * NOTE: this is basically a copy of the Zend handle()
+ * but with $soap->fault returning faultactor + faultdetail
+ *
+ * Handle a request
+ *
+ * Instantiates SoapServer object with options set in object, and
+ * dispatches its handle() method.
+ *
+ * $request may be any of:
+ * - DOMDocument; if so, then cast to XML
+ * - DOMNode; if so, then grab owner document and cast to XML
+ * - SimpleXMLElement; if so, then cast to XML
+ * - stdClass; if so, calls __toString() and verifies XML
+ * - string; if so, verifies XML
+ *
+ * If no request is passed, pulls request using php:://input (for
+ * cross-platform compatability purposes).
+ *
+ * @param DOMDocument|DOMNode|SimpleXMLElement|stdClass|string $request Optional request
+ * @return void|string
+ */
+ public function handle($request = null)
+ {
+ if (null === $request) {
+ $request = file_get_contents('php://input');
+ }
+
+ // Set Zend_Soap_Server error handler
+ $displayErrorsOriginalState = $this->_initializeSoapErrorContext();
+
+ $setRequestException = null;
+ /**
+ * @see Zend_Soap_Server_Exception
+ */
+ require_once 'Zend/Soap/Server/Exception.php';
+ try {
+ $this->_setRequest($request);
+ } catch (Zend_Soap_Server_Exception $e) {
+ $setRequestException = $e;
+ }
+
+ $soap = $this->_getSoap();
+
+ ob_start();
+ if($setRequestException instanceof Exception) {
+ // Send SOAP fault message if we've catched exception
+ $soap->fault("Sender", $setRequestException->getMessage());
+ } else {
+ try {
+ $soap->handle($request);
+ } catch (Exception $e) {
+ $fault = $this->fault($e);
+ $faultactor = isset($fault->faultactor) ? $fault->faultactor : null;
+ $detail = isset($fault->detail) ? $fault->detail : null;
+ $soap->fault($fault->faultcode, $fault->faultstring, $faultactor, $detail);
+ }
+ }
+ $this->_response = ob_get_clean();
+
+ // Restore original error handler
+ restore_error_handler();
+ ini_set('display_errors', $displayErrorsOriginalState);
+
+ if (!$this->_returnResponse) {
+ echo $this->_response;
+ return;
+ }
+
+ return $this->_response;
}
}
View
14 webservice/xmlrpc/locallib.php
@@ -50,9 +50,21 @@ public function fault($fault = null, $code = 404)
{
//intercept any exceptions with debug info and transform it in Moodle exception
if ($fault instanceof Exception) {
+ // code php exception must be a long
+ // we obtain a hash of the errorcode, and then to get an integer hash
+ $code = base_convert(md5($fault->errorcode), 16, 10);
+ // code php exception being a long, it has a maximum number of digits.
+ // we strip the $code to 8 digits, and hope for no error code collisions.
+ // Collisions should be pretty rare, and if needed the client can retrieve
+ // the accurate errorcode from the last | in the exception message.
+ $code = substr($code, 0, 8);
//add the debuginfo to the exception message if debuginfo must be returned
if (debugging() and isset($fault->debuginfo)) {
- $fault = new Exception($fault->getMessage() . ' | DEBUG INFO: ' . $fault->debuginfo, 0);
+ $fault = new Exception($fault->getMessage() . ' | DEBUG INFO: ' . $fault->debuginfo
+ . ' | ERRORCODE: ' . $fault->errorcode, $code);
+ } else {
+ $fault = new Exception($fault->getMessage()
+ . ' | ERRORCODE: ' . $fault->errorcode, $code);
}
}

0 comments on commit 506df9a

Please sign in to comment.
Something went wrong with that request. Please try again.