Skip to content

Commit 6c5ff75

Browse files
committed
Add http.referrer_host tag
1 parent e08d99c commit 6c5ff75

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

ddtrace/contrib/internal/trace_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,27 @@ def _get_request_header_user_agent(headers, headers_are_case_sensitive=False):
172172
return ""
173173

174174

175+
def _get_request_header_referer_host(headers, headers_are_case_sensitive=False):
176+
# type: (Mapping[str, str], bool) -> str
177+
"""Get referer host from request headers
178+
:param headers: A dict of http headers to be stored in the span
179+
:type headers: dict or list
180+
:param headers_are_case_sensitive: Whether the headers are case sensitive
181+
:type headers_are_case_sensitive: bool
182+
:return: The referer host if found, empty string otherwise
183+
:rtype: str
184+
"""
185+
referer = _get_header_value_case_insensitive(headers, "referer") if headers_are_case_sensitive else headers.get("referer")
186+
if referer:
187+
try:
188+
parsed_url = parse.urlparse(referer)
189+
if parsed_url.netloc:
190+
return parsed_url.netloc
191+
except Exception:
192+
log.debug("failed to parse referer header value: %r", referer)
193+
return ""
194+
195+
175196
def _get_request_header_client_ip(headers, peer_ip=None, headers_are_case_sensitive=False):
176197
# type: (Optional[Mapping[str, str]], Optional[str], bool) -> str
177198

@@ -501,6 +522,11 @@ def set_http_meta(
501522
if user_agent:
502523
span.set_tag_str(http.USER_AGENT, user_agent)
503524

525+
# Extract referrer host if referer header is present
526+
referer_host = _get_request_header_referer_host(request_headers, headers_are_case_sensitive)
527+
if referer_host:
528+
span.set_tag_str(http.REFERRER_HOST, referer_host)
529+
504530
# We always collect the IP if appsec is enabled to report it on potential vulnerabilities.
505531
# https://datadoghq.atlassian.net/wiki/spaces/APS/pages/2118779066/Client+IP+addresses+resolution
506532
if asm_config._asm_enabled or config._retrieve_client_ip:

ddtrace/ext/http.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
VERSION = "http.version"
1818
CLIENT_IP = "http.client_ip"
1919
ROUTE = "http.route"
20+
REFERRER_HOST = "http.referrer_host"
2021

2122
# template render span type
2223
TEMPLATE = "template"

tests/tracer/test_trace_utils.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,38 @@ def test_whitelist_case_insensitive(self, span, integration_config):
252252
)
253253
assert span.get_tag("http.response.headers.content-type") == "some;value"
254254

255+
def test_referer_host_extraction(self, span, integration_config):
256+
"""Test that referer host is correctly extracted from referer header"""
257+
headers = {
258+
"referer": "https://example.com/path?query=1",
259+
}
260+
trace_utils.set_http_meta(span, integration_config, request_headers=headers)
261+
assert span.get_tag("http.referrer_host") == "example.com"
262+
263+
def test_referer_host_case_insensitive(self, span, integration_config):
264+
"""Test that referer host extraction works with case-insensitive header names"""
265+
headers = {
266+
"Referer": "https://example.com/path?query=1",
267+
}
268+
trace_utils.set_http_meta(span, integration_config, request_headers=headers, headers_are_case_sensitive=True)
269+
assert span.get_tag("http.referrer_host") == "example.com"
270+
271+
def test_referer_host_missing(self, span, integration_config):
272+
"""Test that no referer host tag is set when referer header is missing"""
273+
headers = {
274+
"other-header": "value",
275+
}
276+
trace_utils.set_http_meta(span, integration_config, request_headers=headers)
277+
assert span.get_tag("http.referrer_host") is None
278+
279+
def test_referer_host_invalid_url(self, span, integration_config):
280+
"""Test that no referer host tag is set when referer URL is invalid"""
281+
headers = {
282+
"referer": "not-a-valid-url",
283+
}
284+
trace_utils.set_http_meta(span, integration_config, request_headers=headers)
285+
assert span.get_tag("http.referrer_host") is None
286+
255287

256288
@pytest.mark.parametrize(
257289
"pin,config_val,default,global_service,expected",

0 commit comments

Comments
 (0)