Fix HTTPS scheme detection behind reverse proxy
When behind a reverse proxy that terminates SSL, the server sees HTTP requests internally. Added _get_base_url() helper that respects the X-Forwarded-Proto header to generate correct external HTTPS URLs. This fixes links in the PyPI simple index showing http:// instead of https:// when accessed via HTTPS through a load balancer.
This commit is contained in:
@@ -81,6 +81,26 @@ def _get_basic_auth(source) -> Optional[tuple[str, str]]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_base_url(request: Request) -> str:
|
||||||
|
"""
|
||||||
|
Get the external base URL, respecting X-Forwarded-Proto header.
|
||||||
|
|
||||||
|
When behind a reverse proxy that terminates SSL, the request.base_url
|
||||||
|
will show http:// even though the external URL is https://. This function
|
||||||
|
checks the X-Forwarded-Proto header to determine the correct scheme.
|
||||||
|
"""
|
||||||
|
base_url = str(request.base_url).rstrip('/')
|
||||||
|
|
||||||
|
# Check for X-Forwarded-Proto header (set by reverse proxies)
|
||||||
|
forwarded_proto = request.headers.get('x-forwarded-proto')
|
||||||
|
if forwarded_proto:
|
||||||
|
# Replace the scheme with the forwarded protocol
|
||||||
|
parsed = urlparse(base_url)
|
||||||
|
base_url = f"{forwarded_proto}://{parsed.netloc}{parsed.path}"
|
||||||
|
|
||||||
|
return base_url
|
||||||
|
|
||||||
|
|
||||||
def _rewrite_package_links(html: str, base_url: str, package_name: str, upstream_base_url: str) -> str:
|
def _rewrite_package_links(html: str, base_url: str, package_name: str, upstream_base_url: str) -> str:
|
||||||
"""
|
"""
|
||||||
Rewrite download links in a PyPI simple page to go through our proxy.
|
Rewrite download links in a PyPI simple page to go through our proxy.
|
||||||
@@ -189,7 +209,7 @@ async def pypi_simple_index(
|
|||||||
content = response.text
|
content = response.text
|
||||||
|
|
||||||
# Rewrite package links to go through our proxy
|
# Rewrite package links to go through our proxy
|
||||||
base_url = str(request.base_url).rstrip('/')
|
base_url = _get_base_url(request)
|
||||||
content = re.sub(
|
content = re.sub(
|
||||||
r'href="([^"]+)/"',
|
r'href="([^"]+)/"',
|
||||||
lambda m: f'href="{base_url}/pypi/simple/{m.group(1)}/"',
|
lambda m: f'href="{base_url}/pypi/simple/{m.group(1)}/"',
|
||||||
@@ -235,7 +255,7 @@ async def pypi_package_versions(
|
|||||||
detail="No PyPI upstream sources configured"
|
detail="No PyPI upstream sources configured"
|
||||||
)
|
)
|
||||||
|
|
||||||
base_url = str(request.base_url).rstrip('/')
|
base_url = _get_base_url(request)
|
||||||
|
|
||||||
# Normalize package name (PEP 503)
|
# Normalize package name (PEP 503)
|
||||||
normalized_name = re.sub(r'[-_.]+', '-', package_name).lower()
|
normalized_name = re.sub(r'[-_.]+', '-', package_name).lower()
|
||||||
|
|||||||
Reference in New Issue
Block a user