httpd: sendfile support
authorDenis Vlasenko <vda.linux@googlemail.com>
Sun, 12 Aug 2007 21:05:49 +0000 (21:05 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sun, 12 Aug 2007 21:05:49 +0000 (21:05 -0000)
networking/Config.in
networking/httpd.c

index 2ea0650a0ab98163747eafa23783e78700e1dd46..3013be676decda3ae73c8963047d2d0d870b8c8e 100644 (file)
@@ -83,6 +83,14 @@ config HTTPD
        help
          Serve web pages via an HTTP server.
 
+config FEATURE_HTTPD_USE_SENDFILE
+       bool "Use sendfile system call"
+       default n
+       depends on HTTPD
+       help
+         When enabled, httpd will use the kernel sendfile() function
+         instead of read/write loop.
+
 config FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP
        bool "Support reloading the global config file using hup signal"
        default n
index b083d645ca6f02d5807f50cade5135a3f8f8d517..3e3117a796aaf7db160e96d92a9cb629b396a42e 100644 (file)
@@ -92,6 +92,9 @@
 */
 
 #include "libbb.h"
+#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+#include <sys/sendfile.h>
+#endif
 
 /* amount of buffering in a pipe */
 #ifndef PIPE_BUF
@@ -922,15 +925,15 @@ static int sendHeaders(HttpResponseNum responseNum)
        len += 2;
        if (infoString) {
                len += sprintf(buf+len,
-                               "<HEAD><TITLE>%d %s</TITLE></HEAD>\n"
-                               "<BODY><H1>%d %s</H1>\n%s\n</BODY>\n",
+                               "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n"
+                               "<BODY><H1>%d %s</H1>\n%s\n</BODY></HTML>\n",
                                responseNum, responseString,
                                responseNum, responseString, infoString);
        }
        if (DEBUG)
                fprintf(stderr, "headers: '%s'\n", buf);
        i = accepted_socket;
-       if (i == 0) i++; /* write to fd1 in inetd mode */
+       if (i == 0) i++; /* write to fd #1 in inetd mode */
        return full_write(i, buf, len);
 }
 
@@ -1342,10 +1345,15 @@ static int sendCgi(const char *url,
  ****************************************************************************/
 static int sendFile(const char *url)
 {
-       char * suffix;
+       char *suffix;
        int f;
+       int fd;
        const char *const *table;
        const char *try_suffix;
+       ssize_t count;
+#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+       off_t offset = 0;
+#endif
 
        suffix = strrchr(url, '.');
 
@@ -1360,7 +1368,6 @@ static int sendFile(const char *url)
 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES
        if (suffix) {
                Htaccess * cur;
-
                for (cur = mime_a; cur; cur = cur->next) {
                        if (strcmp(cur->before_colon, suffix) == 0) {
                                found_mime_type = cur->after_colon;
@@ -1375,25 +1382,36 @@ static int sendFile(const char *url)
                        url, found_mime_type);
 
        f = open(url, O_RDONLY);
-       if (f >= 0) {
-               int count;
-               char *buf = iobuf;
-
-               sendHeaders(HTTP_OK);
-               /* TODO: sendfile() */
-               while ((count = full_read(f, buf, MAX_MEMORY_BUFF)) > 0) {
-                       int fd = accepted_socket;
-                       if (fd == 0) fd++; /* write to fd# 1 in inetd mode */
-                       if (full_write(fd, buf, count) != count)
-                               break;
-               }
-               close(f);
-       } else {
+       if (f < 0) {
                if (DEBUG)
                        bb_perror_msg("cannot open '%s'", url);
                sendHeaders(HTTP_NOT_FOUND);
+               return 0;
        }
 
+       sendHeaders(HTTP_OK);
+       fd = accepted_socket;
+       if (fd == 0)
+               fd++; /* write to fd #1 in inetd mode */
+#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
+       do {
+               count = sendfile(fd, f, &offset, MAXINT(ssize_t));
+               if (count < 0) {
+                       if (offset == 0)
+                               goto fallback;
+                       bb_perror_msg("sendfile '%s'", url);
+               }
+       } while (count > 0);
+       close(f);
+       return 0;
+
+ fallback:
+#endif
+       while ((count = full_read(f, iobuf, MAX_MEMORY_BUFF)) > 0) {
+               if (full_write(fd, iobuf, count) != count)
+                       break;
+       }
+       close(f);
        return 0;
 }
 
@@ -1689,11 +1707,11 @@ static void handleIncoming(void)
                                if ((STRNCASECMP(buf, "Content-length:") == 0)) {
                                        /* extra read only for POST */
                                        if (prequest != request_GET) {
-                                               test = buf + sizeof("Content-length:")-1;
+                                               test = buf + sizeof("Content-length:") - 1;
                                                if (!test[0])
                                                        goto bail_out;
                                                errno = 0;
-                                               /* not using strtoul: it ignores leading munis! */
+                                               /* not using strtoul: it ignores leading minus! */
                                                length = strtol(test, &test, 10);
                                                /* length is "ulong", but we need to pass it to int later */
                                                /* so we check for negative or too large values in one go: */