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 efd1aca
Showing 1 changed file with 26 additions and 8 deletions.
Expand Up @@ -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},
Expand Down Expand Up @@ -178,12 +180,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 +218,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 efd1aca

Please sign in to comment.