* i2psnark: Support HTTP request ranges so in-browser and other http-aware media players work better.

Single range only; no multipart
This commit is contained in:
zzz
2013-04-28 16:46:52 +00:00
parent 0cf7e91475
commit 188ff3392d
4 changed files with 78 additions and 30 deletions

View File

@ -23,6 +23,8 @@ import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
@ -318,8 +320,14 @@ class BasicServlet extends HttpServlet
out = new WriterOutputStream(response.getWriter());
}
// Write content normally
long content_length = content.getContentLength();
// see if there are any range headers
Enumeration reqRanges = request.getHeaders("Range");
if (reqRanges == null || !reqRanges.hasMoreElements()) {
// if there were no ranges, send entire entity
// Write content normally
writeHeaders(response,content,content_length);
if (content_length >= 0 && request.getMethod().equals("HEAD")) {
// if we know the content length, don't send it to be counted
@ -329,10 +337,32 @@ class BasicServlet extends HttpServlet
// GET or unknown size for HEAD
copy(in, out);
}
return;
}
// Parse the satisfiable ranges
List<InclusiveByteRange> ranges = InclusiveByteRange.satisfiableRanges(reqRanges, content_length);
// if there are no satisfiable ranges, send 416 response
// Completely punt on multiple ranges (unlike Default)
if (ranges == null || ranges.size() != 1) {
writeHeaders(response, content, content_length);
response.setStatus(416);
response.setHeader("Content-Range", InclusiveByteRange.to416HeaderRangeString(content_length));
return;
}
// if there is only a single valid range (must be satisfiable
// since were here now), send that range with a 216 response
InclusiveByteRange singleSatisfiableRange = ranges.get(0);
long singleLength = singleSatisfiableRange.getSize(content_length);
writeHeaders(response, content, singleLength);
response.setStatus(206);
response.setHeader("Content-Range", singleSatisfiableRange.toHeaderRangeString(content_length));
copy(in, singleSatisfiableRange.getFirst(content_length), out, singleLength);
}
/* ------------------------------------------------------------ */
protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
throws IOException
@ -532,11 +562,29 @@ class BasicServlet extends HttpServlet
* Write from in to out
*/
private void copy(InputStream in, OutputStream out) throws IOException {
copy(in, 0, out, -1);
}
/**
* Write from in to out
*/
private void copy(InputStream in, long skip, OutputStream out, final long len) throws IOException {
ByteArray ba = _cache.acquire();
byte[] buf = ba.getData();
try {
if (skip > 0)
in.skip(skip);
int read = 0;
while ( (read = in.read(buf)) != -1) {
long tot = 0;
boolean done = false;
while ( (read = in.read(buf)) != -1 && !done) {
if (len >= 0) {
tot += read;
if (tot >= len) {
read -= (int) (tot - len);
done = true;
}
}
out.write(buf, 0, read);
}
} finally {

View File

@ -16,16 +16,13 @@
// ========================================================================
//
package org.eclipse.jetty.server;
package org.klomp.snark.web;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/** Byte range inclusive of end points.
* <PRE>
@ -49,8 +46,6 @@ import org.eclipse.jetty.util.log.Logger;
*/
public class InclusiveByteRange
{
private static final Logger LOG = Log.getLogger(InclusiveByteRange.class);
long first = 0;
long last = 0;
@ -76,11 +71,11 @@ public class InclusiveByteRange
/**
* @param headers Enumeration of Range header fields.
* @param size Size of the resource.
* @return LazyList of satisfiable ranges
* @return List of satisfiable ranges
*/
public static List satisfiableRanges(Enumeration headers, long size)
public static List<InclusiveByteRange> satisfiableRanges(Enumeration headers, long size)
{
Object satRanges=null;
List<InclusiveByteRange> satRanges = null;
// walk through all Range headers
headers:
@ -105,7 +100,6 @@ public class InclusiveByteRange
{
if ("bytes".equals(t))
continue;
LOG.warn("Bad range format: {}",t);
continue headers;
}
else if (d == 0)
@ -114,7 +108,6 @@ public class InclusiveByteRange
last = Long.parseLong(t.substring(d + 1).trim());
else
{
LOG.warn("Bad range format: {}",t);
continue;
}
}
@ -134,25 +127,23 @@ public class InclusiveByteRange
if (first < size)
{
if (satRanges == null)
satRanges = new ArrayList(4);
InclusiveByteRange range = new InclusiveByteRange(first,last);
satRanges = LazyList.add(satRanges,range);
satRanges.add(range);
}
}
catch (NumberFormatException e)
{
LOG.warn("Bad range format: {}",t);
LOG.ignore(e);
continue;
}
}
}
catch(Exception e)
{
LOG.warn("Bad range format: {}",t);
LOG.ignore(e);
}
}
return LazyList.getList(satRanges,true);
return satRanges;
}
/* ------------------------------------------------------------ */

View File

@ -1,3 +1,12 @@
2013-04-28 zzz
* i2psnark:
- Improve page nav
- Ensure current stats and correct event delivered in announce
- Only show lower section on first page
- Dir page CSS tweaks
- Parameter fixes
- Support HTTP request ranges
2013-04-26 zzz
* Console: Show log location on /logs even if not opened yet (ticket #905)
* HTTP proxy: Verify nonce count in digest auth

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 18;
public final static long BUILD = 19;
/** for example "-test" */
public final static String EXTRA = "";