CherryPyTicketUrlFix / cherrypy / _cpwsgi.py

"""WSGI interface (see PEP 333)."""

import cherrypy as _cherrypy
from cherrypy import _cpwsgiserver
from cherrypy.lib import http as _http


class pipeline(list):
    """An ordered list of configurable WSGI middleware.
    
    self: a list of (name, wsgiapp) pairs. Each 'wsgiapp' MUST be a
        constructor that takes an initial, positional wsgiapp argument,
        plus optional keyword arguments, and returns a WSGI application
        (that takes environ and start_response arguments). The 'name' can
        be any you choose, and will correspond to keys in self.config.
    config: a dict whose keys match names listed in the pipeline. Each
        value is a further dict which will be passed to the corresponding
        named WSGI callable (from the pipeline) as keyword arguments.
    """
    
    def __new__(cls, app, members=None, key="wsgi"):
        return list.__new__(cls)
    
    def __init__(self, app, members=None, key="wsgi"):
        self.app = app
        if members:
            self.extend(members)
        self.head = None
        self.tail = None
        self.config = {}
        self.key = key
        app.namespaces[key] = self.namespace_handler
        app.wsgi_pipeline = self
    
    def namespace_handler(self, k, v):
        """Config handler for our namespace."""
        if k == "pipeline":
            # Note this allows multiple entries to be aggregated (but also
            # note dicts are essentially unordered). It should also allow
            # developers to set default middleware in code (passed to
            # pipeline.__init__) that deployers can add to but not remove.
            self.extend(v)
            
            if self:
                # If self is empty, there's no need to replace app.wsgiapp.
                # Also note we're grabbing app.wsgiapp, not app.__call__,
                # so we can "play nice" with other Application-manglers
                # (hopefully, they'll do the same).
                self.tail = self.app.wsgiapp
                self.app.wsgiapp = self.__call__
        else:
            name, arg = k.split(".", 1)
            bucket = self.config.setdefault(name, {})
            bucket[arg] = v
    
    def __call__(self, environ, start_response):
        if not self.head:
            # This class may be used without calling namespace_handler,
            # in which case self.tail may still be None.
            self.head = self.tail or self.app.wsgiapp
            pipe = self[:]
            pipe.reverse()
            for name, callable in pipe:
                conf = self.config.get(name, {})
                self.head = callable(self.head, **conf)
        return self.head(environ, start_response)
    
    def __repr__(self):
        return "%s.%s(%r)" % (self.__module__, self.__class__.__name__,
                              list(self))



#                            Server components                            #


class CPHTTPRequest(_cpwsgiserver.HTTPRequest):
    
    def parse_request(self):
        mhs = _cherrypy.server.max_request_header_size
        if mhs > 0:
            self.rfile = _http.SizeCheckWrapper(self.rfile, mhs)
        
        try:
            _cpwsgiserver.HTTPRequest.parse_request(self)
        except _http.MaxSizeExceeded:
            self.simple_response("413 Request Entity Too Large")
            _cherrypy.log(traceback=True)
    
    def decode_chunked(self):
        """Decode the 'chunked' transfer coding."""
        if isinstance(self.rfile, _http.SizeCheckWrapper):
            self.rfile = self.rfile.rfile
        mbs = _cherrypy.server.max_request_body_size
        if mbs > 0:
            self.rfile = _http.SizeCheckWrapper(self.rfile, mbs)
        try:
            return _cpwsgiserver.HTTPRequest.decode_chunked(self)
        except _http.MaxSizeExceeded:
            self.simple_response("413 Request Entity Too Large")
            _cherrypy.log(traceback=True)
            return False


class CPHTTPConnection(_cpwsgiserver.HTTPConnection):
    
    RequestHandlerClass = CPHTTPRequest


class WSGIServer(_cpwsgiserver.CherryPyWSGIServer):
    
    """Wrapper for _cpwsgiserver.CherryPyWSGIServer.
    
    _cpwsgiserver has been designed to not reference CherryPy in any way,
    so that it can be used in other frameworks and applications. Therefore,
    we wrap it here, so we can set our own mount points from cherrypy.tree.
    
    """
    
    ConnectionClass = CPHTTPConnection
    
    def __init__(self):
        server = _cherrypy.server
        sockFile = server.socket_file
        if sockFile:
            bind_addr = sockFile
        else:
            bind_addr = (server.socket_host, server.socket_port)
        
        s = _cpwsgiserver.CherryPyWSGIServer
        # We could just pass cherrypy.tree, but by passing tree.apps,
        # we get correct SCRIPT_NAMEs as early as possible.
        s.__init__(self, bind_addr, _cherrypy.tree.apps.items(),
                   server.thread_pool,
                   server.socket_host,
                   request_queue_size = server.socket_queue_size,
                   timeout = server.socket_timeout,
                   )
        s.protocol = server.protocol_version
        s.ssl_certificate = server.ssl_certificate
        s.ssl_private_key = server.ssl_private_key
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.