[WebUI] Fix setting base path

Simplify the code for setting the base path, both via headers and
config. Replaced putchild since it is not recommended for dynamic
paths and overriding getChildWithDefault provides a proper solution.

This also fixes recursive base path problem with previous code where
appending base paths to URL would still return Deluge web e.g.

    http://localhost:8112/deluge/deluge/deluge

Removed getChild override by consolidating empty path conditional to
getChildWithDefault. This simplifies and combines the returning of
TopLevel resource for root path or base path.

Added workaround for test logfile error with forwardslash in filename
This commit is contained in:
Calum Lind 2023-03-02 21:53:27 +00:00
parent 683a4f906e
commit 4b6ac1f4c4
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
3 changed files with 64 additions and 12 deletions

View File

@ -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

View File

@ -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

View File

@ -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