Source

CherryPy / cherrypy / _cpnative_server.py

"""Native adapter for serving CherryPy via the cheroot HTTP server."""

import logging
import sys

from cheroot import server, ssllib

import cherrypy
from cherrypy._cpcompat import BytesIO
from cherrypy._cperror import format_exc, bare_error
from cherrypy.lib import httputil


class NativeGateway(server.Gateway):
    
    recursive = False
    
    def respond(self):
        req = self.req
        try:
            # Obtain a Request object from CherryPy
            local = req.server.bind_addr
            local = httputil.Host(local[0], local[1], "")
            remote = req.conn.remote_addr, req.conn.remote_port
            remote = httputil.Host(remote[0], remote[1], "")
            
            scheme = req.scheme
            sn = cherrypy.tree.script_name(req.uri or "/")
            if sn is None:
                self.send_response('404 Not Found', [], [''])
            else:
                app = cherrypy.tree.apps[sn]
                method = req.method
                path = req.path
                qs = req.qs or ""
                headers = req.inheaders.items()
                rfile = req.rfile
                prev = None
                
                try:
                    redirections = []
                    while True:
                        request, response = app.get_serving(
                            local, remote, scheme, "HTTP/1.1")
                        request.multithread = True
                        request.multiprocess = False
                        request.app = app
                        request.prev = prev
                        
                        # Run the CherryPy Request object and obtain the response
                        try:
                            request.run(method, path, qs, req.request_protocol, headers, rfile)
                            break
                        except cherrypy.InternalRedirect:
                            ir = sys.exc_info()[1]
                            app.release_serving()
                            prev = request
                            
                            if not self.recursive:
                                if ir.path in redirections:
                                    raise RuntimeError("InternalRedirector visited the "
                                                       "same URL twice: %r" % ir.path)
                                else:
                                    # Add the *previous* path_info + qs to redirections.
                                    if qs:
                                        qs = "?" + qs
                                    redirections.append(sn + path + qs)
                            
                            # Munge environment and try again.
                            method = "GET"
                            path = ir.path
                            qs = ir.query_string
                            rfile = BytesIO()
                    
                    self.send_response(
                        response.output_status, response.header_list,
                        response.body)
                finally:
                    app.release_serving()
        except:
            tb = format_exc()
            #print tb
            cherrypy.log(tb, 'NATIVE_ADAPTER', severity=logging.ERROR)
            s, h, b = bare_error()
            self.send_response(s, h, b)
    
    def send_response(self, status, headers, body):
        req = self.req
        
        # Set response status
        req.status = str(status or "500 Server Error")
        
        # Set response headers
        for header, value in headers:
            req.outheaders.append((header, value))
        if (req.ready and not req.sent_headers):
            req.sent_headers = True
            req.send_headers()
        
        # Set response body
        for seg in body:
            req.write(seg)


class CPHTTPServer(server.HTTPServer):
    
    def __init__(self, server_adapter=cherrypy.server):
        self.server_adapter = server_adapter
        
        server_name = (self.server_adapter.socket_host or
                       self.server_adapter.socket_file or
                       None)
        
        server.HTTPServer.__init__(
            self, server_adapter.bind_addr, NativeGateway,
            minthreads=server_adapter.thread_pool,
            maxthreads=server_adapter.thread_pool_max,
            server_name=server_name)
        
        self.max_request_header_size = self.server_adapter.max_request_header_size or 0
        self.max_request_body_size = self.server_adapter.max_request_body_size or 0
        self.request_queue_size = self.server_adapter.socket_queue_size
        self.timeout = self.server_adapter.socket_timeout
        self.shutdown_timeout = self.server_adapter.shutdown_timeout
        self.protocol = self.server_adapter.protocol_version
        self.nodelay = self.server_adapter.nodelay
        
        ssl_module = self.server_adapter.ssl_module or 'pyopenssl'
        if self.server_adapter.ssl_context:
            adapter_class = ssllib.get_ssl_adapter_class(ssl_module)
            self.ssl_adapter = adapter_class(
                self.server_adapter.ssl_certificate,
                self.server_adapter.ssl_private_key,
                self.server_adapter.ssl_certificate_chain)
            self.ssl_adapter.context = self.server_adapter.ssl_context
        elif self.server_adapter.ssl_certificate:
            adapter_class = ssllib.get_ssl_adapter_class(ssl_module)
            self.ssl_adapter = adapter_class(
                self.server_adapter.ssl_certificate,
                self.server_adapter.ssl_private_key,
                self.server_adapter.ssl_certificate_chain)
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.