Add HttpRange tests, set Accept-Range header, polish

Issue: SPR-10805
This commit is contained in:
Rossen Stoyanchev
2015-03-20 14:54:22 -04:00
parent da48739628
commit 6a96c26dd4
5 changed files with 196 additions and 135 deletions

View File

@@ -246,7 +246,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
return;
}
if (request.getHeader("Range") == null) {
if (request.getHeader(HttpHeaders.RANGE) == null) {
setHeaders(response, resource, mediaType);
writeContent(response, resource);
}
@@ -408,6 +408,8 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
if (resource instanceof EncodedResource) {
response.setHeader(CONTENT_ENCODING, ((EncodedResource) resource).getContentEncoding());
}
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
}
/**
@@ -433,26 +435,25 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
}
/**
* Write partial content out to the given servlet response,
* streaming parts of the resource's content, as indicated by the request's
* {@code Range} header.
* Write parts of the resource as indicated by the request {@code Range} header.
* @param request current servlet request
* @param response current servlet response
* @param resource the identified resource (never {@code null})
* @param contentType the content type
* @throws IOException in case of errors while writing the content
*/
protected void writePartialContent(HttpServletRequest request,
HttpServletResponse response, Resource resource, MediaType contentType) throws IOException {
long resourceLength = resource.contentLength();
protected void writePartialContent(HttpServletRequest request, HttpServletResponse response,
Resource resource, MediaType contentType) throws IOException {
long length = resource.contentLength();
List<HttpRange> ranges;
try {
HttpHeaders requestHeaders =
new ServletServerHttpRequest(request).getHeaders();
ranges = requestHeaders.getRange();
} catch (IllegalArgumentException ex) {
response.addHeader("Content-Range", "bytes */" + resourceLength);
HttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();
ranges = headers.getRange();
}
catch (IllegalArgumentException ex) {
response.addHeader("Content-Range", "bytes */" + length);
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return;
}
@@ -462,20 +463,17 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
if (ranges.size() == 1) {
HttpRange range = ranges.get(0);
long rangeStart = range.getRangeStart(resourceLength);
long rangeEnd = range.getRangeEnd(resourceLength);
long rangeLength = rangeEnd - rangeStart + 1;
long start = range.getRangeStart(length);
long end = range.getRangeEnd(length);
long rangeLength = end - start + 1;
setHeaders(response, resource, contentType);
response.addHeader("Content-Range", "bytes "
+ rangeStart + "-"
+ rangeEnd + "/"
+ resourceLength);
response.addHeader("Content-Range", "bytes " + start + "-" + end + "/" + length);
response.setContentLength((int) rangeLength);
InputStream in = resource.getInputStream();
try {
copyRange(in, response.getOutputStream(), rangeStart, rangeEnd);
copyRange(in, response.getOutputStream(), start, end);
}
finally {
try {
@@ -493,8 +491,8 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
ServletOutputStream out = response.getOutputStream();
for (HttpRange range : ranges) {
long rangeStart = range.getRangeStart(resourceLength);
long rangeEnd = range.getRangeEnd(resourceLength);
long start = range.getRangeStart(length);
long end = range.getRangeEnd(length);
InputStream in = resource.getInputStream();
@@ -504,27 +502,23 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
if (contentType != null) {
out.println("Content-Type: " + contentType);
}
out.println("Content-Range: bytes " + rangeStart + "-" +
rangeEnd + "/" + resourceLength);
out.println("Content-Range: bytes " + start + "-" + end + "/" + length);
out.println();
// Printing content
copyRange(in, out, rangeStart, rangeEnd);
copyRange(in, out, start, end);
}
out.println();
out.print("--" + boundaryString + "--");
}
}
private void copyRange(InputStream in, OutputStream out, long start, long end)
throws IOException {
private void copyRange(InputStream in, OutputStream out, long start, long end) throws IOException {
long skipped = in.skip(start);
if (skipped < start) {
throw new IOException("Could only skip " + skipped + " bytes out of " +
start + " required");
throw new IOException("Skipped only " + skipped + " bytes out of " + start + " required.");
}
long bytesToCopy = end - start + 1;
@@ -546,6 +540,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
}
}
@Override
public String toString() {
return "ResourceHttpRequestHandler [locations=" +

View File

@@ -286,8 +286,7 @@ public class ResourceHttpRequestHandlerTests {
assertEquals(206, this.response.getStatus());
assertEquals("text/plain", this.response.getContentType());
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());
}
@@ -300,8 +299,7 @@ public class ResourceHttpRequestHandlerTests {
assertEquals(206, this.response.getStatus());
assertEquals("text/plain", this.response.getContentType());
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());
}
@@ -314,8 +312,7 @@ public class ResourceHttpRequestHandlerTests {
assertEquals(206, this.response.getStatus());
assertEquals("text/plain", this.response.getContentType());
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());
}
@@ -328,8 +325,7 @@ public class ResourceHttpRequestHandlerTests {
assertEquals(206, this.response.getStatus());
assertEquals("text/plain", this.response.getContentType());
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());
}
@@ -342,21 +338,18 @@ public class ResourceHttpRequestHandlerTests {
assertEquals(206, this.response.getStatus());
assertEquals("text/plain", this.response.getContentType());
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());
}
@Test
public void partialContentInvalidRangeHeader() throws Exception {
this.request.addHeader("Range", "bytes= foo bar");
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,
"foo.txt");
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.txt");
this.handler.handleRequest(this.request, this.response);
assertEquals(416, this.response.getStatus());
assertEquals("bytes */10",
this.response.getHeader("Content-Range"));
assertEquals("bytes */10", this.response.getHeader("Content-Range"));
}
@Test
@@ -366,13 +359,12 @@ public class ResourceHttpRequestHandlerTests {
this.handler.handleRequest(this.request, this.response);
assertEquals(206, this.response.getStatus());
assertTrue(this.response.getContentType()
.startsWith("multipart/byteranges; boundary="));
assertTrue(this.response.getContentType().startsWith("multipart/byteranges; boundary="));
String boundary = "--" + this.response.getContentType().substring(31);
String[] ranges = StringUtils.tokenizeToStringArray(this.response.getContentAsString(),
"\r\n", false, true);
String content = this.response.getContentAsString();
String[] ranges = StringUtils.tokenizeToStringArray(content, "\r\n", false, true);
assertEquals(boundary, ranges[0]);
assertEquals("Content-Type: text/plain", ranges[1]);
@@ -391,8 +383,6 @@ public class ResourceHttpRequestHandlerTests {
}
private long headerAsLong(String responseHeaderName) {
return Long.valueOf(this.response.getHeader(responseHeaderName));
}