@@ -95,7 +95,9 @@ public class GatewayBridge {
9595  // subscriber cache 
9696  private  volatile  DataSubscriberInfo  initialReqDataSubInfo ;
9797  private  volatile  DataSubscriberInfo  rawRequestBodySubInfo ;
98+   private  volatile  DataSubscriberInfo  rawResponseBodySubInfo ;
9899  private  volatile  DataSubscriberInfo  requestBodySubInfo ;
100+   private  volatile  DataSubscriberInfo  responseBodySubInfo ;
99101  private  volatile  DataSubscriberInfo  pathParamsSubInfo ;
100102  private  volatile  DataSubscriberInfo  respDataSubInfo ;
101103  private  volatile  DataSubscriberInfo  grpcServerMethodSubInfo ;
@@ -142,6 +144,8 @@ public void init() {
142144    subscriptionService .registerCallback (EVENTS .responseStarted (), this ::onResponseStarted );
143145    subscriptionService .registerCallback (EVENTS .responseHeader (), this ::onResponseHeader );
144146    subscriptionService .registerCallback (EVENTS .responseHeaderDone (), this ::onResponseHeaderDone );
147+     subscriptionService .registerCallback (EVENTS .responseBodyStart (), this ::onResponseBodyStart );
148+     subscriptionService .registerCallback (EVENTS .responseBodyDone (), this ::onResponseBodyDone );
145149    subscriptionService .registerCallback (EVENTS .grpcServerMethod (), this ::onGrpcServerMethod );
146150    subscriptionService .registerCallback (
147151        EVENTS .grpcServerRequestMessage (), this ::onGrpcServerRequestMessage );
@@ -164,6 +168,10 @@ public void init() {
164168      subscriptionService .registerCallback (
165169          EVENTS .requestBodyProcessed (), this ::onRequestBodyProcessed );
166170    }
171+     if  (additionalIGEvents .contains (EVENTS .responseBodyProcessed ())) {
172+       subscriptionService .registerCallback (
173+           EVENTS .responseBodyProcessed (), this ::onResponseBodyProcessed );
174+     }
167175  }
168176
169177  /** 
@@ -173,7 +181,9 @@ public void init() {
173181  public  void  reset () {
174182    initialReqDataSubInfo  = null ;
175183    rawRequestBodySubInfo  = null ;
184+     rawResponseBodySubInfo  = null ;
176185    requestBodySubInfo  = null ;
186+     responseBodySubInfo  = null ;
177187    pathParamsSubInfo  = null ;
178188    respDataSubInfo  = null ;
179189    grpcServerMethodSubInfo  = null ;
@@ -596,6 +606,40 @@ private Flow<Void> onRequestBodyProcessed(RequestContext ctx_, Object obj) {
596606    }
597607  }
598608
609+   private  Flow <Void > onResponseBodyProcessed (RequestContext  ctx_ , Object  obj ) {
610+     AppSecRequestContext  ctx  = ctx_ .getData (RequestContextSlot .APPSEC );
611+     if  (ctx  == null ) {
612+       return  NoopFlow .INSTANCE ;
613+     }
614+ 
615+     if  (ctx .isConvertedResBodyPublished ()) {
616+       log .debug (
617+           "Response body already published; will ignore new value of type {}" , obj .getClass ());
618+       return  NoopFlow .INSTANCE ;
619+     }
620+     ctx .setConvertedResBodyPublished (true );
621+ 
622+     while  (true ) {
623+       DataSubscriberInfo  subInfo  = responseBodySubInfo ;
624+       if  (subInfo  == null ) {
625+         subInfo  = producerService .getDataSubscribers (KnownAddresses .RESPONSE_BODY_OBJECT );
626+         responseBodySubInfo  = subInfo ;
627+       }
628+       if  (subInfo  == null  || subInfo .isEmpty ()) {
629+         return  NoopFlow .INSTANCE ;
630+       }
631+       DataBundle  bundle  =
632+           new  SingletonDataBundle <>(
633+               KnownAddresses .RESPONSE_BODY_OBJECT , ObjectIntrospection .convert (obj , ctx ));
634+       try  {
635+         GatewayContext  gwCtx  = new  GatewayContext (false );
636+         return  producerService .publishDataEvent (subInfo , ctx , bundle , gwCtx );
637+       } catch  (ExpiredSubscriberInfoException  e ) {
638+         responseBodySubInfo  = null ;
639+       }
640+     }
641+   }
642+ 
599643  private  Flow <Void > onRequestBodyDone (RequestContext  ctx_ , StoredBodySupplier  supplier ) {
600644    AppSecRequestContext  ctx  = ctx_ .getData (RequestContextSlot .APPSEC );
601645    if  (ctx  == null  || ctx .isRawReqBodyPublished ()) {
@@ -614,7 +658,7 @@ private Flow<Void> onRequestBodyDone(RequestContext ctx_, StoredBodySupplier sup
614658      }
615659
616660      CharSequence  bodyContent  = supplier .get ();
617-       if  (bodyContent  ==  null  ||  bodyContent .length () == 0 ) {
661+       if  (bodyContent .length () == 0 ) {
618662        return  NoopFlow .INSTANCE ;
619663      }
620664      DataBundle  bundle  = new  SingletonDataBundle <>(KnownAddresses .REQUEST_BODY_RAW , bodyContent );
@@ -627,6 +671,38 @@ private Flow<Void> onRequestBodyDone(RequestContext ctx_, StoredBodySupplier sup
627671    }
628672  }
629673
674+   private  Flow <Void > onResponseBodyDone (RequestContext  ctx_ , StoredBodySupplier  supplier ) {
675+     AppSecRequestContext  ctx  = ctx_ .getData (RequestContextSlot .APPSEC );
676+     if  (ctx  == null  || ctx .isRawResBodyPublished ()) {
677+       return  NoopFlow .INSTANCE ;
678+     }
679+     ctx .setRawResBodyPublished (true );
680+ 
681+     while  (true ) {
682+       DataSubscriberInfo  subInfo  = responseBodySubInfo ;
683+       if  (subInfo  == null ) {
684+         subInfo  = producerService .getDataSubscribers (KnownAddresses .RESPONSE_BODY_OBJECT );
685+         responseBodySubInfo  = subInfo ;
686+       }
687+       if  (subInfo  == null  || subInfo .isEmpty ()) {
688+         return  NoopFlow .INSTANCE ;
689+       }
690+ 
691+       CharSequence  bodyContent  = supplier .toString ();
692+       if  (bodyContent .length () == 0 ) {
693+         return  NoopFlow .INSTANCE ;
694+       }
695+       DataBundle  bundle  =
696+           new  SingletonDataBundle <>(KnownAddresses .RESPONSE_BODY_OBJECT , bodyContent );
697+       try  {
698+         GatewayContext  gwCtx  = new  GatewayContext (false );
699+         return  producerService .publishDataEvent (subInfo , ctx , bundle , gwCtx );
700+       } catch  (ExpiredSubscriberInfoException  e ) {
701+         responseBodySubInfo  = null ;
702+       }
703+     }
704+   }
705+ 
630706  private  Flow <Void > onRequestPathParams (RequestContext  ctx_ , Map <String , ?> data ) {
631707    AppSecRequestContext  ctx  = ctx_ .getData (RequestContextSlot .APPSEC );
632708    if  (ctx  == null  || ctx .isPathParamsPublished ()) {
@@ -663,6 +739,16 @@ private Void onRequestBodyStart(RequestContext ctx_, StoredBodySupplier supplier
663739    return  null ;
664740  }
665741
742+   private  Void  onResponseBodyStart (RequestContext  ctx_ , StoredBodySupplier  supplier ) {
743+     AppSecRequestContext  ctx  = ctx_ .getData (RequestContextSlot .APPSEC );
744+     if  (ctx  == null ) {
745+       return  null ;
746+     }
747+ 
748+     ctx .setStoredResponseBodySupplier (supplier );
749+     return  null ;
750+   }
751+ 
666752  private  Flow <AppSecRequestContext > onRequestStarted () {
667753    if  (!AppSecSystem .isActive ()) {
668754      return  RequestContextSupplier .EMPTY ;
@@ -1032,8 +1118,10 @@ private Flow<Void> maybePublishResponseData(AppSecRequestContext ctx) {
10321118
10331119    MapDataBundle  bundle  =
10341120        MapDataBundle .of (
1035-             KnownAddresses .RESPONSE_STATUS , String .valueOf (ctx .getResponseStatus ()),
1036-             KnownAddresses .RESPONSE_HEADERS_NO_COOKIES , ctx .getResponseHeaders ());
1121+             KnownAddresses .RESPONSE_STATUS ,
1122+             String .valueOf (ctx .getResponseStatus ()),
1123+             KnownAddresses .RESPONSE_HEADERS_NO_COOKIES ,
1124+             ctx .getResponseHeaders ());
10371125
10381126    while  (true ) {
10391127      DataSubscriberInfo  subInfo  = respDataSubInfo ;
@@ -1128,6 +1216,10 @@ private static class IGAppSecEventDependencies {
11281216          KnownAddresses .REQUEST_BODY_RAW , l (EVENTS .requestBodyStart (), EVENTS .requestBodyDone ()));
11291217      DATA_DEPENDENCIES .put (KnownAddresses .REQUEST_PATH_PARAMS , l (EVENTS .requestPathParams ()));
11301218      DATA_DEPENDENCIES .put (KnownAddresses .REQUEST_BODY_OBJECT , l (EVENTS .requestBodyProcessed ()));
1219+       DATA_DEPENDENCIES .put (
1220+           KnownAddresses .RESPONSE_BODY_RAW ,
1221+           l (EVENTS .responseBodyStart (), EVENTS .responseBodyDone ()));
1222+       DATA_DEPENDENCIES .put (KnownAddresses .RESPONSE_BODY_OBJECT , l (EVENTS .responseBodyProcessed ()));
11311223    }
11321224
11331225    private  static  Collection <datadog .trace .api .gateway .EventType <?>> l (
0 commit comments