Browse Source

ResourceHttpRequestHandler sets "Accept-Ranges" header only once

Issue: SPR-14221
pull/1052/head
Juergen Hoeller 10 years ago
parent
commit
e5dbe12e85
  1. 44
      spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
  2. 33
      spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java

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

@ -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);
} }
} }

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

@ -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

Loading…
Cancel
Save