[git commit master] httpd: shrink mime type matching code (suggested by Bernhard)

Denys Vlasenko vda.linux at googlemail.com
Wed Sep 9 23:46:02 UTC 2009


commit: http://git.busybox.net/busybox/commit/?id=33d8d08f7818a6d10e14ad8397c61adfcd377a6f
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 libbb/isdirectory.c |    2 +-
 networking/httpd.c  |   97 +++++++++++++++++++++++++++++----------------------
 2 files changed, 56 insertions(+), 43 deletions(-)

diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c
index 28ed3ec..4a2961e 100644
--- a/libbb/isdirectory.c
+++ b/libbb/isdirectory.c
@@ -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;
diff --git a/networking/httpd.c b/networking/httpd.c
index 07dcd71..a2a52b5 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -20,14 +20,14 @@
  * 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();
-- 
1.6.3.3



More information about the busybox-cvs mailing list