Right now in Spring MVC and WebFlux we support byte-range requests for Resource response bodies. This is supported by infrastructure like ResourceRegion, HttpRange and ResourceRegionHttpMessageConverter - those are able to convert parts of Resource instances according to the requested ranges.
In Spring MVC, a critical part for that is implemented in AbstractMessageConverterMethodProcessor: detecting whether the request asks for byte ranges, and turning the Resource into a collection of ResourceRegion accordingly, to then let the message converter write those to the response.
In Spring MVC functional endpoints, we're missing that last part currently.
We can achieve that currently with:
Resource resource = ...
List<HttpRange> httpRanges = request.headers().range();
if(!httpRanges.isEmpty()) {
return ServerResponse.status(HttpStatus.PARTIAL_CONTENT)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(HttpRange.toResourceRegions(httpRanges, resource), new ParameterizedTypeReference<List<ResourceRegion>>() {});
}
Now I'm wondering how we could make this easier with functional endpoints. Handling that directly in ServerResponse can be challenging since it might be not expected by developers and we don't have access to the request at that point.
The ResourceHandlerFunction might be a better place for that, but it might lack flexibility since it would only work when mapping a particular handler and not whenever we want to return a Resource as a response body.
Comment From: rstoyanchev
It's another case where access to both request and response is useful for writing to a server response. Perhaps a static, @Nullable method in ResourceRegionHttpMessageConverter that takes the input and output message and returns List<ResourceRegion> could help encapsulate the logic at least?
Update: from a quick experiment, it doesn't seem to help much.
Comment From: poutsma
I decided to put the functionality directly in EntityResponse::writeEntityWithMessageConverters, where we do have access to both request and response. There is some shared functionality with the AbstractMessageConverterMethodProcessor, but nothing terrible, since most of the logic is already in HttpRange.