Skip to content

Commit d91b66a

Browse files
committed
Allow Resource to add headers for range requests
Closes gh-25976
1 parent b6dae6a commit d91b66a

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -352,15 +352,14 @@ public Mono<Void> handle(ServerWebExchange exchange) {
352352

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

356357
// Content phase
357358
if (HttpMethod.HEAD.matches(exchange.getRequest().getMethodValue())) {
358-
setHeaders(exchange, resource, mediaType);
359359
exchange.getResponse().getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
360360
return Mono.empty();
361361
}
362362

363-
setHeaders(exchange, resource, mediaType);
364363
ResourceHttpMessageWriter writer = getResourceHttpMessageWriter();
365364
Assert.state(writer != null, "No ResourceHttpMessageWriter");
366365
return writer.write(Mono.just(resource),
@@ -535,6 +534,7 @@ protected void setHeaders(ServerWebExchange exchange, Resource resource, @Nullab
535534
if (mediaType != null) {
536535
headers.setContentType(mediaType);
537536
}
537+
538538
if (resource instanceof HttpResource) {
539539
HttpHeaders resourceHeaders = ((HttpResource) resource).getResponseHeaders();
540540
exchange.getResponse().getHeaders().putAll(resourceHeaders);

spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -508,22 +508,20 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon
508508

509509
// Check the media type for the resource
510510
MediaType mediaType = getMediaType(request, resource);
511+
setHeaders(response, resource, mediaType);
511512

512513
// Content phase
513514
if (METHOD_HEAD.equals(request.getMethod())) {
514-
setHeaders(response, resource, mediaType);
515515
return;
516516
}
517517

518518
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
519519
if (request.getHeader(HttpHeaders.RANGE) == null) {
520520
Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");
521-
setHeaders(response, resource, mediaType);
522521
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
523522
}
524523
else {
525524
Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized");
526-
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
527525
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
528526
try {
529527
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
@@ -532,7 +530,7 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon
532530
HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
533531
}
534532
catch (IllegalArgumentException ex) {
535-
response.setHeader("Content-Range", "bytes */" + resource.contentLength());
533+
response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
536534
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
537535
}
538536
}
@@ -750,6 +748,7 @@ protected void setHeaders(HttpServletResponse response, Resource resource, @Null
750748
if (mediaType != null) {
751749
response.setContentType(mediaType.toString());
752750
}
751+
753752
if (resource instanceof HttpResource) {
754753
HttpHeaders resourceHeaders = ((HttpResource) resource).getResponseHeaders();
755754
resourceHeaders.forEach((headerName, headerValues) -> {
@@ -765,6 +764,7 @@ protected void setHeaders(HttpServletResponse response, Resource resource, @Null
765764
}
766765
});
767766
}
767+
768768
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
769769
}
770770

spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import org.junit.jupiter.api.BeforeEach;
2828
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.api.extension.ExtendWith;
2930

3031
import org.springframework.core.io.ClassPathResource;
3132
import org.springframework.core.io.Resource;
@@ -58,6 +59,7 @@
5859
* @author Rossen Stoyanchev
5960
* @author Brian Clozel
6061
*/
62+
@ExtendWith(GzipSupport.class)
6163
public class ResourceHttpRequestHandlerTests {
6264

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

660+
@Test // gh-25976
661+
public void partialContentByteRangeWithEncodedResource(GzipSupport.GzippedFiles gzippedFiles) throws Exception {
662+
String path = "js/foo.js";
663+
gzippedFiles.create(path);
664+
665+
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
666+
handler.setResourceResolvers(Arrays.asList(new EncodedResourceResolver(), new PathResourceResolver()));
667+
handler.setLocations(Collections.singletonList(new ClassPathResource("test/", getClass())));
668+
handler.setServletContext(new MockServletContext());
669+
handler.afterPropertiesSet();
670+
671+
this.request.addHeader("Accept-Encoding", "gzip");
672+
this.request.addHeader("Range", "bytes=0-1");
673+
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, path);
674+
handler.handleRequest(this.request, this.response);
675+
676+
assertThat(this.response.getStatus()).isEqualTo(206);
677+
assertThat(this.response.getHeaderNames()).containsExactlyInAnyOrder(
678+
"Content-Type", "Content-Length", "Content-Range", "Accept-Ranges",
679+
"Last-Modified", "Content-Encoding", "Vary");
680+
681+
assertThat(this.response.getContentType()).isEqualTo("text/javascript");
682+
assertThat(this.response.getContentLength()).isEqualTo(2);
683+
assertThat(this.response.getHeader("Content-Range")).isEqualTo("bytes 0-1/66");
684+
assertThat(this.response.getHeaderValues("Accept-Ranges")).containsExactly("bytes");
685+
assertThat(this.response.getHeaderValues("Content-Encoding")).containsExactly("gzip");
686+
assertThat(this.response.getHeaderValues("Vary")).containsExactly("Accept-Encoding");
687+
}
688+
658689
@Test // SPR-14005
659690
public void doOverwriteExistingCacheControlHeaders() throws Exception {
660691
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");

0 commit comments

Comments
 (0)