diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContentProducer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContentProducer.java index 8a0e813665e..b18b91c8b73 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContentProducer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContentProducer.java @@ -19,6 +19,7 @@ import java.util.concurrent.locks.Condition; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.thread.AutoLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +66,8 @@ class AsyncContentProducer implements ContentProducer assertLocked(); if (LOG.isDebugEnabled()) LOG.debug("recycling {}", this); + if (_interceptor instanceof Destroyable) + ((Destroyable)_interceptor).destroy(); _interceptor = null; _rawContent = null; _transformedContent = null; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContentProducerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContentProducerTest.java index 047a5382755..ef327fc3194 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContentProducerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncContentProducerTest.java @@ -28,6 +28,7 @@ import java.util.zip.GZIPOutputStream; import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.handler.gzip.GzipHttpInputInterceptor; +import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.compression.InflaterPool; import org.eclipse.jetty.util.thread.AutoLock; import org.hamcrest.core.Is; @@ -58,6 +59,22 @@ public class AsyncContentProducerTest scheduledExecutorService.shutdownNow(); } + @Test + public void testDestroyInterceptorOnRecycle() + { + DestroyableInterceptor interceptor = new DestroyableInterceptor(); + + AsyncContentProducer contentProducer = new AsyncContentProducer(null); + try (AutoLock lock = contentProducer.lock()) + { + contentProducer.setInterceptor(interceptor); + + assertThat(interceptor.destroyed, is(false)); + contentProducer.recycle(); + assertThat(interceptor.destroyed, is(true)); + } + } + @Test public void testAsyncContentProducerNoInterceptor() throws Exception { @@ -347,4 +364,21 @@ public class AsyncContentProducerTest return false; } } + + private static class DestroyableInterceptor implements Destroyable, HttpInput.Interceptor + { + private boolean destroyed = false; + + @Override + public void destroy() + { + destroyed = true; + } + + @Override + public HttpInput.Content readFrom(HttpInput.Content content) + { + return null; + } + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingContentProducerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingContentProducerTest.java index 8cc7ca8b523..5278d59ffe1 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingContentProducerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/BlockingContentProducerTest.java @@ -25,8 +25,10 @@ import java.util.zip.GZIPOutputStream; import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.handler.gzip.GzipHttpInputInterceptor; +import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.compression.InflaterPool; import org.eclipse.jetty.util.thread.AutoLock; +import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,6 +55,22 @@ public class BlockingContentProducerTest scheduledExecutorService.shutdownNow(); } + @Test + public void testDestroyInterceptorOnRecycle() + { + DestroyableInterceptor interceptor = new DestroyableInterceptor(); + + BlockingContentProducer contentProducer = new BlockingContentProducer(new AsyncContentProducer(null)); + try (AutoLock lock = contentProducer.lock()) + { + contentProducer.setInterceptor(interceptor); + + assertThat(interceptor.destroyed, is(false)); + contentProducer.recycle(); + assertThat(interceptor.destroyed, is(true)); + } + } + @Test public void testBlockingContentProducerNoInterceptor() { @@ -347,4 +365,21 @@ public class BlockingContentProducerTest return false; } } + + private static class DestroyableInterceptor implements Destroyable, HttpInput.Interceptor + { + private boolean destroyed = false; + + @Override + public void destroy() + { + destroyed = true; + } + + @Override + public HttpInput.Content readFrom(HttpInput.Content content) + { + return null; + } + } }