diff --git a/CHANGES.txt b/CHANGES.txt index 167e062d5..451abab22 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -51,6 +51,10 @@ - Files included via the `[include]` section are read in sorted order. In past versions, the order was undefined. Patch by Ionel Cristian Mărieș. +- Added ``base_path`` option in the `[inet_http_server]` section. This + allows to put the web interface behind a reverse proxy (i.e. web server). + The default value is ``/``. + - Fixed a bug introduced in 3.1.0 where ``supervisord`` could crash when attempting to display a resource limit error. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index a2b709589..5fa0f689f 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -48,3 +48,5 @@ Contributors - Márk Sági-Kazár, 2013-12-16 - Gülşah Köse, 2014-07-17 + +- Seyeong Jeong, 2015-03-19 diff --git a/TODO.txt b/TODO.txt index c29ca78e6..d13687d83 100644 --- a/TODO.txt +++ b/TODO.txt @@ -69,8 +69,6 @@ - Option to automatically refresh the status page (issue #73). - - Better support for use with proxy servers (issue #29) - - Expat error on Jens' system running slapd as root after reload. - Command-line arg tests. diff --git a/docs/configuration.rst b/docs/configuration.rst index ab30f7768..56fa578b2 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -175,6 +175,18 @@ configuration values are as follows. *Introduced*: 3.0 +``base_path`` + + Specify the base path for the web interface. For example, + ``base_path=/supervisor/`` yields the web interface accessible at + ``http://localhost:4567/supervisor/``. + + *Default*: ``/`` + + *Required*: No. + + *Introduced*: 4.0 + ``[inet_http_server]`` Section Example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/supervisor/http.py b/supervisor/http.py index 759424b3a..989dc64d1 100644 --- a/supervisor/http.py +++ b/supervisor/http.py @@ -420,6 +420,11 @@ def found_terminator (self): command, uri, version = http_server.crack_request (request) header = http_server.join_headers (lines[1:]) + # strip the ``base_path`` so that the handlers don't need to know + # about the ``base_path``. + if uri.startswith(self.server.base_path): + uri = '/' + uri[len(self.server.base_path):] + # unquote path if necessary (thanks to Skip Montanaro for pointing # out that we must unquote in piecemeal fashion). rpath, rquery = http_server.splitquery(uri) @@ -522,12 +527,13 @@ def log_info(self, message, type='info'): class supervisor_af_inet_http_server(supervisor_http_server): """ AF_INET version of supervisor HTTP server """ - def __init__(self, ip, port, logger_object): + def __init__(self, ip, port, logger_object, base_path='/'): self.ip = ip self.port = port sock = text_socket.text_socket(socket.AF_INET, socket.SOCK_STREAM) self.prebind(sock, logger_object) self.bind((ip, port)) + self.base_path = base_path if not ip: self.log_info('Computing default hostname', 'warning') @@ -799,8 +805,10 @@ def log(self, msg): if family == socket.AF_INET: host, port = config['host'], config['port'] + base_path = config.get('base_path', '/') hs = supervisor_af_inet_http_server(host, port, - logger_object=wrapper) + logger_object=wrapper, + base_path=base_path) elif family == socket.AF_UNIX: socketname = config['file'] sockchmod = config['chmod'] diff --git a/supervisor/options.py b/supervisor/options.py index 32c3b26f5..292f1e3db 100644 --- a/supervisor/options.py +++ b/supervisor/options.py @@ -1025,6 +1025,15 @@ def server_configs_from_parser(self, parser): config['host'] = host config['port'] = port config['section'] = section + + # sanitize base_path + base_path = get(section, 'base_path', '/') + if not base_path.endswith('/'): + base_path += '/' + if not base_path.startswith('/'): + base_path = '/' + base_path + config['base_path'] = base_path + configs.append(config) unix_serverdefs = self._parse_servernames(parser, 'unix_http_server') diff --git a/supervisor/skel/sample.conf b/supervisor/skel/sample.conf index 1ae42bd62..938c49480 100644 --- a/supervisor/skel/sample.conf +++ b/supervisor/skel/sample.conf @@ -19,6 +19,7 @@ file=/tmp/supervisor.sock ; (the path to the socket file) ;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface) ;username=user ; (default is no username (open server)) ;password=123 ; (default is no password (open server)) +;base_path=/supervisor/ ; (default is /) [supervisord] logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log) diff --git a/supervisor/tests/base.py b/supervisor/tests/base.py index a06e957f6..15d662f84 100644 --- a/supervisor/tests/base.py +++ b/supervisor/tests/base.py @@ -604,6 +604,7 @@ def log(self, category, msg): class DummyMedusaServer: def __init__(self): self.logger = DummyMedusaServerLogger() + self.base_path = '/' class DummyMedusaChannel: def __init__(self): diff --git a/supervisor/ui/status.html b/supervisor/ui/status.html index bfef1e00e..2341ca76d 100644 --- a/supervisor/ui/status.html +++ b/supervisor/ui/status.html @@ -6,6 +6,7 @@