Skip to content

Commit 37bd51c

Browse files
committed
Handle Resources beyond int length through Servlet 3.1's setContentLengthLong
Issue: SPR-14135
1 parent 463c8f1 commit 37bd51c

File tree

3 files changed

+65
-64
lines changed

3 files changed

+65
-64
lines changed

build.gradle

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -744,52 +744,6 @@ project("spring-web") {
744744
}
745745
}
746746

747-
project("spring-websocket") {
748-
description = "Spring WebSocket"
749-
750-
dependencies {
751-
compile(project(":spring-core"))
752-
compile(project(":spring-context"))
753-
compile(project(":spring-web"))
754-
optional(project(":spring-messaging"))
755-
optional(project(":spring-webmvc"))
756-
optional("javax.servlet:javax.servlet-api:3.1.0")
757-
optional("javax.websocket:javax.websocket-api:1.0")
758-
optional("org.apache.tomcat:tomcat-websocket:${tomcatVersion}") {
759-
exclude group: "org.apache.tomcat", module: "tomcat-websocket-api"
760-
exclude group: "org.apache.tomcat", module: "tomcat-servlet-api"
761-
}
762-
optional("org.glassfish.tyrus:tyrus-spi:${tyrusVersion}")
763-
optional("org.glassfish.tyrus:tyrus-core:${tyrusVersion}")
764-
optional("org.glassfish.tyrus:tyrus-server:${tyrusVersion}")
765-
optional("org.glassfish.tyrus:tyrus-container-servlet:${tyrusVersion}")
766-
optional("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
767-
exclude group: "javax.servlet", module: "javax.servlet"
768-
}
769-
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
770-
exclude group: "javax.servlet", module: "javax.servlet"
771-
}
772-
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
773-
optional("org.eclipse.jetty:jetty-client:${jettyVersion}")
774-
optional("io.undertow:undertow-core:${undertowVersion}")
775-
optional("io.undertow:undertow-servlet:${undertowVersion}") {
776-
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
777-
exclude group: "org.jboss.spec.javax.annotation", module: "jboss-annotations-api_1.2_spec"
778-
}
779-
optional("io.undertow:undertow-websockets-jsr:${undertowVersion}") {
780-
exclude group: "org.jboss.spec.javax.websocket", module: "jboss-websocket-api_1.1_spec"
781-
}
782-
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
783-
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
784-
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
785-
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
786-
testCompile("io.projectreactor:reactor-net:${reactorVersion}")
787-
testCompile("io.netty:netty-all:${nettyVersion}")
788-
testCompile("log4j:log4j:1.2.17")
789-
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
790-
}
791-
}
792-
793747
project("spring-orm") {
794748
description = "Spring Object/Relational Mapping"
795749

@@ -874,7 +828,7 @@ project("spring-webmvc") {
874828
compile(files(project(":spring-core").objenesisRepackJar))
875829
compile(project(":spring-expression"))
876830
compile(project(":spring-web"))
877-
provided("javax.servlet:javax.servlet-api:3.0.1")
831+
provided("javax.servlet:javax.servlet-api:3.1.0")
878832
optional(project(":spring-context-support")) // for Velocity support
879833
optional(project(":spring-oxm")) // for MarshallingView
880834
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
@@ -993,6 +947,52 @@ project("spring-webmvc-portlet") {
993947
}
994948
}
995949

950+
project("spring-websocket") {
951+
description = "Spring WebSocket"
952+
953+
dependencies {
954+
compile(project(":spring-core"))
955+
compile(project(":spring-context"))
956+
compile(project(":spring-web"))
957+
optional(project(":spring-messaging"))
958+
optional(project(":spring-webmvc"))
959+
optional("javax.servlet:javax.servlet-api:3.1.0")
960+
optional("javax.websocket:javax.websocket-api:1.0")
961+
optional("org.apache.tomcat:tomcat-websocket:${tomcatVersion}") {
962+
exclude group: "org.apache.tomcat", module: "tomcat-websocket-api"
963+
exclude group: "org.apache.tomcat", module: "tomcat-servlet-api"
964+
}
965+
optional("org.glassfish.tyrus:tyrus-spi:${tyrusVersion}")
966+
optional("org.glassfish.tyrus:tyrus-core:${tyrusVersion}")
967+
optional("org.glassfish.tyrus:tyrus-server:${tyrusVersion}")
968+
optional("org.glassfish.tyrus:tyrus-container-servlet:${tyrusVersion}")
969+
optional("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
970+
exclude group: "javax.servlet", module: "javax.servlet"
971+
}
972+
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
973+
exclude group: "javax.servlet", module: "javax.servlet"
974+
}
975+
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
976+
optional("org.eclipse.jetty:jetty-client:${jettyVersion}")
977+
optional("io.undertow:undertow-core:${undertowVersion}")
978+
optional("io.undertow:undertow-servlet:${undertowVersion}") {
979+
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
980+
exclude group: "org.jboss.spec.javax.annotation", module: "jboss-annotations-api_1.2_spec"
981+
}
982+
optional("io.undertow:undertow-websockets-jsr:${undertowVersion}") {
983+
exclude group: "org.jboss.spec.javax.websocket", module: "jboss-websocket-api_1.1_spec"
984+
}
985+
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
986+
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
987+
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
988+
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
989+
testCompile("io.projectreactor:reactor-net:${reactorVersion}")
990+
testCompile("io.netty:netty-all:${nettyVersion}")
991+
testCompile("log4j:log4j:1.2.17")
992+
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
993+
}
994+
}
995+
996996
project("spring-test") {
997997
description = "Spring TestContext Framework"
998998

spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.io.InputStream;
2222
import java.io.OutputStream;
2323
import java.util.List;
24-
2524
import javax.activation.FileTypeMap;
2625
import javax.activation.MimetypesFileTypeMap;
2726

@@ -108,9 +107,6 @@ protected Long getContentLength(Resource resource, MediaType contentType) throws
108107
return null;
109108
}
110109
long contentLength = resource.contentLength();
111-
if (contentLength > Integer.MAX_VALUE) {
112-
throw new IOException("Resource content too long (beyond Integer.MAX_VALUE): " + resource);
113-
}
114110
return (contentLength < 0 ? null : contentLength);
115111
}
116112

@@ -158,24 +154,19 @@ protected void writeContent(Resource resource, HttpOutputMessage outputMessage)
158154
* @throws IOException in case of errors while writing the content
159155
*/
160156
protected void writePartialContent(HttpRangeResource resource, HttpOutputMessage outputMessage) throws IOException {
161-
162157
Assert.notNull(resource, "Resource should not be null");
163-
164158
List<HttpRange> ranges = resource.getHttpRanges();
165159
HttpHeaders responseHeaders = outputMessage.getHeaders();
166160
MediaType contentType = responseHeaders.getContentType();
167161
Long length = getContentLength(resource, contentType);
168162

169163
if (ranges.size() == 1) {
170164
HttpRange range = ranges.get(0);
171-
172165
long start = range.getRangeStart(length);
173166
long end = range.getRangeEnd(length);
174167
long rangeLength = end - start + 1;
175-
176168
responseHeaders.add("Content-Range", "bytes " + start + "-" + end + "/" + length);
177-
responseHeaders.setContentLength((int) rangeLength);
178-
169+
responseHeaders.setContentLength(rangeLength);
179170
InputStream in = resource.getInputStream();
180171
try {
181172
copyRange(in, outputMessage.getBody(), start, end);
@@ -192,15 +183,11 @@ protected void writePartialContent(HttpRangeResource resource, HttpOutputMessage
192183
else {
193184
String boundaryString = MimeTypeUtils.generateMultipartBoundaryString();
194185
responseHeaders.set(HttpHeaders.CONTENT_TYPE, "multipart/byteranges; boundary=" + boundaryString);
195-
196186
OutputStream out = outputMessage.getBody();
197-
198187
for (HttpRange range : ranges) {
199188
long start = range.getRangeStart(length);
200189
long end = range.getRangeEnd(length);
201-
202190
InputStream in = resource.getInputStream();
203-
204191
// Writing MIME header.
205192
println(out);
206193
print(out, "--" + boundaryString);
@@ -212,7 +199,6 @@ protected void writePartialContent(HttpRangeResource resource, HttpOutputMessage
212199
print(out, "Content-Range: bytes " + start + "-" + end + "/" + length);
213200
println(out);
214201
println(out);
215-
216202
// Printing content
217203
copyRange(in, out, start, end);
218204
}

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.ArrayList;
2222
import java.util.List;
2323
import javax.servlet.ServletException;
24+
import javax.servlet.ServletResponse;
2425
import javax.servlet.http.HttpServletRequest;
2526
import javax.servlet.http.HttpServletResponse;
2627

@@ -38,6 +39,7 @@
3839
import org.springframework.http.server.ServletServerHttpRequest;
3940
import org.springframework.http.server.ServletServerHttpResponse;
4041
import org.springframework.util.Assert;
42+
import org.springframework.util.ClassUtils;
4143
import org.springframework.util.CollectionUtils;
4244
import org.springframework.util.ObjectUtils;
4345
import org.springframework.util.ResourceUtils;
@@ -88,8 +90,13 @@
8890
public class ResourceHttpRequestHandler extends WebContentGenerator
8991
implements HttpRequestHandler, InitializingBean, CorsConfigurationSource {
9092

93+
// Servlet 3.1 setContentLengthLong(long) available?
94+
private static final boolean contentLengthLongAvailable =
95+
ClassUtils.hasMethod(ServletResponse.class, "setContentLengthLong", long.class);
96+
9197
private static final Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class);
9298

99+
93100
private final List<Resource> locations = new ArrayList<Resource>(4);
94101

95102
private final List<ResourceResolver> resourceResolvers = new ArrayList<ResourceResolver>(4);
@@ -515,9 +522,17 @@ protected MediaType getMediaType(Resource resource) {
515522
protected void setHeaders(HttpServletResponse response, Resource resource, MediaType mediaType) throws IOException {
516523
long length = resource.contentLength();
517524
if (length > Integer.MAX_VALUE) {
518-
throw new IOException("Resource content too long (beyond Integer.MAX_VALUE): " + resource);
525+
if (contentLengthLongAvailable) {
526+
response.setContentLengthLong(length);
527+
}
528+
else {
529+
response.setHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(length));
530+
}
519531
}
520-
response.setContentLength((int) length);
532+
else {
533+
response.setContentLength((int) length);
534+
}
535+
521536
if (mediaType != null) {
522537
response.setContentType(mediaType.toString());
523538
}

0 commit comments

Comments
 (0)