Search in sources :

Example 11 with ResourceRegion

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 + "--");
}
Also used : HttpHeaders(org.springframework.http.HttpHeaders) ResourceRegion(org.springframework.core.io.support.ResourceRegion) InputStream(java.io.InputStream) OutputStream(java.io.OutputStream) MediaType(org.springframework.http.MediaType)

Example 12 with ResourceRegion

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();
}
Also used : ResourceRegion(org.springframework.core.io.support.ResourceRegion) Test(org.junit.Test)

Example 13 with ResourceRegion

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();
}
Also used : ResourceRegion(org.springframework.core.io.support.ResourceRegion) DataBuffer(org.springframework.core.io.buffer.DataBuffer)

Example 14 with ResourceRegion

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);
        }
    }
}
Also used : ServletServerHttpRequest(org.springframework.http.server.ServletServerHttpRequest) ResourceRegion(org.springframework.core.io.support.ResourceRegion) Resource(org.springframework.core.io.Resource) MediaType(org.springframework.http.MediaType) ServletServerHttpResponse(org.springframework.http.server.ServletServerHttpResponse) ServletWebRequest(org.springframework.web.context.request.ServletWebRequest) HttpRange(org.springframework.http.HttpRange)

Example 15 with ResourceRegion

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();
}
Also used : ResourceRegion(org.springframework.core.io.support.ResourceRegion) ClassPathResource(org.springframework.core.io.ClassPathResource) Resource(org.springframework.core.io.Resource) ClassPathResource(org.springframework.core.io.ClassPathResource) DataBuffer(org.springframework.core.io.buffer.DataBuffer) Test(org.junit.jupiter.api.Test)

Aggregations

ResourceRegion (org.springframework.core.io.support.ResourceRegion)20 Test (org.junit.jupiter.api.Test)12 ClassPathResource (org.springframework.core.io.ClassPathResource)10 Resource (org.springframework.core.io.Resource)10 DataBuffer (org.springframework.core.io.buffer.DataBuffer)8 HttpHeaders (org.springframework.http.HttpHeaders)7 HttpRange (org.springframework.http.HttpRange)5 MockHttpOutputMessage (org.springframework.http.MockHttpOutputMessage)5 MediaType (org.springframework.http.MediaType)3 ArrayList (java.util.ArrayList)2 Test (org.junit.Test)2 ByteArrayResource (org.springframework.core.io.ByteArrayResource)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 OutputStream (java.io.OutputStream)1 StandardCharsets (java.nio.charset.StandardCharsets)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 OptionalLong (java.util.OptionalLong)1