OSDN Git Service

httpd: shrink mime type matching code (suggested by Bernhard)
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 9 Sep 2009 23:46:02 +0000 (01:46 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 9 Sep 2009 23:46:02 +0000 (01:46 +0200)
function                                             old     new   delta
static.suffixTable                                   100     231    +131
send_file_and_exit                                   625     658     +33
handle_incoming_and_exit                            2749    2745      -4
send_cgi_and_exit                                    936     901     -35
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/2 up/down: 164/-39)           Total: 125 bytes
   text    data     bss     dec     hex filename
 824631     458    6956  832045   cb22d busybox_old
 824550     458    6956  831964   cb1dc busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
libbb/isdirectory.c
networking/httpd.c

index 28ed3ec..4a2961e 100644 (file)
@@ -15,7 +15,7 @@
  * Return TRUE if fileName is a directory.
  * Nonexistent files return FALSE.
  */
-int FAST_FUNC is_directory(const char *fileName, const int followLinks, struct stat *statBuf)
+int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf)
 {
        int status;
        struct stat astatBuf;
index 07dcd71..a2a52b5 100644 (file)
  * httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication"
  *
  *
- * When a url starts by "/cgi-bin/" it is assumed to be a cgi script.  The
+ * When an url starts by "/cgi-bin/" it is assumed to be a cgi script.  The
  * server changes directory to the location of the script and executes it
  * after setting QUERY_STRING and other environment variables.
  *
  * Doc:
  * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html
  *
- * The applet can also be invoked as a url arg decoder and html text encoder
+ * The applet can also be invoked as an url arg decoder and html text encoder
  * as follows:
  *  foo=`httpd -d $foo`           # decode "Hello%20World" as "Hello World"
  *  bar=`httpd -e "<Hello World>"`  # encode as "&#60Hello&#32World&#62"
@@ -1325,10 +1325,8 @@ static void send_cgi_and_exit(
        /* Check for [dirs/]script.cgi/PATH_INFO */
        script = (char*)url;
        while ((script = strchr(script + 1, '/')) != NULL) {
-               struct stat sb;
-
                *script = '\0';
-               if (!is_directory(url + 1, 1, &sb)) {
+               if (!is_directory(url + 1, 1, NULL)) {
                        /* not directory, found script.cgi/PATH_INFO */
                        *script = '/';
                        break;
@@ -1504,32 +1502,8 @@ static void send_cgi_and_exit(
  */
 static NOINLINE void send_file_and_exit(const char *url, int what)
 {
-       static const char *const suffixTable[] = {
-       /* Warning: shorter equivalent suffix in one line must be first */
-               ".htm.html", "text/html",
-               ".jpg.jpeg", "image/jpeg",
-               ".gif",      "image/gif",
-               ".png",      "image/png",
-               ".txt.h.c.cc.cpp", "text/plain",
-               ".css",      "text/css",
-               ".wav",      "audio/wav",
-               ".avi",      "video/x-msvideo",
-               ".qt.mov",   "video/quicktime",
-               ".mpe.mpeg", "video/mpeg",
-               ".mid.midi", "audio/midi",
-               ".mp3",      "audio/mpeg",
-#if 0                        /* unpopular */
-               ".au",       "audio/basic",
-               ".pac",      "application/x-ns-proxy-autoconfig",
-               ".vrml.wrl", "model/vrml",
-#endif
-               NULL
-       };
-
        char *suffix;
        int fd;
-       const char *const *table;
-       const char *try_suffix;
        ssize_t count;
 
        fd = open(url, O_RDONLY);
@@ -1547,22 +1521,61 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
         * (happens if you abort downloads from local httpd): */
        signal(SIGPIPE, SIG_IGN);
 
-       suffix = strrchr(url, '.');
-
-       /* If not found, set default as "application/octet-stream";  */
+       /* If not found, default is "application/octet-stream" */
        found_mime_type = "application/octet-stream";
+       suffix = strrchr(url, '.');
        if (suffix) {
+               static const char suffixTable[] ALIGN1 =
+                       /* Shorter suffix must be first:
+                        * ".html.htm" will fail for ".htm"
+                        */
+                       ".txt.h.c.cc.cpp\0" "text/plain\0"
+                       /* .htm line must be after .h line */
+                       ".htm.html\0" "text/html\0"
+                       ".jpg.jpeg\0" "image/jpeg\0"
+                       ".gif\0"      "image/gif\0"
+                       ".png\0"      "image/png\0"
+                       /* .css line must be after .c line */
+                       ".css\0"      "text/css\0"
+                       ".wav\0"      "audio/wav\0"
+                       ".avi\0"      "video/x-msvideo\0"
+                       ".qt.mov\0"   "video/quicktime\0"
+                       ".mpe.mpeg\0" "video/mpeg\0"
+                       ".mid.midi\0" "audio/midi\0"
+                       ".mp3\0"      "audio/mpeg\0"
+#if 0  /* unpopular */
+                       ".au\0"       "audio/basic\0"
+                       ".pac\0"      "application/x-ns-proxy-autoconfig\0"
+                       ".vrml.wrl\0" "model/vrml\0"
+#endif
+                       /* compiler adds another "\0" here */
+               ;
                Htaccess *cur;
-               for (table = suffixTable; *table; table += 2) {
-                       try_suffix = strstr(table[0], suffix);
-                       if (try_suffix) {
-                               try_suffix += strlen(suffix);
-                               if (*try_suffix == '\0' || *try_suffix == '.') {
-                                       found_mime_type = table[1];
-                                       break;
-                               }
+
+               /* Examine built-in table */
+               const char *table = suffixTable;
+               const char *table_next;
+               for (; *table; table = table_next) {
+                       const char *try_suffix;
+                       const char *mime_type;
+                       mime_type  = table + strlen(table) + 1;
+                       table_next = mime_type + strlen(mime_type) + 1;
+                       try_suffix = strstr(table, suffix);
+                       if (!try_suffix)
+                               continue;
+                       try_suffix += strlen(suffix);
+                       if (*try_suffix == '\0' || *try_suffix == '.') {
+                               found_mime_type = mime_type;
+                               break;
                        }
+                       /* Example: strstr(table, ".av") != NULL, but it
+                        * does not match ".avi" after all and we end up here.
+                        * The table is arranged so that in this case we know
+                        * that it can't match anything in the following lines,
+                        * and we stop the search: */
+                       break;
                }
+               /* ...then user's table */
                for (cur = mime_a; cur; cur = cur->next) {
                        if (strcmp(cur->before_colon, suffix) == 0) {
                                found_mime_type = cur->after_colon;
@@ -1919,7 +1932,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
 
        /* If URL is a directory, add '/' */
        if (urlp[-1] != '/') {
-               if (is_directory(urlcopy + 1, 1, &sb)) {
+               if (is_directory(urlcopy + 1, 1, NULL)) {
                        found_moved_temporarily = urlcopy;
                }
        }
@@ -1933,7 +1946,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
        while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) {
                /* have path1/path2 */
                *tptr = '\0';
-               if (is_directory(urlcopy + 1, 1, &sb)) {
+               if (is_directory(urlcopy + 1, 1, NULL)) {
                        /* may have subdir config */
                        parse_conf(urlcopy + 1, SUBDIR_PARSE);
                        ip_allowed = checkPermIP();