Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support panel fastapi behind reverse proxy #7278

Merged
merged 4 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 41 additions & 27 deletions panel/io/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,46 @@
from bokeh.server.contexts import BokehSessionContext
from pyviz_comms import Comm

def _get_location_params(protocol: str|None, host: str| None, uri: str| None)->dict:
MarcSkovMadsen marked this conversation as resolved.
Show resolved Hide resolved
params = {}
href = ''
if protocol:
params['protocol'] = href = f'{protocol}:'
if host:
if host.startswith("::ffff:"):
host = host.replace("::ffff:", "")

href += f'//{host}'
if ':' in host:
params['hostname'], params['port'] = host.split(':')
else:
params['hostname'] = host
if uri:
search = hash = None

if uri.startswith("https,"):
uri = uri.replace("https,", "")

if uri.startswith("http"):
uri = urlparse.urlparse(uri).path

href += uri
if '?' in uri and '#' in uri:
params['pathname'], query = uri.split('?')
search, hash = query.split('#')
elif '?' in uri:
params['pathname'], search = uri.split('?')
elif '#' in uri:
params['pathname'], hash = uri.split('#')
else:
params['pathname'] = uri
if search:
params['search'] = f'?{search}'
if hash:
params['hash'] = f'#{hash}'
params['href'] = href
return params

class Location(Syncable):
"""
The Location component can be made available in a server context
Expand Down Expand Up @@ -70,33 +110,7 @@ def from_request(cls, request):
except ImportError:
return cls()

params = {}
href = ''
if request.protocol:
params['protocol'] = href = f'{request.protocol}:'
if request.host:
href += f'//{request.host}'
if ':' in request.host:
params['hostname'], params['port'] = request.host.split(':')
else:
params['hostname'] = request.host
if request.uri:
search = hash = None
href += request.uri
if '?' in request.uri and '#' in request.uri:
params['pathname'], query = request.uri.split('?')
search, hash = query.split('#')
elif '?' in request.uri:
params['pathname'], search = request.uri.split('?')
elif '#' in request.uri:
params['pathname'], hash = request.uri.split('#')
else:
params['pathname'] = request.uri
if search:
params['search'] = f'?{search}'
if hash:
params['hash'] = f'#{hash}'
params['href'] = href
params = _get_location_params(request.protocol, request.host, request.uri)
loc = cls()
with edit_readonly(loc):
loc.param.update(params)
Expand Down
19 changes: 18 additions & 1 deletion panel/tests/io/test_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import param
import pytest

from panel.io.location import Location
from panel.io.location import Location, _get_location_params
from panel.io.state import state
from panel.tests.util import serve_and_request, wait_until
from panel.util import edit_readonly
Expand Down Expand Up @@ -188,3 +188,20 @@ def test_location_sync_to_dataframe_with_initial_value(location, dataframe):
location.search = "?dataframe=%5B%7B%22x%22%3A+1%7D%5D"
location.sync(p)
pd.testing.assert_frame_equal(p.dataframe, dataframe)

@pytest.mark.parametrize(("protocol", "host", "uri", "expected"), [
# Started with the command fastapi dev script.py on local laptop
(
"http", "127.0.0.1", "/panel",
{'protocol': 'http:', 'hostname': '127.0.0.1', 'pathname': '/panel', 'href': 'http://127.0.0.1/panel'}
),
# Started with the command fastapi dev script.py --root-path /some/path in VS Code terminal on JupyterHub
(
"http", "::ffff:172.20.0.233", "https,http://sub.domain.dk/some/path/panel",
# I believe the below should be the result. But do not know for sure
{"protocol": "http:", "hostname": "172.20.0.233", "pathname": "/some/path/panel", 'href': 'http://172.20.0.233/some/path/panel'}
)
])
def test_get_location_params(protocol, host, uri, expected):
params = _get_location_params(protocol, host, uri)
assert params==expected
Loading