ResourceHttpRequestHandler sets "Accept-Ranges" header only once
Issue: SPR-14221
This commit is contained in:
@@ -20,7 +20,6 @@ import java.io.IOException;
|
|||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@@ -120,7 +119,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a {@code List} of {@code Resource} paths to use as sources
|
* Set the {@code List} of {@code Resource} paths to use as sources
|
||||||
* for serving static resources.
|
* for serving static resources.
|
||||||
*/
|
*/
|
||||||
public void setLocations(List<Resource> locations) {
|
public void setLocations(List<Resource> locations) {
|
||||||
@@ -129,6 +128,10 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
this.locations.addAll(locations);
|
this.locations.addAll(locations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@code List} of {@code Resource} paths to use as sources
|
||||||
|
* for serving static resources.
|
||||||
|
*/
|
||||||
public List<Resource> getLocations() {
|
public List<Resource> getLocations() {
|
||||||
return this.locations;
|
return this.locations;
|
||||||
}
|
}
|
||||||
@@ -173,12 +176,16 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
/**
|
/**
|
||||||
* Configure the {@link ResourceHttpMessageConverter} to use.
|
* Configure the {@link ResourceHttpMessageConverter} to use.
|
||||||
* <p>By default a {@link ResourceHttpMessageConverter} will be configured.
|
* <p>By default a {@link ResourceHttpMessageConverter} will be configured.
|
||||||
* @since 4.3.0
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
public void setResourceHttpMessageConverter(ResourceHttpMessageConverter resourceHttpMessageConverter) {
|
public void setResourceHttpMessageConverter(ResourceHttpMessageConverter resourceHttpMessageConverter) {
|
||||||
this.resourceHttpMessageConverter = resourceHttpMessageConverter;
|
this.resourceHttpMessageConverter = resourceHttpMessageConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of configured resource converters.
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
public ResourceHttpMessageConverter getResourceHttpMessageConverter() {
|
public ResourceHttpMessageConverter getResourceHttpMessageConverter() {
|
||||||
return this.resourceHttpMessageConverter;
|
return this.resourceHttpMessageConverter;
|
||||||
}
|
}
|
||||||
@@ -186,15 +193,18 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
/**
|
/**
|
||||||
* Configure the {@link ResourceRegionHttpMessageConverter} to use.
|
* Configure the {@link ResourceRegionHttpMessageConverter} to use.
|
||||||
* <p>By default a {@link ResourceRegionHttpMessageConverter} will be configured.
|
* <p>By default a {@link ResourceRegionHttpMessageConverter} will be configured.
|
||||||
* @since 4.3.0
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter() {
|
public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter) {
|
||||||
return resourceRegionHttpMessageConverter;
|
this.resourceRegionHttpMessageConverter = resourceRegionHttpMessageConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResourceRegionHttpMessageConverter(
|
/**
|
||||||
ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter) {
|
* Return the list of configured resource region converters.
|
||||||
this.resourceRegionHttpMessageConverter = resourceRegionHttpMessageConverter;
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter() {
|
||||||
|
return this.resourceRegionHttpMessageConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,6 +225,10 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
this.contentNegotiationManager = contentNegotiationManager;
|
this.contentNegotiationManager = contentNegotiationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the specified content negotiation manager.
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
public ContentNegotiationManager getContentNegotiationManager() {
|
public ContentNegotiationManager getContentNegotiationManager() {
|
||||||
return this.contentNegotiationManager;
|
return this.contentNegotiationManager;
|
||||||
}
|
}
|
||||||
@@ -227,6 +241,9 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
this.corsConfiguration = corsConfiguration;
|
this.corsConfiguration = corsConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the specified CORS configuration.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
|
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
|
||||||
return this.corsConfiguration;
|
return this.corsConfiguration;
|
||||||
@@ -348,13 +365,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
|
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
|
||||||
outputMessage.getHeaders().add(HttpHeaders.ACCEPT_RANGES, "bytes");
|
|
||||||
|
|
||||||
if (request.getHeader(HttpHeaders.RANGE) == null) {
|
if (request.getHeader(HttpHeaders.RANGE) == null) {
|
||||||
setHeaders(response, resource, mediaType);
|
setHeaders(response, resource, mediaType);
|
||||||
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
|
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
|
||||||
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
|
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
|
||||||
try {
|
try {
|
||||||
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
|
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
|
||||||
@@ -364,12 +380,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
|||||||
this.resourceRegionHttpMessageConverter.write(resourceRegion, mediaType, outputMessage);
|
this.resourceRegionHttpMessageConverter.write(resourceRegion, mediaType, outputMessage);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.resourceRegionHttpMessageConverter
|
this.resourceRegionHttpMessageConverter.write(
|
||||||
.write(HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
|
HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
response.addHeader("Content-Range", "bytes */" + resource.contentLength());
|
response.setHeader("Content-Range", "bytes */" + resource.contentLength());
|
||||||
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
|
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package org.springframework.web.servlet.resource;
|
package org.springframework.web.servlet.resource;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -26,7 +24,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
@@ -48,6 +45,8 @@ import org.springframework.web.accept.ContentNegotiationManager;
|
|||||||
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
|
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
|
||||||
import org.springframework.web.servlet.HandlerMapping;
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for ResourceHttpRequestHandler.
|
* Unit tests for ResourceHttpRequestHandler.
|
||||||
*
|
*
|
||||||
@@ -97,6 +96,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
||||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||||
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +113,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
||||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||||
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
assertEquals(0, this.response.getContentAsByteArray().length);
|
assertEquals(0, this.response.getContentAsByteArray().length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +137,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals("no-store", this.response.getHeader("Cache-Control"));
|
assertEquals("no-store", this.response.getHeader("Cache-Control"));
|
||||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||||
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -147,6 +152,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
this.handler.handleRequest(this.request, this.response);
|
this.handler.handleRequest(this.request, this.response);
|
||||||
|
|
||||||
assertEquals("\"versionString\"", this.response.getHeader("ETag"));
|
assertEquals("\"versionString\"", this.response.getHeader("ETag"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -163,6 +170,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertTrue(dateHeaderAsLong("Expires") >= System.currentTimeMillis() - 1000 + (3600 * 1000));
|
assertTrue(dateHeaderAsLong("Expires") >= System.currentTimeMillis() - 1000 + (3600 * 1000));
|
||||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||||
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -181,6 +190,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertTrue(dateHeaderAsLong("Expires") <= System.currentTimeMillis());
|
assertTrue(dateHeaderAsLong("Expires") <= System.currentTimeMillis());
|
||||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||||
assertEquals(dateHeaderAsLong("Last-Modified") / 1000, resourceLastModified("test/foo.css") / 1000);
|
assertEquals(dateHeaderAsLong("Last-Modified") / 1000, resourceLastModified("test/foo.css") / 1000);
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -192,6 +203,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
||||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||||
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.html"));
|
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.html"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -204,6 +217,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
|
||||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||||
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("testalternatepath/baz.css"));
|
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("testalternatepath/baz.css"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
assertEquals("h1 { color:red; }", this.response.getContentAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,6 +470,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals(2, this.response.getContentLength());
|
assertEquals(2, this.response.getContentLength());
|
||||||
assertEquals("bytes 0-1/10", this.response.getHeader("Content-Range"));
|
assertEquals("bytes 0-1/10", this.response.getHeader("Content-Range"));
|
||||||
assertEquals("So", this.response.getContentAsString());
|
assertEquals("So", this.response.getContentAsString());
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -468,6 +485,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals(1, this.response.getContentLength());
|
assertEquals(1, this.response.getContentLength());
|
||||||
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
|
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
|
||||||
assertEquals(".", this.response.getContentAsString());
|
assertEquals(".", this.response.getContentAsString());
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -481,6 +500,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals(1, this.response.getContentLength());
|
assertEquals(1, this.response.getContentLength());
|
||||||
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
|
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
|
||||||
assertEquals(".", this.response.getContentAsString());
|
assertEquals(".", this.response.getContentAsString());
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -494,6 +515,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals(1, this.response.getContentLength());
|
assertEquals(1, this.response.getContentLength());
|
||||||
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
|
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
|
||||||
assertEquals(".", this.response.getContentAsString());
|
assertEquals(".", this.response.getContentAsString());
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -507,6 +530,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
assertEquals(10, this.response.getContentLength());
|
assertEquals(10, this.response.getContentLength());
|
||||||
assertEquals("bytes 0-9/10", this.response.getHeader("Content-Range"));
|
assertEquals("bytes 0-9/10", this.response.getHeader("Content-Range"));
|
||||||
assertEquals("Some text.", this.response.getContentAsString());
|
assertEquals("Some text.", this.response.getContentAsString());
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -517,6 +542,8 @@ public class ResourceHttpRequestHandlerTests {
|
|||||||
|
|
||||||
assertEquals(416, this.response.getStatus());
|
assertEquals(416, this.response.getStatus());
|
||||||
assertEquals("bytes */10", this.response.getHeader("Content-Range"));
|
assertEquals("bytes */10", this.response.getHeader("Content-Range"));
|
||||||
|
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
|
||||||
|
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user