Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 836

Show
Ignore:
Timestamp:
11/26/05 13:08:27
Author:
fumanchu
Message:

Cleaned up xmlrpcfilter (to prepare for #311 fix).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/filters/xmlrpcfilter.py

    r814 r836  
    8080###################################################################### 
    8181 
     82 
     83import sys 
    8284import xmlrpclib 
    8385 
     
    108110    def testValidityOfRequest(self): 
    109111        # test if the content-length was sent 
    110         result = False 
    111         if cherrypy.request.headerMap.has_key('Content-Length'): 
    112             length = cherrypy.request.headerMap.get('Content-Length', 0) 
    113             if length is None or length == "": length = 0 
    114             result = int(length) > 0 
    115         ct = 'text/xml' 
    116         if cherrypy.request.headerMap.has_key('Content-Type'): 
    117             ct = cherrypy.request.headerMap.get('Content-Type', 'text/xml').lower() 
    118             if ct is None or ct == "": ct = 'text/xml' 
    119         result = result and ct in ['text/xml'] 
    120         return result 
     112        length = cherrypy.request.headerMap.get('Content-Length') or 0 
     113        ct = cherrypy.request.headerMap.get('Content-Type') or 'text/xml' 
     114        return int(length) > 0 and ct.lower() in ['text/xml'] 
    121115     
    122116    def beforeRequestBody(self): 
     
    126120        request.xmlRpcFilterOn = cherrypy.config.get('xmlRpcFilter.on', False) 
    127121        if not request.xmlRpcFilterOn: 
    128             return True 
     122            return 
    129123         
    130124        request.isRPC = self.testValidityOfRequest() 
    131125        if not request.isRPC:  
    132             # used for debugging or more info 
    133             # print 'not a valid xmlrpc call' 
    134             return # break this if it's not for this filter!! 
     126            return 
    135127         
    136128        request.processRequestBody = False 
    137         dataLength = int(request.headerMap.get('Content-Length', 0)
     129        dataLength = int(request.headerMap.get('Content-Length') or 0
    138130        data = request.rfile.read(dataLength) 
    139131        try: 
     
    158150        """This is a variation of main() from _cphttptools. 
    159151         
    160         The reason it is redone here is because we don't want 
    161         cherrypy.response.body = iterable(body) - we want to us
    162         whatever real value the user returned from their callable 
    163         to reach the xmlrpcfilter unchanged.""" 
     152        It is redone here because: 
     153            1. we want to handle responses of any typ
     154            2. we need to pass our own paramList 
     155        """ 
    164156         
    165157        if (not cherrypy.config.get('xmlRpcFilter.on', False) 
     
    168160         
    169161        path = cherrypy.request.objectPath 
    170         page_handler, object_path, virtual_path = cherrypy.request.mapPathToObject(path) 
    171  
    172         # Remove "root" from object_path and join it to get objectPath 
    173         cherrypy.request.objectPath = '/' + '/'.join(object_path[1:]) 
    174         args = virtual_path + cherrypy.request.paramList 
    175         body = page_handler(*args, **cherrypy.request.paramMap) 
    176         cherrypy.response.body = body 
    177      
    178     def beforeFinalize(self): 
    179         """ Called before finalizing output """ 
    180         if (not cherrypy.config.get('xmlRpcFilter.on', False) 
    181             or not getattr(cherrypy.request, 'isRPC', False)): 
    182             return 
    183  
    184         encoding = cherrypy.config.get('xmlRpcFilter.encoding', 'utf-8') 
    185  
     162        while True: 
     163            try: 
     164                page_handler, object_path, virtual_path = cherrypy.request.mapPathToObject(path) 
     165                 
     166                # Decode any leftover %2F in the virtual_path atoms. 
     167                virtual_path = [x.replace("%2F", "/") for x in virtual_path] 
     168                 
     169                # Remove "root" from object_path and join it to get objectPath 
     170                self.objectPath = '/' + '/'.join(object_path[1:]) 
     171                args = virtual_path + cherrypy.request.paramList 
     172                body = page_handler(*args, **cherrypy.request.paramMap) 
     173                # Don't form an iterable like CP core main() does 
     174##                cherrypy.response.body = iterable(body) 
     175                break 
     176            except cherrypy.InternalRedirect, x: 
     177                # Try again with the new path 
     178                path = x.path 
     179         
    186180        # See xmlrpclib documentation 
    187181        # Python's None value cannot be used in standard XML-RPC; 
    188182        # to allow using it via an extension, provide a true value for allow_none. 
    189         cherrypy.response.body = [xmlrpclib.dumps( 
    190             (cherrypy.response.body,), 
    191             methodresponse=1, 
    192             encoding=encoding, 
    193             allow_none=0)] 
    194         cherrypy.response.headerMap['Content-Type'] = 'text/xml' 
    195         cherrypy.response.headerMap['Content-Length'] = len(cherrypy.response.body[0]) 
    196      
    197     def beforeErrorResponse(self): 
    198         try: 
    199             if (not cherrypy.config.get('xmlRpcFilter.on', False) 
    200                 or not getattr(cherrypy.request, 'isRPC', False)): 
    201                 return 
    202             import sys 
    203             # Since we got here because of an exception, let's get its error message if any 
    204             message = str(sys.exc_info()[1]) 
    205             body = ''.join([chunk for chunk in message]) 
    206             cherrypy.response.body = [xmlrpclib.dumps(xmlrpclib.Fault(1, body))] 
    207             cherrypy.response.headerMap['Content-Type'] = 'text/xml' 
    208             cherrypy.response.headerMap['Content-Length'] = len(cherrypy.response.body[0]) 
    209         except: 
    210             pass 
    211          
     183        encoding = cherrypy.config.get('xmlRpcFilter.encoding', 'utf-8') 
     184        body = xmlrpclib.dumps((body,), methodresponse=1, 
     185                               encoding=encoding, allow_none=0) 
     186        self.respond(body) 
     187     
    212188    def afterErrorResponse(self): 
    213189        if (not cherrypy.config.get('xmlRpcFilter.on', False) 
    214190            or not getattr(cherrypy.request, 'isRPC', False)): 
    215191            return 
     192         
     193        # Since we got here because of an exception, 
     194        # let's get its error message if any 
     195        body = str(sys.exc_info()[1]) 
     196        body = xmlrpclib.dumps(xmlrpclib.Fault(1, body)) 
     197        self.respond(body) 
     198     
     199    def respond(self, body): 
    216200        # The XML-RPC spec (http://www.xmlrpc.com/spec) says: 
    217201        # "Unless there's a lower-level error, always return 200 OK." 
    218         # However if arrived here we do have a status set to 500 then 
    219         # it means we got an error we didn't want to trap explicitely 
    220         # so let's assume it's part of the "lower-level error" defined above. 
    221         if cherrypy.response.status[:3] != '500': 
    222             cherrypy.response.status = '200 OK' 
     202        # Since Python's xmlrpclib interprets a non-200 response 
     203        # as a "Protocol Error", we'll just return 200 every time. 
     204        response = cherrypy.response 
     205        response.status = '200 OK' 
     206        response.body = [body] 
     207        response.headerMap['Content-Type'] = 'text/xml' 
     208        response.headerMap['Content-Length'] = len(body) 
     209 
  • trunk/cherrypy/test/test_xmlrpc_filter.py

    r804 r836  
    1010    index.exposed = True 
    1111 
    12      
     12 
    1313class XmlRpc: 
    1414    def return_single_item_list(self): 
     
    5555cherrypy.root.xmlrpc = XmlRpc() 
    5656 
     57 
    5758import helper 
    58          
     59 
    5960cherrypy.config.update({ 
    6061    'global': {'server.logToScreen': False, 
     
    6465               'server.socketPort': helper.CPWebCase.PORT, 
    6566               }, 
    66     '/xmlrpc': 
    67                {'xmlRpcFilter.on':True} 
    68               }) 
     67    '/xmlrpc': {'xmlRpcFilter.on':True}, 
     68    }) 
    6969 
    70          
     70 
    7171class ServerlessProxy(object): 
    7272    """An xmlrpc proxy for the test suite's 'serverless' tests.""" 
     
    7474        self._webcase = webcase 
    7575        self.url = url 
    76  
     76     
    7777    def __getattr__(self, attr, *args): 
    7878        def xmlrpc_method(*args): 
     
    8181            cl = len(body) 
    8282            headers = [('Content-Type', 'text/xml'), ('Content-Length', str(cl))] 
    83             self._webcase.getPage(self.url, headers=headers, method="POST", body=body) 
    84             return xmlrpclib.loads("".join(self._webcase.body))[0][0]             
     83            self._webcase.getPage(self.url, headers=headers, 
     84                                  method="POST", body=body) 
     85            p, u = xmlrpclib.getparser() 
     86            for line in self._webcase.body: 
     87                p.feed(line) 
     88            p.close() 
     89            response = u.close() 
     90            if len(response) == 1: 
     91                response = response[0] 
     92            return response 
    8593        return xmlrpc_method 
    8694 
     
    8896class XmlRpcFilterTest(helper.CPWebCase): 
    8997    def testXmlRpcFilter(self): 
    90  
     98         
    9199        # load the appropriate xmlrpc proxy 
    92         if cherrypy.server.httpserver is None:         
    93             proxy = ServerlessProxy(self, 'http://localhost:%s/xmlrpc/' % (self.PORT)) 
     100        url = 'http://localhost:%s/xmlrpc/' % (self.PORT) 
     101        if cherrypy.server.httpserver is None: 
     102            proxy = ServerlessProxy(self, url) 
    94103        else: 
    95             proxy = xmlrpclib.ServerProxy('http://localhost:%s/xmlrpc/' % (self.PORT)
    96  
     104            proxy = xmlrpclib.ServerProxy(url
     105         
    97106        # begin the tests ... 
    98         self.assertEqual(proxy.return_single_item_list(), 
    99                          [42] 
    100                          ) 
    101         self.assertNotEqual(proxy.return_single_item_list(), 
    102                          'one bazillion' 
    103                          ) 
    104         self.assertEqual(proxy.return_string(), 
    105                          "here is a string" 
    106                          ) 
    107         self.assertEqual(proxy.return_tuple(), 
    108                          list(('here', 'is', 1, 'tuple')) 
    109                          ) 
    110         self.assertEqual(proxy.return_dict(), 
    111                          {'a': 1, 'c': 3, 'b': 2} 
    112                          ) 
     107        self.assertEqual(proxy.return_single_item_list(), [42]) 
     108        self.assertNotEqual(proxy.return_single_item_list(), 'one bazillion') 
     109        self.assertEqual(proxy.return_string(), "here is a string") 
     110        self.assertEqual(proxy.return_tuple(), list(('here', 'is', 1, 'tuple'))) 
     111        self.assertEqual(proxy.return_dict(), {'a': 1, 'c': 3, 'b': 2}) 
    113112        self.assertEqual(proxy.return_composite(), 
    114                          [{'a': 1, 'z': 26}, 'hi', ['welcome', 'friend']] 
    115                          ) 
    116         self.assertEqual(proxy.return_int(), 
    117                          42 
    118                          ) 
    119         self.assertEqual(proxy.return_float(), 
    120                                3.14 
    121                         ) 
     113                         [{'a': 1, 'z': 26}, 'hi', ['welcome', 'friend']]) 
     114        self.assertEqual(proxy.return_int(), 42) 
     115        self.assertEqual(proxy.return_float(), 3.14) 
    122116        self.assertEqual(proxy.return_datetime(), 
    123                          xmlrpclib.DateTime((2003, 10, 7, 8, 1, 0, 1, 280, -1)) 
    124                          ) 
    125         self.assertEqual(proxy.return_boolean(), 
    126                          True 
    127                          ) 
    128         self.assertEqual(proxy.test_argument_passing(22),  
    129                         22 * 2 
    130                         ) 
     117                         xmlrpclib.DateTime((2003, 10, 7, 8, 1, 0, 1, 280, -1))) 
     118        self.assertEqual(proxy.return_boolean(), True) 
     119        self.assertEqual(proxy.test_argument_passing(22), 22 * 2) 
     120         
     121        # Test an error in the page handler (should raise an xmlrpclib.Fault) 
     122        ignore = helper.webtest.ignored_exceptions 
     123        ignore.append(TypeError) 
     124        try: 
     125            try: 
     126                proxy.test_argument_passing({}) 
     127            except Exception, x: 
     128                self.assertEqual(x.__class__, xmlrpclib.Fault) 
     129                self.assertEqual(x.faultString, ("unsupported operand type(s) " 
     130                                                 "for *: 'dict' and 'int'")) 
     131            else: 
     132                self.fail("Expected xmlrpclib.Fault") 
     133        finally: 
     134            ignore.pop() 
    131135 
    132136 
     
    135139    serverClass = _cpwsgi.WSGIServer 
    136140    helper.testmain(serverClass) 
    137      
     141 

Hosted by WebFaction

Log in as guest/cpguest to create tickets