| """Native adapter for serving CherryPy via its builtin server.""" |
| |
| import logging |
| import sys |
| |
| import cherrypy |
| from cherrypy._cpcompat import BytesIO |
| from cherrypy._cperror import format_exc, bare_error |
| from cherrypy.lib import httputil |
| from cherrypy import wsgiserver |
| |
| |
| class NativeGateway(wsgiserver.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(wsgiserver.HTTPServer): |
| """Wrapper for wsgiserver.HTTPServer. |
| |
| wsgiserver 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 apply some attributes |
| from config -> cherrypy.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) |
| |
| wsgiserver.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 = wsgiserver.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 = wsgiserver.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) |
| |
| |