diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ebf867d..ebd8ad57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ where X.Y.Z is the semver of the most recent choreographer release. ### Added - Add `enable_extensions` option to control browser extension loading [[#303](https://github.com/plotly/choreographer/pull/303)], with thanks to @hirohira9119 for the contribution! +- Add `proxy_server` browser configuration with a `CHOREO_PROXY_SERVER` environment fallback [[#304](https://github.com/plotly/choreographer/pull/304)], with thanks to @ColumbusLabs for the contribution! ### Fixed - Improve platform architecture detection for arm on Linux and Windows [[#290](https://github.com/plotly/choreographer/pull/290)], with thanks to @juliabeliaeva for the contribution! diff --git a/src/choreographer/browsers/chromium.py b/src/choreographer/browsers/chromium.py index 0b32239a..56920c5d 100644 --- a/src/choreographer/browsers/chromium.py +++ b/src/choreographer/browsers/chromium.py @@ -68,6 +68,8 @@ class Chromium: """True if we should use the gpu. False by default for compatibility.""" headless: bool """True if we should not show the browser. True by default.""" + proxy_server: str | None + """Proxy server passed to Chromium, if configured.""" sandbox_enabled: bool """True to enable the sandbox. False by default.""" skip_local: bool @@ -147,6 +149,8 @@ def __init__( enable_extensions (default True): Enable extensions? enable_gpu (default False): Turn on GPU? Doesn't work in all envs. headless (default True): Run the browser in headless mode? + proxy_server (default None): Proxy server URL passed to Chromium. + Falls back to the `CHOREO_PROXY_SERVER` environment variable. enable_sandbox (default False): Enable sandbox- a persnickety thing depending on environment, OS, user, etc tmp_dir (default None): Manually set the temporary directory @@ -161,6 +165,9 @@ def __init__( self.extensions_enabled = kwargs.pop("enable_extensions", True) self.gpu_enabled = kwargs.pop("enable_gpu", False) self.headless = kwargs.pop("headless", True) + self.proxy_server = kwargs.pop("proxy_server", None) or os.environ.get( + "CHOREO_PROXY_SERVER", + ) self.sandbox_enabled = kwargs.pop("enable_sandbox", False) self._tmp_dir_path = kwargs.pop("tmp_dir", None) if kwargs: @@ -247,6 +254,8 @@ def get_cli(self) -> Sequence[str]: cli.append("--disable-gpu") if self.headless: cli.append("--headless") + if self.proxy_server: + cli.append(f"--proxy-server={self.proxy_server}") if not self.sandbox_enabled: cli.append("--no-sandbox") diff --git a/tests/test_chromium.py b/tests/test_chromium.py new file mode 100644 index 00000000..7512f4e1 --- /dev/null +++ b/tests/test_chromium.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from choreographer.browsers.chromium import Chromium +from choreographer.channels import Pipe + + +def _get_cli(tmp_path, **kwargs) -> list[str]: + executable = tmp_path / "chrome" + executable.touch() + channel = Pipe() + browser = Chromium(channel, executable, **kwargs) + browser.pre_open() + try: + return list(browser.get_cli()) + finally: + browser.clean() + channel.close() + + +def test_proxy_server_argument(tmp_path, monkeypatch): + monkeypatch.delenv("CHOREO_PROXY_SERVER", raising=False) + + cli = _get_cli(tmp_path, proxy_server="http://proxy.example:8080") + + assert "--proxy-server=http://proxy.example:8080" in cli + + +def test_proxy_server_environment_variable(tmp_path, monkeypatch): + monkeypatch.setenv("CHOREO_PROXY_SERVER", "socks5://proxy.example:1080") + + cli = _get_cli(tmp_path) + + assert "--proxy-server=socks5://proxy.example:1080" in cli + + +def test_proxy_server_argument_overrides_environment(tmp_path, monkeypatch): + monkeypatch.setenv("CHOREO_PROXY_SERVER", "http://environment.example:8080") + + cli = _get_cli(tmp_path, proxy_server="http://argument.example:8080") + + assert "--proxy-server=http://argument.example:8080" in cli + assert "--proxy-server=http://environment.example:8080" not in cli + + +def test_proxy_server_is_not_added_by_default(tmp_path, monkeypatch): + monkeypatch.delenv("CHOREO_PROXY_SERVER", raising=False) + + cli = _get_cli(tmp_path) + + assert not any(arg.startswith("--proxy-server=") for arg in cli) + + +def test_none_proxy_server_uses_environment_fallback(tmp_path, monkeypatch): + monkeypatch.setenv("CHOREO_PROXY_SERVER", "http://environment.example:8080") + + cli = _get_cli(tmp_path, proxy_server=None) + + assert "--proxy-server=http://environment.example:8080" in cli + + +def test_empty_proxy_server_uses_environment_fallback(tmp_path, monkeypatch): + monkeypatch.setenv("CHOREO_PROXY_SERVER", "http://environment.example:8080") + + cli = _get_cli(tmp_path, proxy_server="") + + assert "--proxy-server=http://environment.example:8080" in cli