diff --git a/deluge/tests/common.py b/deluge/tests/common.py index b5941568d..0e82bf12b 100644 --- a/deluge/tests/common.py +++ b/deluge/tests/common.py @@ -113,7 +113,7 @@ class ProcessOutputHandler(protocol.ProcessProtocol): self.shutdown_func = shutdown_func self.log_output = '' self.stderr_out = '' - self.logfile = logfile + self.logfile = logfile.replace('/', '_') if logfile else None self.print_stdout = print_stdout self.print_stderr = print_stderr self.quit_d = None diff --git a/deluge/tests/test_webserver.py b/deluge/tests/test_webserver.py index 69a424e77..683ab97a1 100644 --- a/deluge/tests/test_webserver.py +++ b/deluge/tests/test_webserver.py @@ -9,6 +9,7 @@ import json as json_lib from io import BytesIO +import pytest import pytest_twisted import twisted.web.client from twisted.internet import reactor @@ -57,3 +58,56 @@ class TestWebServer(WebServerTestBase, WebServerMockBase): print('aoeu') assert json['error'] is None assert 'torrent_filehash' == json['result']['name'] + + @pytest.mark.parametrize('base', ['', '/', 'deluge']) + @pytest_twisted.ensureDeferred + async def test_base_with_config(self, base): + agent = Agent(reactor) + root_url = f'http://127.0.0.1:{self.deluge_web.port}' + base_url = f'{root_url}/{base}' + + self.deluge_web.base = base + + response = await agent.request(b'GET', root_url.encode()) + assert response.code == 200 + body = await twisted.web.client.readBody(response) + assert 'Deluge WebUI' in body.decode() + + response = await agent.request(b'GET', base_url.encode()) + assert response.code == 200 + + @pytest.mark.parametrize('base', ['/', 'deluge']) + @pytest_twisted.ensureDeferred + async def test_base_with_config_recurring_basepath(self, base): + agent = Agent(reactor) + base_url = f'http://127.0.0.1:{self.deluge_web.port}/{base}' + + self.deluge_web.base = base + + response = await agent.request(b'GET', base_url.encode()) + assert response.code == 200 + + recursive_url = f'{base_url}/{base}' + response = await agent.request(b'GET', recursive_url.encode()) + assert response.code == 404 if base.strip('/') else 200 + + recursive_url = f'{recursive_url}/{base}' + response = await agent.request(b'GET', recursive_url.encode()) + assert response.code == 404 if base.strip('/') else 200 + + @pytest_twisted.ensureDeferred + async def test_base_with_deluge_header(self): + """Ensure base path is set and HTML contains path""" + agent = Agent(reactor) + base = 'deluge' + url = f'http://127.0.0.1:{self.deluge_web.port}' + headers = Headers({'X-Deluge-Base': [base]}) + + response = await agent.request(b'GET', url.encode(), headers) + body = await twisted.web.client.readBody(response) + assert f'href="/{base}/' in body.decode() + + # Header only changes HTML base path so ensure no resource at server path + url = f'{url}/{base}' + response = await agent.request(b'GET', url.encode(), headers) + assert response.code == 404 diff --git a/deluge/ui/web/server.py b/deluge/ui/web/server.py index 06b25923b..fe563f130 100644 --- a/deluge/ui/web/server.py +++ b/deluge/ui/web/server.py @@ -569,18 +569,20 @@ class TopLevel(resource.Resource): self.__scripts.remove(script) self.__debug_scripts.remove(script) - def getChild(self, path, request): # NOQA: N802 - if not path: - return self - else: - return super().getChild(path, request) - def getChildWithDefault(self, path, request): # NOQA: N802 # Calculate the request base header = request.getHeader('x-deluge-base') - base = header if header else component.get('DelugeWeb').base + config_base = component.get('DelugeWeb').base + base = header if header else config_base + + first_request = not hasattr(request, 'base') request.base = absolute_base_url(base).encode() + base_resource = first_request and path.decode() == config_base.strip('/') + + if not path or base_resource: + return self + return super().getChildWithDefault(path, request) def render(self, request): @@ -680,10 +682,6 @@ class DelugeWeb(component.Component): elif options.no_ssl: self.https = False - if self.base != '/': - # Strip away slashes and serve on the base path as well as root path - self.top_level.putChild(self.base.strip('/').encode(), self.top_level) - setup_translation() # Remove twisted version number from 'server' http-header for security reasons