From 577588778657bf163224234f198d7a7a74ee4707 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 15 Feb 2023 23:24:47 +1100 Subject: [PATCH] Issue #9336 - remember ContentSources to fail from ChunksPart Signed-off-by: Lachlan Roberts --- .../org/eclipse/jetty/http/MultiPart.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java index 6ef5b7d9243a..1511f6985a44 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java @@ -24,6 +24,7 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -120,7 +121,7 @@ public static String generateBoundary(String prefix, int randomLength) */ public abstract static class Part implements Closeable { - private static final Throwable CLOSE_EXCEPTION = new StaticException("Closed"); + static final Throwable CLOSE_EXCEPTION = new StaticException("Closed"); private final String name; private final String fileName; @@ -347,6 +348,9 @@ public String toString() public static class ChunksPart extends Part { private final List content; + private final List contentSources = new ArrayList<>(); + private final AutoLock lock = new AutoLock(); + private boolean closed = false; public ChunksPart(String name, String fileName, HttpFields fields, List content) { @@ -358,17 +362,36 @@ public ChunksPart(String name, String fileName, HttpFields fields, List newChunks = content.stream() - .map(chunk -> Content.Chunk.from(chunk.getByteBuffer().slice(), chunk.isLast())) - .toList(); - return new ChunksContentSource(newChunks); + try (AutoLock l = lock.lock()) + { + if (closed) + return null; + ChunksContentSource newContentSource = new ChunksContentSource(content.stream() + .map(chunk -> Content.Chunk.from(chunk.getByteBuffer().slice(), chunk.isLast())) + .toList()); + contentSources.add(newContentSource); + return newContentSource; + } } @Override public void close() { + List contentSourcesToFail = null; + try (AutoLock l = lock.lock()) + { + closed = true; + if (!contentSources.isEmpty()) + { + contentSourcesToFail = new ArrayList<>(contentSources); + contentSources.clear(); + } + } + super.close(); content.forEach(Content.Chunk::release); + if (contentSourcesToFail != null) + contentSourcesToFail.forEach(cs -> cs.fail(CLOSE_EXCEPTION)); } @Override