[REF-3633] [main] Introduce a workaround for enterprise users who get stuck with httpx.get SSL (#3847)
* [REF-3633] Introduce a workaround for enterprise users who get stuck with httpx.get SSL Setting SSL_NO_VERIFY=1 will disable SSL verification during `reflex init` * Also install fnm using `reflex.utils.net.get`
This commit is contained in:
parent
be71254250
commit
3fa9f1fc06
43
reflex/utils/net.py
Normal file
43
reflex/utils/net.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""Helpers for downloading files from the network."""
|
||||
|
||||
import os
|
||||
|
||||
import httpx
|
||||
|
||||
from . import console
|
||||
|
||||
|
||||
def _httpx_verify_kwarg() -> bool:
|
||||
"""Get the value of the HTTPX verify keyword argument.
|
||||
|
||||
Returns:
|
||||
True if SSL verification is enabled, False otherwise
|
||||
"""
|
||||
ssl_no_verify = os.environ.get("SSL_NO_VERIFY", "").lower() in ["true", "1", "yes"]
|
||||
return not ssl_no_verify
|
||||
|
||||
|
||||
def get(url: str, **kwargs) -> httpx.Response:
|
||||
"""Make an HTTP GET request.
|
||||
|
||||
Args:
|
||||
url: The URL to request.
|
||||
**kwargs: Additional keyword arguments to pass to httpx.get.
|
||||
|
||||
Returns:
|
||||
The response object.
|
||||
|
||||
Raises:
|
||||
httpx.ConnectError: If the connection cannot be established.
|
||||
"""
|
||||
kwargs.setdefault("verify", _httpx_verify_kwarg())
|
||||
try:
|
||||
return httpx.get(url, **kwargs)
|
||||
except httpx.ConnectError as err:
|
||||
if "CERTIFICATE_VERIFY_FAILED" in str(err):
|
||||
# If the error is a certificate verification error, recommend mitigating steps.
|
||||
console.error(
|
||||
f"Certificate verification failed for {url}. Set environment variable SSL_CERT_FILE to the "
|
||||
"path of the certificate file or SSL_NO_VERIFY=1 to disable verification."
|
||||
)
|
||||
raise
|
@ -34,7 +34,7 @@ from reflex import constants, model
|
||||
from reflex.base import Base
|
||||
from reflex.compiler import templates
|
||||
from reflex.config import Config, get_config
|
||||
from reflex.utils import console, path_ops, processes
|
||||
from reflex.utils import console, net, path_ops, processes
|
||||
from reflex.utils.format import format_library_name
|
||||
from reflex.utils.registry import _get_best_registry
|
||||
|
||||
@ -80,7 +80,7 @@ def check_latest_package_version(package_name: str):
|
||||
# Get the latest version from PyPI
|
||||
current_version = importlib.metadata.version(package_name)
|
||||
url = f"https://pypi.org/pypi/{package_name}/json"
|
||||
response = httpx.get(url)
|
||||
response = net.get(url)
|
||||
latest_version = response.json()["info"]["version"]
|
||||
if (
|
||||
version.parse(current_version) < version.parse(latest_version)
|
||||
@ -670,7 +670,7 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
|
||||
"""
|
||||
# Download the script
|
||||
console.debug(f"Downloading {url}")
|
||||
response = httpx.get(url)
|
||||
response = net.get(url)
|
||||
if response.status_code != httpx.codes.OK:
|
||||
response.raise_for_status()
|
||||
|
||||
@ -700,11 +700,11 @@ def download_and_extract_fnm_zip():
|
||||
try:
|
||||
# Download the FNM zip release.
|
||||
# TODO: show progress to improve UX
|
||||
with httpx.stream("GET", url, follow_redirects=True) as response:
|
||||
response.raise_for_status()
|
||||
with open(fnm_zip_file, "wb") as output_file:
|
||||
for chunk in response.iter_bytes():
|
||||
output_file.write(chunk)
|
||||
response = net.get(url, follow_redirects=True)
|
||||
response.raise_for_status()
|
||||
with open(fnm_zip_file, "wb") as output_file:
|
||||
for chunk in response.iter_bytes():
|
||||
output_file.write(chunk)
|
||||
|
||||
# Extract the downloaded zip file.
|
||||
with zipfile.ZipFile(fnm_zip_file, "r") as zip_ref:
|
||||
@ -1222,7 +1222,7 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
|
||||
"""
|
||||
|
||||
def get_release_by_tag(tag: str) -> dict | None:
|
||||
response = httpx.get(constants.Reflex.RELEASES_URL)
|
||||
response = net.get(constants.Reflex.RELEASES_URL)
|
||||
response.raise_for_status()
|
||||
releases = response.json()
|
||||
for release in releases:
|
||||
@ -1243,7 +1243,7 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
|
||||
else:
|
||||
templates_url = asset["browser_download_url"]
|
||||
|
||||
templates_data = httpx.get(templates_url, follow_redirects=True).json()["templates"]
|
||||
templates_data = net.get(templates_url, follow_redirects=True).json()["templates"]
|
||||
|
||||
for template in templates_data:
|
||||
if template["name"] == "blank":
|
||||
@ -1286,7 +1286,7 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
|
||||
zip_file_path = Path(temp_dir) / "template.zip"
|
||||
try:
|
||||
# Note: following redirects can be risky. We only allow this for reflex built templates at the moment.
|
||||
response = httpx.get(template_url, follow_redirects=True)
|
||||
response = net.get(template_url, follow_redirects=True)
|
||||
console.debug(f"Server responded download request: {response}")
|
||||
response.raise_for_status()
|
||||
except httpx.HTTPError as he:
|
||||
@ -1417,7 +1417,7 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash:
|
||||
generation_hash: The generation hash from reflex.build.
|
||||
"""
|
||||
# Download the reflex code for the generation.
|
||||
resp = httpx.get(
|
||||
resp = net.get(
|
||||
constants.Templates.REFLEX_BUILD_CODE_URL.format(
|
||||
generation_hash=generation_hash
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user