diff --git a/httpx/_client.py b/httpx/_client.py index 2249231f8c..ee644045a1 100644 --- a/httpx/_client.py +++ b/httpx/_client.py @@ -5,6 +5,7 @@ import logging import time import typing +import re import warnings from contextlib import asynccontextmanager, contextmanager from types import TracebackType @@ -91,6 +92,17 @@ def _same_origin(url: URL, other: URL) -> bool: ) +SANITIZE_URL_PATTERN = re.compile(r"://([^:@]+):([^:@]+)@") + + +def sanitize_url(url): + """ + Removes credentials (password) from URLs while preserving username if present. + Example: 'http://user:pass@example.com' -> 'http://user@example.com' + """ + return SANITIZE_URL_PATTERN.sub(r"://\1@", url) + + class UseClientDefault: """ For some parameters such as `auth=...` and `timeout=...` we need to be able @@ -1022,10 +1034,10 @@ def _send_single_request(self, request: Request) -> Response: self.cookies.extract_cookies(response) response.default_encoding = self._default_encoding - logger.info( + logger.debug( 'HTTP Request: %s %s "%s %d %s"', request.method, - request.url, + sanitize_url(request.url), response.http_version, response.status_code, response.reason_phrase, @@ -1737,10 +1749,10 @@ async def _send_single_request(self, request: Request) -> Response: self.cookies.extract_cookies(response) response.default_encoding = self._default_encoding - logger.info( + logger.debug( 'HTTP Request: %s %s "%s %d %s"', request.method, - request.url, + sanitize_url(request.url), response.http_version, response.status_code, response.reason_phrase,