use of org.springframework.core.io.support.ResourceRegion in project spring-framework by spring-projects.
the class ResourceRegionHttpMessageConverter method writeResourceRegionCollection.
private void writeResourceRegionCollection(Collection<ResourceRegion> resourceRegions, HttpOutputMessage outputMessage) throws IOException {
Assert.notNull(resourceRegions, "Collection of ResourceRegion should not be null");
HttpHeaders responseHeaders = outputMessage.getHeaders();
MediaType contentType = responseHeaders.getContentType();
String boundaryString = MimeTypeUtils.generateMultipartBoundaryString();
responseHeaders.set(HttpHeaders.CONTENT_TYPE, "multipart/byteranges; boundary=" + boundaryString);
OutputStream out = outputMessage.getBody();
for (ResourceRegion region : resourceRegions) {
long start = region.getPosition();
long end = start + region.getCount() - 1;
InputStream in = region.getResource().getInputStream();
// Writing MIME header.
println(out);
print(out, "--" + boundaryString);
println(out);
if (contentType != null) {
print(out, "Content-Type: " + contentType.toString());
println(out);
}
Long resourceLength = region.getResource().contentLength();
end = Math.min(end, resourceLength - 1);
print(out, "Content-Range: bytes " + start + '-' + end + '/' + resourceLength);
println(out);
println(out);
// Printing content
StreamUtils.copyRange(in, out, start, end);
}
println(out);
print(out, "--" + boundaryString + "--");
}
use of org.springframework.core.io.support.ResourceRegion in project spring-framework by spring-projects.
the class ResourceRegionHttpMessageWriterTests method shouldWriteResourceRegion.
@Test
public void shouldWriteResourceRegion() throws Exception {
ResourceRegion region = new ResourceRegion(this.resource, 0, 6);
Map<String, Object> hints = Collections.emptyMap();
Mono<Void> mono = this.writer.writeRegions(Mono.just(region), MediaType.TEXT_PLAIN, this.response, hints);
StepVerifier.create(mono).expectComplete().verify();
assertThat(this.response.getHeaders().getContentType(), is(MediaType.TEXT_PLAIN));
assertThat(this.response.getHeaders().getFirst(HttpHeaders.CONTENT_RANGE), is("bytes 0-5/39"));
assertThat(this.response.getHeaders().getContentLength(), is(6L));
Mono<String> result = response.getBodyAsString();
StepVerifier.create(result).expectNext("Spring").expectComplete().verify();
}
use of org.springframework.core.io.support.ResourceRegion in project spring-framework by spring-projects.
the class ResourceRegionEncoderTests method shouldEncodeMultipleResourceRegions.
private void shouldEncodeMultipleResourceRegions(Resource resource) {
Flux<ResourceRegion> regions = Flux.just(new ResourceRegion(resource, 0, 6), new ResourceRegion(resource, 7, 9), new ResourceRegion(resource, 17, 4), new ResourceRegion(resource, 22, 17));
String boundary = MimeTypeUtils.generateMultipartBoundaryString();
Flux<DataBuffer> result = this.encoder.encode(regions, this.bufferFactory, ResolvableType.forClass(ResourceRegion.class), MimeType.valueOf("text/plain"), Collections.singletonMap(ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary));
Mono<DataBuffer> reduced = result.reduce(bufferFactory.allocateBuffer(), (previous, current) -> {
previous.write(current);
DataBufferUtils.release(current);
return previous;
});
StepVerifier.create(reduced).consumeNextWith(buf -> {
String content = DataBufferTestUtils.dumpString(buf, StandardCharsets.UTF_8);
String[] ranges = StringUtils.tokenizeToStringArray(content, "\r\n", false, true);
String[] expected = new String[] { "--" + boundary, "Content-Type: text/plain", "Content-Range: bytes 0-5/39", "Spring", "--" + boundary, "Content-Type: text/plain", "Content-Range: bytes 7-15/39", "Framework", "--" + boundary, "Content-Type: text/plain", "Content-Range: bytes 17-20/39", "test", "--" + boundary, "Content-Type: text/plain", "Content-Range: bytes 22-38/39", "resource content.", "--" + boundary + "--" };
assertArrayEquals(expected, ranges);
}).expectComplete().verify();
}
use of org.springframework.core.io.support.ResourceRegion in project spring-framework by spring-projects.
the class ResourceHttpRequestHandler method handleRequest.
/**
* Processes a resource request.
* <p>Checks for the existence of the requested resource in the configured list of locations.
* If the resource does not exist, a {@code 404} response will be returned to the client.
* If the resource exists, the request will be checked for the presence of the
* {@code Last-Modified} header, and its value will be compared against the last-modified
* timestamp of the given resource, returning a {@code 304} status code if the
* {@code Last-Modified} value is greater. If the resource is newer than the
* {@code Last-Modified} value, or the header is not present, the content resource
* of the resource will be written to the response with caching headers
* set to expire one year in the future.
*/
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// For very general mappings (e.g. "/") we need to check 404 first
Resource resource = getResource(request);
if (resource == null) {
logger.trace("No matching resource found - returning 404");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
response.setHeader("Allow", getAllowHeader());
return;
}
// Supported methods and required session
checkRequest(request);
// Header phase
if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
logger.trace("Resource not modified - returning 304");
return;
}
// Apply cache settings, if any
prepareResponse(response);
// Check the media type for the resource
MediaType mediaType = getMediaType(request, resource);
if (mediaType != null) {
if (logger.isTraceEnabled()) {
logger.trace("Determined media type '" + mediaType + "' for " + resource);
}
} else {
if (logger.isTraceEnabled()) {
logger.trace("No media type found for " + resource + " - not sending a content-type header");
}
}
// Content phase
if (METHOD_HEAD.equals(request.getMethod())) {
setHeaders(response, resource, mediaType);
logger.trace("HEAD request - skipping content");
return;
}
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
if (request.getHeader(HttpHeaders.RANGE) == null) {
setHeaders(response, resource, mediaType);
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
} else {
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
try {
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
if (httpRanges.size() == 1) {
ResourceRegion resourceRegion = httpRanges.get(0).toResourceRegion(resource);
this.resourceRegionHttpMessageConverter.write(resourceRegion, mediaType, outputMessage);
} else {
this.resourceRegionHttpMessageConverter.write(HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
}
} catch (IllegalArgumentException ex) {
response.setHeader("Content-Range", "bytes */" + resource.contentLength());
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
}
}
}
use of org.springframework.core.io.support.ResourceRegion in project spring-framework by spring-projects.
the class ResourceRegionEncoderTests method nonExisting.
@Test
void nonExisting() {
Resource resource = new ClassPathResource("ResourceRegionEncoderTests.txt", getClass());
Resource nonExisting = new ClassPathResource("does not exist", getClass());
Flux<ResourceRegion> regions = Flux.just(new ResourceRegion(resource, 0, 6), new ResourceRegion(nonExisting, 0, 6));
String boundary = MimeTypeUtils.generateMultipartBoundaryString();
Flux<DataBuffer> result = this.encoder.encode(regions, this.bufferFactory, ResolvableType.forClass(ResourceRegion.class), MimeType.valueOf("text/plain"), Collections.singletonMap(ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary));
StepVerifier.create(result).consumeNextWith(stringConsumer("\r\n--" + boundary + "\r\n")).consumeNextWith(stringConsumer("Content-Type: text/plain\r\n")).consumeNextWith(stringConsumer("Content-Range: bytes 0-5/39\r\n\r\n")).consumeNextWith(stringConsumer("Spring")).expectError(EncodingException.class).verify();
}
Aggregations