1
1
/*
2
- * Copyright 2002-2016 the original author or authors.
2
+ * Copyright 2002-2018 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
43
43
*/
44
44
public abstract class HttpRange {
45
45
46
+ /** Maximum ranges per request. */
47
+ private static final int MAX_RANGES = 100 ;
48
+
46
49
private static final String BYTE_RANGE_PREFIX = "bytes=" ;
47
50
48
51
@@ -58,16 +61,23 @@ public ResourceRegion toResourceRegion(Resource resource) {
58
61
// Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
59
62
Assert .isTrue (resource .getClass () != InputStreamResource .class ,
60
63
"Cannot convert an InputStreamResource to a ResourceRegion" );
64
+ long contentLength = getLengthFor (resource );
65
+ Assert .isTrue (contentLength > 0 , "Resource content length should be > 0" );
66
+ long start = getRangeStart (contentLength );
67
+ long end = getRangeEnd (contentLength );
68
+ return new ResourceRegion (resource , start , end - start + 1 );
69
+ }
70
+
71
+ private static long getLengthFor (Resource resource ) {
72
+ long contentLength ;
61
73
try {
62
- long contentLength = resource .contentLength ();
74
+ contentLength = resource .contentLength ();
63
75
Assert .isTrue (contentLength > 0 , "Resource content length should be > 0" );
64
- long start = getRangeStart (contentLength );
65
- long end = getRangeEnd (contentLength );
66
- return new ResourceRegion (resource , start , end - start + 1 );
67
76
}
68
77
catch (IOException ex ) {
69
- throw new IllegalArgumentException ("Failed to convert Resource to ResourceRegion " , ex );
78
+ throw new IllegalArgumentException ("Failed to obtain Resource content length " , ex );
70
79
}
80
+ return contentLength ;
71
81
}
72
82
73
83
/**
@@ -121,7 +131,8 @@ public static HttpRange createSuffixRange(long suffixLength) {
121
131
* <p>This method can be used to parse an {@code Range} header.
122
132
* @param ranges the string to parse
123
133
* @return the list of ranges
124
- * @throws IllegalArgumentException if the string cannot be parsed
134
+ * @throws IllegalArgumentException if the string cannot be parsed, or if
135
+ * the number of ranges is greater than 100.
125
136
*/
126
137
public static List <HttpRange > parseRanges (String ranges ) {
127
138
if (!StringUtils .hasLength (ranges )) {
@@ -133,6 +144,7 @@ public static List<HttpRange> parseRanges(String ranges) {
133
144
ranges = ranges .substring (BYTE_RANGE_PREFIX .length ());
134
145
135
146
String [] tokens = StringUtils .tokenizeToStringArray (ranges , "," );
147
+ Assert .isTrue (tokens .length <= MAX_RANGES , "Too many ranges " + tokens .length );
136
148
List <HttpRange > result = new ArrayList <HttpRange >(tokens .length );
137
149
for (String token : tokens ) {
138
150
result .add (parseRange (token ));
@@ -169,6 +181,8 @@ else if (dashIdx == 0) {
169
181
* @param resource the resource to select the regions from
170
182
* @return the list of regions for the given resource
171
183
* @since 4.3
184
+ * @throws IllegalArgumentException if the sum of all ranges exceeds the
185
+ * resource length.
172
186
*/
173
187
public static List <ResourceRegion > toResourceRegions (List <HttpRange > ranges , Resource resource ) {
174
188
if (CollectionUtils .isEmpty (ranges )) {
@@ -178,6 +192,15 @@ public static List<ResourceRegion> toResourceRegions(List<HttpRange> ranges, Res
178
192
for (HttpRange range : ranges ) {
179
193
regions .add (range .toResourceRegion (resource ));
180
194
}
195
+ if (ranges .size () > 1 ) {
196
+ long length = getLengthFor (resource );
197
+ long total = 0 ;
198
+ for (ResourceRegion region : regions ) {
199
+ total += region .getCount ();
200
+ }
201
+ Assert .isTrue (total < length , "The sum of all ranges (" + total + ") " +
202
+ "should be less than the resource length (" + length + ")" );
203
+ }
181
204
return regions ;
182
205
}
183
206
0 commit comments