Read a header value case-insensitively from a headers mapping. Supports both plain ``dict`` headers and framework header objects (Werkzeug/Django ``HttpHeaders``) that expose a ``get`` method, which is already case-insensitive.
(headers: t.Any, name: str)
| 1416 | |
| 1417 | @staticmethod |
| 1418 | def _get_header(headers: t.Any, name: str) -> t.Optional[str]: |
| 1419 | """Read a header value case-insensitively from a headers mapping. |
| 1420 | |
| 1421 | Supports both plain ``dict`` headers and framework header objects |
| 1422 | (Werkzeug/Django ``HttpHeaders``) that expose a ``get`` method, which is |
| 1423 | already case-insensitive. |
| 1424 | """ |
| 1425 | if headers is None: |
| 1426 | return None |
| 1427 | |
| 1428 | get = getattr(headers, "get", None) |
| 1429 | if callable(get): |
| 1430 | value = get(name) |
| 1431 | if value is not None: |
| 1432 | return str(value) |
| 1433 | |
| 1434 | # Fall back to a manual case-insensitive scan for plain mappings. |
| 1435 | try: |
| 1436 | items = headers.items() |
| 1437 | except AttributeError: |
| 1438 | return None |
| 1439 | |
| 1440 | target = name.lower() |
| 1441 | for key, value in items: |
| 1442 | if isinstance(key, str) and key.lower() == target: |
| 1443 | return str(value) if value is not None else None |
| 1444 | return None |
| 1445 | |
| 1446 | def _verify_webhook_signature( |
| 1447 | self, |