Skip to content

Commit e5dbe12

Browse files
committed
ResourceHttpRequestHandler sets "Accept-Ranges" header only once
Issue: SPR-14221
1 parent 1b1aac9 commit e5dbe12

File tree

2 files changed

+60
-17
lines changed

2 files changed

+60
-17
lines changed

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

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.net.URLDecoder;
2121
import java.util.ArrayList;
2222
import java.util.List;
23-
2423
import javax.servlet.ServletException;
2524
import javax.servlet.ServletResponse;
2625
import javax.servlet.http.HttpServletRequest;
@@ -120,7 +119,7 @@ public ResourceHttpRequestHandler() {
120119

121120

122121
/**
123-
* Set a {@code List} of {@code Resource} paths to use as sources
122+
* Set the {@code List} of {@code Resource} paths to use as sources
124123
* for serving static resources.
125124
*/
126125
public void setLocations(List<Resource> locations) {
@@ -129,6 +128,10 @@ public void setLocations(List<Resource> locations) {
129128
this.locations.addAll(locations);
130129
}
131130

131+
/**
132+
* Return the {@code List} of {@code Resource} paths to use as sources
133+
* for serving static resources.
134+
*/
132135
public List<Resource> getLocations() {
133136
return this.locations;
134137
}
@@ -173,28 +176,35 @@ public List<ResourceTransformer> getResourceTransformers() {
173176
/**
174177
* Configure the {@link ResourceHttpMessageConverter} to use.
175178
* <p>By default a {@link ResourceHttpMessageConverter} will be configured.
176-
* @since 4.3.0
179+
* @since 4.3
177180
*/
178181
public void setResourceHttpMessageConverter(ResourceHttpMessageConverter resourceHttpMessageConverter) {
179182
this.resourceHttpMessageConverter = resourceHttpMessageConverter;
180183
}
181184

185+
/**
186+
* Return the list of configured resource converters.
187+
* @since 4.3
188+
*/
182189
public ResourceHttpMessageConverter getResourceHttpMessageConverter() {
183190
return this.resourceHttpMessageConverter;
184191
}
185192

186193
/**
187194
* Configure the {@link ResourceRegionHttpMessageConverter} to use.
188195
* <p>By default a {@link ResourceRegionHttpMessageConverter} will be configured.
189-
* @since 4.3.0
196+
* @since 4.3
190197
*/
191-
public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter() {
192-
return resourceRegionHttpMessageConverter;
198+
public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter) {
199+
this.resourceRegionHttpMessageConverter = resourceRegionHttpMessageConverter;
193200
}
194201

195-
public void setResourceRegionHttpMessageConverter(
196-
ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter) {
197-
this.resourceRegionHttpMessageConverter = resourceRegionHttpMessageConverter;
202+
/**
203+
* Return the list of configured resource region converters.
204+
* @since 4.3
205+
*/
206+
public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter() {
207+
return this.resourceRegionHttpMessageConverter;
198208
}
199209

200210
/**
@@ -215,6 +225,10 @@ public void setContentNegotiationManager(ContentNegotiationManager contentNegoti
215225
this.contentNegotiationManager = contentNegotiationManager;
216226
}
217227

228+
/**
229+
* Return the specified content negotiation manager.
230+
* @since 4.3
231+
*/
218232
public ContentNegotiationManager getContentNegotiationManager() {
219233
return this.contentNegotiationManager;
220234
}
@@ -227,6 +241,9 @@ public void setCorsConfiguration(CorsConfiguration corsConfiguration) {
227241
this.corsConfiguration = corsConfiguration;
228242
}
229243

244+
/**
245+
* Return the specified CORS configuration.
246+
*/
230247
@Override
231248
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
232249
return this.corsConfiguration;
@@ -348,13 +365,12 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon
348365
}
349366

350367
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
351-
outputMessage.getHeaders().add(HttpHeaders.ACCEPT_RANGES, "bytes");
352-
353368
if (request.getHeader(HttpHeaders.RANGE) == null) {
354369
setHeaders(response, resource, mediaType);
355370
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
356371
}
357372
else {
373+
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
358374
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
359375
try {
360376
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
@@ -364,12 +380,12 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon
364380
this.resourceRegionHttpMessageConverter.write(resourceRegion, mediaType, outputMessage);
365381
}
366382
else {
367-
this.resourceRegionHttpMessageConverter
368-
.write(HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
383+
this.resourceRegionHttpMessageConverter.write(
384+
HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
369385
}
370386
}
371387
catch (IllegalArgumentException ex) {
372-
response.addHeader("Content-Range", "bytes */" + resource.contentLength());
388+
response.setHeader("Content-Range", "bytes */" + resource.contentLength());
373389
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
374390
}
375391
}

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

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.web.servlet.resource;
1818

19-
import static org.junit.Assert.*;
20-
2119
import java.io.IOException;
2220
import java.text.SimpleDateFormat;
2321
import java.util.ArrayList;
@@ -26,7 +24,6 @@
2624
import java.util.List;
2725
import java.util.Locale;
2826
import java.util.TimeZone;
29-
3027
import javax.servlet.http.HttpServletResponse;
3128

3229
import org.hamcrest.Matchers;
@@ -48,6 +45,8 @@
4845
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
4946
import org.springframework.web.servlet.HandlerMapping;
5047

48+
import static org.junit.Assert.*;
49+
5150
/**
5251
* Unit tests for ResourceHttpRequestHandler.
5352
*
@@ -97,6 +96,8 @@ public void getResource() throws Exception {
9796
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
9897
assertTrue(this.response.containsHeader("Last-Modified"));
9998
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
99+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
100+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
100101
assertEquals("h1 { color:red; }", this.response.getContentAsString());
101102
}
102103

@@ -112,6 +113,8 @@ public void getResourceHttpHeader() throws Exception {
112113
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
113114
assertTrue(this.response.containsHeader("Last-Modified"));
114115
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
116+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
117+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
115118
assertEquals(0, this.response.getContentAsByteArray().length);
116119
}
117120

@@ -134,6 +137,8 @@ public void getResourceNoCache() throws Exception {
134137
assertEquals("no-store", this.response.getHeader("Cache-Control"));
135138
assertTrue(this.response.containsHeader("Last-Modified"));
136139
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
140+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
141+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
137142
}
138143

139144
@Test
@@ -147,6 +152,8 @@ public void getVersionedResource() throws Exception {
147152
this.handler.handleRequest(this.request, this.response);
148153

149154
assertEquals("\"versionString\"", this.response.getHeader("ETag"));
155+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
156+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
150157
}
151158

152159
@Test
@@ -163,6 +170,8 @@ public void getResourceHttp10BehaviorCache() throws Exception {
163170
assertTrue(dateHeaderAsLong("Expires") >= System.currentTimeMillis() - 1000 + (3600 * 1000));
164171
assertTrue(this.response.containsHeader("Last-Modified"));
165172
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.css"));
173+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
174+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
166175
}
167176

168177
@Test
@@ -181,6 +190,8 @@ public void getResourceHttp10BehaviorNoCache() throws Exception {
181190
assertTrue(dateHeaderAsLong("Expires") <= System.currentTimeMillis());
182191
assertTrue(this.response.containsHeader("Last-Modified"));
183192
assertEquals(dateHeaderAsLong("Last-Modified") / 1000, resourceLastModified("test/foo.css") / 1000);
193+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
194+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
184195
}
185196

186197
@Test
@@ -192,6 +203,8 @@ public void getResourceWithHtmlMediaType() throws Exception {
192203
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
193204
assertTrue(this.response.containsHeader("Last-Modified"));
194205
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("test/foo.html"));
206+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
207+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
195208
}
196209

197210
@Test
@@ -204,6 +217,8 @@ public void getResourceFromAlternatePath() throws Exception {
204217
assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
205218
assertTrue(this.response.containsHeader("Last-Modified"));
206219
assertEquals(this.response.getHeader("Last-Modified"), resourceLastModifiedDate("testalternatepath/baz.css"));
220+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
221+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
207222
assertEquals("h1 { color:red; }", this.response.getContentAsString());
208223
}
209224

@@ -455,6 +470,8 @@ public void partialContentByteRange() throws Exception {
455470
assertEquals(2, this.response.getContentLength());
456471
assertEquals("bytes 0-1/10", this.response.getHeader("Content-Range"));
457472
assertEquals("So", this.response.getContentAsString());
473+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
474+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
458475
}
459476

460477
@Test
@@ -468,6 +485,8 @@ public void partialContentByteRangeNoEnd() throws Exception {
468485
assertEquals(1, this.response.getContentLength());
469486
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
470487
assertEquals(".", this.response.getContentAsString());
488+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
489+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
471490
}
472491

473492
@Test
@@ -481,6 +500,8 @@ public void partialContentByteRangeLargeEnd() throws Exception {
481500
assertEquals(1, this.response.getContentLength());
482501
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
483502
assertEquals(".", this.response.getContentAsString());
503+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
504+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
484505
}
485506

486507
@Test
@@ -494,6 +515,8 @@ public void partialContentSuffixRange() throws Exception {
494515
assertEquals(1, this.response.getContentLength());
495516
assertEquals("bytes 9-9/10", this.response.getHeader("Content-Range"));
496517
assertEquals(".", this.response.getContentAsString());
518+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
519+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
497520
}
498521

499522
@Test
@@ -507,6 +530,8 @@ public void partialContentSuffixRangeLargeSuffix() throws Exception {
507530
assertEquals(10, this.response.getContentLength());
508531
assertEquals("bytes 0-9/10", this.response.getHeader("Content-Range"));
509532
assertEquals("Some text.", this.response.getContentAsString());
533+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
534+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
510535
}
511536

512537
@Test
@@ -517,6 +542,8 @@ public void partialContentInvalidRangeHeader() throws Exception {
517542

518543
assertEquals(416, this.response.getStatus());
519544
assertEquals("bytes */10", this.response.getHeader("Content-Range"));
545+
assertEquals("bytes", this.response.getHeader("Accept-Ranges"));
546+
assertEquals(1, this.response.getHeaders("Accept-Ranges").size());
520547
}
521548

522549
@Test

0 commit comments

Comments
 (0)