From d65f8e628dd7edc038c7e890bfc005dc1d97f7b6 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 12 Feb 2025 13:37:17 +0100 Subject: [PATCH 1/2] Ensure index redirects are relative --- panel/io/server.py | 18 ++++++++++++++++++ panel/tests/ui/io/test_server.py | 14 ++++++++++++++ panel/tests/util.py | 6 +++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/panel/io/server.py b/panel/io/server.py index 0e838512b3..c5ddc5bfe6 100644 --- a/panel/io/server.py +++ b/panel/io/server.py @@ -577,6 +577,24 @@ class RootHandler(LoginUrlMixin, BkRootHandler): template variable. """ + @authenticated + async def get(self, *args, **kwargs): + if self.use_redirect and len(self.applications) == 1: + app_names = list(self.applications.keys()) + redirect_to = f".{app_names[0]}" + self.redirect(redirect_to) + else: + apps = sorted(self.applications.keys()) + if self.index is None: + index = "app_index.html" + else: + index = self.index + apps = [ + app if self.request.uri.endswith('/') or not self.prefix else f"{self.prefix}{app}" + for app in apps + ] + self.render(index, prefix=self.prefix, items=apps) + def render(self, *args, **kwargs): kwargs['PANEL_CDN'] = CDN_DIST return super().render(*args, **kwargs) diff --git a/panel/tests/ui/io/test_server.py b/panel/tests/ui/io/test_server.py index 357c09bded..0680abfe97 100644 --- a/panel/tests/ui/io/test_server.py +++ b/panel/tests/ui/io/test_server.py @@ -11,6 +11,20 @@ pytestmark = pytest.mark.ui +@pytest.mark.parametrize('prefix', ['', '/prefix/']) +def test_server_index_redirect(page, prefix): + serve_component(page, '### App', prefix=prefix, suffix=prefix) + + expect(page.locator("h3")).to_have_text('App') + +@pytest.mark.parametrize('prefix', ['', '/prefix/']) +def test_server_index_redirect_via_proxy(page, prefix, reverse_proxy): + port, proxy = reverse_proxy + serve_component(page, '### App', prefix=prefix, suffix=f"/proxy{prefix or '/'}", port=port, proxy=proxy) + + expect(page.locator("h3")).to_have_text('App') + + def test_server_reuse_sessions(page, reuse_sessions): def app(counts=[0]): content = f'### Count {counts[0]}' diff --git a/panel/tests/util.py b/panel/tests/util.py index 9c58f8249a..59c46d60dc 100644 --- a/panel/tests/util.py +++ b/panel/tests/util.py @@ -300,6 +300,8 @@ def serve_and_wait(app, page=None, prefix=None, port=None, proxy=None, **kwargs) port = port or get_open_ports()[0] else: serve_app = serve + if proxy: + kwargs['websocket_origin'] = [f'localhost:{proxy}'] serve_app(app, port=port or 0, threaded=True, show=False, liveness=True, server_id=server_id, prefix=prefix or "", **kwargs) wait_until(lambda: server_id in state._servers, page) server = state._servers[server_id][0] @@ -338,7 +340,9 @@ def serve_and_request(app, suffix="", n=1, port=None, proxy=None, **kwargs): def wait_for_server(port, prefix=None, timeout=3): start = time.time() prefix = prefix or "" - url = f"http://localhost:{port}{prefix}/liveness" + if not prefix.endswith('/'): + prefix += '/' + url = f"http://localhost:{port}{prefix}liveness" while True: try: if requests.get(url).ok: From 18cdbaf59c935fdce3e93e800039f9bde19aae28 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Wed, 12 Feb 2025 13:50:17 +0100 Subject: [PATCH 2/2] More tests --- panel/tests/ui/io/test_server.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/panel/tests/ui/io/test_server.py b/panel/tests/ui/io/test_server.py index 0680abfe97..9f0762a099 100644 --- a/panel/tests/ui/io/test_server.py +++ b/panel/tests/ui/io/test_server.py @@ -24,6 +24,23 @@ def test_server_index_redirect_via_proxy(page, prefix, reverse_proxy): expect(page.locator("h3")).to_have_text('App') +@pytest.mark.parametrize('prefix', ['', '/prefix/']) +def test_server_index_page_links(page, prefix): + serve_component(page, {'app1': '### App1', 'app2': '### App2'}, prefix=prefix, suffix=prefix, wait=False) + + page.locator('.card-link').nth(0).click() + + expect(page.locator("h3")).to_have_text('App1') + +@pytest.mark.parametrize('prefix', ['', '/prefix/']) +def test_server_index_page_links_via_proxy(page, prefix, reverse_proxy): + port, proxy = reverse_proxy + serve_component(page, {'app1': '### App1', 'app2': '### App2'}, prefix=prefix, suffix=f"/proxy{prefix or '/'}", port=port, proxy=proxy, wait=False) + + page.locator('.card-link').nth(0).click() + + expect(page.locator("h3")).to_have_text('App1') + def test_server_reuse_sessions(page, reuse_sessions): def app(counts=[0]):