5858from . import constants
5959from .backoff_policies import exponential_backoff
6060from .cache import CacheEntry , SFDictCache , SFDictFileCache
61+ from .constants import OCSP_ROOT_CERTS_DICT_LOCK_TIMEOUT_DEFAULT_NO_TIMEOUT
6162from .telemetry import TelemetryField , generate_telemetry_data_dict
6263from .url_util import extract_top_level_domain_from_hostname , url_encode_str
6364from .util_text import _base64_bytes_to_str
@@ -1037,6 +1038,7 @@ def __init__(
10371038 use_ocsp_cache_server = None ,
10381039 use_post_method : bool = True ,
10391040 use_fail_open : bool = True ,
1041+ root_certs_dict_lock_timeout : int = OCSP_ROOT_CERTS_DICT_LOCK_TIMEOUT_DEFAULT_NO_TIMEOUT ,
10401042 ** kwargs ,
10411043 ) -> None :
10421044 self .test_mode = os .getenv ("SF_OCSP_TEST_MODE" , None )
@@ -1045,6 +1047,7 @@ def __init__(
10451047 logger .debug ("WARNING - DRIVER CONFIGURED IN TEST MODE" )
10461048
10471049 self ._use_post_method = use_post_method
1050+ self ._root_certs_dict_lock_timeout = root_certs_dict_lock_timeout
10481051 self .OCSP_CACHE_SERVER = OCSPServer (
10491052 top_level_domain = extract_top_level_domain_from_hostname (
10501053 kwargs .pop ("hostname" , None )
@@ -1415,67 +1418,79 @@ def _check_ocsp_response_cache_server(
14151418
14161419 def _lazy_read_ca_bundle (self ) -> None :
14171420 """Reads the local cabundle file and cache it in memory."""
1418- with SnowflakeOCSP .ROOT_CERTIFICATES_DICT_LOCK :
1419- if SnowflakeOCSP .ROOT_CERTIFICATES_DICT :
1420- # return if already loaded
1421- return
1422-
1421+ lock_acquired = SnowflakeOCSP .ROOT_CERTIFICATES_DICT_LOCK .acquire (
1422+ timeout = self ._root_certs_dict_lock_timeout
1423+ )
1424+ if lock_acquired :
14231425 try :
1424- ca_bundle = environ .get ("REQUESTS_CA_BUNDLE" ) or environ .get (
1425- "CURL_CA_BUNDLE"
1426- )
1427- if ca_bundle and path .exists (ca_bundle ):
1428- # if the user/application specifies cabundle.
1429- self .read_cert_bundle (ca_bundle )
1430- else :
1431- import sys
1432-
1433- # This import that depends on these libraries is to import certificates from them,
1434- # we would like to have these as up to date as possible.
1435- from requests import certs
1426+ if SnowflakeOCSP .ROOT_CERTIFICATES_DICT :
1427+ # return if already loaded
1428+ return
14361429
1437- if (
1438- hasattr (certs , "__file__" )
1439- and path .exists (certs .__file__ )
1440- and path .exists (
1441- path .join (path .dirname (certs .__file__ ), "cacert.pem" )
1442- )
1443- ):
1444- # if cacert.pem exists next to certs.py in request
1445- # package.
1446- ca_bundle = path .join (
1447- path .dirname (certs .__file__ ), "cacert.pem"
1448- )
1430+ try :
1431+ ca_bundle = environ .get ("REQUESTS_CA_BUNDLE" ) or environ .get (
1432+ "CURL_CA_BUNDLE"
1433+ )
1434+ if ca_bundle and path .exists (ca_bundle ):
1435+ # if the user/application specifies cabundle.
14491436 self .read_cert_bundle (ca_bundle )
1450- elif hasattr (sys , "_MEIPASS" ):
1451- # if pyinstaller includes cacert.pem
1452- cabundle_candidates = [
1453- ["botocore" , "vendored" , "requests" , "cacert.pem" ],
1454- ["requests" , "cacert.pem" ],
1455- ["cacert.pem" ],
1456- ]
1457- for filename in cabundle_candidates :
1458- ca_bundle = path .join (sys ._MEIPASS , * filename )
1459- if path .exists (ca_bundle ):
1460- self .read_cert_bundle (ca_bundle )
1461- break
1462- else :
1463- logger .error ("No cabundle file is found in _MEIPASS" )
1464- try :
1465- import certifi
1466-
1467- self .read_cert_bundle (certifi .where ())
1468- except Exception :
1469- logger .debug ("no certifi is installed. ignored." )
1470-
1471- except Exception as e :
1472- logger .error ("Failed to read ca_bundle: %s" , e )
1473-
1474- if not SnowflakeOCSP .ROOT_CERTIFICATES_DICT :
1475- logger .error (
1476- "No CA bundle file is found in the system. "
1477- "Set REQUESTS_CA_BUNDLE to the file."
1478- )
1437+ else :
1438+ import sys
1439+
1440+ # This import that depends on these libraries is to import certificates from them,
1441+ # we would like to have these as up to date as possible.
1442+ from requests import certs
1443+
1444+ if (
1445+ hasattr (certs , "__file__" )
1446+ and path .exists (certs .__file__ )
1447+ and path .exists (
1448+ path .join (path .dirname (certs .__file__ ), "cacert.pem" )
1449+ )
1450+ ):
1451+ # if cacert.pem exists next to certs.py in request
1452+ # package.
1453+ ca_bundle = path .join (
1454+ path .dirname (certs .__file__ ), "cacert.pem"
1455+ )
1456+ self .read_cert_bundle (ca_bundle )
1457+ elif hasattr (sys , "_MEIPASS" ):
1458+ # if pyinstaller includes cacert.pem
1459+ cabundle_candidates = [
1460+ ["botocore" , "vendored" , "requests" , "cacert.pem" ],
1461+ ["requests" , "cacert.pem" ],
1462+ ["cacert.pem" ],
1463+ ]
1464+ for filename in cabundle_candidates :
1465+ ca_bundle = path .join (sys ._MEIPASS , * filename )
1466+ if path .exists (ca_bundle ):
1467+ self .read_cert_bundle (ca_bundle )
1468+ break
1469+ else :
1470+ logger .error ("No cabundle file is found in _MEIPASS" )
1471+ try :
1472+ import certifi
1473+
1474+ self .read_cert_bundle (certifi .where ())
1475+ except Exception :
1476+ logger .debug ("no certifi is installed. ignored." )
1477+
1478+ except Exception as e :
1479+ logger .error ("Failed to read ca_bundle: %s" , e )
1480+
1481+ if not SnowflakeOCSP .ROOT_CERTIFICATES_DICT :
1482+ logger .error (
1483+ "No CA bundle file is found in the system. "
1484+ "Set REQUESTS_CA_BUNDLE to the file."
1485+ )
1486+ finally :
1487+ SnowflakeOCSP .ROOT_CERTIFICATES_DICT_LOCK .release ()
1488+ else :
1489+ logger .info (
1490+ "Failed to acquire lock for ROOT_CERTIFICATES_DICT_LOCK. "
1491+ "Skipping reading CA bundle."
1492+ )
1493+ return
14791494
14801495 @staticmethod
14811496 def _calculate_tolerable_validity (this_update : float , next_update : float ) -> int :
0 commit comments