| 312 | ) |
| 313 | |
| 314 | def _params_from_url(self, url, defaults): |
| 315 | scheme, host, port, username, password, path, query = _parse_url(url) |
| 316 | connparams = dict( |
| 317 | defaults, **dictfilter({ |
| 318 | 'host': host, 'port': port, 'username': username, |
| 319 | 'password': password, 'db': query.pop('virtual_host', None)}) |
| 320 | ) |
| 321 | |
| 322 | if scheme == 'socket': |
| 323 | # use 'path' as path to the socket… in this case |
| 324 | # the database number should be given in 'query' |
| 325 | connparams.update({ |
| 326 | 'connection_class': self.redis.UnixDomainSocketConnection, |
| 327 | 'path': '/' + path, |
| 328 | }) |
| 329 | # host+port are invalid options when using this connection type. |
| 330 | connparams.pop('host', None) |
| 331 | connparams.pop('port', None) |
| 332 | connparams.pop('socket_connect_timeout') |
| 333 | else: |
| 334 | connparams['db'] = path |
| 335 | |
| 336 | ssl_param_keys = ['ssl_ca_certs', 'ssl_certfile', 'ssl_keyfile', |
| 337 | 'ssl_cert_reqs'] |
| 338 | |
| 339 | if scheme == 'redis': |
| 340 | # If connparams or query string contain ssl params, raise error |
| 341 | if (any(key in connparams for key in ssl_param_keys) or |
| 342 | any(key in query for key in ssl_param_keys)): |
| 343 | raise ValueError(E_REDIS_SSL_PARAMS_AND_SCHEME_MISMATCH) |
| 344 | |
| 345 | if scheme == 'rediss': |
| 346 | connparams['connection_class'] = redis.SSLConnection |
| 347 | # The following parameters, if present in the URL, are encoded. We |
| 348 | # must add the decoded values to connparams. |
| 349 | for ssl_setting in ssl_param_keys: |
| 350 | ssl_val = query.pop(ssl_setting, None) |
| 351 | if ssl_val: |
| 352 | connparams[ssl_setting] = unquote(ssl_val) |
| 353 | |
| 354 | # db may be string and start with / like in kombu. |
| 355 | db = connparams.get('db') or 0 |
| 356 | db = db.strip('/') if isinstance(db, str) else db |
| 357 | connparams['db'] = int(db) |
| 358 | |
| 359 | # credential provider as query string |
| 360 | credential_provider = query.pop("credential_provider", None) |
| 361 | if credential_provider: |
| 362 | if isinstance(credential_provider, str): |
| 363 | credential_provider_cls = symbol_by_name(credential_provider) |
| 364 | credential_provider = credential_provider_cls() |
| 365 | |
| 366 | if not isinstance(credential_provider, CredentialProvider): |
| 367 | raise ValueError( |
| 368 | "Credential provider is not an instance of a redis.CredentialProvider or a subclass" |
| 369 | ) |
| 370 | |
| 371 | connparams['credential_provider'] = credential_provider |