From efd1acab724eb723a79e6af4c0d7c6e419f70e86 Mon Sep 17 00:00:00 2001 From: Randomnicode Date: Sat, 14 Dec 2019 10:45:33 -0800 Subject: [PATCH] Reuse InputStream for ResourceRegionHttpMessageConverter Dynamically generated input streams cannot be closed and reopened multiple times. This fix reuses the same InputStream across multiple ResourceRegion writes. This is a proposal for and closes #24210 --- .../ResourceRegionHttpMessageConverter.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java index be98db9122a1..626dc8ccd8b5 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java @@ -35,6 +35,8 @@ import org.springframework.util.Assert; import org.springframework.util.MimeTypeUtils; import org.springframework.util.StreamUtils; +import java.util.HashSet; +import java.util.Set; /** * Implementation of {@link HttpMessageConverter} that can write a single {@link ResourceRegion}, @@ -178,12 +180,28 @@ private void writeResourceRegionCollection(Collection resourceRe String boundaryString = MimeTypeUtils.generateMultipartBoundaryString(); responseHeaders.set(HttpHeaders.CONTENT_TYPE, "multipart/byteranges; boundary=" + boundaryString); OutputStream out = outputMessage.getBody(); + // Allows reuse of streams + Map cleanup = new HashMap<>(); + List exs = new ArrayList<>(); + + try { + for (ResourceRegion region : resourceRegions) { + long start = region.getPosition(); + long end = start + region.getCount() - 1; + + InputStream in = cleanup.computeIfAbsent(region.getResource(), r -> { + try { + return r.getInputStream(); + } catch (IOException e) { + exs.add(e); + return null; + } + }); + + if (!exs.isEmpty()) { + throw exs.get(0); + } - for (ResourceRegion region : resourceRegions) { - long start = region.getPosition(); - long end = start + region.getCount() - 1; - InputStream in = region.getResource().getInputStream(); - try { // Writing MIME header. println(out); print(out, "--" + boundaryString); @@ -200,11 +218,11 @@ private void writeResourceRegionCollection(Collection resourceRe // Printing content StreamUtils.copyRange(in, out, start, end); } - finally { + } finally { + for (InputStream in : cleanup) { try { in.close(); - } - catch (IOException ex) { + } catch (IOException ex) { // ignore } }