class
HTTPServer(
object
):
def
__init__(
self
, request_callback, no_keep_alive
=
False
, io_loop
=
None
,xheaders
=
False
, ssl_options
=
None
):
self
.request_callback
=
request_callback
self
.no_keep_alive
=
no_keep_alive
self
.io_loop
=
io_loop
self
.xheaders
=
xheaders
self
.ssl_options
=
ssl_options
self
._socket
=
None
self
._started
=
False
def
listen(
self
, port, address
=
""):
self
.bind(port, address)
self
.start(
1
)
def
bind(
self
, port, address
=
None
, family
=
socket.AF_UNSPEC):
assert
not
self
._socket
self
._socket
=
socket.socket(socket.AF_INET, socket.SOCK_STREAM,
0
)
flags
=
fcntl.fcntl(
self
._socket.fileno(), fcntl.F_GETFD)
flags |
=
fcntl.FD_CLOEXEC
fcntl.fcntl(
self
._socket.fileno(), fcntl.F_SETFD, flags)
self
._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,
1
)
self
._socket.setblocking(
0
)
self
._socket.bind((address, port))
self
._socket.listen(
128
)
def
start(
self
, num_processes
=
1
):
assert
not
self
._started
self
._started
=
True
if
num_processes
is
None
or
num_processes <
=
0
:
num_processes
=
_cpu_count()
if
num_processes >
1
and
ioloop.IOLoop.initialized():
logging.error(
"Cannot run in multiple processes: IOLoop instance "
"has already been initialized. You cannot call "
"IOLoop.instance() before calling start()"
)
num_processes
=
1
if
num_processes >
1
:
logging.info(
"Pre-forking %d server processes"
, num_processes)
for
i
in
range
(num_processes):
if
os.fork()
=
=
0
:
import
random
from
binascii
import
hexlify
try
:
seed
=
long
(hexlify(os.urandom(
16
)),
16
)
except
NotImplementedError:
seed(
int
(time.time()
*
1000
) ^ os.getpid())
random.seed(seed)
self
.io_loop
=
ioloop.IOLoop.instance()
self
.io_loop.add_handler(
self
._socket.fileno(),
self
._handle_events,
ioloop.IOLoop.READ)
return
os.waitpid(
-
1
,
0
)
else
:
if
not
self
.io_loop:
self
.io_loop
=
ioloop.IOLoop.instance()
self
.io_loop.add_handler(
self
._socket.fileno(),
self
._handle_events,
ioloop.IOLoop.READ)
def
_handle_events(
self
, fd, events):
while
True
:
try
:
connection, address
=
self
._socket.accept()
except
socket.error, e:
if
e.args[
0
]
in
(errno.EWOULDBLOCK, errno.EAGAIN):
return
raise
if
self
.ssl_options
is
not
None
:
assert
ssl,
"Python 2.6+ and OpenSSL required for SSL"
try
:
connection
=
ssl.wrap_socket(connection,server_side
=
True
,do_handshake_on_connect
=
False
,
*
*
self
.ssl_options)
except
ssl.SSLError, err:
if
err.args[
0
]
=
=
ssl.SSL_ERROR_EOF:
return
connection.close()
else
:
raise
except
socket.error, err:
if
err.args[
0
]
=
=
errno.ECONNABORTED:
return
connection.close()
else
:
raise
try
:
if
self
.ssl_options
is
not
None
:
stream
=
iostream.SSLIOStream(connection, io_loop
=
self
.io_loop)
else
:
stream
=
iostream.IOStream(connection, io_loop
=
self
.io_loop)
HTTPConnection(stream, address,
self
.request_callback,
self
.no_keep_alive,
self
.xheaders)
except
:
logging.error(
"Error in connection callback"
, exc_info
=
True
)