@@ -11,7 +11,6 @@ import com.datadog.appsec.report.AppSecEvent
1111import com.datadog.appsec.report.AppSecEventWrapper
1212import datadog.trace.api.ProductTraceSource
1313import datadog.trace.api.config.GeneralConfig
14- import static datadog.trace.api.config.IastConfig.IAST_DEDUPLICATION_ENABLED
1514import datadog.trace.api.function.TriConsumer
1615import datadog.trace.api.function.TriFunction
1716import datadog.trace.api.gateway.BlockResponseFunction
@@ -114,6 +113,8 @@ class GatewayBridgeSpecification extends DDSpecification {
114113 BiFunction<RequestContext , String , Flow<Void > > shellCmdCB
115114 BiFunction<RequestContext , String , Flow<Void > > userCB
116115 TriFunction<RequestContext , LoginEvent , String , Flow<Void > > loginEventCB
116+ BiFunction<RequestContext , StoredBodySupplier , Void > responseBodyStartCB
117+ BiFunction<RequestContext , StoredBodySupplier , Flow<Void > > responseBodyDoneCB
117118
118119 WafMetricCollector wafMetricCollector = Mock (WafMetricCollector )
119120
@@ -452,6 +453,8 @@ class GatewayBridgeSpecification extends DDSpecification {
452453 1 * ig. registerCallback(EVENTS . responseStarted(), _) >> { responseStartedCB = it[1 ]; null }
453454 1 * ig. registerCallback(EVENTS . responseHeader(), _) >> { respHeaderCB = it[1 ]; null }
454455 1 * ig. registerCallback(EVENTS . responseHeaderDone(), _) >> { respHeadersDoneCB = it[1 ]; null }
456+ 1 * ig. registerCallback(EVENTS . responseBodyStart(), _) >> { responseBodyStartCB = it[1 ]; null }
457+ 1 * ig. registerCallback(EVENTS . responseBodyDone(), _) >> { responseBodyDoneCB = it[1 ]; null }
455458 1 * ig. registerCallback(EVENTS . grpcServerMethod(), _) >> { grpcServerMethodCB = it[1 ]; null }
456459 1 * ig. registerCallback(EVENTS . grpcServerRequestMessage(), _) >> { grpcServerRequestMessageCB = it[1 ]; null }
457460 1 * ig. registerCallback(EVENTS . graphqlServerRequestMessage(), _) >> { graphqlServerRequestMessageCB = it[1 ]; null }
@@ -933,7 +936,7 @@ class GatewayBridgeSpecification extends DDSpecification {
933936 }
934937
935938 @Override
936- def <T> T getOrCreateMetaStructTop (String key , Function<String , T> defaultValue ) {
939+ < T> T getOrCreateMetaStructTop(String key, Function<String , T> defaultValue) {
937940 return null
938941 }
939942
@@ -991,7 +994,7 @@ class GatewayBridgeSpecification extends DDSpecification {
991994 getTraceSegment() >> traceSegment
992995 }
993996 final spanInfo = Mock (AgentSpan ) {
994- getTags() >> [' http.route' :' /' ]
997+ getTags() >> [' http.route' : ' /' ]
995998 }
996999
9971000 when :
@@ -1127,7 +1130,7 @@ class GatewayBridgeSpecification extends DDSpecification {
11271130 }
11281131 }
11291132
1130- void "test onLoginFailure (# mode ) " () {
1133+ void " test onLoginFailure" () {
11311134 setup :
11321135 eventDispatcher. getDataSubscribers(_) >> nonEmptyDsInfo
11331136
@@ -1222,4 +1225,95 @@ class GatewayBridgeSpecification extends DDSpecification {
12221225 1 * traceSegment. setTagTop(Tags . PROPAGATED_TRACE_SOURCE , ProductTraceSource . ASM )
12231226 }
12241227
1228+ void ' forwards response body start events and stores the supplier' () {
1229+ StoredBodySupplier supplier = Stub ()
1230+
1231+ setup :
1232+ supplier. get() >> ' response content'
1233+
1234+ expect :
1235+ ctx. data. storedResponseBody == null
1236+
1237+ when :
1238+ responseBodyStartCB. apply(ctx, supplier)
1239+
1240+ then :
1241+ ctx. data. storedResponseBody == ' response content'
1242+ }
1243+
1244+ void ' forwards response body done events and distributes the body contents' () {
1245+ DataBundle bundle
1246+ GatewayContext gatewayContext
1247+ StoredBodySupplier supplier = Stub ()
1248+
1249+ setup :
1250+ supplier. get() >> ' response body content'
1251+ eventDispatcher. getDataSubscribers({ KnownAddresses . RESPONSE_BODY_RAW in it }) >> nonEmptyDsInfo
1252+ eventDispatcher. publishDataEvent(nonEmptyDsInfo, ctx. data, _ as DataBundle , _ as GatewayContext ) >>
1253+ { bundle = it[2 ]; gatewayContext = it[3 ]; NoopFlow . INSTANCE }
1254+
1255+ when :
1256+ responseBodyDoneCB. apply(ctx, supplier)
1257+
1258+ then :
1259+ bundle. get(KnownAddresses . RESPONSE_BODY_OBJECT ) == ' response body content'
1260+ gatewayContext. isTransient == false
1261+ gatewayContext. isRasp == false
1262+ }
1263+
1264+ void ' response body does not get published twice' () {
1265+ StoredBodySupplier supplier = Stub ()
1266+ Flow flow
1267+
1268+ given :
1269+ supplier. get() >> ' response body content'
1270+
1271+ when :
1272+ ctx. data. setRawResBodyPublished(true )
1273+ flow = responseBodyDoneCB. apply(ctx, supplier)
1274+
1275+ then :
1276+ flow == NoopFlow . INSTANCE
1277+ 0 * eventDispatcher. getDataSubscribers(KnownAddresses . RESPONSE_BODY_RAW )
1278+ }
1279+
1280+ void ' response body with empty content is not published' () {
1281+ StoredBodySupplier supplier = Stub ()
1282+ Flow flow
1283+
1284+ given :
1285+ supplier. get() >> ' '
1286+
1287+ when :
1288+ flow = responseBodyDoneCB. apply(ctx, supplier)
1289+
1290+ then :
1291+ flow == NoopFlow . INSTANCE
1292+ 1 * eventDispatcher. getDataSubscribers({ KnownAddresses . RESPONSE_BODY_RAW in it }) >> nonEmptyDsInfo
1293+ 0 * eventDispatcher. publishDataEvent(_, _, _, _)
1294+ }
1295+
1296+ void ' response data includes response body when available' () {
1297+ setup :
1298+ eventDispatcher. getDataSubscribers({ KnownAddresses . RESPONSE_STATUS in it }) >> nonEmptyDsInfo
1299+ ctx. data. responseStatus = 200
1300+ ctx. data. addResponseHeader(' Content-Type' , ' application/json' )
1301+
1302+ StoredBodySupplier supplier = Stub ()
1303+ supplier. get() >> ' {"status":"success"}'
1304+ ctx. data. storedResponseBodySupplier = supplier
1305+
1306+ DataBundle bundle
1307+
1308+ when :
1309+ respHeadersDoneCB. apply(ctx)
1310+
1311+ then :
1312+ 1 * eventDispatcher. publishDataEvent(nonEmptyDsInfo, ctx. data, _ as DataBundle , _ as GatewayContext ) >>
1313+ { dsInfo , appSecCtx , db , gwCtx -> bundle = db; NoopFlow . INSTANCE }
1314+ bundle. get(KnownAddresses . RESPONSE_STATUS ) == ' 200'
1315+ bundle. get(KnownAddresses . RESPONSE_HEADERS_NO_COOKIES ) == [' content-type' : [' application/json' ]]
1316+ bundle. get(KnownAddresses . RESPONSE_BODY_OBJECT ) == ' {"status":"success"}'
1317+ }
1318+
12251319}
0 commit comments