Skip to content

Commit bf37a48

Browse files
committed
Handle proxy tunnels in httlib integration
1 parent b0885b8 commit bf37a48

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

sentry_sdk/integrations/stdlib.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,18 @@ def _install_httplib() -> None:
6969
def putrequest(
7070
self: "HTTPConnection", method: str, url: str, *args: "Any", **kwargs: "Any"
7171
) -> "Any":
72-
host = self.host
73-
port = self.port
72+
# proxy info is in _tunnel_host/_tunnel_port
73+
host = getattr(self, "_tunnel_host", None) or self.host
74+
7475
default_port = self.default_port
76+
tunnel_port = getattr(self, "_tunnel_port", None)
77+
if tunnel_port:
78+
port = tunnel_port
79+
# need to override default_port for correct url recording
80+
if tunnel_port == 443:
81+
default_port = 443
82+
else:
83+
port = self.port
7584

7685
client = sentry_sdk.get_client()
7786
if client.get_integration(StdlibIntegration) is None or is_sentry_url(
@@ -104,6 +113,11 @@ def putrequest(
104113
span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query)
105114
span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
106115

116+
# Set network peer address and port (the actual connection endpoint)
117+
# for proxies, these point to the proxy host/port
118+
span.set_data(SPANDATA.NETWORK_PEER_ADDRESS, self.host)
119+
span.set_data(SPANDATA.NETWORK_PEER_PORT, self.port)
120+
107121
rv = real_putrequest(self, method, url, *args, **kwargs)
108122

109123
if should_propagate_trace(client, real_url):

tests/integrations/stdlib/test_httplib.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import os
22
import datetime
3+
import socket
34
from http.client import HTTPConnection, HTTPSConnection
5+
from http.server import BaseHTTPRequestHandler, HTTPServer
46
from socket import SocketIO
7+
from threading import Thread
58
from urllib.error import HTTPError
69
from urllib.request import urlopen
710
from unittest import mock
@@ -12,11 +15,35 @@
1215
from sentry_sdk.consts import MATCH_ALL, SPANDATA
1316
from sentry_sdk.integrations.stdlib import StdlibIntegration
1417

15-
from tests.conftest import ApproxDict, create_mock_http_server
18+
from tests.conftest import ApproxDict, create_mock_http_server, get_free_port
1619

1720
PORT = create_mock_http_server()
1821

1922

23+
class MockProxyRequestHandler(BaseHTTPRequestHandler):
24+
def do_CONNECT(self):
25+
self.send_response(200, "Connection Established")
26+
self.end_headers()
27+
28+
self.rfile.readline()
29+
30+
response = b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
31+
self.wfile.write(response)
32+
self.wfile.flush()
33+
34+
35+
def create_mock_proxy_server():
36+
proxy_port = get_free_port()
37+
proxy_server = HTTPServer(("localhost", proxy_port), MockProxyRequestHandler)
38+
proxy_thread = Thread(target=proxy_server.serve_forever)
39+
proxy_thread.daemon = True
40+
proxy_thread.start()
41+
return proxy_port
42+
43+
44+
PROXY_PORT = create_mock_proxy_server()
45+
46+
2047
def test_crumb_capture(sentry_init, capture_events):
2148
sentry_init(integrations=[StdlibIntegration()])
2249
events = capture_events()
@@ -642,3 +669,23 @@ def test_http_timeout(monkeypatch, sentry_init, capture_envelopes):
642669
span = transaction["spans"][0]
643670
assert span["op"] == "http.client"
644671
assert span["description"] == f"GET http://localhost:{PORT}/bla" # noqa: E231
672+
673+
674+
def test_proxy_https_tunnel(sentry_init, capture_events):
675+
sentry_init(traces_sample_rate=1.0)
676+
events = capture_events()
677+
678+
with start_transaction(name="test_transaction"):
679+
conn = HTTPConnection("localhost", PROXY_PORT)
680+
conn.set_tunnel("api.example.com", 443)
681+
conn.request("GET", "/foo")
682+
conn.getresponse()
683+
684+
(event,) = events
685+
(span,) = event["spans"]
686+
687+
assert span["description"] == "GET https://api.example.com/foo"
688+
assert span["data"]["url"] == "https://api.example.com/foo"
689+
assert span["data"][SPANDATA.HTTP_METHOD] == "GET"
690+
assert span["data"][SPANDATA.NETWORK_PEER_ADDRESS] == "localhost"
691+
assert span["data"][SPANDATA.NETWORK_PEER_PORT] == PROXY_PORT

0 commit comments

Comments
 (0)