@@ -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