Merge remote-tracking branch 'origin/jetty-8'
Conflicts: jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
This commit is contained in:
commit
73d90623c7
|
@ -966,7 +966,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
||||||
// content-length header
|
// content-length header
|
||||||
//
|
//
|
||||||
writeHeaders(response,content,-1);
|
writeHeaders(response,content,-1);
|
||||||
String mimetype=content.getContentType().toString();
|
String mimetype=(content.getContentType()==null?null:content.getContentType().toString());
|
||||||
|
if (mimetype==null)
|
||||||
|
LOG.warn("Unknown mimetype for "+request.getRequestURI());
|
||||||
MultiPartOutputStream multi = new MultiPartOutputStream(out);
|
MultiPartOutputStream multi = new MultiPartOutputStream(out);
|
||||||
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
||||||
|
|
||||||
|
@ -993,7 +995,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
||||||
length+=
|
length+=
|
||||||
((i>0)?2:0)+
|
((i>0)?2:0)+
|
||||||
2+multi.getBoundary().length()+2+
|
2+multi.getBoundary().length()+2+
|
||||||
HttpHeader.CONTENT_TYPE.asString().length()+2+mimetype.length()+2+
|
(mimetype==null?0:HttpHeader.CONTENT_TYPE.asString().length()+2+mimetype.length())+2+
|
||||||
HttpHeader.CONTENT_RANGE.asString().length()+2+header[i].length()+2+
|
HttpHeader.CONTENT_RANGE.asString().length()+2+header[i].length()+2+
|
||||||
2+
|
2+
|
||||||
(ibr.getLast(content_length)-ibr.getFirst(content_length))+1;
|
(ibr.getLast(content_length)-ibr.getFirst(content_length))+1;
|
||||||
|
|
|
@ -23,6 +23,8 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
|
@ -462,6 +464,153 @@ public class DefaultServletTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRangeRequests() throws Exception
|
||||||
|
{
|
||||||
|
testdir.ensureEmpty();
|
||||||
|
File resBase = testdir.getFile("docroot");
|
||||||
|
FS.ensureDirExists(resBase);
|
||||||
|
File data = new File(resBase, "data.txt");
|
||||||
|
createFile(data, "01234567890123456789012345678901234567890123456789012345678901234567890123456789");
|
||||||
|
String resBasePath = resBase.getAbsolutePath();
|
||||||
|
|
||||||
|
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
|
||||||
|
defholder.setInitParameter("dirAllowed", "false");
|
||||||
|
defholder.setInitParameter("redirectWelcome", "false");
|
||||||
|
defholder.setInitParameter("welcomeServlets", "false");
|
||||||
|
defholder.setInitParameter("gzip", "false");
|
||||||
|
defholder.setInitParameter("acceptRanges", "true");
|
||||||
|
defholder.setInitParameter("resourceBase", resBasePath);
|
||||||
|
|
||||||
|
String response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n\r\n");
|
||||||
|
assertResponseContains("200 OK", response);
|
||||||
|
assertResponseContains("Accept-Ranges: bytes", response);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Range: bytes=0-9\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
assertResponseContains("206 Partial", response);
|
||||||
|
assertResponseContains("Content-Type: text/plain", response);
|
||||||
|
assertResponseContains("Content-Length: 10", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
|
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
int start = response.indexOf("--jetty");
|
||||||
|
String body = response.substring(start);
|
||||||
|
String boundary = body.substring(0, body.indexOf("\r\n"));
|
||||||
|
assertResponseContains("206 Partial", response);
|
||||||
|
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||||
|
assertResponseContains("Content-Length: " + body.length(), response);
|
||||||
|
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Range: bytes=0-9,20-29,40-49,70-79\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
start = response.indexOf("--jetty");
|
||||||
|
body = response.substring(start);
|
||||||
|
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||||
|
assertResponseContains("206 Partial", response);
|
||||||
|
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 70-79/80", response);
|
||||||
|
assertResponseContains("Content-Length: " + body.length(), response);
|
||||||
|
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/data.txt HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
start = response.indexOf("--jetty");
|
||||||
|
body = response.substring(start);
|
||||||
|
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||||
|
assertResponseContains("206 Partial", response);
|
||||||
|
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 60-60/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 70-79/80", response);
|
||||||
|
assertResponseContains("Content-Length: " + body.length(), response);
|
||||||
|
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||||
|
|
||||||
|
//test a range request with a file with no suffix, therefore no mimetype
|
||||||
|
|
||||||
|
File nofilesuffix = new File(resBase, "nofilesuffix");
|
||||||
|
createFile(nofilesuffix, "01234567890123456789012345678901234567890123456789012345678901234567890123456789");
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"\r\n");
|
||||||
|
assertResponseContains("200 OK", response);
|
||||||
|
assertResponseContains("Accept-Ranges: bytes", response);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Range: bytes=0-9\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
assertResponseContains("206 Partial", response);
|
||||||
|
assertResponseContains("Content-Length: 10", response);
|
||||||
|
assertTrue(!response.contains("Content-Type:"));
|
||||||
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Range: bytes=0-9,20-29,40-49\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
start = response.indexOf("--jetty");
|
||||||
|
body = response.substring(start);
|
||||||
|
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||||
|
assertResponseContains("206 Partial", response);
|
||||||
|
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||||
|
assertResponseContains("Content-Length: " + body.length(), response);
|
||||||
|
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
|
||||||
|
"\r\n");
|
||||||
|
start = response.indexOf("--jetty");
|
||||||
|
body = response.substring(start);
|
||||||
|
boundary = body.substring(0, body.indexOf("\r\n"));
|
||||||
|
assertResponseContains("206 Partial", response);
|
||||||
|
assertResponseContains("Content-Type: multipart/byteranges; boundary=", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 0-9/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 20-29/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 60-60/80", response);
|
||||||
|
assertResponseContains("Content-Range: bytes 70-79/80", response);
|
||||||
|
assertResponseContains("Content-Length: " + body.length(), response);
|
||||||
|
assertTrue(body.endsWith(boundary + "--\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFiltered() throws Exception
|
public void testFiltered() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,6 +96,7 @@ public class MultiPartOutputStream extends FilterOutputStream
|
||||||
out.write(__DASHDASH);
|
out.write(__DASHDASH);
|
||||||
out.write(boundaryBytes);
|
out.write(boundaryBytes);
|
||||||
out.write(__CRLF);
|
out.write(__CRLF);
|
||||||
|
if (contentType != null)
|
||||||
out.write(("Content-Type: "+contentType).getBytes(StringUtil.__ISO_8859_1));
|
out.write(("Content-Type: "+contentType).getBytes(StringUtil.__ISO_8859_1));
|
||||||
out.write(__CRLF);
|
out.write(__CRLF);
|
||||||
out.write(__CRLF);
|
out.write(__CRLF);
|
||||||
|
@ -113,6 +114,7 @@ public class MultiPartOutputStream extends FilterOutputStream
|
||||||
out.write(__DASHDASH);
|
out.write(__DASHDASH);
|
||||||
out.write(boundaryBytes);
|
out.write(boundaryBytes);
|
||||||
out.write(__CRLF);
|
out.write(__CRLF);
|
||||||
|
if (contentType != null)
|
||||||
out.write(("Content-Type: "+contentType).getBytes(StringUtil.__ISO_8859_1));
|
out.write(("Content-Type: "+contentType).getBytes(StringUtil.__ISO_8859_1));
|
||||||
out.write(__CRLF);
|
out.write(__CRLF);
|
||||||
for (int i=0;headers!=null && i<headers.length;i++)
|
for (int i=0;headers!=null && i<headers.length;i++)
|
||||||
|
|
Loading…
Reference in New Issue