Skip to content

Commit f7057df

Browse files
ZStriker19majorgreysbrettlangdon
authored
fix: remove url parts from http.url tag [backport #4904 to 1.6] (#4906)
This fix removes unintended url parts in the `http.url` tag. Co-authored-by: Brett Langdon <[email protected]> ## Description <!-- Briefly describe the change and why it was required. --> <!-- If this is a breaking change, explain why it is necessary. Breaking changes must append `!` after the type/scope. See https://ddtrace.readthedocs.io/en/stable/contributing.html for more details. --> ## Checklist - [x] Followed the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/contributing.html#Release-Note-Guidelines) when writing a release note. - [x] Add additional sections for `feat` and `fix` pull requests. - [x] [Library documentation](https://github.com/DataDog/dd-trace-py/tree/1.x/docs) and/or [Datadog's documentation site](https://github.com/DataDog/documentation/) is updated. Link to doc PR in description. <!-- Copy and paste the relevant snippet based on the type of pull request --> <!-- START feat --> ## Motivation <!-- Expand on why the change is required, include relevant context for reviewers --> ## Design <!-- Include benefits from the change as well as possible drawbacks and trade-offs --> ## Testing strategy <!-- Describe the automated tests and/or the steps for manual testing. <!-- END feat --> <!-- START fix --> ## Relevant issue(s) <!-- Link the pull request to any issues related to the fix. Use keywords for links to automate closing the issues once the pull request is merged. --> ## Testing strategy <!-- Describe any added regression tests and/or the manual testing performed. --> <!-- END fix --> ## Reviewer Checklist - [ ] Title is accurate. - [ ] Description motivates each change. - [ ] No unnecessary changes were introduced in this PR. - [ ] Avoid breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes unless absolutely necessary. - [ ] Tests provided or description of manual testing performed is included in the code or PR. - [ ] Release note has been added and follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/contributing.html#Release-Note-Guidelines), or else `changelog/no-changelog` label added. - [ ] All relevant GitHub issues are correctly linked. - [ ] Backports are identified and tagged with Mergifyio. Co-authored-by: Tahir H. Butt <[email protected]> Co-authored-by: Brett Langdon <[email protected]>
1 parent 87a442d commit f7057df

File tree

6 files changed

+96
-2
lines changed

6 files changed

+96
-2
lines changed

ddtrace/contrib/trace_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from ddtrace.ext import http
2424
from ddtrace.ext import user
2525
from ddtrace.internal import _context
26+
from ddtrace.internal.compat import parse
2627
from ddtrace.internal.compat import six
2728
from ddtrace.internal.logger import get_logger
2829
from ddtrace.internal.utils.cache import cached
@@ -280,6 +281,29 @@ def _store_response_headers(headers, span, integration_config):
280281
_store_headers(headers, span, integration_config, RESPONSE)
281282

282283

284+
def _sanitized_url(url):
285+
# type: (str) -> str
286+
"""
287+
Sanitize url by removing parts with potential auth info
288+
"""
289+
if "@" in url:
290+
parsed = parse.urlparse(url)
291+
netloc = parsed.netloc
292+
netloc = netloc[netloc.index("@") + 1 :]
293+
return parse.urlunparse(
294+
(
295+
parsed.scheme,
296+
netloc,
297+
parsed.path,
298+
"",
299+
parsed.query,
300+
"",
301+
)
302+
)
303+
304+
return url
305+
306+
283307
def with_traced_module(func):
284308
"""Helper for providing tracing essentials (module and pin) for tracing
285309
wrappers.
@@ -417,6 +441,8 @@ def set_http_meta(
417441
span.set_tag_str(http.METHOD, method)
418442

419443
if url is not None:
444+
url = _sanitized_url(url)
445+
420446
if integration_config.http_tag_query_string: # Tagging query string in http.url
421447
if config.global_query_string_obfuscation_disabled: # No redacting of query strings
422448
span.set_tag_str(http.URL, url)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
fixes:
3+
- |
4+
This fix removes unintended url parts in the ``http.url`` tag.

tests/contrib/aiohttp/test_aiohttp_client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
PORT = HTTPBIN_CONFIG["port"]
1717
SOCKET = "{}:{}".format(HOST, PORT)
1818
URL = "http://{}".format(SOCKET)
19+
URL_AUTH = "http://user:pass@{}".format(SOCKET)
1920
URL_200 = "{}/status/200".format(URL)
21+
URL_AUTH_200 = "{}/status/200".format(URL_AUTH)
2022
URL_500 = "{}/status/500".format(URL)
2123

2224

@@ -35,6 +37,14 @@ async def test_200_request(snapshot_context):
3537
assert resp.status == 200
3638

3739

40+
@pytest.mark.asyncio
41+
async def test_auth_200_request(snapshot_context):
42+
with snapshot_context():
43+
async with aiohttp.ClientSession() as session:
44+
async with session.get(URL_AUTH_200) as resp:
45+
assert resp.status == 200
46+
47+
3848
@pytest.mark.asyncio
3949
async def test_200_request_post(snapshot_context):
4050
with snapshot_context():

tests/contrib/requests/test_requests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
SOCKET = "httpbin.org"
3131
URL_200 = "http://{}/status/200".format(SOCKET)
3232
URL_500 = "http://{}/status/500".format(SOCKET)
33+
URL_AUTH_200 = "http://user:pass@{}/status/200".format(SOCKET)
3334

3435

3536
class BaseRequestTestCase(object):
@@ -125,6 +126,13 @@ def test_200(self):
125126
assert s.span_type == "http"
126127
assert http.QUERY_STRING not in s.get_tags()
127128

129+
def test_auth_200(self):
130+
self.session.get(URL_AUTH_200)
131+
spans = self.pop_spans()
132+
assert len(spans) == 1
133+
s = spans[0]
134+
assert s.get_tag(http.URL) == URL_200
135+
128136
def test_200_send(self):
129137
# when calling send directly
130138
req = requests.Request(url=URL_200, method="GET")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[[
2+
{
3+
"name": "aiohttp.request",
4+
"service": null,
5+
"resource": "aiohttp.request",
6+
"trace_id": 0,
7+
"span_id": 1,
8+
"parent_id": 0,
9+
"type": "http",
10+
"meta": {
11+
"_dd.p.dm": "-0",
12+
"http.method": "GET",
13+
"http.status_code": "200",
14+
"http.status_msg": "OK",
15+
"http.url": "http://localhost:8001/status/200",
16+
"runtime-id": "7a569f0d94574038b2b11ee3579d0936"
17+
},
18+
"metrics": {
19+
"_dd.agent_psr": 1.0,
20+
"_dd.top_level": 1,
21+
"_dd.tracer_kr": 1.0,
22+
"_sampling_priority_v1": 1,
23+
"system.pid": 57194
24+
},
25+
"duration": 8933000,
26+
"start": 1673646330398679000
27+
},
28+
{
29+
"name": "TCPConnector.connect",
30+
"service": null,
31+
"resource": "TCPConnector.connect",
32+
"trace_id": 0,
33+
"span_id": 2,
34+
"parent_id": 1,
35+
"duration": 1426000,
36+
"start": 1673646330399204000
37+
}]]

tests/tracer/test_trace_utils.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,9 @@ def test_ext_service(int_config, pin, config_val, default, expected):
336336
{"id": "val", "name": "vlad"},
337337
None,
338338
),
339+
("GET", "http://user:pass@localhost/", 0, None, None, None, None, None, None, None),
340+
("GET", "http://user@localhost/", 0, None, None, None, None, None, None, None),
341+
("GET", "http://user:pass@localhost/api?q=test", 0, None, None, None, None, None, None, None),
339342
],
340343
)
341344
def test_set_http_meta(
@@ -376,10 +379,16 @@ def test_set_http_meta(
376379
assert http.METHOD not in span.get_tags()
377380

378381
if url is not None:
382+
if url.startswith("http://user"):
383+
# Remove any userinfo that may be in the original url
384+
expected_url = url[: url.index(":")] + "://" + url[url.index("@") + 1 :]
385+
else:
386+
expected_url = url
387+
379388
if query and int_config.trace_query_string:
380-
assert span.get_tag(http.URL) == stringify(url + "?" + query)
389+
assert span.get_tag(http.URL) == stringify(expected_url + "?" + query)
381390
else:
382-
assert span.get_tag(http.URL) == stringify(url)
391+
assert span.get_tag(http.URL) == stringify(expected_url)
383392
else:
384393
assert http.URL not in span.get_tags()
385394

0 commit comments

Comments
 (0)