httpd: optional support for gzip-compressed pages
authorPeter Korsgaard <jacmet@sunsite.dk>
Sun, 25 Jul 2010 01:20:53 +0000 (03:20 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 25 Jul 2010 01:20:53 +0000 (03:20 +0200)
function                                             old     new   delta
send_file_and_exit                                   662     761     +99
handle_incoming_and_exit                            2756    2830     +74
send_headers                                         603     654     +51
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 224/0)             Total: 224 bytes

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/Config.src
networking/httpd.c

index 2d29c423a2d1d6825a21b086e177f1b9d6c4544f..8604c53e9ba2a31d0a8ec69787614a1fadefcd56 100644 (file)
@@ -270,6 +270,14 @@ config FEATURE_HTTPD_PROXY
          Then a request to /url/myfile will be forwarded to
          http://hostname[:port]/new/path/myfile.
 
+config FEATURE_HTTPD_GZIP
+       bool "Support for GZIP content encoding"
+       default y
+       depends on HTTPD
+       help
+         Makes httpd send files using GZIP content encoding if the
+         client supports it and a pre-compressed <file>.gz exists.
+
 config IFCONFIG
        bool "ifconfig"
        default y
index 12bad597a0e9f20d09ffc91b7c6fc5ae7d1dee1c..cad45cd5d6120cd565e75df84abc6e64b0bda7bd 100644 (file)
@@ -277,6 +277,10 @@ struct globals {
 #if ENABLE_FEATURE_HTTPD_PROXY
        Htaccess_Proxy *proxy;
 #endif
+#if ENABLE_FEATURE_HTTPD_GZIP
+       /* client can handle gzip / we are going to send gzip */
+       smallint content_gzip;
+#endif
 };
 #define G (*ptr_to_globals)
 #define verbose           (G.verbose          )
@@ -319,6 +323,11 @@ enum {
 #define hdr_cnt           (G.hdr_cnt          )
 #define http_error_page   (G.http_error_page  )
 #define proxy             (G.proxy            )
+#if ENABLE_FEATURE_HTTPD_GZIP
+# define content_gzip     (G.content_gzip     )
+#else
+# define content_gzip     0
+#endif
 #define INIT_G() do { \
        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
        IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
@@ -1027,10 +1036,14 @@ static void send_headers(int responseNum)
 #endif
                        "Last-Modified: %s\r\n%s %"OFF_FMT"u\r\n",
                                tmp_str,
-                               "Content-length:",
+                               content_gzip ? "Transfer-length:" : "Content-length:",
                                file_size
                );
        }
+
+       if (content_gzip)
+               len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n");
+
        iobuf[len++] = '\r';
        iobuf[len++] = '\n';
        if (infoString) {
@@ -1500,7 +1513,22 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
        int fd;
        ssize_t count;
 
-       fd = open(url, O_RDONLY);
+       if (content_gzip) {
+               /* does <url>.gz exist? Then use it instead */
+               char *gzurl = xasprintf("%s.gz", url);
+               fd = open(gzurl, O_RDONLY);
+               free(gzurl);
+               if (fd != -1) {
+                       struct stat sb;
+                       fstat(fd, &sb);
+                       file_size = sb.st_size;
+               } else {
+                       IF_FEATURE_HTTPD_GZIP(content_gzip = 0;)
+                       fd = open(url, O_RDONLY);
+               }
+       } else {
+               fd = open(url, O_RDONLY);
+       }
        if (fd < 0) {
                if (DEBUG)
                        bb_perror_msg("can't open '%s'", url);
@@ -1583,8 +1611,11 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
                        url, found_mime_type);
 
 #if ENABLE_FEATURE_HTTPD_RANGES
-       if (what == SEND_BODY)
-               range_start = 0; /* err pages and ranges don't mix */
+       if (what == SEND_BODY /* err pages and ranges don't mix */
+        || content_gzip /* we are sending compressed page: can't do ranges */  ///why?
+       ) {
+               range_start = 0;
+       }
        range_len = MAXINT(off_t);
        if (range_start) {
                if (!range_end) {
@@ -2047,6 +2078,23 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
                                        }
                                }
                        }
+#endif
+#if ENABLE_FEATURE_HTTPD_GZIP
+                       if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) {
+                               char *s = iobuf + sizeof("Accept-Encoding:")-1;
+                               while (*s) {
+                                       ///is "Accept-Encoding: compress,gzip" valid?
+                                       // (that is, no space after ',') -
+                                       // this code won't handle that
+                                       s = skip_whitespace(s);
+                                       if (STRNCASECMP(s, "gzip") == 0)
+                                               content_gzip = 1;
+                                       /* Note: we do not support "gzip;q=0"
+                                        * method of _disabling_ gzip
+                                        * delivery */
+                                       s = skip_non_whitespace(s);
+                               }
+                       }
 #endif
                } /* while extra header reading */
        }