This patch adds a new FEATURE_HTTPD_RANGE supporting partial file downloads, 
requested with the HTTP Range header.

I have tested all 4 combinations of FEATURE_HTTPD_RANGE & 
FEATURE_HTTPD_USE_SENDFILE.

Regards,
Chris.

---

--- busybox-1.7.2/networking/Config.in.orig     2007-09-03 12:48:27.000000000 
+0100
+++ busybox-1.7.2/networking/Config.in  2007-10-11 17:54:08.000000000 +0100
@@ -183,6 +183,14 @@
          '/path/e404.html' file instead of the terse '404 NOT FOUND'
          message.
 
+config FEATURE_HTTPD_RANGE
+       bool "Enable support for partial file requests"
+       default n
+       depends on HTTPD
+       help
+         This option adds support for the HTTP Range header. Only
+         a single range per request in byte units is supported.
+
 config IFCONFIG
        bool "ifconfig"
        default n
--- busybox-1.7.2/networking/httpd.c.orig       2007-09-30 00:54:12.000000000 
+0100
+++ busybox-1.7.2/networking/httpd.c    2007-10-11 17:52:02.000000000 +0100
@@ -253,6 +253,10 @@
 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES
        const char *http_error_page[ARRAY_SIZE(http_response_type)];
 #endif
+#if ENABLE_FEATURE_HTTPD_RANGE
+       off_t range_start;      /* -1 - unspecified */
+       off_t range_end;        /* -1 - unspecified */
+#endif
 };
 #define G (*ptr_to_globals)
 #define verbose           (G.verbose          )
@@ -279,11 +283,15 @@
 #define hdr_ptr           (G.hdr_ptr          )
 #define hdr_cnt           (G.hdr_cnt          )
 #define http_error_page   (G.http_error_page  )
+#define range_start       (G.range_start      )
+#define range_end         (G.range_end        )
 #define INIT_G() do { \
        PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
        USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
        bind_addr_or_port = "80"; \
        ContentLength = -1; \
+       USE_FEATURE_HTTPD_RANGE(range_start = -1;) \
+       USE_FEATURE_HTTPD_RANGE(range_end = -1;) \
 } while (0)
 
 
@@ -921,6 +929,30 @@
        }
 #endif
 
+#if ENABLE_FEATURE_HTTPD_RANGE
+       if( ContentLength == -1 ) {
+               range_start = -1;
+               range_end = -1;
+       } else if (range_start == -1 && range_end != -1) {
+               /* range_end is suffix length */
+               range_start = ContentLength - range_end;
+               range_end = ContentLength - 1;
+       } else if (range_start != -1 && range_end == -1) {
+               range_end = ContentLength - 1;
+       }
+
+       if (range_start != -1 && range_end != -1) {
+               if (range_end >= ContentLength || range_end < range_start) {
+                       range_start = -1;
+                       range_end = -1;
+               } else {
+                       len += sprintf(iobuf + len, "Content-Range: bytes 
%"OFF_FMT"d-%"OFF_FMT"d/%"OFF_FMT"d\r\n",
+                               range_start, range_end, ContentLength);
+                       ContentLength = range_end - range_start + 1;
+               }
+       }
+#endif
+
        if (ContentLength != -1) {    /* file */
                strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, 
gmtime(&last_mod));
                len += sprintf(iobuf + len, "Last-Modified: %s\r\n%s 
%"OFF_FMT"d\r\n",
@@ -1372,6 +1404,7 @@
        const char *const *table;
        const char *try_suffix;
        ssize_t count;
+       size_t remaining;
 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
        off_t offset = 0;
 #endif
@@ -1424,24 +1457,45 @@
        signal(SIGPIPE, SIG_IGN);
 
 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+#if ENABLE_FEATURE_HTTPD_RANGE
+       if (range_start != -1) {
+               offset = range_start;
+               remaining = ContentLength;
+       } else
+#endif
+               remaining = MAXINT(ssize_t) - 0xffff;
        do {
                /* byte count (3rd arg) is rounded down to 64k */
-               count = sendfile(1, f, &offset, MAXINT(ssize_t) - 0xffff);
+               count = sendfile(1, f, &offset, remaining);
                if (count < 0) {
                        if (offset == 0)
                                goto fallback;
                        goto fin;
                }
+#if ENABLE_FEATURE_HTTPD_RANGE
+               if (range_start != -1)
+                       remaining -= count;
+#endif
        } while (count > 0);
        log_and_exit();
 
  fallback:
 #endif
-       while ((count = safe_read(f, iobuf, IOBUF_SIZE)) > 0) {
+#if ENABLE_FEATURE_HTTPD_RANGE
+       if (range_start != -1) {
+               remaining = ContentLength;
+       } else
+#endif
+               remaining = IOBUF_SIZE;
+       while ((count = safe_read(f, iobuf, MIN(remaining, IOBUF_SIZE))) > 0) {
                ssize_t n = count;
                count = full_write(1, iobuf, count);
                if (count != n)
                        break;
+#if ENABLE_FEATURE_HTTPD_RANGE
+               if (range_start != -1)
+                       remaining -= count;
+#endif
        }
 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
  fin:
@@ -1585,7 +1639,6 @@
        int ip_allowed;
 #if ENABLE_FEATURE_HTTPD_CGI
        const char *prequest;
-       unsigned long length = 0;
        char *cookie = 0;
        char *content_type = 0;
 #endif
@@ -1593,6 +1646,12 @@
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
        int credentials = -1;  /* if not required this is Ok */
 #endif
+#if ENABLE_FEATURE_HTTPD_CGI || ENABLE_FEATURE_HTTPD_RANGE
+       unsigned long length = 0;
+#endif
+#if ENABLE_FEATURE_HTTPD_RANGE
+       char *eptr;
+#endif
 
        /* Allocation of iobuf is postponed until now
         * (IOW, server process doesn't need to waste 8k) */
@@ -1788,6 +1847,48 @@
                                credentials = checkPerm(urlcopy, tptr);
                        }
 #endif          /* FEATURE_HTTPD_BASIC_AUTH */
+#if ENABLE_FEATURE_HTTPD_RANGE
+                       if (STRNCASECMP(iobuf, "Range:") == 0) {
+                               /*
+                                * Don't support multiple ranges, only one of
+                                *              Range: bytes=first-last
+                                *              Range: bytes=first-
+                                *              Range: bytes=-suffixLen
+                                *
+                                * Ignore unparsable Range headers (whole file 
sent).
+                                */
+                               tptr = skip_whitespace(iobuf + 
sizeof("Range:")-1);
+                               if (STRNCASECMP(tptr, "bytes=") != 0)
+                                       continue;
+                               tptr += sizeof("bytes=")-1;
+                               if (tptr[0] == '-') {
+                                       ++tptr;
+                               } else if (!isdigit(tptr[0])) {
+                                       continue;
+                               } else {
+                                       errno = 0;
+                                       length = strtoul(tptr, &eptr, 10);
+                                       if (errno || eptr == tptr || length > 
INT_MAX || eptr[0] != '-' )
+                                               continue;
+                                       range_start = length;
+                                       tptr = eptr + 1;
+                               }
+                               if (!tptr[0]) {
+                                       continue;
+                               } else if (!isdigit(tptr[0])) {
+                                       range_start = -1;
+                                       continue;
+                               } else {
+                                       errno = 0;
+                                       length = strtoul(tptr, &eptr, 10);
+                                       if (errno || eptr == tptr || length > 
INT_MAX || eptr[0] ) {
+                                               range_start = -1;
+                                               continue;
+                                       }
+                                       range_end = length;
+                               }
+                       }
+#endif          /* FEATURE_HTTPD_RANGE */
                } /* while extra header reading */
        }
 

_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to