[dev] Horde_RPC_soap tweaks

John Morrissey jwm at horde.net
Fri May 18 18:16:51 UTC 2007


We've made some changes to Horde_RPC_soap locally to support a somewhat
substantial (~55-70k SOAP calls/day) Horde application.

I haven't been able to follow horde-cvs as much as I'd like recently, so
I'd like to bounce these changes off dev@ to make sure I'm being sane.
The patch below adds/changes three things:

1. Adds a restrictCalls parameter, a regex that calls must match to be
   allowed.
2. Adds a serviceName parameter, to specify an alternate service name
   to emit in the WSDL.
3. Adds logging of SOAP calls (method, arguments, calling user,
   elapsed time, and bytes output) at PEAR_LOG_INFO.

(1) came up when we wanted to expose a subset of the application's methods
via an alternate endpoint. Specifically, internal callers are allowed to
access any of this application's methods, but we wanted to maintain a
separate SOAP endpoint for customers to use. We didn't want to expose the
existence of the non-allowed calls since that would cause confusion and
bloat any autogenerated stubs.

(2) came up when we were testing this second endpoint. Our test cases make
calls to the application via the internal endpoint (contains all methods) as
well as the external endpoint (public methods only). The problem is that the
PEAR SOAP module generates a proxy class named after the WSDL service name.
We noticed that some tests would fail because the restricted endpoint would
be called first, the proxy class declared, and subsequent calls would simply
use the same class because it was already declared. Changing the serviceName
for one of the endpoints fixes this.

(3) is just useful. Maybe a little verbose, though?

We normally run FRAMEWORK_3, but the patch below is against HEAD. I'd like
to commit this and merge it into FRAMEWORK_3. AFAICT, this should be OK
since it raises no BC issues?

thanks,
john


Index: soap.php
===================================================================
RCS file: /repository/framework/RPC/RPC/soap.php,v
retrieving revision 1.24
diff -u -u -r1.24 soap.php
--- soap.php	2 Jan 2007 12:47:23 -0000	1.24
+++ soap.php	18 May 2007 17:40:32 -0000
@@ -24,6 +24,21 @@
     var $_server;
 
     /**
+     * Regex specifying the method names to display in the WSDL and allow
+     * calls to.
+     *
+     * @var string
+     */
+    var $_restrictCalls = null;
+
+    /**
+     * Name of the SOAP service to use in the WSDL.
+     *
+     * @var string
+     */
+    var $_serviceName = null;
+
+    /**
      * Hash holding all methods' signatures.
      *
      * @var array
@@ -39,6 +54,13 @@
     {
         parent::Horde_RPC($params);
 
+        if (!empty($params['restrictCalls'])) {
+            $this->_restrictCalls = $params['restrictCalls'];
+        }
+        if (!empty($params['serviceName'])) {
+            $this->_serviceName = $params['serviceName'];
+        }
+
         require_once 'SOAP/Server.php';
         $this->_server = new SOAP_Server();
         $this->_server->_auto_translation = true;
@@ -58,6 +80,10 @@
             if (!is_array($signature)) {
                 continue;
             }
+            if (!empty($this->_restrictCalls) &&
+                !preg_match($this->_restrictCalls, $method)) {
+                continue;
+            }
             $method = str_replace('/', '.', $method);
             $this->__dispatch_map[$method] = array(
                 'in' => $signature[0],
@@ -107,6 +133,14 @@
         global $registry;
         $method = str_replace('.', '/', $method);
 
+        if (!empty($this->_params['restrictCalls']) &&
+            !preg_match($this->_params['restrictCalls'], $method)) {
+            return sprintf(_("Method \"%s\" is not defined"), $method);
+        }
+
+        $GLOBALS['__horde_rpc_soap']['lastMethodCalled'] = $method;
+        $GLOBALS['__horde_rpc_soap']['lastMethodParams'] = $params;
+
         if (!$registry->hasMethod($method)) {
             return sprintf(_("Method \"%s\" is not defined"), $method);
         }
@@ -128,7 +162,8 @@
 
         if ($request == 'disco' || $request == 'wsdl') {
             require_once 'SOAP/Disco.php';
-            $disco = new SOAP_DISCO_Server($this->_server, 'horde');
+            $disco = new SOAP_DISCO_Server($this->_server,
+                !empty($this->_serviceName) ? $this->_serviceName : 'horde');
             if ($request == 'wsdl') {
                 $this->_setupDispatchMap();
                 return $disco->getWSDL();
@@ -141,7 +176,15 @@
 
         /* We can't use Util::bufferOutput() here for some reason. */
         ob_start();
+        $beginTime = time();
         $this->_server->service($request);
+        Horde::logMessage(
+            sprintf(_("SOAP call: %s(%s) by %s serviced in %d seconds, sent %d bytes in response"),
+                $GLOBALS['__horde_rpc_soap']['lastMethodCalled'],
+                join(', ', $GLOBALS['__horde_rpc_soap']['lastMethodParams']),
+                Auth::getAuth(), time() - $beginTime, strlen($output)
+            ), __FILE__, __LINE__, PEAR_LOG_INFO
+        );
         return ob_get_clean();
     }
 

-- 
John Morrissey          _o            /\         ----  __o
jwm at horde.net        _-< \_          /  \       ----  <  \,
www.horde.net/    __(_)/_(_)________/    \_______(_) /_(_)__


More information about the dev mailing list