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