@@ -339,6 +339,78 @@ def test_api10_res_body(self):
339339 interfaces .library .validate_one_span (self .r , validator = self .validate_absence )
340340
341341
342+ class API10ResponseBodyIgnored (API10 ):
343+ """Base for downstream response body guard tests."""
344+
345+ TAGS_NOT_EXPECTED = ["_dd.appsec.trace.res_body" ]
346+
347+ def validate_ignored (self , span : DataDogLibrarySpan ):
348+ if span .get ("parent_id" ) not in (0 , None ):
349+ return None
350+
351+ if not self .validate_metric (span ):
352+ return None
353+
354+ for tag in self .TAGS_NOT_EXPECTED :
355+ assert tag not in span .get ("meta" , {}), f"Tag { tag } should NOT be present in span's meta"
356+
357+ return True
358+
359+
360+ @rfc ("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx" )
361+ @features .api10
362+ @scenarios .appsec_rasp
363+ class Test_API10_response_body_ignored_content_type (API10ResponseBodyIgnored ):
364+ """Downstream response body ignored when content-type is unsupported."""
365+
366+ TAGS_EXPECTED_METRIC = [
367+ ("_dd.appsec.downstream_request.response_body_ignored.content_type_invalid" , "1" ),
368+ ]
369+
370+ def setup_api10_response_body_ignored_content_type (self ):
371+ self .r = weblog .get ("/external_request/body_limit/invalid_content_type" )
372+
373+ def test_api10_response_body_ignored_content_type (self ):
374+ assert self .r .status_code == 200
375+ interfaces .library .validate_one_span (self .r , validator = self .validate_ignored )
376+
377+
378+ @rfc ("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx" )
379+ @features .api10
380+ @scenarios .appsec_rasp
381+ class Test_API10_response_body_ignored_content_length_missing (API10ResponseBodyIgnored ):
382+ """Downstream response body ignored when content-length is missing."""
383+
384+ TAGS_EXPECTED_METRIC = [
385+ ("_dd.appsec.downstream_request.response_body_ignored.content_length_missing" , "1" ),
386+ ]
387+
388+ def setup_api10_response_body_ignored_content_length_missing (self ):
389+ self .r = weblog .get ("/external_request/body_limit/content_length_missing" )
390+
391+ def test_api10_response_body_ignored_content_length_missing (self ):
392+ assert self .r .status_code == 200
393+ interfaces .library .validate_one_span (self .r , validator = self .validate_ignored )
394+
395+
396+ @rfc ("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx" )
397+ @features .api10
398+ @scenarios .appsec_rasp
399+ class Test_API10_response_body_ignored_content_length_too_big (API10ResponseBodyIgnored ):
400+ """Downstream response body ignored when content-length exceeds maxBytes."""
401+
402+ TAGS_EXPECTED_METRIC = [
403+ ("_dd.appsec.downstream_request.response_body_ignored.content_length_too_big" , "1" ),
404+ ]
405+
406+ def setup_api10_response_body_ignored_content_length_too_big (self ):
407+ self .r = weblog .get ("/external_request/body_limit/content_length_too_big" )
408+
409+ def test_api10_response_body_ignored_content_length_too_big (self ):
410+ assert self .r .status_code == 200
411+ interfaces .library .validate_one_span (self .r , validator = self .validate_ignored )
412+
413+
342414@rfc ("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx" )
343415@features .api10
344416@scenarios .appsec_rasp
0 commit comments