We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
How to configure TLS beyond client certificate and CA root certs?
Typically in requests you can use a __HTTPAdapter__ to hijack and set the SSL context and define what ciphers to use, how does one go about doing the same in __httpx__?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `httpx/config.py`
Content:
```
1 import ssl
2 import typing
3 from pathlib import Path
4 
5 import certifi
6 
7 from .__version__ import __version__
8 
9 CertTypes = typing.Union[str, typing.Tuple[str, str], typing.Tuple[str, str, str]]
10 VerifyTypes = typing.Union[str, bool]
11 TimeoutTypes = typing.Union[float, typing.Tuple[float, float, float], "TimeoutConfig"]
12 
13 
14 USER_AGENT = f"python-httpx/{__version__}"
15 
16 DEFAULT_CIPHERS = ":".join(
17     [
18         "ECDHE+AESGCM",
19         "ECDHE+CHACHA20",
20         "DHE+AESGCM",
21         "DHE+CHACHA20",
22         "ECDH+AESGCM",
23         "DH+AESGCM",
24         "ECDH+AES",
25         "DH+AES",
26         "RSA+AESGCM",
27         "RSA+AES",
28         "!aNULL",
29         "!eNULL",
30         "!MD5",
31         "!DSS",
32     ]
33 )
34 
35 
36 class SSLConfig:
37     """
38     SSL Configuration.
39     """
40 
41     def __init__(self, *, cert: CertTypes = None, verify: VerifyTypes = True):
42         self.cert = cert
43         self.verify = verify
44 
45         self.ssl_context: typing.Optional[ssl.SSLContext] = None
46 
47     def __eq__(self, other: typing.Any) -> bool:
48         return (
49             isinstance(other, self.__class__)
50             and self.cert == other.cert
51             and self.verify == other.verify
52         )
53 
54     def __repr__(self) -> str:
55         class_name = self.__class__.__name__
56         return f"{class_name}(cert={self.cert}, verify={self.verify})"
57 
58     def with_overrides(
59         self, cert: CertTypes = None, verify: VerifyTypes = None
60     ) -> "SSLConfig":
61         cert = self.cert if cert is None else cert
62         verify = self.verify if verify is None else verify
63         if (cert == self.cert) and (verify == self.verify):
64             return self
65         return SSLConfig(cert=cert, verify=verify)
66 
67     def load_ssl_context(self) -> ssl.SSLContext:
68         if self.ssl_context is None:
69             self.ssl_context = (
70                 self.load_ssl_context_verify()
71                 if self.verify
72                 else self.load_ssl_context_no_verify()
73             )
74 
75         assert self.ssl_context is not None
76         return self.ssl_context
77 
78     def load_ssl_context_no_verify(self) -> ssl.SSLContext:
79         """
80         Return an SSL context for unverified connections.
81         """
82         context = self._create_default_ssl_context()
83         context.verify_mode = ssl.CERT_NONE
84         context.check_hostname = False
85         return context
86 
87     def load_ssl_context_verify(self) -> ssl.SSLContext:
88         """
89         Return an SSL context for verified connections.
90         """
91         if isinstance(self.verify, bool):
92             ca_bundle_path = DEFAULT_CA_BUNDLE_PATH
93         elif Path(self.verify).exists():
94             ca_bundle_path = Path(self.verify)
95         else:
96             raise IOError(
97                 "Could not find a suitable TLS CA certificate bundle, "
98                 "invalid path: {}".format(self.verify)
99             )
100 
101         context = self._create_default_ssl_context()
102         context.verify_mode = ssl.CERT_REQUIRED
103         context.check_hostname = True
104 
105         # Signal to server support for PHA in TLS 1.3. Raises an
106         # AttributeError if only read-only access is implemented.
107         try:
108             context.post_handshake_auth = True  # type: ignore
109         except AttributeError:  # pragma: nocover
110             pass
111 
112         # Disable using 'commonName' for SSLContext.check_hostname
113         # when the 'subjectAltName' extension isn't available.
114         try:
115             context.hostname_checks_common_name = False  # type: ignore
116         except AttributeError:  # pragma: nocover
117             pass
118 
119         if ca_bundle_path.is_file():
120             context.load_verify_locations(cafile=str(ca_bundle_path))
121         elif ca_bundle_path.is_dir():
122             context.load_verify_locations(capath=str(ca_bundle_path))
123 
124         if self.cert is not None:
125             if isinstance(self.cert, str):
126                 context.load_cert_chain(certfile=self.cert)
127             elif isinstance(self.cert, tuple) and len(self.cert) == 2:
128                 context.load_cert_chain(certfile=self.cert[0], keyfile=self.cert[1])
129             elif isinstance(self.cert, tuple) and len(self.cert) == 3:
130                 context.load_cert_chain(
131                     certfile=self.cert[0],
132                     keyfile=self.cert[1],
133                     password=self.cert[2],  # type: ignore
134                 )
135 
136         return context
137 
138     def _create_default_ssl_context(self) -> ssl.SSLContext:
139         """
140         Creates the default SSLContext object that's used for both verified
141         and unverified connections.
142         """
143         context = ssl.SSLContext(ssl.PROTOCOL_TLS)
144         context.options |= ssl.OP_NO_SSLv2
145         context.options |= ssl.OP_NO_SSLv3
146         context.options |= ssl.OP_NO_TLSv1
147         context.options |= ssl.OP_NO_TLSv1_1
148         context.options |= ssl.OP_NO_COMPRESSION
149         context.set_ciphers(DEFAULT_CIPHERS)
150 
151         if ssl.HAS_ALPN:
152             context.set_alpn_protocols(["h2", "http/1.1"])
153         if ssl.HAS_NPN:
154             context.set_npn_protocols(["h2", "http/1.1"])
155 
156         return context
157 
158 
159 class TimeoutConfig:
160     """
161     Timeout values.
162     """
163 
164     def __init__(
165         self,
166         timeout: TimeoutTypes = None,
167         *,
168         connect_timeout: float = None,
169         read_timeout: float = None,
170         write_timeout: float = None,
171     ):
172         if timeout is None:
173             self.connect_timeout = connect_timeout
174             self.read_timeout = read_timeout
175             self.write_timeout = write_timeout
176         else:
177             # Specified as a single timeout value
178             assert connect_timeout is None
179             assert read_timeout is None
180             assert write_timeout is None
181             if isinstance(timeout, TimeoutConfig):
182                 self.connect_timeout = timeout.connect_timeout
183                 self.read_timeout = timeout.read_timeout
184                 self.write_timeout = timeout.write_timeout
185             elif isinstance(timeout, tuple):
186                 self.connect_timeout = timeout[0]
187                 self.read_timeout = timeout[1]
188                 self.write_timeout = timeout[2]
189             else:
190                 self.connect_timeout = timeout
191                 self.read_timeout = timeout
192                 self.write_timeout = timeout
193 
194     def __eq__(self, other: typing.Any) -> bool:
195         return (
196             isinstance(other, self.__class__)
197             and self.connect_timeout == other.connect_timeout
198             and self.read_timeout == other.read_timeout
199             and self.write_timeout == other.write_timeout
200         )
201 
202     def __repr__(self) -> str:
203         class_name = self.__class__.__name__
204         if len({self.connect_timeout, self.read_timeout, self.write_timeout}) == 1:
205             return f"{class_name}(timeout={self.connect_timeout})"
206         return (
207             f"{class_name}(connect_timeout={self.connect_timeout}, "
208             f"read_timeout={self.read_timeout}, write_timeout={self.write_timeout})"
209         )
210 
211 
212 class PoolLimits:
213     """
214     Limits on the number of connections in a connection pool.
215     """
216 
217     def __init__(
218         self,
219         *,
220         soft_limit: int = None,
221         hard_limit: int = None,
222         pool_timeout: float = None,
223     ):
224         self.soft_limit = soft_limit
225         self.hard_limit = hard_limit
226         self.pool_timeout = pool_timeout
227 
228     def __eq__(self, other: typing.Any) -> bool:
229         return (
230             isinstance(other, self.__class__)
231             and self.soft_limit == other.soft_limit
232             and self.hard_limit == other.hard_limit
233             and self.pool_timeout == other.pool_timeout
234         )
235 
236     def __repr__(self) -> str:
237         class_name = self.__class__.__name__
238         return (
239             f"{class_name}(soft_limit={self.soft_limit}, "
240             f"hard_limit={self.hard_limit}, pool_timeout={self.pool_timeout})"
241         )
242 
243 
244 DEFAULT_SSL_CONFIG = SSLConfig(cert=None, verify=True)
245 DEFAULT_TIMEOUT_CONFIG = TimeoutConfig(timeout=5.0)
246 DEFAULT_POOL_LIMITS = PoolLimits(soft_limit=10, hard_limit=100, pool_timeout=5.0)
247 DEFAULT_CA_BUNDLE_PATH = Path(certifi.where())
248 DEFAULT_MAX_REDIRECTS = 20
249
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/httpx/config.py b/httpx/config.py
--- a/httpx/config.py
+++ b/httpx/config.py
@@ -7,7 +7,7 @@
 from .__version__ import __version__
 
 CertTypes = typing.Union[str, typing.Tuple[str, str], typing.Tuple[str, str, str]]
-VerifyTypes = typing.Union[str, bool]
+VerifyTypes = typing.Union[str, bool, ssl.SSLContext]
 TimeoutTypes = typing.Union[float, typing.Tuple[float, float, float], "TimeoutConfig"]
 
 
@@ -40,9 +40,17 @@
 
     def __init__(self, *, cert: CertTypes = None, verify: VerifyTypes = True):
         self.cert = cert
-        self.verify = verify
 
-        self.ssl_context: typing.Optional[ssl.SSLContext] = None
+        # Allow passing in our own SSLContext object that's pre-configured.
+        # If you do this we assume that you want verify=True as well.
+        ssl_context = None
+        if isinstance(verify, ssl.SSLContext):
+            ssl_context = verify
+            verify = True
+            self._load_client_certs(ssl_context)
+
+        self.ssl_context: typing.Optional[ssl.SSLContext] = ssl_context
+        self.verify: typing.Union[str, bool] = verify
 
     def __eq__(self, other: typing.Any) -> bool:
         return (
@@ -121,17 +129,7 @@
         elif ca_bundle_path.is_dir():
             context.load_verify_locations(capath=str(ca_bundle_path))
 
-        if self.cert is not None:
-            if isinstance(self.cert, str):
-                context.load_cert_chain(certfile=self.cert)
-            elif isinstance(self.cert, tuple) and len(self.cert) == 2:
-                context.load_cert_chain(certfile=self.cert[0], keyfile=self.cert[1])
-            elif isinstance(self.cert, tuple) and len(self.cert) == 3:
-                context.load_cert_chain(
-                    certfile=self.cert[0],
-                    keyfile=self.cert[1],
-                    password=self.cert[2],  # type: ignore
-                )
+        self._load_client_certs(context)
 
         return context
 
@@ -155,6 +153,22 @@
 
         return context
 
+    def _load_client_certs(self, ssl_context: ssl.SSLContext) -> None:
+        """
+        Loads client certificates into our SSLContext object
+        """
+        if self.cert is not None:
+            if isinstance(self.cert, str):
+                ssl_context.load_cert_chain(certfile=self.cert)
+            elif isinstance(self.cert, tuple) and len(self.cert) == 2:
+                ssl_context.load_cert_chain(certfile=self.cert[0], keyfile=self.cert[1])
+            elif isinstance(self.cert, tuple) and len(self.cert) == 3:
+                ssl_context.load_cert_chain(
+                    certfile=self.cert[0],
+                    keyfile=self.cert[1],
+                    password=self.cert[2],  # type: ignore
+                )
+
 
 class TimeoutConfig:
     """

{"golden_diff": "diff --git a/httpx/config.py b/httpx/config.py\n--- a/httpx/config.py\n+++ b/httpx/config.py\n@@ -7,7 +7,7 @@\n from .__version__ import __version__\n \n CertTypes = typing.Union[str, typing.Tuple[str, str], typing.Tuple[str, str, str]]\n-VerifyTypes = typing.Union[str, bool]\n+VerifyTypes = typing.Union[str, bool, ssl.SSLContext]\n TimeoutTypes = typing.Union[float, typing.Tuple[float, float, float], \"TimeoutConfig\"]\n \n \n@@ -40,9 +40,17 @@\n \n     def __init__(self, *, cert: CertTypes = None, verify: VerifyTypes = True):\n         self.cert = cert\n-        self.verify = verify\n \n-        self.ssl_context: typing.Optional[ssl.SSLContext] = None\n+        # Allow passing in our own SSLContext object that's pre-configured.\n+        # If you do this we assume that you want verify=True as well.\n+        ssl_context = None\n+        if isinstance(verify, ssl.SSLContext):\n+            ssl_context = verify\n+            verify = True\n+            self._load_client_certs(ssl_context)\n+\n+        self.ssl_context: typing.Optional[ssl.SSLContext] = ssl_context\n+        self.verify: typing.Union[str, bool] = verify\n \n     def __eq__(self, other: typing.Any) -> bool:\n         return (\n@@ -121,17 +129,7 @@\n         elif ca_bundle_path.is_dir():\n             context.load_verify_locations(capath=str(ca_bundle_path))\n \n-        if self.cert is not None:\n-            if isinstance(self.cert, str):\n-                context.load_cert_chain(certfile=self.cert)\n-            elif isinstance(self.cert, tuple) and len(self.cert) == 2:\n-                context.load_cert_chain(certfile=self.cert[0], keyfile=self.cert[1])\n-            elif isinstance(self.cert, tuple) and len(self.cert) == 3:\n-                context.load_cert_chain(\n-                    certfile=self.cert[0],\n-                    keyfile=self.cert[1],\n-                    password=self.cert[2],  # type: ignore\n-                )\n+        self._load_client_certs(context)\n \n         return context\n \n@@ -155,6 +153,22 @@\n \n         return context\n \n+    def _load_client_certs(self, ssl_context: ssl.SSLContext) -> None:\n+        \"\"\"\n+        Loads client certificates into our SSLContext object\n+        \"\"\"\n+        if self.cert is not None:\n+            if isinstance(self.cert, str):\n+                ssl_context.load_cert_chain(certfile=self.cert)\n+            elif isinstance(self.cert, tuple) and len(self.cert) == 2:\n+                ssl_context.load_cert_chain(certfile=self.cert[0], keyfile=self.cert[1])\n+            elif isinstance(self.cert, tuple) and len(self.cert) == 3:\n+                ssl_context.load_cert_chain(\n+                    certfile=self.cert[0],\n+                    keyfile=self.cert[1],\n+                    password=self.cert[2],  # type: ignore\n+                )\n+\n \n class TimeoutConfig:\n     \"\"\"\n", "issue": "How to configure TLS beyond client certificate and CA root certs?\nTypically in requests you can use a __HTTPAdapter__ to hijack and set the SSL context and define what ciphers to use, how does one go about doing the same in __httpx__?\n", "before_files": [{"content": "import ssl\nimport typing\nfrom pathlib import Path\n\nimport certifi\n\nfrom .__version__ import __version__\n\nCertTypes = typing.Union[str, typing.Tuple[str, str], typing.Tuple[str, str, str]]\nVerifyTypes = typing.Union[str, bool]\nTimeoutTypes = typing.Union[float, typing.Tuple[float, float, float], \"TimeoutConfig\"]\n\n\nUSER_AGENT = f\"python-httpx/{__version__}\"\n\nDEFAULT_CIPHERS = \":\".join(\n    [\n        \"ECDHE+AESGCM\",\n        \"ECDHE+CHACHA20\",\n        \"DHE+AESGCM\",\n        \"DHE+CHACHA20\",\n        \"ECDH+AESGCM\",\n        \"DH+AESGCM\",\n        \"ECDH+AES\",\n        \"DH+AES\",\n        \"RSA+AESGCM\",\n        \"RSA+AES\",\n        \"!aNULL\",\n        \"!eNULL\",\n        \"!MD5\",\n        \"!DSS\",\n    ]\n)\n\n\nclass SSLConfig:\n    \"\"\"\n    SSL Configuration.\n    \"\"\"\n\n    def __init__(self, *, cert: CertTypes = None, verify: VerifyTypes = True):\n        self.cert = cert\n        self.verify = verify\n\n        self.ssl_context: typing.Optional[ssl.SSLContext] = None\n\n    def __eq__(self, other: typing.Any) -> bool:\n        return (\n            isinstance(other, self.__class__)\n            and self.cert == other.cert\n            and self.verify == other.verify\n        )\n\n    def __repr__(self) -> str:\n        class_name = self.__class__.__name__\n        return f\"{class_name}(cert={self.cert}, verify={self.verify})\"\n\n    def with_overrides(\n        self, cert: CertTypes = None, verify: VerifyTypes = None\n    ) -> \"SSLConfig\":\n        cert = self.cert if cert is None else cert\n        verify = self.verify if verify is None else verify\n        if (cert == self.cert) and (verify == self.verify):\n            return self\n        return SSLConfig(cert=cert, verify=verify)\n\n    def load_ssl_context(self) -> ssl.SSLContext:\n        if self.ssl_context is None:\n            self.ssl_context = (\n                self.load_ssl_context_verify()\n                if self.verify\n                else self.load_ssl_context_no_verify()\n            )\n\n        assert self.ssl_context is not None\n        return self.ssl_context\n\n    def load_ssl_context_no_verify(self) -> ssl.SSLContext:\n        \"\"\"\n        Return an SSL context for unverified connections.\n        \"\"\"\n        context = self._create_default_ssl_context()\n        context.verify_mode = ssl.CERT_NONE\n        context.check_hostname = False\n        return context\n\n    def load_ssl_context_verify(self) -> ssl.SSLContext:\n        \"\"\"\n        Return an SSL context for verified connections.\n        \"\"\"\n        if isinstance(self.verify, bool):\n            ca_bundle_path = DEFAULT_CA_BUNDLE_PATH\n        elif Path(self.verify).exists():\n            ca_bundle_path = Path(self.verify)\n        else:\n            raise IOError(\n                \"Could not find a suitable TLS CA certificate bundle, \"\n                \"invalid path: {}\".format(self.verify)\n            )\n\n        context = self._create_default_ssl_context()\n        context.verify_mode = ssl.CERT_REQUIRED\n        context.check_hostname = True\n\n        # Signal to server support for PHA in TLS 1.3. Raises an\n        # AttributeError if only read-only access is implemented.\n        try:\n            context.post_handshake_auth = True  # type: ignore\n        except AttributeError:  # pragma: nocover\n            pass\n\n        # Disable using 'commonName' for SSLContext.check_hostname\n        # when the 'subjectAltName' extension isn't available.\n        try:\n            context.hostname_checks_common_name = False  # type: ignore\n        except AttributeError:  # pragma: nocover\n            pass\n\n        if ca_bundle_path.is_file():\n            context.load_verify_locations(cafile=str(ca_bundle_path))\n        elif ca_bundle_path.is_dir():\n            context.load_verify_locations(capath=str(ca_bundle_path))\n\n        if self.cert is not None:\n            if isinstance(self.cert, str):\n                context.load_cert_chain(certfile=self.cert)\n            elif isinstance(self.cert, tuple) and len(self.cert) == 2:\n                context.load_cert_chain(certfile=self.cert[0], keyfile=self.cert[1])\n            elif isinstance(self.cert, tuple) and len(self.cert) == 3:\n                context.load_cert_chain(\n                    certfile=self.cert[0],\n                    keyfile=self.cert[1],\n                    password=self.cert[2],  # type: ignore\n                )\n\n        return context\n\n    def _create_default_ssl_context(self) -> ssl.SSLContext:\n        \"\"\"\n        Creates the default SSLContext object that's used for both verified\n        and unverified connections.\n        \"\"\"\n        context = ssl.SSLContext(ssl.PROTOCOL_TLS)\n        context.options |= ssl.OP_NO_SSLv2\n        context.options |= ssl.OP_NO_SSLv3\n        context.options |= ssl.OP_NO_TLSv1\n        context.options |= ssl.OP_NO_TLSv1_1\n        context.options |= ssl.OP_NO_COMPRESSION\n        context.set_ciphers(DEFAULT_CIPHERS)\n\n        if ssl.HAS_ALPN:\n            context.set_alpn_protocols([\"h2\", \"http/1.1\"])\n        if ssl.HAS_NPN:\n            context.set_npn_protocols([\"h2\", \"http/1.1\"])\n\n        return context\n\n\nclass TimeoutConfig:\n    \"\"\"\n    Timeout values.\n    \"\"\"\n\n    def __init__(\n        self,\n        timeout: TimeoutTypes = None,\n        *,\n        connect_timeout: float = None,\n        read_timeout: float = None,\n        write_timeout: float = None,\n    ):\n        if timeout is None:\n            self.connect_timeout = connect_timeout\n            self.read_timeout = read_timeout\n            self.write_timeout = write_timeout\n        else:\n            # Specified as a single timeout value\n            assert connect_timeout is None\n            assert read_timeout is None\n            assert write_timeout is None\n            if isinstance(timeout, TimeoutConfig):\n                self.connect_timeout = timeout.connect_timeout\n                self.read_timeout = timeout.read_timeout\n                self.write_timeout = timeout.write_timeout\n            elif isinstance(timeout, tuple):\n                self.connect_timeout = timeout[0]\n                self.read_timeout = timeout[1]\n                self.write_timeout = timeout[2]\n            else:\n                self.connect_timeout = timeout\n                self.read_timeout = timeout\n                self.write_timeout = timeout\n\n    def __eq__(self, other: typing.Any) -> bool:\n        return (\n            isinstance(other, self.__class__)\n            and self.connect_timeout == other.connect_timeout\n            and self.read_timeout == other.read_timeout\n            and self.write_timeout == other.write_timeout\n        )\n\n    def __repr__(self) -> str:\n        class_name = self.__class__.__name__\n        if len({self.connect_timeout, self.read_timeout, self.write_timeout}) == 1:\n            return f\"{class_name}(timeout={self.connect_timeout})\"\n        return (\n            f\"{class_name}(connect_timeout={self.connect_timeout}, \"\n            f\"read_timeout={self.read_timeout}, write_timeout={self.write_timeout})\"\n        )\n\n\nclass PoolLimits:\n    \"\"\"\n    Limits on the number of connections in a connection pool.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        soft_limit: int = None,\n        hard_limit: int = None,\n        pool_timeout: float = None,\n    ):\n        self.soft_limit = soft_limit\n        self.hard_limit = hard_limit\n        self.pool_timeout = pool_timeout\n\n    def __eq__(self, other: typing.Any) -> bool:\n        return (\n            isinstance(other, self.__class__)\n            and self.soft_limit == other.soft_limit\n            and self.hard_limit == other.hard_limit\n            and self.pool_timeout == other.pool_timeout\n        )\n\n    def __repr__(self) -> str:\n        class_name = self.__class__.__name__\n        return (\n            f\"{class_name}(soft_limit={self.soft_limit}, \"\n            f\"hard_limit={self.hard_limit}, pool_timeout={self.pool_timeout})\"\n        )\n\n\nDEFAULT_SSL_CONFIG = SSLConfig(cert=None, verify=True)\nDEFAULT_TIMEOUT_CONFIG = TimeoutConfig(timeout=5.0)\nDEFAULT_POOL_LIMITS = PoolLimits(soft_limit=10, hard_limit=100, pool_timeout=5.0)\nDEFAULT_CA_BUNDLE_PATH = Path(certifi.where())\nDEFAULT_MAX_REDIRECTS = 20\n", "path": "httpx/config.py"}], "after_files": [{"content": "import ssl\nimport typing\nfrom pathlib import Path\n\nimport certifi\n\nfrom .__version__ import __version__\n\nCertTypes = typing.Union[str, typing.Tuple[str, str], typing.Tuple[str, str, str]]\nVerifyTypes = typing.Union[str, bool, ssl.SSLContext]\nTimeoutTypes = typing.Union[float, typing.Tuple[float, float, float], \"TimeoutConfig\"]\n\n\nUSER_AGENT = f\"python-httpx/{__version__}\"\n\nDEFAULT_CIPHERS = \":\".join(\n    [\n        \"ECDHE+AESGCM\",\n        \"ECDHE+CHACHA20\",\n        \"DHE+AESGCM\",\n        \"DHE+CHACHA20\",\n        \"ECDH+AESGCM\",\n        \"DH+AESGCM\",\n        \"ECDH+AES\",\n        \"DH+AES\",\n        \"RSA+AESGCM\",\n        \"RSA+AES\",\n        \"!aNULL\",\n        \"!eNULL\",\n        \"!MD5\",\n        \"!DSS\",\n    ]\n)\n\n\nclass SSLConfig:\n    \"\"\"\n    SSL Configuration.\n    \"\"\"\n\n    def __init__(self, *, cert: CertTypes = None, verify: VerifyTypes = True):\n        self.cert = cert\n\n        # Allow passing in our own SSLContext object that's pre-configured.\n        # If you do this we assume that you want verify=True as well.\n        ssl_context = None\n        if isinstance(verify, ssl.SSLContext):\n            ssl_context = verify\n            verify = True\n            self._load_client_certs(ssl_context)\n\n        self.ssl_context: typing.Optional[ssl.SSLContext] = ssl_context\n        self.verify: typing.Union[str, bool] = verify\n\n    def __eq__(self, other: typing.Any) -> bool:\n        return (\n            isinstance(other, self.__class__)\n            and self.cert == other.cert\n            and self.verify == other.verify\n        )\n\n    def __repr__(self) -> str:\n        class_name = self.__class__.__name__\n        return f\"{class_name}(cert={self.cert}, verify={self.verify})\"\n\n    def with_overrides(\n        self, cert: CertTypes = None, verify: VerifyTypes = None\n    ) -> \"SSLConfig\":\n        cert = self.cert if cert is None else cert\n        verify = self.verify if verify is None else verify\n        if (cert == self.cert) and (verify == self.verify):\n            return self\n        return SSLConfig(cert=cert, verify=verify)\n\n    def load_ssl_context(self) -> ssl.SSLContext:\n        if self.ssl_context is None:\n            self.ssl_context = (\n                self.load_ssl_context_verify()\n                if self.verify\n                else self.load_ssl_context_no_verify()\n            )\n\n        assert self.ssl_context is not None\n        return self.ssl_context\n\n    def load_ssl_context_no_verify(self) -> ssl.SSLContext:\n        \"\"\"\n        Return an SSL context for unverified connections.\n        \"\"\"\n        context = self._create_default_ssl_context()\n        context.verify_mode = ssl.CERT_NONE\n        context.check_hostname = False\n        return context\n\n    def load_ssl_context_verify(self) -> ssl.SSLContext:\n        \"\"\"\n        Return an SSL context for verified connections.\n        \"\"\"\n        if isinstance(self.verify, bool):\n            ca_bundle_path = DEFAULT_CA_BUNDLE_PATH\n        elif Path(self.verify).exists():\n            ca_bundle_path = Path(self.verify)\n        else:\n            raise IOError(\n                \"Could not find a suitable TLS CA certificate bundle, \"\n                \"invalid path: {}\".format(self.verify)\n            )\n\n        context = self._create_default_ssl_context()\n        context.verify_mode = ssl.CERT_REQUIRED\n        context.check_hostname = True\n\n        # Signal to server support for PHA in TLS 1.3. Raises an\n        # AttributeError if only read-only access is implemented.\n        try:\n            context.post_handshake_auth = True  # type: ignore\n        except AttributeError:  # pragma: nocover\n            pass\n\n        # Disable using 'commonName' for SSLContext.check_hostname\n        # when the 'subjectAltName' extension isn't available.\n        try:\n            context.hostname_checks_common_name = False  # type: ignore\n        except AttributeError:  # pragma: nocover\n            pass\n\n        if ca_bundle_path.is_file():\n            context.load_verify_locations(cafile=str(ca_bundle_path))\n        elif ca_bundle_path.is_dir():\n            context.load_verify_locations(capath=str(ca_bundle_path))\n\n        self._load_client_certs(context)\n\n        return context\n\n    def _create_default_ssl_context(self) -> ssl.SSLContext:\n        \"\"\"\n        Creates the default SSLContext object that's used for both verified\n        and unverified connections.\n        \"\"\"\n        context = ssl.SSLContext(ssl.PROTOCOL_TLS)\n        context.options |= ssl.OP_NO_SSLv2\n        context.options |= ssl.OP_NO_SSLv3\n        context.options |= ssl.OP_NO_TLSv1\n        context.options |= ssl.OP_NO_TLSv1_1\n        context.options |= ssl.OP_NO_COMPRESSION\n        context.set_ciphers(DEFAULT_CIPHERS)\n\n        if ssl.HAS_ALPN:\n            context.set_alpn_protocols([\"h2\", \"http/1.1\"])\n        if ssl.HAS_NPN:\n            context.set_npn_protocols([\"h2\", \"http/1.1\"])\n\n        return context\n\n    def _load_client_certs(self, ssl_context: ssl.SSLContext) -> None:\n        \"\"\"\n        Loads client certificates into our SSLContext object\n        \"\"\"\n        if self.cert is not None:\n            if isinstance(self.cert, str):\n                ssl_context.load_cert_chain(certfile=self.cert)\n            elif isinstance(self.cert, tuple) and len(self.cert) == 2:\n                ssl_context.load_cert_chain(certfile=self.cert[0], keyfile=self.cert[1])\n            elif isinstance(self.cert, tuple) and len(self.cert) == 3:\n                ssl_context.load_cert_chain(\n                    certfile=self.cert[0],\n                    keyfile=self.cert[1],\n                    password=self.cert[2],  # type: ignore\n                )\n\n\nclass TimeoutConfig:\n    \"\"\"\n    Timeout values.\n    \"\"\"\n\n    def __init__(\n        self,\n        timeout: TimeoutTypes = None,\n        *,\n        connect_timeout: float = None,\n        read_timeout: float = None,\n        write_timeout: float = None,\n    ):\n        if timeout is None:\n            self.connect_timeout = connect_timeout\n            self.read_timeout = read_timeout\n            self.write_timeout = write_timeout\n        else:\n            # Specified as a single timeout value\n            assert connect_timeout is None\n            assert read_timeout is None\n            assert write_timeout is None\n            if isinstance(timeout, TimeoutConfig):\n                self.connect_timeout = timeout.connect_timeout\n                self.read_timeout = timeout.read_timeout\n                self.write_timeout = timeout.write_timeout\n            elif isinstance(timeout, tuple):\n                self.connect_timeout = timeout[0]\n                self.read_timeout = timeout[1]\n                self.write_timeout = timeout[2]\n            else:\n                self.connect_timeout = timeout\n                self.read_timeout = timeout\n                self.write_timeout = timeout\n\n    def __eq__(self, other: typing.Any) -> bool:\n        return (\n            isinstance(other, self.__class__)\n            and self.connect_timeout == other.connect_timeout\n            and self.read_timeout == other.read_timeout\n            and self.write_timeout == other.write_timeout\n        )\n\n    def __repr__(self) -> str:\n        class_name = self.__class__.__name__\n        if len({self.connect_timeout, self.read_timeout, self.write_timeout}) == 1:\n            return f\"{class_name}(timeout={self.connect_timeout})\"\n        return (\n            f\"{class_name}(connect_timeout={self.connect_timeout}, \"\n            f\"read_timeout={self.read_timeout}, write_timeout={self.write_timeout})\"\n        )\n\n\nclass PoolLimits:\n    \"\"\"\n    Limits on the number of connections in a connection pool.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        soft_limit: int = None,\n        hard_limit: int = None,\n        pool_timeout: float = None,\n    ):\n        self.soft_limit = soft_limit\n        self.hard_limit = hard_limit\n        self.pool_timeout = pool_timeout\n\n    def __eq__(self, other: typing.Any) -> bool:\n        return (\n            isinstance(other, self.__class__)\n            and self.soft_limit == other.soft_limit\n            and self.hard_limit == other.hard_limit\n            and self.pool_timeout == other.pool_timeout\n        )\n\n    def __repr__(self) -> str:\n        class_name = self.__class__.__name__\n        return (\n            f\"{class_name}(soft_limit={self.soft_limit}, \"\n            f\"hard_limit={self.hard_limit}, pool_timeout={self.pool_timeout})\"\n        )\n\n\nDEFAULT_SSL_CONFIG = SSLConfig(cert=None, verify=True)\nDEFAULT_TIMEOUT_CONFIG = TimeoutConfig(timeout=5.0)\nDEFAULT_POOL_LIMITS = PoolLimits(soft_limit=10, hard_limit=100, pool_timeout=5.0)\nDEFAULT_CA_BUNDLE_PATH = Path(certifi.where())\nDEFAULT_MAX_REDIRECTS = 20\n", "path": "httpx/config.py"}]}