Source

trac-rpc-mq / t0000 / t0000-reuse-method-r7971.diff

Reuse method object if used in parse_rpc_request

diff -r c0729ae7dd57 trunk/tracrpc/api.py
--- a/trunk/tracrpc/api.py	Fri Sep 10 23:09:17 2010 -0400
+++ b/trunk/tracrpc/api.py	Sat Sep 11 00:10:34 2010 -0400
@@ -96,20 +96,25 @@
         RPC subsystem, will be protocol-specific, and SHOULD NOT be 
         needed in order to invoke a given method.
 
-        method  (MANDATORY): target method name (e.g. 'ticket.get')
-        params  (OPTIONAL) : a tuple containing input positional arguments
-        kwparams (OPTIONAL): a dictionary containing input keyword arguments
-        headers (OPTIONAL) : if the protocol supports custom headers set 
-                              by the client, then this value SHOULD be a 
-                              dictionary binding `header name` to `value`. 
-                              However, protocol handlers as well as target 
-                              RPC methods *MUST (SHOULD ?) NOT* rely on 
-                              specific values assigned to a particular 
-                              header in order to send a response back 
-                              to the client.
-        mimetype           : request MIME-type. This value will be set
-                              by core RPC components after calling
-                              this method so, please, ignore
+        method   (MANDATORY) : target method name (e.g. 'ticket.get')
+        methodobj (OPTIONAL) : target method object if already instantiated  
+                                inside `parse_rpc_request`. This may be 
+                                useful for protocolos using method 
+                                signatures to decode RPC messages (e.g. 
+                                static-typed RPC protocols).
+        params    (OPTIONAL) : a tuple containing input positional arguments
+        kwparams  (OPTIONAL) : a dictionary containing input keyword arguments
+        headers   (OPTIONAL) : if the protocol supports custom headers set 
+                                by the client, then this value SHOULD be a 
+                                dictionary binding `header name` to `value`. 
+                                However, protocol handlers as well as target 
+                                RPC methods *MUST (SHOULD ?) NOT* rely on 
+                                specific values assigned to a particular 
+                                header in order to send a response back 
+                                to the client.
+        mimetype             : request MIME-type. This value will be set
+                                by core RPC components after calling
+                                this method so, please, ignore
 
         If the request cannot be parsed this method *MUST* raise 
         an instance of `ProtocolException` optionally wrapping another 
diff -r c0729ae7dd57 trunk/tracrpc/tests/api.py
--- a/trunk/tracrpc/tests/api.py	Fri Sep 10 23:09:17 2010 -0400
+++ b/trunk/tracrpc/tests/api.py	Sat Sep 11 00:10:34 2010 -0400
@@ -143,6 +143,60 @@
         self.assertEquals(resp.headers['Content-Type'],
                               'text/plain;charset=utf-8')
 
+    def test_methodobj_reuse(self):
+        # Confirm the request won't work before adding plugin
+        req = urllib2.Request(rpc_testenv.url_anon,
+                        headers={'Content-Type': 'application/x-tracrpc-test'},
+                        data="Fail! No RPC for application/x-tracrpc-test")
+        try:
+            resp = urllib2.urlopen(req)
+            self.fail("Expected urllib2.HTTPError")
+        except urllib2.HTTPError, e:
+            self.assertEquals(e.code, 415)
+        open(self.pluginfile, 'w').write(
+            "from trac.core import *\n"
+            "from tracrpc.api import *\n"
+            "class MethodCallTracker(Method):\n"
+            "    callcount = 0\n"
+            "    def __call__(self, req, args, kwds=None):\n"
+            "        self.callcount+= 1\n"
+            "        return Method.__call__(self, req, args, kwds)\n"
+            "class DummyProvider(Component):\n"
+            "    implements(IRPCProtocol)\n"
+            "    def rpc_info(self):\n"
+            "        return ('TEST-RPC', 'No Docs!')\n"
+            "    def rpc_match(self):\n"
+            "        yield ('rpc', 'application/x-tracrpc-test')\n"
+            "    def parse_rpc_request(self, req, content_type):\n"
+            "        method = XMLRPCSystem(self.env).get_method("
+            "                                   'system.getAPIVersion')\n"
+            "        method.__class__ = MethodCallTracker\n"
+            "        return {'method' : 'system.getAPIVersion',"
+            "                   'methodobj' : method}\n"
+            "        \n"
+            "    def send_rpc_error(self, req, e):\n"
+            "        rpcreq = req.rpc\n"
+            "        req.send_error(None, template='', content_type=rpcreq['mimetype'],\n"
+            "                       status=500, env=None, data='Test failure ')\n"
+            "    def send_rpc_result(self, req, result):\n"
+            "        rpcreq = req.rpc\n"
+            "        method = req.rpc.get('methodobj')\n"
+            "        if method is None:"
+            "            response = 'Method object missing !'\n"
+            "        elif not hasattr(method, 'callcount'):\n"
+            "            response = 'Callcount missing'\n"
+            "        else:\n"
+            "            response = 'Call count ' + str(method.callcount)\n"
+            "        req.send(response, 'text/plain', 200)\n")
+        rpc_testenv.restart()
+        req = urllib2.Request(rpc_testenv.url_anon,
+                    headers={'Content-Type': 'application/x-tracrpc-test'})
+        resp = urllib2.urlopen(req)
+        self.assertEquals(200, resp.code)
+        self.assertEquals("Call count 1", resp.read())
+        self.assertEquals(resp.headers['Content-Type'],
+                              'text/plain;charset=utf-8')
+
     def test_general_provider_error(self):
         open(self.pluginfile, 'w').write(
             "from trac.core import *\n"
diff -r c0729ae7dd57 trunk/tracrpc/web_ui.py
--- a/trunk/tracrpc/web_ui.py	Fri Sep 10 23:09:17 2010 -0400
+++ b/trunk/tracrpc/web_ui.py	Sat Sep 11 00:10:34 2010 -0400
@@ -155,7 +155,9 @@
             self.log.debug("RPC(%s) call by '%s' %s", proto_id, \
                                               req.authname, method_name)
             try :
-                result = (XMLRPCSystem(self.env).get_method(method_name)(req, args, kwargs))[0]
+                method = rpcreq.get('methodobj') or \
+                         XMLRPCSystem(self.env).get_method(method_name)
+                result = method(req, args, kwargs)[0]
                 if isinstance(result, GeneratorType):
                     result = list(result)
             except (RPCError, PermissionError, ResourceNotFound), e:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.