add fallback

This commit is contained in:
Ali Asadi 2026-08-01 10:15:23 +03:30
parent 7e04edbc48
commit fa34e459cb
5 changed files with 55 additions and 6 deletions

View file

@ -6,6 +6,8 @@ import requests
from django.conf import settings
from django.core.cache import cache
from utils.http_fallback import request_with_ssl_fallback
logger = logging.getLogger(__name__)
CACHE_KEY_TEMPLATE = "proxy_upstream_openapi_schema_{service}"
@ -37,7 +39,7 @@ def _fetch_service_schema(service, base_url, schema_path):
url = f"{base_url.rstrip('/')}{schema_path}"
try:
response = requests.get(url, timeout=FETCH_TIMEOUT_SECONDS)
response = request_with_ssl_fallback("GET", url, timeout=FETCH_TIMEOUT_SECONDS)
response.raise_for_status()
schema = response.json()
except (requests.RequestException, ValueError) as exc:

View file

@ -5,6 +5,8 @@ from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from utils.http_fallback import request_with_ssl_fallback
# Headers that must not be copied verbatim between hops (RFC 7230 6.1) plus
# framing headers that HttpResponse recomputes itself.
HOP_BY_HOP_HEADERS = {
@ -54,9 +56,9 @@ class ServiceProxyView(View):
target_url = f"{target_url}?{query_string}"
try:
upstream = requests.request(
method=request.method,
url=target_url,
upstream = request_with_ssl_fallback(
request.method,
target_url,
headers=_incoming_headers(request),
data=request.body,
timeout=settings.SERVICE_REQUEST_TIMEOUT,

View file

@ -9,6 +9,7 @@ from httpx import Request
from utils.clients.gooyal_accounts_client import AuthenticatedClient
from utils.clients.gooyal_accounts_client.models import Account
from utils.clients.gooyal_accounts_client.api.users import (users_api_users_details_retrieve)
from utils.http_fallback import request_with_ssl_fallback, resolve_verify_ssl
@ -31,7 +32,7 @@ def login_as_client_credentials():
}
auth = (settings.OAUTH2_PROVIDER_CLIENT_ID, settings.OAUTH2_PROVIDER_CLIENT_SECRET)
response = requests.post(f'{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/',
response = request_with_ssl_fallback('POST', f'{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/',
data=data,
auth=auth)
print(response.content)
@ -57,7 +58,9 @@ def log_response(response):
def get_client():
access_token = login_as_client_credentials()['access_token']
verify_ssl = resolve_verify_ssl(settings.ACCOUNTS_BASE_PUBLIC_URL)
client = AuthenticatedClient(base_url=settings.ACCOUNTS_BASE_PUBLIC_URL, token=access_token,
verify_ssl=verify_ssl,
httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}},
)
return client

View file

@ -11,6 +11,7 @@ from utils.clients.gooyal_advertising_client.api.crm.crm_application_tickets_lis
from utils.clients.gooyal_advertising_client.api.suggestions.suggestions_suggest_list import sync as suggestions_suggest_list_sync
from utils.clients.gooyal_advertising_client.models.paginated_ticket_list import PaginatedTicketList
from utils.clients.gooyal_advertising_client.models.paginated_suggestion_list import PaginatedSuggestionList
from utils.http_fallback import request_with_ssl_fallback, resolve_verify_ssl
def login_as_client_credentials():
@ -27,7 +28,8 @@ def login_as_client_credentials():
}
auth = (settings.OAUTH2_PROVIDER_CLIENT_ID, settings.OAUTH2_PROVIDER_CLIENT_SECRET)
response = requests.post(
response = request_with_ssl_fallback(
'POST',
f'{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/',
data=data,
auth=auth,
@ -56,9 +58,11 @@ def log_response(response):
def get_client():
access_token = login_as_client_credentials()['access_token']
verify_ssl = resolve_verify_ssl(settings.ADVERTISING_BASE_PUBLIC_URL)
client = AuthenticatedClient(
base_url=settings.ADVERTISING_BASE_PUBLIC_URL,
token=access_token,
verify_ssl=verify_ssl,
httpx_args={
'event_hooks': {
'request': [log_request],

38
utils/http_fallback.py Normal file
View file

@ -0,0 +1,38 @@
import logging
import requests
import urllib3
logger = logging.getLogger(__name__)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def request_with_ssl_fallback(method, url, **kwargs):
"""Issue a request; if it fails purely due to a TLS/SSL error (e.g. an
expired upstream certificate), retry the same request with certificate
verification disabled. Still encrypted, but no longer authenticates the
server -- only safe for known internal/staging hosts, never for
arbitrary user-supplied URLs."""
try:
return requests.request(method, url, **kwargs)
except requests.exceptions.SSLError:
logger.warning("TLS verification failed for %s; retrying with verification disabled", url)
return requests.request(method, url, **{**kwargs, "verify": False})
def resolve_verify_ssl(base_url, timeout=5):
"""Probe whether `base_url` currently presents a valid TLS certificate.
For callers stuck building an httpx-based client up front (e.g. the
generated SDK clients' `verify_ssl=`), whose requests happen lazily and
can't be retried after the fact."""
if not base_url.startswith("https://"):
return True
try:
requests.head(base_url, timeout=timeout)
return True
except requests.exceptions.SSLError:
logger.warning("TLS verification failed for %s; disabling verification for this client", base_url)
return False
except requests.exceptions.RequestException:
return True