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

Reply via email to