Skip to content
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
5 changes: 3 additions & 2 deletions marimo/_server/api/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,10 @@ async def __call__(
if self.path_rewrite:
ws_path = self.path_rewrite(ws_path)
ws_url = urljoin(ws_target_url, ws_path)
if scope["scheme"] in ("http", "ws"):
scheme = urlparse(ws_url).scheme
if scheme in ("http", "ws"):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the target scheme is already ws or wss, I don't think it needs to be replaced?

Also, that might lead to an unexpected replacement with a target such as ws://example.com/http which would be replaced to ws://example.com/ws.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right. i will fix this

ws_url = ws_url.replace("http", "ws", 1)
elif scope["scheme"] in ("https", "wss"):
elif scheme in ("https", "wss"):
ws_url = ws_url.replace("https", "wss", 1)

LOGGER.debug(f"Creating websocket proxy for {ws_url}")
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,9 @@ output_max_bytes = 10_000_000
std_stream_max_bytes = 2_000_000
dotenv = [".env"]

[tool.marimo.package_management]
manager = "uv"

[tool.marimo.keymap]
vimrc = "configs/.vimrc"

Expand Down
50 changes: 49 additions & 1 deletion tests/_server/api/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,4 +594,52 @@ def test_proxy_websocket_with_invalid_id(
assert message["type"] == "error"
assert "invalid" in message["message"].lower()

# Could be good to go on to test the happy path for mpl but we're already doing that with the test client above so leaving just this invalid ID test for
async def test_proxy_middleware_websocket_protocol(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test that ProxyMiddleware correctly converts http/https to ws/wss."""
# Create a simple app and middleware
app = Starlette()
middleware = ProxyMiddleware(app, "/proxy", "http://example.com")

# Mock the _proxy_websocket method to capture the URL
proxy_calls: list[str] = []

async def mock_proxy_websocket(
self: Any, scope: Scope, receive: Receive, send: Send, ws_url: str
):
del self, scope, receive, send
proxy_calls.append(ws_url)

monkeypatch.setattr(
ProxyMiddleware, "_proxy_websocket", mock_proxy_websocket
)

# Create test scope for websocket
scope = {
"type": "websocket",
"path": "/proxy/test",
"query_string": b"",
}

# Test with http target
middleware.target_url = "http://example.com"
await middleware(scope, None, None)
assert proxy_calls[-1] == "ws://example.com/proxy/test"

# Test with https target
middleware.target_url = "https://example.com"
await middleware(scope, None, None)
assert proxy_calls[-1] == "wss://example.com/proxy/test"

# Test with callable target that returns http
middleware.target_url = lambda _path: "http://example.com"
await middleware(scope, None, None)
assert proxy_calls[-1] == "ws://example.com/proxy/test"

# Test with callable target that returns https
middleware.target_url = lambda _path: "https://example.com"
await middleware(scope, None, None)
assert proxy_calls[-1] == "wss://example.com/proxy/test"

# Could be good to go on to test the happy path for mpl but we're already doing that with the test client above so leaving just this invalid ID test for
2 changes: 1 addition & 1 deletion tests/_server/templates/snapshots/export1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<marimo-filename hidden>notebook.py</marimo-filename>
<marimo-mode data-mode='read' hidden></marimo-mode>
<marimo-version data-version='0.0.0' hidden></marimo-version>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "uv"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "pixi"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-app-config data-config='{"sql_output": "auto", "width": "compact"}' hidden></marimo-app-config>
<marimo-server-token data-token='token' hidden></marimo-server-token>
<title>notebook</title>
Expand Down
2 changes: 1 addition & 1 deletion tests/_server/templates/snapshots/export2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<marimo-filename hidden></marimo-filename>
<marimo-mode data-mode='read' hidden></marimo-mode>
<marimo-version data-version='0.0.0' hidden></marimo-version>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "uv"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "pixi"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-app-config data-config='{"sql_output": "auto", "width": "compact"}' hidden></marimo-app-config>
<marimo-server-token data-token='token' hidden></marimo-server-token>
<title>marimo</title>
Expand Down
2 changes: 1 addition & 1 deletion tests/_server/templates/snapshots/export3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<marimo-filename hidden>notebook.py</marimo-filename>
<marimo-mode data-mode='read' hidden></marimo-mode>
<marimo-version data-version='0.0.0' hidden></marimo-version>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "uv"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "pixi"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-app-config data-config='{"sql_output": "auto", "width": "compact"}' hidden></marimo-app-config>
<marimo-server-token data-token='token' hidden></marimo-server-token>
<title>notebook</title>
Expand Down
2 changes: 1 addition & 1 deletion tests/_server/templates/snapshots/export4.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<marimo-filename hidden>notebook.py</marimo-filename>
<marimo-mode data-mode='read' hidden></marimo-mode>
<marimo-version data-version='0.0.0' hidden></marimo-version>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "uv"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "pixi"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-app-config data-config='{"css_file": "custom.css", "sql_output": "auto", "width": "compact"}' hidden></marimo-app-config>
<marimo-server-token data-token='token' hidden></marimo-server-token>
<title>notebook</title>
Expand Down
2 changes: 1 addition & 1 deletion tests/_server/templates/snapshots/export5.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<marimo-filename hidden>notebook.py</marimo-filename>
<marimo-mode data-mode='read' hidden></marimo-mode>
<marimo-version data-version='0.0.0' hidden></marimo-version>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "uv"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "pixi"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-app-config data-config='{"app_title": "My App", "html_head_file": "head.html", "sql_output": "auto", "width": "compact"}' hidden></marimo-app-config>
<marimo-server-token data-token='token' hidden></marimo-server-token>
<title>My App</title>
Expand Down
2 changes: 1 addition & 1 deletion tests/_server/templates/snapshots/export6.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<marimo-filename hidden>notebook.py</marimo-filename>
<marimo-mode data-mode='read' hidden></marimo-mode>
<marimo-version data-version='0.0.0' hidden></marimo-version>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "custom_css": ["custom1.css", "custom2.css"], "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "uv"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-user-config data-config='{"completion": {"activate_on_typing": true, "copilot": false}, "display": {"cell_output": "above", "code_editor_font_size": 14, "custom_css": ["custom1.css", "custom2.css"], "dataframes": "rich", "default_table_page_size": 10, "default_width": "medium", "theme": "light"}, "formatting": {"line_length": 79}, "keymap": {"overrides": {}, "preset": "default"}, "language_servers": {"pylsp": {"enable_flake8": false, "enable_mypy": true, "enable_pydocstyle": false, "enable_pyflakes": false, "enable_pylint": false, "enable_ruff": true, "enabled": true}}, "package_management": {"manager": "pixi"}, "runtime": {"auto_instantiate": true, "auto_reload": "off", "on_cell_change": "autorun", "output_max_bytes": 8000000, "reactive_tests": true, "std_stream_max_bytes": 1000000, "watcher_on_save": "lazy"}, "save": {"autosave": "after_delay", "autosave_delay": 1000, "format_on_save": false}, "server": {"browser": "default", "follow_symlink": false}, "snippets": {"custom_paths": [], "include_default_snippets": true}}' data-overrides='{"formatting": {"line_length": 100}}' hidden></marimo-user-config>
<marimo-app-config data-config='{"sql_output": "auto", "width": "compact"}' hidden></marimo-app-config>
<marimo-server-token data-token='token' hidden></marimo-server-token>
<title>notebook</title>
Expand Down
Loading