Skip to content

Commit

Permalink
Allow Resource to add headers for range requests
Browse files Browse the repository at this point in the history
Closes gh-25976
  • Loading branch information
rstoyanchev committed Oct 27, 2020
1 parent b6dae6a commit d91b66a
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -352,15 +352,14 @@ public Mono<Void> handle(ServerWebExchange exchange) {

// Check the media type for the resource
MediaType mediaType = MediaTypeFactory.getMediaType(resource).orElse(null);
setHeaders(exchange, resource, mediaType);

// Content phase
if (HttpMethod.HEAD.matches(exchange.getRequest().getMethodValue())) {
setHeaders(exchange, resource, mediaType);
exchange.getResponse().getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
return Mono.empty();
}

setHeaders(exchange, resource, mediaType);
ResourceHttpMessageWriter writer = getResourceHttpMessageWriter();
Assert.state(writer != null, "No ResourceHttpMessageWriter");
return writer.write(Mono.just(resource),
Expand Down Expand Up @@ -535,6 +534,7 @@ protected void setHeaders(ServerWebExchange exchange, Resource resource, @Nullab
if (mediaType != null) {
headers.setContentType(mediaType);
}

if (resource instanceof HttpResource) {
HttpHeaders resourceHeaders = ((HttpResource) resource).getResponseHeaders();
exchange.getResponse().getHeaders().putAll(resourceHeaders);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,22 +508,20 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon

// Check the media type for the resource
MediaType mediaType = getMediaType(request, resource);
setHeaders(response, resource, mediaType);

// Content phase
if (METHOD_HEAD.equals(request.getMethod())) {
setHeaders(response, resource, mediaType);
return;
}

ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
if (request.getHeader(HttpHeaders.RANGE) == null) {
Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");
setHeaders(response, resource, mediaType);
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
}
else {
Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized");
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
try {
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
Expand All @@ -532,7 +530,7 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon
HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
}
catch (IllegalArgumentException ex) {
response.setHeader("Content-Range", "bytes */" + resource.contentLength());
response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
}
}
Expand Down Expand Up @@ -750,6 +748,7 @@ protected void setHeaders(HttpServletResponse response, Resource resource, @Null
if (mediaType != null) {
response.setContentType(mediaType.toString());
}

if (resource instanceof HttpResource) {
HttpHeaders resourceHeaders = ((HttpResource) resource).getResponseHeaders();
resourceHeaders.forEach((headerName, headerValues) -> {
Expand All @@ -765,6 +764,7 @@ protected void setHeaders(HttpServletResponse response, Resource resource, @Null
}
});
}

response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
Expand Down Expand Up @@ -58,6 +59,7 @@
* @author Rossen Stoyanchev
* @author Brian Clozel
*/
@ExtendWith(GzipSupport.class)
public class ResourceHttpRequestHandlerTests {

private ResourceHttpRequestHandler handler;
Expand Down Expand Up @@ -655,6 +657,35 @@ public void partialContentMultipleByteRanges() throws Exception {
assertThat(ranges[11]).isEqualTo("t.");
}

@Test // gh-25976
public void partialContentByteRangeWithEncodedResource(GzipSupport.GzippedFiles gzippedFiles) throws Exception {
String path = "js/foo.js";
gzippedFiles.create(path);

ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
handler.setResourceResolvers(Arrays.asList(new EncodedResourceResolver(), new PathResourceResolver()));
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
handler.setServletContext(new MockServletContext());
handler.afterPropertiesSet();

this.request.addHeader("Accept-Encoding", "gzip");
this.request.addHeader("Range", "bytes=0-1");
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, path);
handler.handleRequest(this.request, this.response);

assertThat(this.response.getStatus()).isEqualTo(206);
assertThat(this.response.getHeaderNames()).containsExactlyInAnyOrder(
"Content-Type", "Content-Length", "Content-Range", "Accept-Ranges",
"Last-Modified", "Content-Encoding", "Vary");

assertThat(this.response.getContentType()).isEqualTo("text/javascript");
assertThat(this.response.getContentLength()).isEqualTo(2);
assertThat(this.response.getHeader("Content-Range")).isEqualTo("bytes 0-1/66");
assertThat(this.response.getHeaderValues("Accept-Ranges")).containsExactly("bytes");
assertThat(this.response.getHeaderValues("Content-Encoding")).containsExactly("gzip");
assertThat(this.response.getHeaderValues("Vary")).containsExactly("Accept-Encoding");
}

@Test // SPR-14005
public void doOverwriteExistingCacheControlHeaders() throws Exception {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
Expand Down

0 comments on commit d91b66a

Please sign in to comment.