Skip to content

Commit

Permalink
Reuse InputStream for ResourceRegionHttpMessageConverter
Browse files Browse the repository at this point in the history
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 spring-projects#24210
  • Loading branch information
randomnicode committed Dec 15, 2019
1 parent 5f91780 commit 5efe7a2
Showing 1 changed file with 28 additions and 8 deletions.
Expand Up @@ -22,7 +22,11 @@
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourceRegion;
Expand Down Expand Up @@ -178,12 +182,28 @@ private void writeResourceRegionCollection(Collection<ResourceRegion> resourceRe
String boundaryString = MimeTypeUtils.generateMultipartBoundaryString();
responseHeaders.set(HttpHeaders.CONTENT_TYPE, "multipart/byteranges; boundary=" + boundaryString);
OutputStream out = outputMessage.getBody();
// Allows reuse of streams
Map<Resource, InputStream> cleanup = new HashMap<>();
List<IOException> 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);
Expand All @@ -200,11 +220,11 @@ private void writeResourceRegionCollection(Collection<ResourceRegion> 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
}
}
Expand Down

0 comments on commit 5efe7a2

Please sign in to comment.