/usr/share/pyshared/cherrypy/_cpserver.py is in python-cherrypy 2.3.0-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | """Create and manage the CherryPy server."""
import threading
import time
import cherrypy
from cherrypy import _cphttptools
from cherrypy.lib import cptools
from cherrypy._cpengine import Engine, STOPPED, STARTING, STARTED
_missing = object()
class Server(Engine):
def __init__(self):
Engine.__init__(self)
self._is_setup = False
self.blocking = True
self.httpserver = None
# Starting in 2.2, the "httpserverclass" attr is essentially dead;
# no CP code uses it. Inspect "httpserver" instead.
self.httpserverclass = None
# Backward compatibility:
self.onStopServerList = self.on_stop_server_list
self.onStartThreadList = self.on_start_thread_list
self.onStartServerList = self.on_start_server_list
self.onStopThreadList = self.on_stop_thread_list
def start(self, init_only=False, server_class=_missing, server=None, **kwargs):
"""Main function. MUST be called from the main thread.
Set initOnly to True to keep this function from blocking.
Set serverClass and server to None to skip starting any HTTP server.
"""
# Read old variable names for backward compatibility
if 'initOnly' in kwargs:
init_only = kwargs['initOnly']
if 'serverClass' in kwargs:
server_class = kwargs['serverClass']
conf = cherrypy.config.get
if not init_only:
init_only = conf('server.init_only', False)
if server is None:
server = conf('server.instance', None)
if server is None:
if server_class is _missing:
server_class = conf("server.class", _missing)
if server_class is _missing:
import _cpwsgi
server_class = _cpwsgi.WSGIServer
elif server_class and isinstance(server_class, basestring):
# Dynamically load the class from the given string
server_class = cptools.attributes(server_class)
self.httpserverclass = server_class
if server_class is not None:
self.httpserver = server_class()
else:
if isinstance(server, basestring):
server = cptools.attributes(server)
self.httpserverclass = server.__class__
self.httpserver = server
self.blocking = not init_only
Engine.start(self)
def _start(self):
if not self._is_setup:
self.setup()
self._is_setup = True
Engine._start(self)
self.start_http_server()
if self.blocking:
self.block()
def restart(self):
"""Restart the application server engine."""
self.stop()
self.state = STARTING
self.interrupt = None
self._start()
def start_http_server(self, blocking=True):
"""Start the requested HTTP server."""
if not self.httpserver:
return
if cherrypy.config.get('server.socket_port'):
host = cherrypy.config.get('server.socket_host')
port = cherrypy.config.get('server.socket_port')
wait_for_free_port(host, port)
if not host:
host = '0.0.0.0'
on_what = "http://%s:%s/" % (host, port)
else:
on_what = "socket file: %s" % cherrypy.config.get('server.socket_file')
# HTTP servers MUST be started in a new thread, so that the
# main thread persists to receive KeyboardInterrupt's. If an
# exception is raised in the http server's main thread then it's
# trapped here, and the CherryPy app server is shut down (via
# self.interrupt).
def _start_http():
try:
self.httpserver.start()
except KeyboardInterrupt, exc:
self.interrupt = exc
self.stop()
except SystemExit, exc:
self.interrupt = exc
self.stop()
raise
t = threading.Thread(target=_start_http)
t.setName("CPHTTPServer " + t.getName())
t.start()
if blocking:
self.wait_for_http_ready()
cherrypy.log("Serving HTTP on %s" % on_what, 'HTTP')
def wait(self):
"""Block the caller until ready to receive requests (or error)."""
Engine.wait(self)
self.wait_for_http_ready()
def wait_for_http_ready(self):
if self.httpserver:
while (not getattr(self.httpserver, "ready", True)
and not self.interrupt
and self.state != STOPPED):
time.sleep(.1)
# Wait for port to be occupied
if cherrypy.config.get('server.socket_port'):
host = cherrypy.config.get('server.socket_host')
port = cherrypy.config.get('server.socket_port')
if not host:
host = 'localhost'
for trial in xrange(50):
if self.interrupt:
break
try:
check_port(host, port)
except IOError:
break
else:
time.sleep(.1)
else:
cherrypy.log("Port %s not bound on %s" %
(repr(port), repr(host)), 'HTTP')
raise cherrypy.NotReady("Port not bound.")
def stop(self):
"""Stop, including any HTTP servers."""
self.stop_http_server()
Engine.stop(self)
def stop_http_server(self):
"""Stop the HTTP server."""
try:
httpstop = self.httpserver.stop
except AttributeError:
pass
else:
# httpstop() MUST block until the server is *truly* stopped.
httpstop()
cherrypy.log("HTTP Server shut down", "HTTP")
def start_with_callback(self, func, args=None, kwargs=None,
server_class = _missing, serverClass = None):
"""Start, then callback the given func in a new thread."""
# Read old name for backward compatibility
if serverClass is not None:
server_class = None
if args is None:
args = ()
if kwargs is None:
kwargs = {}
args = (func,) + args
def _callback(func, *args, **kwargs):
self.wait()
func(*args, **kwargs)
t = threading.Thread(target=_callback, args=args, kwargs=kwargs)
t.setName("CPServer Callback " + t.getName())
t.start()
self.start(server_class = server_class)
def check_port(host, port):
"""Raise an error if the given port is not free on the given host."""
sock_file = cherrypy.config.get('server.socket_file')
if sock_file:
return
if not host:
host = 'localhost'
port = int(port)
import socket
# AF_INET or AF_INET6 socket
# Get the correct address family for our host (allows IPv6 addresses)
for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
s = None
try:
s = socket.socket(af, socktype, proto)
# See http://groups.google.com/group/cherrypy-users/
# browse_frm/thread/bbfe5eb39c904fe0
s.settimeout(1.0)
s.connect((host, port))
s.close()
raise IOError("Port %s is in use on %s; perhaps the previous "
"server did not shut down properly." %
(repr(port), repr(host)))
except socket.error:
if s:
s.close()
def wait_for_free_port(host, port):
"""Wait for the specified port to become free (drop requests)."""
if not host:
host = 'localhost'
for trial in xrange(50):
try:
check_port(host, port)
except IOError:
# Give the old server thread time to free the port.
time.sleep(.1)
else:
return
cherrypy.log("Port %s not free on %s" % (repr(port), repr(host)), 'HTTP')
raise cherrypy.NotReady("Port not free.")
def wait_for_occupied_port(host, port):
"""Wait for the specified port to become active (receive requests)."""
if not host:
host = 'localhost'
for trial in xrange(50):
try:
check_port(host, port)
except IOError:
return
else:
time.sleep(.1)
cherrypy.log("Port %s not bound on %s" % (repr(port), repr(host)), 'HTTP')
raise cherrypy.NotReady("Port not bound.")
|