Range:-Header support

Andreas Kotes <[email protected]> Wed, 12 Jun 2002 16:04:41 +0200
Newsgroups gmane.comp.djb.publicfile
Message-ID <[email protected]>
Hi!

there's no Range:-Header support for publicfile yet, I've hacked
together a rudimentary version which runs with recent wgets.

Please have a look at it and comment .. It may be included under the
same license as publicfile, in case you want to.

Regards

   Count

-- 
Andreas Kotes - ICQ: 3741366 - The views expressed herein are (only) mine.
Look to the future, because that is where you'll spend the rest of your
life.
-- George Burnsh                          -- OpenPGP Key 0x8F94C228
publicfile-0.52-range-support.diff (text/plain, 3.5 KB)
diff -ur publicfile-0.52.orig/httpd.c publicfile-0.52/httpd.c
--- publicfile-0.52.orig/httpd.c	Tue Nov  9 08:23:46 1999
+++ publicfile-0.52/httpd.c	Wed Jun 12 15:59:19 2002
@@ -1,3 +1,4 @@
+#include <unistd.h>
 #include "pathdecode.h"
 #include "file.h"
 #include "filetype.h"
@@ -51,6 +52,8 @@
 stralloc host = {0};
 stralloc path = {0};
 stralloc ims = {0};
+stralloc range = { 0 };
+int rangedelim = 0;
 int flagbody = 1;
 
 char filebuf[1024];
@@ -105,6 +108,9 @@
 
 void get(void)
 {
+  unsigned long firstbyte = 0;
+  unsigned long lastbyte = 0;
+  unsigned long curbyte = 0;
   unsigned long length;
   int fd;
   int r;
@@ -128,13 +134,44 @@
   fd = file_open(fn.s,&mtime,&length,1);
   if (fd == -1)
     barf("404 ",error_str(errno));
+  lastbyte = length;
+
+  if (range.len && (protocolnum != 1))
+     barf ("500 ", "Range:-Header supported with HTTP/1.0 only. Strange, but true.");
+
+  if (byte_chr (range.s, range.len, ",") < range.len)
+    barf ("500 ", "Only single ranges supported.");
+
+  rangedelim = byte_chr (range.s, range.len, "-");
+  if (range.len && (range.s[0] == '-'))
+    barf ("500 ", "Ranges to the end of file not supported.");
+  scan_ulong (range.s, &firstbyte);
+  if (rangedelim+1 < range.len)
+     scan_ulong (range.s+rangedelim+1, &lastbyte);
+  
+  if (lastbyte > length)
+     barf ("500 ", "Range extends beyond file length");
+
+  if (firstbyte > lastbyte)
+     barf ("500 ", "Range starts after its own end");
 
   if (protocolnum > 0) {
     tai_now(&now);
     if (!httpdate(&mtimestr,&mtime)) _exit(21);
-    if ((ims.len < mtimestr.len) || byte_diff(mtimestr.s,mtimestr.len,ims.s))
-      header("200 ","OK");
-    else {
+    if ((ims.len < mtimestr.len) || byte_diff(mtimestr.s,mtimestr.len,ims.s)) {
+      if (!range.len)
+	header("200 ","OK");
+      else {
+	header ("206 ", "Partial content");
+	out_puts ("Content-Range: bytes ");
+	out_put (strnum, fmt_ulong (strnum, firstbyte));
+	out_puts ("-");
+	out_put (strnum, fmt_ulong (strnum, lastbyte));
+	out_puts ("/");
+	out_put (strnum, fmt_ulong (strnum, length));
+	out_puts ("\r\n");
+      }
+    } else {
       header("304 ","OK");
       flagbody = 0;
     }
@@ -152,19 +189,24 @@
       out_puts("Transfer-Encoding: chunked\r\n");
     else {
       out_puts("Content-Length: ");
-      out_put(strnum,fmt_ulong(strnum,length)); /* XXX: could change */
+      out_put (strnum, fmt_ulong (strnum, lastbyte - firstbyte));	/* XXX: could change */
       out_puts("\r\n");
     }
     out_puts("\r\n");
   }
 
   if (protocolnum < 2) {
+    if (firstbyte)
+      curbyte = lseek (fd, firstbyte, SEEK_SET);
     if (flagbody)
       for (;;) {
         r = read(fd,filebuf,sizeof filebuf);
         if (r == -1) _exit(23);
         if (r == 0) break;
+	if (curbyte + r > lastbyte) r = lastbyte-curbyte;
         out_put(filebuf,r);
+	curbyte += r;
+	if (curbyte == lastbyte) break;
       }
     out_flush();
     _exit(0);
@@ -227,6 +269,7 @@
     if (!stralloc_copys(&path,"")) _exit(21);
     if (!stralloc_copys(&protocol,"")) _exit(21);
     if (!stralloc_copys(&ims,"")) _exit(21);
+    if (!stralloc_copys (&range, "")) _exit (21);
     protocolnum = 2;
 
     spaces = 0;
@@ -302,6 +345,8 @@
                     if (!stralloc_append(&host,&field.s[i])) _exit(21);
           if (case_startb(field.s,field.len,"if-modified-since:"))
 	    if (!stralloc_copyb(&ims,field.s + 18,field.len - 18)) _exit(21);
+	  if (case_startb (field.s, field.len, "range: bytes="))
+	    if (!stralloc_copyb (&range, field.s + 13, field.len - 13)) _exit (21);
           field.len = 0;
         }
         if (!line.len) break;