1 """Native adapter for serving CherryPy via its builtin server."""
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
13 class NativeGateway(wsgiserver
.Gateway
):
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], "")
27 sn
= cherrypy
.tree
.script_name(req
.uri
or "/")
29 self
.send_response('404 Not Found', [], [''])
31 app
= cherrypy
.tree
.apps
[sn
]
35 headers
= req
.inheaders
.items()
42 request
, response
= app
.get_serving(
43 local
, remote
, scheme
, "HTTP/1.1")
44 request
.multithread
= True
45 request
.multiprocess
= False
49 # Run the CherryPy Request object and obtain the response
51 request
.run(method
, path
, qs
, req
.request_protocol
, headers
, rfile
)
53 except cherrypy
.InternalRedirect
:
54 ir
= sys
.exc_info()[1]
58 if not self
.recursive
:
59 if ir
.path
in redirections
:
60 raise RuntimeError("InternalRedirector visited the "
61 "same URL twice: %r" % ir
.path
)
63 # Add the *previous* path_info + qs to redirections.
66 redirections
.append(sn
+ path
+ qs
)
68 # Munge environment and try again.
75 response
.output_status
, response
.header_list
,
82 cherrypy
.log(tb
, 'NATIVE_ADAPTER', severity
=logging
.ERROR
)
83 s
, h
, b
= bare_error()
84 self
.send_response(s
, h
, b
)
86 def send_response(self
, status
, headers
, body
):
90 req
.status
= str(status
or "500 Server Error")
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
104 class CPHTTPServer(wsgiserver
.HTTPServer
):
105 """Wrapper for wsgiserver.HTTPServer.
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.
113 def __init__(self
, server_adapter
=cherrypy
.server
):
114 self
.server_adapter
= server_adapter
116 server_name
= (self
.server_adapter
.socket_host
or
117 self
.server_adapter
.socket_file
or
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
)
126 self
.max_request_header_size
= self
.server_adapter
.max_request_header_size
or 0
127 self
.max_request_body_size
= self
.server_adapter
.max_request_body_size
or 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
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
)