5
5
import io .roastedroot .proxywasm .StartException ;
6
6
import io .roastedroot .proxywasm .internal .Action ;
7
7
import io .roastedroot .proxywasm .internal .HttpRequestBody ;
8
+ import io .roastedroot .proxywasm .internal .HttpResponseBody ;
8
9
import io .roastedroot .proxywasm .internal .Plugin ;
9
10
import io .roastedroot .proxywasm .internal .PluginHttpContext ;
10
11
import io .roastedroot .proxywasm .internal .Pool ;
@@ -170,32 +171,33 @@ private void filter(ContainerRequestContext requestContext, FilterContext filter
170
171
}
171
172
172
173
// the plugin may not be interested in the request body.
173
- if (httpContext .context ().hasOnRequestBody ()) {
174
+ if (!httpContext .context ().hasOnRequestBody ()) {
175
+ return ;
176
+ }
174
177
175
- HttpRequestBody httpRequestBodyState = httpContext .getHttpRequestBodyState ();
178
+ HttpRequestBody httpRequestBodyState = httpContext .getHttpRequestBodyState ();
176
179
177
- while (true ) {
178
- // if we streamed body updates, then endOfStream would be initially false
179
- var action = httpContext .context ().callOnRequestBody (true );
180
+ while (true ) {
181
+ // if we streamed body updates, then endOfStream would be initially false
182
+ var action = httpContext .context ().callOnRequestBody (true );
180
183
181
- // does the plugin want to respond early?
182
- var sendResponse = httpContext .consumeSentHttpResponse ();
183
- if (sendResponse != null ) {
184
- requestContext .abortWith (toResponse (sendResponse ));
185
- return ;
186
- }
187
-
188
- if (action == Action .CONTINUE ) {
189
- break ;
190
- }
191
- httpContext .maybePause ();
184
+ // does the plugin want to respond early?
185
+ var sendResponse = httpContext .consumeSentHttpResponse ();
186
+ if (sendResponse != null ) {
187
+ requestContext .abortWith (toResponse (sendResponse ));
188
+ return ;
192
189
}
193
190
194
- // Body was accessed and potentially modified, update the request stream
195
- if (httpRequestBodyState .isLoaded ()) {
196
- byte [] bytes = httpRequestBodyState .getBodyIfLoaded ();
197
- requestContext .setEntityStream (new java .io .ByteArrayInputStream (bytes ));
191
+ if (action == Action .CONTINUE ) {
192
+ break ;
198
193
}
194
+ httpContext .maybePause ();
195
+ }
196
+
197
+ // Body was accessed and potentially modified, update the request stream
198
+ if (httpRequestBodyState .isLoaded ()) {
199
+ byte [] bytes = httpRequestBodyState .getBodyIfLoaded ();
200
+ requestContext .setEntityStream (new java .io .ByteArrayInputStream (bytes ));
199
201
}
200
202
201
203
} finally {
@@ -269,19 +271,17 @@ private void filter(
269
271
}
270
272
271
273
// aroundWriteTo won't be called if there is no entity to send.
272
- if (responseContext .getEntity () == null
273
- && httpContext .context ().hasOnResponseBody ()) {
274
+ if (responseContext .getEntity () != null
275
+ || !httpContext .context ().hasOnResponseBody ()) {
276
+ return ;
277
+ }
278
+
279
+ // Set up empty response body for plugins that need it
280
+ HttpResponseBody responseBodyState = new HttpResponseBody (new byte [0 ]);
281
+ httpContext .setHttpResponseBodyState (responseBodyState );
274
282
275
- byte [] bytes = new byte [0 ];
276
- httpContext .setHttpResponseBody (bytes );
283
+ while (true ) {
277
284
action = httpContext .context ().callOnResponseBody (true );
278
- bytes = httpContext .getHttpResponseBody ();
279
- if (action == Action .CONTINUE ) {
280
- // continue means plugin is done reading the body.
281
- httpContext .setHttpResponseBody (null );
282
- } else {
283
- httpContext .maybePause ();
284
- }
285
285
286
286
// does the plugin want to respond early?
287
287
sendResponse = httpContext .consumeSentHttpResponse ();
@@ -292,6 +292,11 @@ private void filter(
292
292
responseContext .setEntity (response .getEntity ());
293
293
return ;
294
294
}
295
+
296
+ if (action == Action .CONTINUE ) {
297
+ break ;
298
+ }
299
+ httpContext .maybePause ();
295
300
}
296
301
297
302
} finally {
@@ -332,41 +337,57 @@ public void aroundWriteTo(WriterInterceptorContext ctx)
332
337
try {
333
338
334
339
var original = ctx .getOutputStream ();
335
- ByteArrayOutputStream baos = new ByteArrayOutputStream ();
336
- ctx .setOutputStream (baos );
337
- ctx .proceed ();
338
340
339
- byte [] bytes = baos .toByteArray ();
341
+ HttpResponseBody sharedResponseBody =
342
+ new HttpResponseBody (
343
+ () -> {
344
+ ByteArrayOutputStream baos = new ByteArrayOutputStream ();
345
+ ctx .setOutputStream (baos );
346
+ try {
347
+ ctx .proceed ();
348
+ } catch (Exception e ) {
349
+ throw new RuntimeException ("Failed to read response body" , e );
350
+ }
351
+ return baos .toByteArray ();
352
+ });
340
353
341
354
for (var filterContext : List .copyOf (filterContexts )) {
342
355
var httpContext = filterContext .httpContext ;
343
356
344
357
httpContext .plugin ().lock ();
345
358
346
- // the plugin may not be interested in the request body.
359
+ // the plugin may not be interested in the response body.
347
360
if (!httpContext .context ().hasOnResponseBody ()) {
348
- ctx . proceed () ;
361
+ continue ;
349
362
}
350
363
351
- httpContext .setHttpResponseBody (bytes );
352
- var action = httpContext .context ().callOnResponseBody (true );
353
- bytes = httpContext .getHttpResponseBody ();
354
- if (action == Action .CONTINUE ) {
355
- // continue means plugin is done reading the body.
356
- httpContext .setHttpResponseBody (null );
357
- } else {
358
- httpContext .maybePause ();
359
- }
364
+ // Set up lazy response body - will only be accessed if plugin needs it
365
+ httpContext .setHttpResponseBodyState (sharedResponseBody );
360
366
361
- // does the plugin want to respond early?
362
- var sendResponse = httpContext .consumeSentHttpResponse ();
363
- if (sendResponse != null ) {
364
- throw new WebApplicationException (toResponse (sendResponse ));
367
+ while (true ) {
368
+ var action = httpContext .context ().callOnResponseBody (true );
369
+
370
+ // does the plugin want to respond early?
371
+ var sendResponse = httpContext .consumeSentHttpResponse ();
372
+ if (sendResponse != null ) {
373
+ throw new WebApplicationException (toResponse (sendResponse ));
374
+ }
375
+
376
+ if (action == Action .CONTINUE ) {
377
+ break ;
378
+ }
379
+ httpContext .maybePause ();
365
380
}
366
381
}
367
382
368
- // plugin may have modified the body
369
- original .write (bytes );
383
+ // Write the response body - if it was accessed and modified, use that,
384
+ // otherwise continue with the original stream.
385
+ if (sharedResponseBody .isLoaded ()) {
386
+ original .write (sharedResponseBody .get ());
387
+ } else {
388
+ // Body was never accessed by any plugin, use original
389
+ ctx .proceed ();
390
+ }
370
391
371
392
} finally {
372
393
for (var filterContext : List .copyOf (filterContexts )) {
0 commit comments