mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-23 19:22:45 +01:00
httpserver: Add support for multiple hosts and IPv6. Closes GH-387.
This commit is contained in:
parent
247ed460b0
commit
784b8c37f8
@ -1085,8 +1085,12 @@ class IP(registry.String):
|
||||
else:
|
||||
registry.String.setValue(self, v)
|
||||
|
||||
registerGlobalValue(supybot.servers.http, 'host',
|
||||
IP('0.0.0.0', _("Determines what host the HTTP server will bind.")))
|
||||
registerGlobalValue(supybot.servers.http, 'hosts4',
|
||||
IP('0.0.0.0', _("""Space-separated list of IPv4 hosts the HTTP server
|
||||
will bind.""")))
|
||||
registerGlobalValue(supybot.servers.http, 'hosts6',
|
||||
IP('', _("""Space-separated list of IPv6 hosts the HTTP server will
|
||||
bind.""")))
|
||||
registerGlobalValue(supybot.servers.http, 'port',
|
||||
registry.Integer(8080, _("""Determines what port the HTTP server will
|
||||
bind.""")))
|
||||
|
@ -33,6 +33,7 @@ An embedded and centralized HTTP server for Supybot's plugins.
|
||||
|
||||
import os
|
||||
import cgi
|
||||
import socket
|
||||
from threading import Event, Thread
|
||||
from cStringIO import StringIO
|
||||
from SocketServer import ThreadingMixIn
|
||||
@ -54,8 +55,18 @@ class RequestNotHandled(Exception):
|
||||
class RealSupyHTTPServer(HTTPServer):
|
||||
# TODO: make this configurable
|
||||
timeout = 0.5
|
||||
callbacks = {}
|
||||
running = False
|
||||
|
||||
def __init__(self, address, protocol, callback):
|
||||
if protocol == 4:
|
||||
self.address_family = socket.AF_INET
|
||||
elif protocol == 6:
|
||||
self.address_family = socket.AF_INET6
|
||||
else:
|
||||
raise AssertionError(protocol)
|
||||
HTTPServer.__init__(self, address, callback)
|
||||
self.callbacks = {}
|
||||
|
||||
def hook(self, subdir, callback):
|
||||
if subdir in self.callbacks:
|
||||
log.warning(('The HTTP subdirectory `%s` was already hooked but '
|
||||
@ -68,6 +79,9 @@ class RealSupyHTTPServer(HTTPServer):
|
||||
callback.doUnhook(self)
|
||||
return callback
|
||||
|
||||
def __str__(self):
|
||||
return 'server at %s %i' % self.server_address[0:2]
|
||||
|
||||
class TestSupyHTTPServer(RealSupyHTTPServer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
@ -241,39 +255,50 @@ class Favicon(SupyHTTPServerCallback):
|
||||
self.end_headers()
|
||||
self.wfile.write(response)
|
||||
|
||||
httpServer = None
|
||||
http_servers = None
|
||||
|
||||
def startServer():
|
||||
"""Starts the HTTP server. Shouldn't be called from other modules.
|
||||
The callback should be an instance of a child of SupyHTTPServerCallback."""
|
||||
global httpServer
|
||||
log.info('Starting HTTP server.')
|
||||
address = (configGroup.host(), configGroup.port())
|
||||
httpServer = SupyHTTPServer(address, SupyHTTPRequestHandler)
|
||||
Thread(target=httpServer.serve_forever, name='HTTP Server').start()
|
||||
global http_servers
|
||||
addresses4 = [(4, (x, configGroup.port()))
|
||||
for x in configGroup.hosts4().split(' ') if x != '']
|
||||
addresses6 = [(6, (x, configGroup.port()))
|
||||
for x in configGroup.hosts6().split(' ') if x != '']
|
||||
http_servers = []
|
||||
for protocol, address in (addresses4 + addresses6):
|
||||
server = SupyHTTPServer(address, protocol, SupyHTTPRequestHandler)
|
||||
Thread(target=server.serve_forever, name='HTTP Server').start()
|
||||
http_servers.append(server)
|
||||
log.info('Starting HTTP server: %s' % str(server))
|
||||
|
||||
def stopServer():
|
||||
"""Stops the HTTP server. Should be run only from this module or from
|
||||
when the bot is dying (ie. from supybot.world)"""
|
||||
global httpServer
|
||||
if httpServer is not None:
|
||||
log.info('Stopping HTTP server.')
|
||||
httpServer.shutdown()
|
||||
httpServer = None
|
||||
global http_servers
|
||||
if http_servers is not None:
|
||||
for server in http_servers:
|
||||
log.info('Stopping HTTP server: %s' % str(server))
|
||||
server.shutdown()
|
||||
server = None
|
||||
|
||||
if configGroup.keepAlive():
|
||||
startServer()
|
||||
|
||||
def hook(subdir, callback):
|
||||
"""Sets a callback for a given subdir."""
|
||||
if httpServer is None:
|
||||
if http_servers is None:
|
||||
startServer()
|
||||
httpServer.hook(subdir, callback)
|
||||
assert isinstance(http_servers, list)
|
||||
for server in http_servers:
|
||||
server.hook(subdir, callback)
|
||||
|
||||
def unhook(subdir):
|
||||
"""Unsets the callback assigned to the given subdir, and return it."""
|
||||
global httpServer
|
||||
assert httpServer is not None
|
||||
callback = httpServer.unhook(subdir)
|
||||
if len(httpServer.callbacks) <= 0 and not configGroup.keepAlive():
|
||||
stopServer()
|
||||
global http_servers
|
||||
assert isinstance(http_servers, list)
|
||||
for server in http_servers:
|
||||
callback = server.unhook(subdir)
|
||||
if len(server.callbacks) <= 0 and not configGroup.keepAlive():
|
||||
server.shutdown()
|
||||
http_servers.remove(server)
|
||||
|
Loading…
Reference in New Issue
Block a user