Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/requests/adapters.py: 25%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

253 statements  

1""" 

2requests.adapters 

3~~~~~~~~~~~~~~~~~ 

4 

5This module contains the transport adapters that Requests uses to define 

6and maintain connections. 

7""" 

8 

9from __future__ import annotations 

10 

11import os.path 

12import socket # noqa: F401 # type: ignore[reportUnusedImport] 

13import typing 

14import warnings 

15from typing import Any 

16 

17from urllib3.exceptions import ( 

18 ClosedPoolError, 

19 ConnectTimeoutError, 

20 LocationValueError, 

21 MaxRetryError, 

22 NewConnectionError, 

23 ProtocolError, 

24 ReadTimeoutError, 

25 ResponseError, 

26) 

27from urllib3.exceptions import HTTPError as _HTTPError 

28from urllib3.exceptions import InvalidHeader as _InvalidHeader 

29from urllib3.exceptions import ProxyError as _ProxyError 

30from urllib3.exceptions import SSLError as _SSLError 

31from urllib3.poolmanager import PoolManager, proxy_from_url 

32from urllib3.util import Timeout as TimeoutSauce 

33from urllib3.util import parse_url 

34from urllib3.util.retry import Retry 

35 

36from .auth import _basic_auth_str # type: ignore[reportPrivateUsage] 

37from .compat import basestring, urlparse 

38from .cookies import extract_cookies_to_jar 

39from .exceptions import ( 

40 ConnectionError, 

41 ConnectTimeout, 

42 InvalidHeader, 

43 InvalidProxyURL, 

44 InvalidSchema, 

45 InvalidURL, 

46 ProxyError, 

47 ReadTimeout, 

48 RetryError, 

49 SSLError, 

50) 

51from .models import Response 

52from .structures import CaseInsensitiveDict 

53from .utils import ( 

54 DEFAULT_CA_BUNDLE_PATH, 

55 get_auth_from_url, 

56 get_encoding_from_headers, 

57 prepend_scheme_if_needed, 

58 select_proxy, 

59 urldefragauth, 

60) 

61 

62try: 

63 from urllib3.contrib.socks import SOCKSProxyManager # type: ignore[assignment] 

64except ImportError: 

65 

66 def SOCKSProxyManager(*args: Any, **kwargs: Any) -> None: 

67 raise InvalidSchema("Missing dependencies for SOCKS support.") 

68 

69 

70if typing.TYPE_CHECKING: 

71 from urllib3.connectionpool import HTTPConnectionPool 

72 from urllib3.poolmanager import PoolManager as _PoolManager 

73 

74 from . import _types as _t 

75 from .models import PreparedRequest 

76 

77from ._types import is_prepared as _is_prepared 

78 

79DEFAULT_POOLBLOCK = False 

80DEFAULT_POOLSIZE = 10 

81DEFAULT_RETRIES = 0 

82DEFAULT_POOL_TIMEOUT = None 

83 

84 

85def _urllib3_request_context( 

86 request: PreparedRequest, 

87 verify: bool | str | None, 

88 client_cert: tuple[str, str] | str | None, 

89 poolmanager: PoolManager, 

90) -> tuple[dict[str, Any], dict[str, Any]]: 

91 host_params: dict[str, Any] = {} 

92 pool_kwargs: dict[str, Any] = {} 

93 parsed_request_url = urlparse(request.url) 

94 scheme = parsed_request_url.scheme.lower() 

95 port = parsed_request_url.port 

96 

97 cert_reqs = "CERT_REQUIRED" 

98 if verify is False: 

99 cert_reqs = "CERT_NONE" 

100 elif isinstance(verify, str): 

101 if not os.path.isdir(verify): 

102 pool_kwargs["ca_certs"] = verify 

103 else: 

104 pool_kwargs["ca_cert_dir"] = verify 

105 pool_kwargs["cert_reqs"] = cert_reqs 

106 if client_cert is not None: 

107 if isinstance(client_cert, tuple) and len(client_cert) == 2: 

108 pool_kwargs["cert_file"] = client_cert[0] 

109 pool_kwargs["key_file"] = client_cert[1] 

110 else: 

111 # According to our docs, we allow users to specify just the client 

112 # cert path 

113 pool_kwargs["cert_file"] = client_cert 

114 host_params = { 

115 "scheme": scheme, 

116 "host": parsed_request_url.hostname, 

117 "port": port, 

118 } 

119 return host_params, pool_kwargs 

120 

121 

122class BaseAdapter: 

123 """The Base Transport Adapter""" 

124 

125 def __init__(self) -> None: 

126 super().__init__() 

127 

128 def send( 

129 self, 

130 request: PreparedRequest, 

131 stream: bool = False, 

132 timeout: _t.TimeoutType = None, 

133 verify: _t.VerifyType = True, 

134 cert: _t.CertType = None, 

135 proxies: dict[str, str] | None = None, 

136 ) -> Response: 

137 """Sends PreparedRequest object. Returns Response object. 

138 

139 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. 

140 :param stream: (optional) Whether to stream the request content. 

141 :param timeout: (optional) How long to wait for the server to send 

142 data before giving up, as a float, or a :ref:`(connect timeout, 

143 read timeout) <timeouts>` tuple. 

144 :type timeout: float or tuple 

145 :param verify: (optional) Either a boolean, in which case it controls whether we verify 

146 the server's TLS certificate, or a string, in which case it must be a path 

147 to a CA bundle to use 

148 :param cert: (optional) Any user-provided SSL certificate to be trusted. 

149 :param proxies: (optional) The proxies dictionary to apply to the request. 

150 """ 

151 raise NotImplementedError 

152 

153 def close(self) -> None: 

154 """Cleans up adapter specific items.""" 

155 raise NotImplementedError 

156 

157 

158class HTTPAdapter(BaseAdapter): 

159 """The built-in HTTP Adapter for urllib3. 

160 

161 Provides a general-case interface for Requests sessions to contact HTTP and 

162 HTTPS urls by implementing the Transport Adapter interface. This class will 

163 usually be created by the :class:`Session <Session>` class under the 

164 covers. 

165 

166 :param pool_connections: The number of urllib3 connection pools to cache. 

167 :param pool_maxsize: The maximum number of connections to save in the pool. 

168 :param max_retries: The maximum number of retries each connection 

169 should attempt. Note, this applies only to failed DNS lookups, socket 

170 connections and connection timeouts, never to requests where data has 

171 made it to the server. By default, Requests does not retry failed 

172 connections. If you need granular control over the conditions under 

173 which we retry a request, import urllib3's ``Retry`` class and pass 

174 that instead. 

175 :param pool_block: Whether the connection pool should block for connections. 

176 

177 Usage:: 

178 

179 >>> import requests 

180 >>> s = requests.Session() 

181 >>> a = requests.adapters.HTTPAdapter(max_retries=3) 

182 >>> s.mount('http://', a) 

183 """ 

184 

185 __attrs__: list[str] = [ 

186 "max_retries", 

187 "config", 

188 "_pool_connections", 

189 "_pool_maxsize", 

190 "_pool_block", 

191 ] 

192 

193 max_retries: Retry 

194 config: dict[str, Any] 

195 proxy_manager: dict[str, Any] 

196 _pool_connections: int 

197 _pool_maxsize: int 

198 _pool_block: bool 

199 poolmanager: _PoolManager 

200 

201 def __init__( 

202 self, 

203 pool_connections: int = DEFAULT_POOLSIZE, 

204 pool_maxsize: int = DEFAULT_POOLSIZE, 

205 max_retries: int | Retry = DEFAULT_RETRIES, 

206 pool_block: bool = DEFAULT_POOLBLOCK, 

207 ) -> None: 

208 if max_retries == DEFAULT_RETRIES: 

209 self.max_retries = Retry(0, read=False) 

210 else: 

211 self.max_retries = Retry.from_int(max_retries) 

212 self.config = {} 

213 self.proxy_manager = {} 

214 

215 super().__init__() 

216 

217 self._pool_connections = pool_connections 

218 self._pool_maxsize = pool_maxsize 

219 self._pool_block = pool_block 

220 

221 self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) 

222 

223 def __getstate__(self) -> dict[str, Any]: 

224 return {attr: getattr(self, attr, None) for attr in self.__attrs__} 

225 

226 def __setstate__(self, state: dict[str, Any]) -> None: 

227 # Can't handle by adding 'proxy_manager' to self.__attrs__ because 

228 # self.poolmanager uses a lambda function, which isn't pickleable. 

229 self.proxy_manager = {} 

230 self.config = {} 

231 

232 for attr, value in state.items(): 

233 setattr(self, attr, value) 

234 

235 self.init_poolmanager( 

236 self._pool_connections, self._pool_maxsize, block=self._pool_block 

237 ) 

238 

239 def init_poolmanager( 

240 self, 

241 connections: int, 

242 maxsize: int, 

243 block: bool = DEFAULT_POOLBLOCK, 

244 **pool_kwargs: Any, 

245 ) -> None: 

246 """Initializes a urllib3 PoolManager. 

247 

248 This method should not be called from user code, and is only 

249 exposed for use when subclassing the 

250 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

251 

252 :param connections: The number of urllib3 connection pools to cache. 

253 :param maxsize: The maximum number of connections to save in the pool. 

254 :param block: Block when no free connections are available. 

255 :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager. 

256 """ 

257 # save these values for pickling 

258 self._pool_connections = connections 

259 self._pool_maxsize = maxsize 

260 self._pool_block = block 

261 

262 self.poolmanager = PoolManager( 

263 num_pools=connections, 

264 maxsize=maxsize, 

265 block=block, 

266 **pool_kwargs, 

267 ) 

268 

269 def proxy_manager_for(self, proxy: str, **proxy_kwargs: Any) -> Any: 

270 """Return urllib3 ProxyManager for the given proxy. 

271 

272 This method should not be called from user code, and is only 

273 exposed for use when subclassing the 

274 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

275 

276 :param proxy: The proxy to return a urllib3 ProxyManager for. 

277 :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager. 

278 :returns: ProxyManager 

279 :rtype: urllib3.ProxyManager 

280 """ 

281 if proxy in self.proxy_manager: 

282 manager = self.proxy_manager[proxy] 

283 elif proxy.lower().startswith("socks"): 

284 username, password = get_auth_from_url(proxy) 

285 manager = self.proxy_manager[proxy] = SOCKSProxyManager( 

286 proxy, 

287 username=username, 

288 password=password, 

289 num_pools=self._pool_connections, 

290 maxsize=self._pool_maxsize, 

291 block=self._pool_block, 

292 **proxy_kwargs, 

293 ) 

294 else: 

295 proxy_headers = self.proxy_headers(proxy) 

296 manager = self.proxy_manager[proxy] = proxy_from_url( 

297 proxy, 

298 proxy_headers=proxy_headers, 

299 num_pools=self._pool_connections, 

300 maxsize=self._pool_maxsize, 

301 block=self._pool_block, 

302 **proxy_kwargs, 

303 ) 

304 

305 return manager 

306 

307 def cert_verify( 

308 self, conn: Any, url: str, verify: _t.VerifyType, cert: _t.CertType 

309 ) -> None: 

310 """Verify a SSL certificate. This method should not be called from user 

311 code, and is only exposed for use when subclassing the 

312 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

313 

314 :param conn: The urllib3 connection object associated with the cert. 

315 :param url: The requested URL. 

316 :param verify: Either a boolean, in which case it controls whether we verify 

317 the server's TLS certificate, or a string, in which case it must be a path 

318 to a CA bundle to use 

319 :param cert: The SSL certificate to verify. 

320 """ 

321 if url.lower().startswith("https") and verify: 

322 cert_loc = None 

323 

324 # Allow self-specified cert location. 

325 if verify is not True: 

326 cert_loc = verify 

327 

328 if not cert_loc: 

329 cert_loc = DEFAULT_CA_BUNDLE_PATH 

330 

331 if not cert_loc or not os.path.exists(cert_loc): 

332 raise OSError( 

333 f"Could not find a suitable TLS CA certificate bundle, " 

334 f"invalid path: {cert_loc}" 

335 ) 

336 

337 conn.cert_reqs = "CERT_REQUIRED" 

338 

339 if not os.path.isdir(cert_loc): 

340 conn.ca_certs = cert_loc 

341 else: 

342 conn.ca_cert_dir = cert_loc 

343 else: 

344 conn.cert_reqs = "CERT_NONE" 

345 conn.ca_certs = None 

346 conn.ca_cert_dir = None 

347 

348 if cert: 

349 if not isinstance(cert, basestring): 

350 conn.cert_file = cert[0] 

351 conn.key_file = cert[1] 

352 else: 

353 conn.cert_file = cert 

354 conn.key_file = None 

355 if conn.cert_file and not os.path.exists(conn.cert_file): 

356 raise OSError( 

357 f"Could not find the TLS certificate file, " 

358 f"invalid path: {conn.cert_file}" 

359 ) 

360 if conn.key_file and not os.path.exists(conn.key_file): 

361 raise OSError( 

362 f"Could not find the TLS key file, invalid path: {conn.key_file}" 

363 ) 

364 

365 def build_response(self, req: PreparedRequest, resp: Any) -> Response: 

366 """Builds a :class:`Response <requests.Response>` object from a urllib3 

367 response. This should not be called from user code, and is only exposed 

368 for use when subclassing the 

369 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>` 

370 

371 :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response. 

372 :param resp: The urllib3 response object. 

373 :rtype: requests.Response 

374 """ 

375 assert _is_prepared(req) 

376 response = Response() 

377 

378 # Fallback to None if there's no status_code, for whatever reason. 

379 response.status_code = getattr(resp, "status", None) # type: ignore[assignment] 

380 

381 # Make headers case-insensitive. 

382 response.headers = CaseInsensitiveDict(getattr(resp, "headers", {})) 

383 

384 # Set encoding. 

385 response.encoding = get_encoding_from_headers(response.headers) 

386 response.raw = resp 

387 response.reason = response.raw.reason 

388 

389 if isinstance(req.url, bytes): 

390 response.url = req.url.decode("utf-8") 

391 else: 

392 response.url = req.url 

393 

394 # Add new cookies from the server. 

395 extract_cookies_to_jar(response.cookies, req, resp) 

396 

397 # Give the Response some context. 

398 response.request = req 

399 response.connection = self 

400 

401 return response 

402 

403 def build_connection_pool_key_attributes( 

404 self, request: PreparedRequest, verify: _t.VerifyType, cert: _t.CertType = None 

405 ) -> tuple[dict[str, Any], dict[str, Any]]: 

406 """Build the PoolKey attributes used by urllib3 to return a connection. 

407 

408 This looks at the PreparedRequest, the user-specified verify value, 

409 and the value of the cert parameter to determine what PoolKey values 

410 to use to select a connection from a given urllib3 Connection Pool. 

411 

412 The SSL related pool key arguments are not consistently set. As of 

413 this writing, use the following to determine what keys may be in that 

414 dictionary: 

415 

416 * If ``verify`` is ``True``, ``"ssl_context"`` will be set and will be the 

417 default Requests SSL Context 

418 * If ``verify`` is ``False``, ``"ssl_context"`` will not be set but 

419 ``"cert_reqs"`` will be set 

420 * If ``verify`` is a string, (i.e., it is a user-specified trust bundle) 

421 ``"ca_certs"`` will be set if the string is not a directory recognized 

422 by :py:func:`os.path.isdir`, otherwise ``"ca_cert_dir"`` will be 

423 set. 

424 * If ``"cert"`` is specified, ``"cert_file"`` will always be set. If 

425 ``"cert"`` is a tuple with a second item, ``"key_file"`` will also 

426 be present 

427 

428 To override these settings, one may subclass this class, call this 

429 method and use the above logic to change parameters as desired. For 

430 example, if one wishes to use a custom :py:class:`ssl.SSLContext` one 

431 must both set ``"ssl_context"`` and based on what else they require, 

432 alter the other keys to ensure the desired behaviour. 

433 

434 :param request: 

435 The PreparedRequest being sent over the connection. 

436 :type request: 

437 :class:`~requests.models.PreparedRequest` 

438 :param verify: 

439 Either a boolean, in which case it controls whether 

440 we verify the server's TLS certificate, or a string, in which case it 

441 must be a path to a CA bundle to use. 

442 :param cert: 

443 (optional) Any user-provided SSL certificate for client 

444 authentication (a.k.a., mTLS). This may be a string (i.e., just 

445 the path to a file which holds both certificate and key) or a 

446 tuple of length 2 with the certificate file path and key file 

447 path. 

448 :returns: 

449 A tuple of two dictionaries. The first is the "host parameters" 

450 portion of the Pool Key including scheme, hostname, and port. The 

451 second is a dictionary of SSLContext related parameters. 

452 """ 

453 return _urllib3_request_context(request, verify, cert, self.poolmanager) 

454 

455 def get_connection_with_tls_context( 

456 self, 

457 request: PreparedRequest, 

458 verify: _t.VerifyType, 

459 proxies: dict[str, str] | None = None, 

460 cert: _t.CertType = None, 

461 ) -> HTTPConnectionPool: 

462 """Returns a urllib3 connection for the given request and TLS settings. 

463 This should not be called from user code, and is only exposed for use 

464 when subclassing the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

465 

466 :param request: 

467 The :class:`PreparedRequest <PreparedRequest>` object to be sent 

468 over the connection. 

469 :param verify: 

470 Either a boolean, in which case it controls whether we verify the 

471 server's TLS certificate, or a string, in which case it must be a 

472 path to a CA bundle to use. 

473 :param proxies: 

474 (optional) The proxies dictionary to apply to the request. 

475 :param cert: 

476 (optional) Any user-provided SSL certificate to be used for client 

477 authentication (a.k.a., mTLS). 

478 :rtype: 

479 urllib3.HTTPConnectionPool 

480 """ 

481 assert _is_prepared(request) 

482 

483 proxy = select_proxy(request.url, proxies) 

484 try: 

485 host_params, pool_kwargs = self.build_connection_pool_key_attributes( 

486 request, 

487 verify, 

488 cert, 

489 ) 

490 except ValueError as e: 

491 raise InvalidURL(e, request=request) 

492 if proxy: 

493 proxy = prepend_scheme_if_needed(proxy, "http") 

494 proxy_url = parse_url(proxy) 

495 if not proxy_url.host: 

496 raise InvalidProxyURL( 

497 "Please check proxy URL. It is malformed " 

498 "and could be missing the host." 

499 ) 

500 proxy_manager = self.proxy_manager_for(proxy) 

501 conn = proxy_manager.connection_from_host( 

502 **host_params, pool_kwargs=pool_kwargs 

503 ) 

504 else: 

505 # Only scheme should be lower case 

506 conn = self.poolmanager.connection_from_host( 

507 **host_params, pool_kwargs=pool_kwargs 

508 ) 

509 

510 return conn 

511 

512 def get_connection( 

513 self, url: str, proxies: dict[str, str] | None = None 

514 ) -> HTTPConnectionPool: 

515 """DEPRECATED: Users should move to `get_connection_with_tls_context` 

516 for all subclasses of HTTPAdapter using Requests>=2.32.2. 

517 

518 Returns a urllib3 connection for the given URL. This should not be 

519 called from user code, and is only exposed for use when subclassing the 

520 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

521 

522 :param url: The URL to connect to. 

523 :param proxies: (optional) A Requests-style dictionary of proxies used on this request. 

524 :rtype: urllib3.HTTPConnectionPool 

525 """ 

526 warnings.warn( 

527 ( 

528 "`get_connection` has been deprecated in favor of " 

529 "`get_connection_with_tls_context`. Custom HTTPAdapter subclasses " 

530 "will need to migrate for Requests>=2.32.2. Please see " 

531 "https://github.com/psf/requests/pull/6710 for more details." 

532 ), 

533 DeprecationWarning, 

534 ) 

535 proxy = select_proxy(url, proxies) 

536 

537 if proxy: 

538 proxy = prepend_scheme_if_needed(proxy, "http") 

539 proxy_url = parse_url(proxy) 

540 if not proxy_url.host: 

541 raise InvalidProxyURL( 

542 "Please check proxy URL. It is malformed " 

543 "and could be missing the host." 

544 ) 

545 proxy_manager = self.proxy_manager_for(proxy) 

546 conn = proxy_manager.connection_from_url(url) 

547 else: 

548 # Only scheme should be lower case 

549 parsed = urlparse(url) 

550 url = parsed.geturl() 

551 conn = self.poolmanager.connection_from_url(url) 

552 

553 return conn 

554 

555 def close(self) -> None: 

556 """Disposes of any internal state. 

557 

558 Currently, this closes the PoolManager and any active ProxyManager, 

559 which closes any pooled connections. 

560 """ 

561 self.poolmanager.clear() 

562 for proxy in self.proxy_manager.values(): 

563 proxy.clear() 

564 

565 def request_url( 

566 self, request: PreparedRequest, proxies: dict[str, str] | None 

567 ) -> str: 

568 """Obtain the url to use when making the final request. 

569 

570 If the message is being sent through a HTTP proxy, the full URL has to 

571 be used. Otherwise, we should only use the path portion of the URL. 

572 

573 This should not be called from user code, and is only exposed for use 

574 when subclassing the 

575 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

576 

577 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. 

578 :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs. 

579 :rtype: str 

580 """ 

581 assert _is_prepared(request) 

582 

583 proxy = select_proxy(request.url, proxies) 

584 scheme = urlparse(request.url).scheme 

585 

586 is_proxied_http_request = proxy and scheme != "https" 

587 using_socks_proxy = False 

588 if proxy: 

589 proxy_scheme = urlparse(proxy).scheme.lower() 

590 using_socks_proxy = proxy_scheme.startswith("socks") 

591 

592 url = request.path_url 

593 

594 if is_proxied_http_request and not using_socks_proxy: 

595 url = urldefragauth(request.url) 

596 

597 return url 

598 

599 def add_headers(self, request: PreparedRequest, **kwargs: Any) -> None: 

600 """Add any headers needed by the connection. As of v2.0 this does 

601 nothing by default, but is left for overriding by users that subclass 

602 the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

603 

604 This should not be called from user code, and is only exposed for use 

605 when subclassing the 

606 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

607 

608 :param request: The :class:`PreparedRequest <PreparedRequest>` to add headers to. 

609 :param kwargs: The keyword arguments from the call to send(). 

610 """ 

611 pass 

612 

613 def proxy_headers(self, proxy: str) -> dict[str, str]: 

614 """Returns a dictionary of the headers to add to any request sent 

615 through a proxy. This works with urllib3 magic to ensure that they are 

616 correctly sent to the proxy, rather than in a tunnelled request if 

617 CONNECT is being used. 

618 

619 This should not be called from user code, and is only exposed for use 

620 when subclassing the 

621 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. 

622 

623 :param proxy: The url of the proxy being used for this request. 

624 :rtype: dict 

625 """ 

626 headers: dict[str, str] = {} 

627 username, password = get_auth_from_url(proxy) 

628 

629 if username: 

630 headers["Proxy-Authorization"] = _basic_auth_str(username, password) 

631 

632 return headers 

633 

634 def send( 

635 self, 

636 request: PreparedRequest, 

637 stream: bool = False, 

638 timeout: _t.TimeoutType = None, 

639 verify: _t.VerifyType = True, 

640 cert: _t.CertType = None, 

641 proxies: dict[str, str] | None = None, 

642 ) -> Response: 

643 """Sends PreparedRequest object. Returns Response object. 

644 

645 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. 

646 :param stream: (optional) Whether to stream the request content. 

647 :param timeout: (optional) How long to wait for the server to send 

648 data before giving up, as a float, or a :ref:`(connect timeout, 

649 read timeout) <timeouts>` tuple. 

650 :type timeout: float or tuple or urllib3 Timeout object 

651 :param verify: (optional) Either a boolean, in which case it controls whether 

652 we verify the server's TLS certificate, or a string, in which case it 

653 must be a path to a CA bundle to use 

654 :param cert: (optional) Any user-provided SSL certificate to be trusted. 

655 :param proxies: (optional) The proxies dictionary to apply to the request. 

656 :rtype: requests.Response 

657 """ 

658 

659 assert _is_prepared(request) 

660 

661 try: 

662 conn = self.get_connection_with_tls_context( 

663 request, verify, proxies=proxies, cert=cert 

664 ) 

665 except LocationValueError as e: 

666 raise InvalidURL(e, request=request) 

667 

668 self.cert_verify(conn, request.url, verify, cert) 

669 url = self.request_url(request, proxies) 

670 self.add_headers( 

671 request, 

672 stream=stream, 

673 timeout=timeout, 

674 verify=verify, 

675 cert=cert, 

676 proxies=proxies, 

677 ) 

678 

679 chunked = not (request.body is None or "Content-Length" in request.headers) 

680 

681 if isinstance(timeout, tuple): 

682 try: 

683 connect, read = timeout 

684 resolved_timeout = TimeoutSauce(connect=connect, read=read) 

685 except ValueError: 

686 raise ValueError( 

687 f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " 

688 f"or a single float to set both timeouts to the same value." 

689 ) 

690 elif isinstance(timeout, TimeoutSauce): 

691 resolved_timeout = timeout 

692 else: 

693 resolved_timeout = TimeoutSauce(connect=timeout, read=timeout) 

694 

695 try: 

696 resp = conn.urlopen( 

697 method=request.method, 

698 url=url, 

699 body=request.body, # type: ignore[arg-type] # urllib3 stubs don't accept Iterable[bytes | str] 

700 headers=request.headers, # type: ignore[arg-type] # urllib3#3072 

701 redirect=False, 

702 assert_same_host=False, 

703 preload_content=False, 

704 decode_content=False, 

705 retries=self.max_retries, 

706 timeout=resolved_timeout, 

707 chunked=chunked, 

708 ) 

709 

710 except (ProtocolError, OSError) as err: 

711 raise ConnectionError(err, request=request) 

712 

713 except MaxRetryError as e: 

714 if isinstance(e.reason, ConnectTimeoutError): 

715 # TODO: Remove this in 3.0.0: see #2811 

716 if not isinstance(e.reason, NewConnectionError): 

717 raise ConnectTimeout(e, request=request) 

718 

719 if isinstance(e.reason, ResponseError): 

720 raise RetryError(e, request=request) 

721 

722 if isinstance(e.reason, _ProxyError): 

723 raise ProxyError(e, request=request) 

724 

725 if isinstance(e.reason, _SSLError): 

726 # This branch is for urllib3 v1.22 and later. 

727 raise SSLError(e, request=request) 

728 

729 raise ConnectionError(e, request=request) 

730 

731 except ClosedPoolError as e: 

732 raise ConnectionError(e, request=request) 

733 

734 except _ProxyError as e: 

735 raise ProxyError(e) 

736 

737 except (_SSLError, _HTTPError) as e: 

738 if isinstance(e, _SSLError): 

739 # This branch is for urllib3 versions earlier than v1.22 

740 raise SSLError(e, request=request) 

741 elif isinstance(e, ReadTimeoutError): 

742 raise ReadTimeout(e, request=request) 

743 elif isinstance(e, _InvalidHeader): 

744 raise InvalidHeader(e, request=request) 

745 else: 

746 raise 

747 

748 return self.build_response(request, resp)