/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sling.launchpad.webapp.integrationtest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.sling.commons.testing.integration.HttpTestBase;
/**
* The <code>RangeStreamingTest</code> tests the Range request header support
* for the StreamRendererServlet introduced with SLING-1814
*/
public class RangeStreamingTest extends HttpTestBase {
private String rootUrl;
@Override
protected void setUp() throws Exception {
super.setUp();
// Create the test nodes under a path that's specific to this class to
// allow collisions
final String path = "/" + getClass().getSimpleName() + "/"
+ System.currentTimeMillis();
testClient.mkdirs(WEBDAV_BASE_URL, path);
rootUrl = uploadTestScript(path, "rangestreaming.txt",
"rangestreaming.txt");
}
@Override
protected void tearDown() throws Exception {
testClient.delete(rootUrl);
super.tearDown();
}
public void test_full_range() throws IOException {
GetMethod get = new GetMethod(rootUrl);
int status = httpClient.executeMethod(get);
assertEquals(200, status);
assertEquals(79, get.getResponseContentLength());
}
public void test_wrong_ranges() throws IOException {
GetMethod get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "unit 1-10"));
int status = httpClient.executeMethod(get);
assertEquals("Expect 416 for unsupported unit", 416, status);
get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes 5"));
status = httpClient.executeMethod(get);
assertEquals("Expect 416 for missing dash", 416, status);
get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes -x"));
status = httpClient.executeMethod(get);
assertEquals("Expect 416 for illegal negative number", 416, status);
get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes -x"));
status = httpClient.executeMethod(get);
assertEquals("Expect 416 for illegal negative number", 416, status);
get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes y-10"));
status = httpClient.executeMethod(get);
assertEquals("Expect 416 for unparseable number", 416, status);
get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes 10-5"));
status = httpClient.executeMethod(get);
assertEquals("Expect 416 for end < start", 416, status);
}
public void test_single_range() throws IOException {
GetMethod get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes 0-9"));
int status = httpClient.executeMethod(get);
assertEquals("Expect 206/PARTIAL CONTENT", 206, status);
assertEquals(10, get.getResponseContentLength());
assertEquals("The quick ", get.getResponseBodyAsString());
get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes -10"));
status = httpClient.executeMethod(get);
assertEquals("Expect 206/PARTIAL CONTENT", 206, status);
assertEquals(10, get.getResponseContentLength());
assertEquals("corpus sic", get.getResponseBodyAsString());
get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes 16-38"));
status = httpClient.executeMethod(get);
assertEquals("Expect 206/PARTIAL CONTENT", 206, status);
assertEquals(23, get.getResponseContentLength());
assertEquals("fox jumps over the lazy", get.getResponseBodyAsString());
}
public void test_multiple_ranges() throws IOException {
GetMethod get = new GetMethod(rootUrl);
get.setRequestHeader(new Header("Range", "bytes 0-9,-10"));
int status = httpClient.executeMethod(get);
assertEquals("Expect 206/PARTIAL CONTENT", 206, status);
String contentType = get.getResponseHeader("Content-Type").getValue();
assertTrue("Content Type must be multipart/byteranges",
contentType.contains("multipart/byteranges"));
String boundary = contentType.substring(contentType.indexOf("boundary=")
+ "boundary=".length());
BufferedReader reader = new BufferedReader(new InputStreamReader(
get.getResponseBodyAsStream()));
String line = reader.readLine();
while (!("--" + boundary).equals(line)) {
line = reader.readLine();
}
assertEquals("Expected content to start with boundary",
"--" + boundary, line);
assertEntityHeaders(reader, "text/plain", "bytes 0-9/79");
assertEquals("The quick ", reader.readLine());
assertEquals("Expected content to start with boundary",
"--" + boundary, reader.readLine());
assertEntityHeaders(reader, "text/plain", "bytes 69-78/79");
assertEquals("corpus sic", reader.readLine());
char[] buf = new char[boundary.length() + 4];
reader.read(buf);
assertEquals("Expected content to start with boundary", "--" + boundary
+ "--", new String(buf));
}
private void assertEntityHeaders(final BufferedReader reader,
final String expectedContentType, final String expectedRange)
throws IOException {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
line = line.toLowerCase();
if (line.startsWith("content-type:")) {
assertTrue("Wrong content type: " + line + "; expected="
+ expectedContentType, line.contains(expectedContentType));
} else if (line.startsWith("content-range:")) {
assertTrue("Wrong content range: " + line + "; expected="
+ expectedRange, line.contains(expectedRange));
} else if (line.length() == 0) {
return;
}
}
// exhausted reader without reaching end of headers
fail("Unexpected end of data");
}
}