Skip to content

Commit 2e67c96

Browse files
merge master
2 parents 878ac1c + e73e600 commit 2e67c96

File tree

3 files changed

+98
-3
lines changed

3 files changed

+98
-3
lines changed

.claude/settings.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(find:*)",
5+
"Bash(ls:*)",
6+
"Bash(git:*)",
7+
"Bash(git status:*)",
8+
"Bash(git log:*)",
9+
"Bash(git diff:*)",
10+
"Bash(git show:*)",
11+
"Bash(git branch:*)",
12+
"Bash(git remote:*)",
13+
"Bash(git tag:*)",
14+
"Bash(git stash list:*)",
15+
"Bash(git rev-parse:*)",
16+
"Bash(gh pr view:*)",
17+
"Bash(gh pr list:*)",
18+
"Bash(gh pr checks:*)",
19+
"Bash(gh pr diff:*)",
20+
"Bash(gh issue view:*)",
21+
"Bash(gh issue list:*)",
22+
"Bash(gh run view:*)",
23+
"Bash(gh run list:*)",
24+
"Bash(gh run logs:*)",
25+
"Bash(gh repo view:*)",
26+
"WebFetch(domain:github.com)",
27+
"WebFetch(domain:docs.sentry.io)",
28+
"WebFetch(domain:develop.sentry.dev)",
29+
"Bash(grep:*)",
30+
"Bash(mv:*)"
31+
],
32+
"deny": []
33+
}
34+
}

sentry_sdk/integrations/stdlib.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,17 @@ 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
7472
default_port = self.default_port
7573

74+
# proxies go through set_tunnel
75+
tunnel_host = getattr(self, "_tunnel_host", None)
76+
if tunnel_host:
77+
host = tunnel_host
78+
port = getattr(self, "_tunnel_port", default_port)
79+
else:
80+
host = self.host
81+
port = self.port
82+
7683
client = sentry_sdk.get_client()
7784
if client.get_integration(StdlibIntegration) is None or is_sentry_url(
7885
client, host
@@ -104,6 +111,11 @@ def putrequest(
104111
span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query)
105112
span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment)
106113

114+
# for proxies, these point to the proxy host/port
115+
if tunnel_host:
116+
span.set_data(SPANDATA.NETWORK_PEER_ADDRESS, self.host)
117+
span.set_data(SPANDATA.NETWORK_PEER_PORT, self.port)
118+
107119
rv = real_putrequest(self, method, url, *args, **kwargs)
108120

109121
if should_propagate_trace(client, real_url):

tests/integrations/stdlib/test_httplib.py

Lines changed: 50 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,25 @@ 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+
@pytest.mark.parametrize("tunnel_port", [8080, None])
675+
def test_proxy_http_tunnel(sentry_init, capture_events, tunnel_port):
676+
sentry_init(traces_sample_rate=1.0)
677+
events = capture_events()
678+
679+
with start_transaction(name="test_transaction"):
680+
conn = HTTPConnection("localhost", PROXY_PORT)
681+
conn.set_tunnel("api.example.com", tunnel_port)
682+
conn.request("GET", "/foo")
683+
conn.getresponse()
684+
685+
(event,) = events
686+
(span,) = event["spans"]
687+
688+
port_modifier = f":{tunnel_port}" if tunnel_port else ""
689+
assert span["description"] == f"GET http://api.example.com{port_modifier}/foo"
690+
assert span["data"]["url"] == f"http://api.example.com{port_modifier}/foo"
691+
assert span["data"][SPANDATA.HTTP_METHOD] == "GET"
692+
assert span["data"][SPANDATA.NETWORK_PEER_ADDRESS] == "localhost"
693+
assert span["data"][SPANDATA.NETWORK_PEER_PORT] == PROXY_PORT

0 commit comments

Comments
 (0)