Skip to content

Commit 9df563e

Browse files
committed
solution2: safely getting all the values
1 parent 1677473 commit 9df563e

File tree

2 files changed

+93
-11
lines changed

2 files changed

+93
-11
lines changed

datadog_lambda/trigger.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,14 @@ def parse_event_source(event: dict) -> _EventSource:
114114

115115
event_source = None
116116

117-
request_context = event.get("requestContext")
117+
# Get requestContext safely and ensure it's a dictionary
118+
request_context = event.get("requestContext", {})
119+
if not isinstance(request_context, dict):
120+
request_context = {}
121+
118122
if request_context and request_context.get("stage"):
119123
if "domainName" in request_context and detect_lambda_function_url_domain(
120-
request_context.get("domainName")
124+
request_context.get("domainName", "")
121125
):
122126
return _EventSource(EventTypes.LAMBDA_FUNCTION_URL)
123127
event_source = _EventSource(EventTypes.API_GATEWAY)
@@ -170,7 +174,8 @@ def parse_event_source(event: dict) -> _EventSource:
170174

171175

172176
def detect_lambda_function_url_domain(domain: str) -> bool:
173-
# e.g. "etsn5fibjr.lambda-url.eu-south-1.amazonaws.com"
177+
if not isinstance(domain, str):
178+
return False
174179
domain_parts = domain.split(".")
175180
if len(domain_parts) < 2:
176181
return False
@@ -283,17 +288,28 @@ def extract_http_tags(event):
283288
Extracts HTTP facet tags from the triggering event
284289
"""
285290
http_tags = {}
286-
request_context = event.get("requestContext")
291+
292+
# Safely get request_context and ensure it's a dictionary
293+
request_context = event.get("requestContext", {})
294+
if not isinstance(request_context, dict):
295+
request_context = {}
296+
287297
path = event.get("path")
288298
method = event.get("httpMethod")
299+
289300
if request_context and request_context.get("stage"):
290-
if request_context.get("domainName"):
291-
http_tags["http.url"] = request_context.get("domainName")
301+
domain_name = request_context.get("domainName")
302+
if domain_name:
303+
http_tags["http.url"] = domain_name
292304

293305
path = request_context.get("path")
294306
method = request_context.get("httpMethod")
307+
295308
# Version 2.0 HTTP API Gateway
296-
apigateway_v2_http = request_context.get("http")
309+
apigateway_v2_http = request_context.get("http", {})
310+
if not isinstance(apigateway_v2_http, dict):
311+
apigateway_v2_http = {}
312+
297313
if event.get("version") == "2.0" and apigateway_v2_http:
298314
path = apigateway_v2_http.get("path")
299315
method = apigateway_v2_http.get("method")
@@ -303,15 +319,23 @@ def extract_http_tags(event):
303319
if method:
304320
http_tags["http.method"] = method
305321

306-
headers = event.get("headers")
322+
# Safely get headers
323+
headers = event.get("headers", {})
324+
if not isinstance(headers, dict):
325+
headers = {}
326+
307327
if headers and headers.get("Referer"):
308328
http_tags["http.referer"] = headers.get("Referer")
309329

310330
# Try to get `routeKey` from API GW v2; otherwise try to get `resource` from API GW v1
311331
route = event.get("routeKey") or event.get("resource")
312-
if route:
313-
# "GET /my/endpoint" = > "/my/endpoint"
314-
http_tags["http.route"] = route.split(" ")[-1]
332+
if route and isinstance(route, str):
333+
try:
334+
# "GET /my/endpoint" = > "/my/endpoint"
335+
http_tags["http.route"] = route.split(" ")[-1]
336+
except Exception:
337+
# If splitting fails, use the route as is
338+
http_tags["http.route"] = route
315339

316340
return http_tags
317341

tests/test_trigger.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,29 @@ def test_event_source_unsupported(self):
256256
self.assertEqual(event_source.to_string(), "unknown")
257257
self.assertEqual(event_source_arn, None)
258258

259+
def test_event_source_with_non_dict_request_context(self):
260+
# Test with requestContext as a string instead of a dict
261+
event = {"requestContext": "not_a_dict"}
262+
event_source = parse_event_source(event)
263+
# Should still return a valid event source (unknown in this case)
264+
self.assertEqual(event_source.to_string(), "unknown")
265+
266+
def test_event_source_with_invalid_domain_name(self):
267+
# Test with domainName that isn't a string
268+
event = {"requestContext": {"stage": "prod", "domainName": 12345}}
269+
event_source = parse_event_source(event)
270+
# Should detect as API Gateway since stage is present
271+
self.assertEqual(event_source.to_string(), "api-gateway")
272+
273+
def test_detect_lambda_function_url_domain_with_invalid_input(self):
274+
from datadog_lambda.trigger import detect_lambda_function_url_domain
275+
# Test with non-string input
276+
self.assertFalse(detect_lambda_function_url_domain(None))
277+
self.assertFalse(detect_lambda_function_url_domain(12345))
278+
self.assertFalse(detect_lambda_function_url_domain({"not": "a-string"}))
279+
# Test with string that would normally cause an exception when split
280+
self.assertFalse(detect_lambda_function_url_domain(""))
281+
259282

260283
class GetTriggerTags(unittest.TestCase):
261284
def test_extract_trigger_tags_api_gateway(self):
@@ -530,6 +553,41 @@ def test_extract_trigger_tags_list_type_event(self):
530553
tags = extract_trigger_tags(event, ctx)
531554
self.assertEqual(tags, {})
532555

556+
def test_extract_http_tags_with_invalid_request_context(self):
557+
from datadog_lambda.trigger import extract_http_tags
558+
# Test with requestContext as a string instead of a dict
559+
event = {"requestContext": "not_a_dict", "path": "/test", "httpMethod": "GET"}
560+
http_tags = extract_http_tags(event)
561+
# Should still extract valid tags from the event
562+
self.assertEqual(http_tags, {"http.url_details.path": "/test", "http.method": "GET"})
563+
564+
def test_extract_http_tags_with_invalid_apigateway_http(self):
565+
from datadog_lambda.trigger import extract_http_tags
566+
# Test with http in requestContext that's not a dict
567+
event = {
568+
"requestContext": {"stage": "prod", "http": "not_a_dict"},
569+
"version": "2.0"
570+
}
571+
http_tags = extract_http_tags(event)
572+
# Should not raise an exception
573+
self.assertEqual(http_tags, {})
574+
575+
def test_extract_http_tags_with_invalid_headers(self):
576+
from datadog_lambda.trigger import extract_http_tags
577+
# Test with headers that's not a dict
578+
event = {"headers": "not_a_dict"}
579+
http_tags = extract_http_tags(event)
580+
# Should not raise an exception
581+
self.assertEqual(http_tags, {})
582+
583+
def test_extract_http_tags_with_invalid_route(self):
584+
from datadog_lambda.trigger import extract_http_tags
585+
# Test with routeKey that would cause a split error
586+
event = {"routeKey": 12345} # Not a string
587+
http_tags = extract_http_tags(event)
588+
# Should not raise an exception
589+
self.assertEqual(http_tags, {})
590+
533591

534592
class ExtractHTTPStatusCodeTag(unittest.TestCase):
535593
def test_extract_http_status_code_tag_from_response_dict(self):

0 commit comments

Comments
 (0)