Ignore:
Timestamp:
Mar 19, 2014, 11:31:01 PM (11 years ago)
Author:
dmik
Message:

python: Merge vendor 2.7.6 to trunk.

Location:
python/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • python/trunk

  • python/trunk/Lib/SimpleXMLRPCServer.py

    r2 r391  
    1 """Simple XML-RPC Server.
     1r"""Simple XML-RPC Server.
    22
    33This module can be used to create simple XML-RPC servers
     
    107107import os
    108108import traceback
     109import re
    109110try:
    110111    import fcntl
     
    161162
    162163    This class is used to register XML-RPC method handlers
    163     and then to dispatch them. There should never be any
    164     reason to instantiate this class directly.
     164    and then to dispatch them. This class doesn't need to be
     165    instanced directly when used by SimpleXMLRPCServer but it
     166    can be instanced when used by the MultiPathXMLRPCServer.
    165167    """
    166168
     
    237239        self.funcs.update({'system.multicall' : self.system_multicall})
    238240
    239     def _marshaled_dispatch(self, data, dispatch_method = None):
     241    def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
    240242        """Dispatches an XML-RPC method from marshalled (XML) data.
    241243
     
    245247        function can be provided as an argument (see comment in
    246248        SimpleXMLRPCRequestHandler.do_POST) but overriding the
    247         existing method through subclassing is the prefered means
     249        existing method through subclassing is the preferred means
    248250        of changing method dispatch behavior.
    249251        """
     
    431433    rpc_paths = ('/', '/RPC2')
    432434
     435    #if not None, encode responses larger than this, if possible
     436    encode_threshold = 1400 #a common MTU
     437
     438    #Override form StreamRequestHandler: full buffering of output
     439    #and no Nagle.
     440    wbufsize = -1
     441    disable_nagle_algorithm = True
     442
     443    # a re to match a gzip Accept-Encoding
     444    aepattern = re.compile(r"""
     445                            \s* ([^\s;]+) \s*            #content-coding
     446                            (;\s* q \s*=\s* ([0-9\.]+))? #q
     447                            """, re.VERBOSE | re.IGNORECASE)
     448
     449    def accept_encodings(self):
     450        r = {}
     451        ae = self.headers.get("Accept-Encoding", "")
     452        for e in ae.split(","):
     453            match = self.aepattern.match(e)
     454            if match:
     455                v = match.group(3)
     456                v = float(v) if v else 1.0
     457                r[match.group(1)] = v
     458        return r
     459
    433460    def is_rpc_path_valid(self):
    434461        if self.rpc_paths:
     
    460487            while size_remaining:
    461488                chunk_size = min(size_remaining, max_chunk_size)
    462                 L.append(self.rfile.read(chunk_size))
     489                chunk = self.rfile.read(chunk_size)
     490                if not chunk:
     491                    break
     492                L.append(chunk)
    463493                size_remaining -= len(L[-1])
    464494            data = ''.join(L)
     495
     496            data = self.decode_request_content(data)
     497            if data is None:
     498                return #response has been sent
    465499
    466500            # In previous versions of SimpleXMLRPCServer, _dispatch
     
    470504            # using that method if present.
    471505            response = self.server._marshaled_dispatch(
    472                     data, getattr(self, '_dispatch', None)
     506                    data, getattr(self, '_dispatch', None), self.path
    473507                )
    474508        except Exception, e: # This should only happen if the module is buggy
     
    482516                self.send_header("X-traceback", traceback.format_exc())
    483517
     518            self.send_header("Content-length", "0")
    484519            self.end_headers()
    485520        else:
     
    487522            self.send_response(200)
    488523            self.send_header("Content-type", "text/xml")
     524            if self.encode_threshold is not None:
     525                if len(response) > self.encode_threshold:
     526                    q = self.accept_encodings().get("gzip", 0)
     527                    if q:
     528                        try:
     529                            response = xmlrpclib.gzip_encode(response)
     530                            self.send_header("Content-Encoding", "gzip")
     531                        except NotImplementedError:
     532                            pass
    489533            self.send_header("Content-length", str(len(response)))
    490534            self.end_headers()
    491535            self.wfile.write(response)
    492536
    493             # shut down the connection
    494             self.wfile.flush()
    495             self.connection.shutdown(1)
     537    def decode_request_content(self, data):
     538        #support gzip encoding of request
     539        encoding = self.headers.get("content-encoding", "identity").lower()
     540        if encoding == "identity":
     541            return data
     542        if encoding == "gzip":
     543            try:
     544                return xmlrpclib.gzip_decode(data)
     545            except NotImplementedError:
     546                self.send_response(501, "encoding %r not supported" % encoding)
     547            except ValueError:
     548                self.send_response(400, "error decoding gzip content")
     549        else:
     550            self.send_response(501, "encoding %r not supported" % encoding)
     551        self.send_header("Content-length", "0")
     552        self.end_headers()
    496553
    497554    def report_404 (self):
     
    503560        self.end_headers()
    504561        self.wfile.write(response)
    505         # shut down the connection
    506         self.wfile.flush()
    507         self.connection.shutdown(1)
    508562
    509563    def log_request(self, code='-', size='-'):
     
    547601            fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
    548602
     603class MultiPathXMLRPCServer(SimpleXMLRPCServer):
     604    """Multipath XML-RPC Server
     605    This specialization of SimpleXMLRPCServer allows the user to create
     606    multiple Dispatcher instances and assign them to different
     607    HTTP request paths.  This makes it possible to run two or more
     608    'virtual XML-RPC servers' at the same port.
     609    Make sure that the requestHandler accepts the paths in question.
     610    """
     611    def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
     612                 logRequests=True, allow_none=False, encoding=None, bind_and_activate=True):
     613
     614        SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests, allow_none,
     615                                    encoding, bind_and_activate)
     616        self.dispatchers = {}
     617        self.allow_none = allow_none
     618        self.encoding = encoding
     619
     620    def add_dispatcher(self, path, dispatcher):
     621        self.dispatchers[path] = dispatcher
     622        return dispatcher
     623
     624    def get_dispatcher(self, path):
     625        return self.dispatchers[path]
     626
     627    def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
     628        try:
     629            response = self.dispatchers[path]._marshaled_dispatch(
     630               data, dispatch_method, path)
     631        except:
     632            # report low level exception back to server
     633            # (each dispatcher should have handled their own
     634            # exceptions)
     635            exc_type, exc_value = sys.exc_info()[:2]
     636            response = xmlrpclib.dumps(
     637                xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)),
     638                encoding=self.encoding, allow_none=self.allow_none)
     639        return response
     640
    549641class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):
    550642    """Simple handler for XML-RPC data passed through CGI."""
     
    581673            }
    582674        print 'Status: %d %s' % (code, message)
    583         print 'Content-Type: text/html'
     675        print 'Content-Type: %s' % BaseHTTPServer.DEFAULT_ERROR_CONTENT_TYPE
    584676        print 'Content-Length: %d' % len(response)
    585677        print
Note: See TracChangeset for help on using the changeset viewer.