Author: saces Date: 2009-03-06 09:18:23 +0000 (Fri, 06 Mar 2009) New Revision: 25900
Added: trunk/freenet/src/freenet/clients/http/HTTPRangeException.java Modified: trunk/freenet/src/freenet/clients/http/FProxyToadlet.java Log: partial HTTP Range support for "hg clone static-http://127.0.0.1:8888/uri", required for big repositories (conditionals are silently ignored) Modified: trunk/freenet/src/freenet/clients/http/FProxyToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/FProxyToadlet.java 2009-03-05 23:01:33 UTC (rev 25899) +++ trunk/freenet/src/freenet/clients/http/FProxyToadlet.java 2009-03-06 09:18:23 UTC (rev 25900) @@ -3,6 +3,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.MalformedURLException; import java.net.SocketException; import java.net.URI; @@ -37,6 +38,7 @@ import freenet.support.api.BucketFactory; import freenet.support.api.HTTPRequest; import freenet.support.io.Closer; +import freenet.support.io.FileUtil; public final class FProxyToadlet extends Toadlet { @@ -131,6 +133,7 @@ } Bucket toFree = null; + Bucket tmpRange = null; try { if((!force) && (!forceDownload)) { FilterOutput fo = ContentFilter.filter(data, bucketFactory, mimeType, key.toURI(basePath), container.enableInlinePrefetch() ? prefetchHook : null); @@ -205,8 +208,31 @@ context.writeData(data); } else { // Send the data, intact - context.sendReplyHeaders(200, "OK", new MultiValueTable<String, String>(), mimeType, data.size()); - context.writeData(data); + MultiValueTable<String, String> hdr = context.getHeaders(); + String rangeStr = hdr.get("range"); + // was a range request + if (rangeStr != null) { + + long range[] = parseRange(rangeStr); + if (range[1] == -1 || range[1] >= data.size()) { + range[1] = data.size() - 1; + } + tmpRange = bucketFactory.makeBucket(range[1] - range[0]); + InputStream is = data.getInputStream(); + OutputStream os = tmpRange.getOutputStream(); + if (range[0] > 0) + is.skip(range[0]); + FileUtil.copy(is, os, range[1] - range[0] + 1); + os.close(); + is.close(); + MultiValueTable<String, String> retHdr = new MultiValueTable<String, String>(); + retHdr.put("Content-Range", "bytes " + range[0] + "-" + range[1] + "/" + data.size()); + context.sendReplyHeaders(206, "Partial content", retHdr, mimeType, tmpRange.size()); + context.writeData(tmpRange); + } else { + context.sendReplyHeaders(200, "OK", new MultiValueTable<String, String>(), mimeType, data.size()); + context.writeData(data); + } } } catch (URISyntaxException use1) { /* shouldn't happen */ @@ -261,8 +287,11 @@ byte[] pageBytes = pageNode.generate().getBytes("UTF-8"); context.sendReplyHeaders(200, "OK", new MultiValueTable<String, String>(), "text/html; charset=utf-8", pageBytes.length); context.writeData(pageBytes); + } catch (HTTPRangeException e) { + ctx.sendReplyHeaders(416, "Requested Range Not Satisfiable", null, null, 0); } finally { if(toFree != null) toFree.free(); + if(tmpRange != null) tmpRange.free(); } } @@ -408,6 +437,19 @@ else maxSize = httprequest.getLongParam("max-size", MAX_LENGTH); + //first check of httprange before get + // only valid number format is checked here + String rangeStr = ctx.getHeaders().get("range"); + if (rangeStr != null) { + try { + parseRange(rangeStr); + } catch (HTTPRangeException e) { + Logger.normal(this, "Invalid Range Header: "+rangeStr, e); + ctx.sendReplyHeaders(416, "Requested Range Not Satisfiable", null, null, 0); + return; + } + } + FreenetURI key; try { key = new FreenetURI(ks); @@ -751,4 +793,33 @@ return s + '.' + ext; } + private static long[] parseRange(String hdrrange) throws HTTPRangeException { + + long result[] = new long[2]; + try { + String[] units = hdrrange.split("=", 2); + // FIXME are MBytes and co valid? if so, we need to adjust the values and + // return always bytes + if (!"bytes".equals(units[0])) { + throw new HTTPRangeException("Unknown unit, only 'bytes' supportet yet"); + } + String[] range = units[1].split("-", 2); + result[0] = Long.parseLong(range[0]); + if (result[0] < 0) + throw new HTTPRangeException("Negative 'from' value"); + if (range[1].trim().length() > 0) { + result[1] = Long.parseLong(range[1]); + if (result[1] <= result[0]) + throw new HTTPRangeException("'from' value must be less then 'to' value"); + } else { + result[1] = -1; + } + } catch (NumberFormatException nfe) { + throw new HTTPRangeException(nfe); + } catch (IndexOutOfBoundsException ioobe) { + throw new HTTPRangeException(ioobe); + } + return result; + } + } Added: trunk/freenet/src/freenet/clients/http/HTTPRangeException.java =================================================================== --- trunk/freenet/src/freenet/clients/http/HTTPRangeException.java (rev 0) +++ trunk/freenet/src/freenet/clients/http/HTTPRangeException.java 2009-03-06 09:18:23 UTC (rev 25900) @@ -0,0 +1,25 @@ +/* This code is part of Freenet. It is distributed under the GNU General + * Public License, version 2 (or at your option any later version). See + * http://www.gnu.org/ for further details of the GPL. */ +package freenet.clients.http; + + +/** + * If thrown, something wrong with http range + */ +public class HTTPRangeException extends Exception { + private static final long serialVersionUID = -1; + + public HTTPRangeException(Throwable cause) { + super(cause); + } + + public HTTPRangeException(String msg) { + super(msg); + } + + @Override + public final synchronized Throwable fillInStackTrace() { + return null; + } +} \ No newline at end of file Property changes on: trunk/freenet/src/freenet/clients/http/HTTPRangeException.java ___________________________________________________________________ Added: svn:mime-type + text/plain _______________________________________________ cvs mailing list [email protected] http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs
