mirror of
https://github.com/rembo10/headphones.git
synced 2026-01-13 16:58:02 -05:00
Mostly just updating libraries, removing string encoding/decoding, fixing some edge cases. No new functionality was added in this commit.
169 lines
6.5 KiB
Python
169 lines
6.5 KiB
Python
"""Native adapter for serving CherryPy via its builtin server."""
|
|
|
|
import logging
|
|
import sys
|
|
import io
|
|
|
|
import cheroot.server
|
|
|
|
import cherrypy
|
|
from cherrypy._cperror import format_exc, bare_error
|
|
from cherrypy.lib import httputil
|
|
from ._cpcompat import tonative
|
|
|
|
|
|
class NativeGateway(cheroot.server.Gateway):
|
|
"""Native gateway implementation allowing to bypass WSGI."""
|
|
|
|
recursive = False
|
|
|
|
def respond(self):
|
|
"""Obtain response from CherryPy machinery and then send it."""
|
|
req = self.req
|
|
try:
|
|
# Obtain a Request object from CherryPy
|
|
local = req.server.bind_addr # FIXME: handle UNIX sockets
|
|
local = tonative(local[0]), local[1]
|
|
local = httputil.Host(local[0], local[1], '')
|
|
remote = tonative(req.conn.remote_addr), req.conn.remote_port
|
|
remote = httputil.Host(remote[0], remote[1], '')
|
|
|
|
scheme = tonative(req.scheme)
|
|
sn = cherrypy.tree.script_name(tonative(req.uri or '/'))
|
|
if sn is None:
|
|
self.send_response('404 Not Found', [], [''])
|
|
else:
|
|
app = cherrypy.tree.apps[sn]
|
|
method = tonative(req.method)
|
|
path = tonative(req.path)
|
|
qs = tonative(req.qs or '')
|
|
headers = (
|
|
(tonative(h), tonative(v))
|
|
for h, v in 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,
|
|
tonative(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 = io.BytesIO()
|
|
|
|
self.send_response(
|
|
response.output_status, response.header_list,
|
|
response.body)
|
|
finally:
|
|
app.release_serving()
|
|
except Exception:
|
|
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):
|
|
"""Send response to HTTP request."""
|
|
req = self.req
|
|
|
|
# Set response status
|
|
req.status = status or b'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(cheroot.server.HTTPServer):
|
|
"""Wrapper for cheroot.server.HTTPServer.
|
|
|
|
cheroot 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):
|
|
"""Initialize CPHTTPServer."""
|
|
self.server_adapter = server_adapter
|
|
|
|
server_name = (self.server_adapter.socket_host or
|
|
self.server_adapter.socket_file or
|
|
None)
|
|
|
|
cheroot.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 = cheroot.server.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.server_adapter.ssl_ciphers)
|
|
self.ssl_adapter.context = self.server_adapter.ssl_context
|
|
elif self.server_adapter.ssl_certificate:
|
|
adapter_class = cheroot.server.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.server_adapter.ssl_ciphers)
|