|
23 | 23 | from sentry_sdk.spotlight import DEFAULT_SPOTLIGHT_URL
|
24 | 24 | from sentry_sdk.utils import capture_internal_exception
|
25 | 25 | from sentry_sdk.integrations.executing import ExecutingIntegration
|
26 |
| -from sentry_sdk.transport import Transport |
| 26 | +from sentry_sdk.transport import Transport, AsyncHttpTransport |
27 | 27 | from sentry_sdk.serializer import MAX_DATABAG_BREADTH
|
28 | 28 | from sentry_sdk.consts import DEFAULT_MAX_BREADCRUMBS, DEFAULT_MAX_VALUE_LENGTH
|
| 29 | +from sentry_sdk._compat import PY38 |
29 | 30 |
|
30 | 31 | from typing import TYPE_CHECKING
|
31 | 32 |
|
@@ -1498,3 +1499,317 @@ def test_keep_alive(env_value, arg_value, expected_value):
|
1498 | 1499 | )
|
1499 | 1500 |
|
1500 | 1501 | assert transport_cls.options["keep_alive"] is expected_value
|
| 1502 | + |
| 1503 | + |
| 1504 | +@pytest.mark.parametrize( |
| 1505 | + "testcase", |
| 1506 | + [ |
| 1507 | + { |
| 1508 | + "dsn": "http://[email protected]/123", |
| 1509 | + "env_http_proxy": None, |
| 1510 | + "env_https_proxy": None, |
| 1511 | + "arg_http_proxy": "http://localhost/123", |
| 1512 | + "arg_https_proxy": None, |
| 1513 | + "expected_proxy_scheme": "http", |
| 1514 | + }, |
| 1515 | + { |
| 1516 | + "dsn": "https://[email protected]/123", |
| 1517 | + "env_http_proxy": None, |
| 1518 | + "env_https_proxy": None, |
| 1519 | + "arg_http_proxy": "https://localhost/123", |
| 1520 | + "arg_https_proxy": None, |
| 1521 | + "expected_proxy_scheme": "https", |
| 1522 | + }, |
| 1523 | + { |
| 1524 | + "dsn": "http://[email protected]/123", |
| 1525 | + "env_http_proxy": None, |
| 1526 | + "env_https_proxy": None, |
| 1527 | + "arg_http_proxy": "http://localhost/123", |
| 1528 | + "arg_https_proxy": "https://localhost/123", |
| 1529 | + "expected_proxy_scheme": "http", |
| 1530 | + }, |
| 1531 | + { |
| 1532 | + "dsn": "https://[email protected]/123", |
| 1533 | + "env_http_proxy": None, |
| 1534 | + "env_https_proxy": None, |
| 1535 | + "arg_http_proxy": "http://localhost/123", |
| 1536 | + "arg_https_proxy": "https://localhost/123", |
| 1537 | + "expected_proxy_scheme": "https", |
| 1538 | + }, |
| 1539 | + { |
| 1540 | + "dsn": "https://[email protected]/123", |
| 1541 | + "env_http_proxy": None, |
| 1542 | + "env_https_proxy": None, |
| 1543 | + "arg_http_proxy": "http://localhost/123", |
| 1544 | + "arg_https_proxy": None, |
| 1545 | + "expected_proxy_scheme": "http", |
| 1546 | + }, |
| 1547 | + { |
| 1548 | + "dsn": "http://[email protected]/123", |
| 1549 | + "env_http_proxy": None, |
| 1550 | + "env_https_proxy": None, |
| 1551 | + "arg_http_proxy": None, |
| 1552 | + "arg_https_proxy": None, |
| 1553 | + "expected_proxy_scheme": None, |
| 1554 | + }, |
| 1555 | + { |
| 1556 | + "dsn": "http://[email protected]/123", |
| 1557 | + "env_http_proxy": "http://localhost/123", |
| 1558 | + "env_https_proxy": None, |
| 1559 | + "arg_http_proxy": None, |
| 1560 | + "arg_https_proxy": None, |
| 1561 | + "expected_proxy_scheme": "http", |
| 1562 | + }, |
| 1563 | + { |
| 1564 | + "dsn": "https://[email protected]/123", |
| 1565 | + "env_http_proxy": None, |
| 1566 | + "env_https_proxy": "https://localhost/123", |
| 1567 | + "arg_http_proxy": None, |
| 1568 | + "arg_https_proxy": None, |
| 1569 | + "expected_proxy_scheme": "https", |
| 1570 | + }, |
| 1571 | + { |
| 1572 | + "dsn": "https://[email protected]/123", |
| 1573 | + "env_http_proxy": "http://localhost/123", |
| 1574 | + "env_https_proxy": None, |
| 1575 | + "arg_http_proxy": None, |
| 1576 | + "arg_https_proxy": None, |
| 1577 | + "expected_proxy_scheme": "http", |
| 1578 | + }, |
| 1579 | + { |
| 1580 | + "dsn": "https://[email protected]/123", |
| 1581 | + "env_http_proxy": "http://localhost/123", |
| 1582 | + "env_https_proxy": "https://localhost/123", |
| 1583 | + "arg_http_proxy": "", |
| 1584 | + "arg_https_proxy": "", |
| 1585 | + "expected_proxy_scheme": None, |
| 1586 | + }, |
| 1587 | + { |
| 1588 | + "dsn": "https://[email protected]/123", |
| 1589 | + "env_http_proxy": "http://localhost/123", |
| 1590 | + "env_https_proxy": "https://localhost/123", |
| 1591 | + "arg_http_proxy": None, |
| 1592 | + "arg_https_proxy": None, |
| 1593 | + "expected_proxy_scheme": "https", |
| 1594 | + }, |
| 1595 | + { |
| 1596 | + "dsn": "https://[email protected]/123", |
| 1597 | + "env_http_proxy": "http://localhost/123", |
| 1598 | + "env_https_proxy": None, |
| 1599 | + "arg_http_proxy": None, |
| 1600 | + "arg_https_proxy": None, |
| 1601 | + "expected_proxy_scheme": "http", |
| 1602 | + }, |
| 1603 | + { |
| 1604 | + "dsn": "https://[email protected]/123", |
| 1605 | + "env_http_proxy": "http://localhost/123", |
| 1606 | + "env_https_proxy": "https://localhost/123", |
| 1607 | + "arg_http_proxy": None, |
| 1608 | + "arg_https_proxy": "", |
| 1609 | + "expected_proxy_scheme": "http", |
| 1610 | + }, |
| 1611 | + { |
| 1612 | + "dsn": "https://[email protected]/123", |
| 1613 | + "env_http_proxy": "http://localhost/123", |
| 1614 | + "env_https_proxy": "https://localhost/123", |
| 1615 | + "arg_http_proxy": "", |
| 1616 | + "arg_https_proxy": None, |
| 1617 | + "expected_proxy_scheme": "https", |
| 1618 | + }, |
| 1619 | + { |
| 1620 | + "dsn": "https://[email protected]/123", |
| 1621 | + "env_http_proxy": None, |
| 1622 | + "env_https_proxy": "https://localhost/123", |
| 1623 | + "arg_http_proxy": None, |
| 1624 | + "arg_https_proxy": "", |
| 1625 | + "expected_proxy_scheme": None, |
| 1626 | + }, |
| 1627 | + { |
| 1628 | + "dsn": "http://[email protected]/123", |
| 1629 | + "env_http_proxy": "http://localhost/123", |
| 1630 | + "env_https_proxy": "https://localhost/123", |
| 1631 | + "arg_http_proxy": None, |
| 1632 | + "arg_https_proxy": None, |
| 1633 | + "expected_proxy_scheme": "http", |
| 1634 | + }, |
| 1635 | + # NO_PROXY testcases |
| 1636 | + { |
| 1637 | + "dsn": "http://[email protected]/123", |
| 1638 | + "env_http_proxy": "http://localhost/123", |
| 1639 | + "env_https_proxy": None, |
| 1640 | + "env_no_proxy": "sentry.io,example.com", |
| 1641 | + "arg_http_proxy": None, |
| 1642 | + "arg_https_proxy": None, |
| 1643 | + "expected_proxy_scheme": None, |
| 1644 | + }, |
| 1645 | + { |
| 1646 | + "dsn": "https://[email protected]/123", |
| 1647 | + "env_http_proxy": None, |
| 1648 | + "env_https_proxy": "https://localhost/123", |
| 1649 | + "env_no_proxy": "example.com,sentry.io", |
| 1650 | + "arg_http_proxy": None, |
| 1651 | + "arg_https_proxy": None, |
| 1652 | + "expected_proxy_scheme": None, |
| 1653 | + }, |
| 1654 | + { |
| 1655 | + "dsn": "http://[email protected]/123", |
| 1656 | + "env_http_proxy": None, |
| 1657 | + "env_https_proxy": None, |
| 1658 | + "env_no_proxy": "sentry.io,example.com", |
| 1659 | + "arg_http_proxy": "http://localhost/123", |
| 1660 | + "arg_https_proxy": None, |
| 1661 | + "expected_proxy_scheme": "http", |
| 1662 | + }, |
| 1663 | + { |
| 1664 | + "dsn": "https://[email protected]/123", |
| 1665 | + "env_http_proxy": None, |
| 1666 | + "env_https_proxy": None, |
| 1667 | + "env_no_proxy": "sentry.io,example.com", |
| 1668 | + "arg_http_proxy": None, |
| 1669 | + "arg_https_proxy": "https://localhost/123", |
| 1670 | + "expected_proxy_scheme": "https", |
| 1671 | + }, |
| 1672 | + { |
| 1673 | + "dsn": "https://[email protected]/123", |
| 1674 | + "env_http_proxy": None, |
| 1675 | + "env_https_proxy": None, |
| 1676 | + "env_no_proxy": "sentry.io,example.com", |
| 1677 | + "arg_http_proxy": None, |
| 1678 | + "arg_https_proxy": "https://localhost/123", |
| 1679 | + "expected_proxy_scheme": "https", |
| 1680 | + "arg_proxy_headers": {"Test-Header": "foo-bar"}, |
| 1681 | + }, |
| 1682 | + ], |
| 1683 | +) |
| 1684 | +@pytest.mark.asyncio |
| 1685 | +@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+") |
| 1686 | +async def test_async_proxy(monkeypatch, testcase): |
| 1687 | + # These are just the same tests as the sync ones, but they need to be run in an event loop |
| 1688 | + # and respect the shutdown behavior of the async transport |
| 1689 | + if testcase["env_http_proxy"] is not None: |
| 1690 | + monkeypatch.setenv("HTTP_PROXY", testcase["env_http_proxy"]) |
| 1691 | + if testcase["env_https_proxy"] is not None: |
| 1692 | + monkeypatch.setenv("HTTPS_PROXY", testcase["env_https_proxy"]) |
| 1693 | + if testcase.get("env_no_proxy") is not None: |
| 1694 | + monkeypatch.setenv("NO_PROXY", testcase["env_no_proxy"]) |
| 1695 | + |
| 1696 | + kwargs = {"_experiments": {"transport_async": True}} |
| 1697 | + |
| 1698 | + if testcase["arg_http_proxy"] is not None: |
| 1699 | + kwargs["http_proxy"] = testcase["arg_http_proxy"] |
| 1700 | + if testcase["arg_https_proxy"] is not None: |
| 1701 | + kwargs["https_proxy"] = testcase["arg_https_proxy"] |
| 1702 | + if testcase.get("arg_proxy_headers") is not None: |
| 1703 | + kwargs["proxy_headers"] = testcase["arg_proxy_headers"] |
| 1704 | + |
| 1705 | + client = Client(testcase["dsn"], **kwargs) |
| 1706 | + assert isinstance(client.transport, AsyncHttpTransport) |
| 1707 | + |
| 1708 | + proxy = getattr( |
| 1709 | + client.transport._pool, |
| 1710 | + "proxy", |
| 1711 | + getattr(client.transport._pool, "_proxy_url", None), |
| 1712 | + ) |
| 1713 | + if testcase["expected_proxy_scheme"] is None: |
| 1714 | + assert proxy is None |
| 1715 | + else: |
| 1716 | + scheme = ( |
| 1717 | + proxy.scheme.decode("ascii") |
| 1718 | + if isinstance(proxy.scheme, bytes) |
| 1719 | + else proxy.scheme |
| 1720 | + ) |
| 1721 | + assert scheme == testcase["expected_proxy_scheme"] |
| 1722 | + |
| 1723 | + if testcase.get("arg_proxy_headers") is not None: |
| 1724 | + proxy_headers = dict( |
| 1725 | + (k.decode("ascii"), v.decode("ascii")) |
| 1726 | + for k, v in client.transport._pool._proxy_headers |
| 1727 | + ) |
| 1728 | + assert proxy_headers == testcase["arg_proxy_headers"] |
| 1729 | + |
| 1730 | + await client.close() |
| 1731 | + |
| 1732 | + |
| 1733 | +@pytest.mark.parametrize( |
| 1734 | + "testcase", |
| 1735 | + [ |
| 1736 | + { |
| 1737 | + "dsn": "https://[email protected]/123", |
| 1738 | + "arg_http_proxy": "http://localhost/123", |
| 1739 | + "arg_https_proxy": None, |
| 1740 | + "should_be_socks_proxy": False, |
| 1741 | + }, |
| 1742 | + { |
| 1743 | + "dsn": "https://[email protected]/123", |
| 1744 | + "arg_http_proxy": "socks4a://localhost/123", |
| 1745 | + "arg_https_proxy": None, |
| 1746 | + "should_be_socks_proxy": True, |
| 1747 | + }, |
| 1748 | + { |
| 1749 | + "dsn": "https://[email protected]/123", |
| 1750 | + "arg_http_proxy": "socks4://localhost/123", |
| 1751 | + "arg_https_proxy": None, |
| 1752 | + "should_be_socks_proxy": True, |
| 1753 | + }, |
| 1754 | + { |
| 1755 | + "dsn": "https://[email protected]/123", |
| 1756 | + "arg_http_proxy": "socks5h://localhost/123", |
| 1757 | + "arg_https_proxy": None, |
| 1758 | + "should_be_socks_proxy": True, |
| 1759 | + }, |
| 1760 | + { |
| 1761 | + "dsn": "https://[email protected]/123", |
| 1762 | + "arg_http_proxy": "socks5://localhost/123", |
| 1763 | + "arg_https_proxy": None, |
| 1764 | + "should_be_socks_proxy": True, |
| 1765 | + }, |
| 1766 | + { |
| 1767 | + "dsn": "https://[email protected]/123", |
| 1768 | + "arg_http_proxy": None, |
| 1769 | + "arg_https_proxy": "socks4a://localhost/123", |
| 1770 | + "should_be_socks_proxy": True, |
| 1771 | + }, |
| 1772 | + { |
| 1773 | + "dsn": "https://[email protected]/123", |
| 1774 | + "arg_http_proxy": None, |
| 1775 | + "arg_https_proxy": "socks4://localhost/123", |
| 1776 | + "should_be_socks_proxy": True, |
| 1777 | + }, |
| 1778 | + { |
| 1779 | + "dsn": "https://[email protected]/123", |
| 1780 | + "arg_http_proxy": None, |
| 1781 | + "arg_https_proxy": "socks5h://localhost/123", |
| 1782 | + "should_be_socks_proxy": True, |
| 1783 | + }, |
| 1784 | + { |
| 1785 | + "dsn": "https://[email protected]/123", |
| 1786 | + "arg_http_proxy": None, |
| 1787 | + "arg_https_proxy": "socks5://localhost/123", |
| 1788 | + "should_be_socks_proxy": True, |
| 1789 | + }, |
| 1790 | + ], |
| 1791 | +) |
| 1792 | +@pytest.mark.asyncio |
| 1793 | +@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+") |
| 1794 | +async def test_async_socks_proxy(testcase): |
| 1795 | + # These are just the same tests as the sync ones, but they need to be run in an event loop |
| 1796 | + # and respect the shutdown behavior of the async transport |
| 1797 | + |
| 1798 | + kwargs = {"_experiments": {"transport_async": True}} |
| 1799 | + |
| 1800 | + if testcase["arg_http_proxy"] is not None: |
| 1801 | + kwargs["http_proxy"] = testcase["arg_http_proxy"] |
| 1802 | + if testcase["arg_https_proxy"] is not None: |
| 1803 | + kwargs["https_proxy"] = testcase["arg_https_proxy"] |
| 1804 | + |
| 1805 | + client = Client(testcase["dsn"], **kwargs) |
| 1806 | + assert isinstance(client.transport, AsyncHttpTransport) |
| 1807 | + |
| 1808 | + assert ("socks" in str(type(client.transport._pool)).lower()) == testcase[ |
| 1809 | + "should_be_socks_proxy" |
| 1810 | + ], ( |
| 1811 | + f"Expected {kwargs} to result in SOCKS == {testcase['should_be_socks_proxy']}" |
| 1812 | + f"but got {str(type(client.transport._pool))}" |
| 1813 | + ) |
| 1814 | + |
| 1815 | + await client.close() |
0 commit comments