OLD | NEW |
(Empty) | |
| 1 """Native adapter for serving CherryPy via its builtin server.""" |
| 2 |
| 3 import logging |
| 4 import sys |
| 5 |
| 6 import cherrypy |
| 7 from cherrypy._cpcompat import BytesIO |
| 8 from cherrypy._cperror import format_exc, bare_error |
| 9 from cherrypy.lib import httputil |
| 10 from cherrypy import wsgiserver |
| 11 |
| 12 |
| 13 class NativeGateway(wsgiserver.Gateway): |
| 14 |
| 15 recursive = False |
| 16 |
| 17 def respond(self): |
| 18 req = self.req |
| 19 try: |
| 20 # Obtain a Request object from CherryPy |
| 21 local = req.server.bind_addr |
| 22 local = httputil.Host(local[0], local[1], "") |
| 23 remote = req.conn.remote_addr, req.conn.remote_port |
| 24 remote = httputil.Host(remote[0], remote[1], "") |
| 25 |
| 26 scheme = req.scheme |
| 27 sn = cherrypy.tree.script_name(req.uri or "/") |
| 28 if sn is None: |
| 29 self.send_response('404 Not Found', [], ['']) |
| 30 else: |
| 31 app = cherrypy.tree.apps[sn] |
| 32 method = req.method |
| 33 path = req.path |
| 34 qs = req.qs or "" |
| 35 headers = req.inheaders.items() |
| 36 rfile = req.rfile |
| 37 prev = None |
| 38 |
| 39 try: |
| 40 redirections = [] |
| 41 while True: |
| 42 request, response = app.get_serving( |
| 43 local, remote, scheme, "HTTP/1.1") |
| 44 request.multithread = True |
| 45 request.multiprocess = False |
| 46 request.app = app |
| 47 request.prev = prev |
| 48 |
| 49 # Run the CherryPy Request object and obtain the respons
e |
| 50 try: |
| 51 request.run(method, path, qs, req.request_protocol,
headers, rfile) |
| 52 break |
| 53 except cherrypy.InternalRedirect: |
| 54 ir = sys.exc_info()[1] |
| 55 app.release_serving() |
| 56 prev = request |
| 57 |
| 58 if not self.recursive: |
| 59 if ir.path in redirections: |
| 60 raise RuntimeError("InternalRedirector visit
ed the " |
| 61 "same URL twice: %r" % ir
.path) |
| 62 else: |
| 63 # Add the *previous* path_info + qs to redir
ections. |
| 64 if qs: |
| 65 qs = "?" + qs |
| 66 redirections.append(sn + path + qs) |
| 67 |
| 68 # Munge environment and try again. |
| 69 method = "GET" |
| 70 path = ir.path |
| 71 qs = ir.query_string |
| 72 rfile = BytesIO() |
| 73 |
| 74 self.send_response( |
| 75 response.output_status, response.header_list, |
| 76 response.body) |
| 77 finally: |
| 78 app.release_serving() |
| 79 except: |
| 80 tb = format_exc() |
| 81 #print tb |
| 82 cherrypy.log(tb, 'NATIVE_ADAPTER', severity=logging.ERROR) |
| 83 s, h, b = bare_error() |
| 84 self.send_response(s, h, b) |
| 85 |
| 86 def send_response(self, status, headers, body): |
| 87 req = self.req |
| 88 |
| 89 # Set response status |
| 90 req.status = str(status or "500 Server Error") |
| 91 |
| 92 # Set response headers |
| 93 for header, value in headers: |
| 94 req.outheaders.append((header, value)) |
| 95 if (req.ready and not req.sent_headers): |
| 96 req.sent_headers = True |
| 97 req.send_headers() |
| 98 |
| 99 # Set response body |
| 100 for seg in body: |
| 101 req.write(seg) |
| 102 |
| 103 |
| 104 class CPHTTPServer(wsgiserver.HTTPServer): |
| 105 """Wrapper for wsgiserver.HTTPServer. |
| 106 |
| 107 wsgiserver has been designed to not reference CherryPy in any way, |
| 108 so that it can be used in other frameworks and applications. |
| 109 Therefore, we wrap it here, so we can apply some attributes |
| 110 from config -> cherrypy.server -> HTTPServer. |
| 111 """ |
| 112 |
| 113 def __init__(self, server_adapter=cherrypy.server): |
| 114 self.server_adapter = server_adapter |
| 115 |
| 116 server_name = (self.server_adapter.socket_host or |
| 117 self.server_adapter.socket_file or |
| 118 None) |
| 119 |
| 120 wsgiserver.HTTPServer.__init__( |
| 121 self, server_adapter.bind_addr, NativeGateway, |
| 122 minthreads=server_adapter.thread_pool, |
| 123 maxthreads=server_adapter.thread_pool_max, |
| 124 server_name=server_name) |
| 125 |
| 126 self.max_request_header_size = self.server_adapter.max_request_header_si
ze or 0 |
| 127 self.max_request_body_size = self.server_adapter.max_request_body_size o
r 0 |
| 128 self.request_queue_size = self.server_adapter.socket_queue_size |
| 129 self.timeout = self.server_adapter.socket_timeout |
| 130 self.shutdown_timeout = self.server_adapter.shutdown_timeout |
| 131 self.protocol = self.server_adapter.protocol_version |
| 132 self.nodelay = self.server_adapter.nodelay |
| 133 |
| 134 ssl_module = self.server_adapter.ssl_module or 'pyopenssl' |
| 135 if self.server_adapter.ssl_context: |
| 136 adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) |
| 137 self.ssl_adapter = adapter_class( |
| 138 self.server_adapter.ssl_certificate, |
| 139 self.server_adapter.ssl_private_key, |
| 140 self.server_adapter.ssl_certificate_chain) |
| 141 self.ssl_adapter.context = self.server_adapter.ssl_context |
| 142 elif self.server_adapter.ssl_certificate: |
| 143 adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) |
| 144 self.ssl_adapter = adapter_class( |
| 145 self.server_adapter.ssl_certificate, |
| 146 self.server_adapter.ssl_private_key, |
| 147 self.server_adapter.ssl_certificate_chain) |
| 148 |
| 149 |
OLD | NEW |