svn commit: trunk/busybox/networking

vda at busybox.net vda at busybox.net
Fri Aug 17 19:21:13 UTC 2007


Author: vda
Date: 2007-08-17 12:21:12 -0700 (Fri, 17 Aug 2007)
New Revision: 19550

Log:
httpd shrink and logging update, part 7 of 7

   text    data     bss     dec     hex filename
   9836       0       0    9836    266c busybox.t1/networking/httpd.o.orig
   9724       0       0    9724    25fc busybox.t2/networking/httpd.o
   9657       0       0    9657    25b9 busybox.t3/networking/httpd.o
   9342       0       0    9342    247e busybox.t4/networking/httpd.o
   9342       0       0    9342    247e busybox.t5/networking/httpd.o
   9262       0       0    9262    242e busybox.t6/networking/httpd.o
   9283       0       0    9283    2443 busybox.t7/networking/httpd.o
   9334       0       0    9334    2476 busybox.t8/networking/httpd.o



Modified:
   trunk/busybox/networking/httpd.c


Changeset:
Modified: trunk/busybox/networking/httpd.c
===================================================================
--- trunk/busybox/networking/httpd.c	2007-08-17 19:20:39 UTC (rev 19549)
+++ trunk/busybox/networking/httpd.c	2007-08-17 19:21:12 UTC (rev 19550)
@@ -934,43 +934,108 @@
 {
 	struct { int rd; int wr; } fromCgi;  /* CGI -> httpd pipe */
 	struct { int rd; int wr; } toCgi;    /* httpd -> CGI pipe */
-	char *argp[] = { NULL, NULL };
-	int pid = 0;
+	char *fullpath;
+	char *script;
+	char *purl;
+	size_t post_read_size, post_read_idx;
 	int buf_count;
 	int status;
-	size_t post_read_size, post_read_idx;
+	int pid = 0;
+	int sv_accepted_socket = accepted_socket;
 
+	/*
+	 * We are mucking with environment _first_ and then vfork/exec,
+	 * this allows us to use vfork safely. Parent don't care about
+	 * these environment changes anyway.
+	 */
+
+	/*
+	 * Find PATH_INFO.
+	 */
+	purl = xstrdup(url);
+	script = purl;
+	while ((script = strchr(script + 1, '/')) != NULL) {
+		/* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */
+		struct stat sb;
+
+		*script = '\0';
+		if (!is_directory(purl + 1, 1, &sb)) {
+			/* not directory, found script.cgi/PATH_INFO */
+			*script = '/';
+			break;
+		}
+		*script = '/';          /* is directory, find next '/' */
+	}
+	setenv1("PATH_INFO", script);   /* set /PATH_INFO or "" */
+	setenv1("REQUEST_METHOD", request);
+	if (g_query) {
+		putenv(xasprintf("%s=%s?%s", "REQUEST_URI", purl, g_query));
+	} else {
+		setenv1("REQUEST_URI", purl);
+	}
+	if (script != NULL)
+		*script = '\0';         /* cut off /PATH_INFO */
+
+	/* SCRIPT_FILENAME required by PHP in CGI mode */
+	fullpath = concat_path_file(home_httpd, purl);
+	setenv1("SCRIPT_FILENAME", fullpath);
+	/* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
+	setenv1("SCRIPT_NAME", purl);
+	/* http://hoohoo.ncsa.uiuc.edu/cgi/env.html:
+	 * QUERY_STRING: The information which follows the ? in the URL
+	 * which referenced this script. This is the query information.
+	 * It should not be decoded in any fashion. This variable
+	 * should always be set when there is query information,
+	 * regardless of command line decoding. */
+	/* (Older versions of bbox seem to do some decoding) */
+	setenv1("QUERY_STRING", g_query);
+	putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER);
+	putenv((char*)"SERVER_PROTOCOL=HTTP/1.0");
+	putenv((char*)"GATEWAY_INTERFACE=CGI/1.1");
+	/* Having _separate_ variables for IP and port defeats
+	 * the purpose of having socket abstraction. Which "port"
+	 * are you using on Unix domain socket?
+	 * IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense.
+	 * Oh well... */
+	{
+		char *p = rmt_ip_str ? rmt_ip_str : (char*)"";
+		char *cp = strrchr(p, ':');
+		if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']'))
+			cp = NULL;
+		if (cp) *cp = '\0'; /* delete :PORT */
+		setenv1("REMOTE_ADDR", p);
+		if (cp) *cp = ':';
+	}
+	setenv1("HTTP_USER_AGENT", user_agent);
+#if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
+	setenv_long("REMOTE_PORT", tcp_port);
+#endif
+	if (bodyLen)
+		setenv_long("CONTENT_LENGTH", bodyLen);
+	if (cookie)
+		setenv1("HTTP_COOKIE", cookie);
+	if (content_type)
+		setenv1("CONTENT_TYPE", content_type);
+#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
+	if (remoteuser) {
+		setenv1("REMOTE_USER", remoteuser);
+		putenv((char*)"AUTH_TYPE=Basic");
+	}
+#endif
+	if (referer)
+		setenv1("HTTP_REFERER", referer);
+
 	xpipe(&fromCgi.rd);
 	xpipe(&toCgi.rd);
 
-/*
- * Note: We can use vfork() here in the no-mmu case, although
- * the child modifies the parent's variables, due to:
- * 1) The parent does not use the child-modified variables.
- * 2) The allocated memory (in the child) is freed when the process
- *    exits. This happens instantly after the child finishes,
- *    since httpd is run from inetd (and it can't run standalone
- *    in uClinux).
- * TODO: we can muck with environment _first_ and then fork/exec,
- * that will be more understandable, and safer wrt vfork!
- */
-
-#if !BB_MMU
 	pid = vfork();
-#else
-	pid = fork();
-#endif
 	if (pid < 0) {
 		/* TODO: log perror? */
 		log_and_exit();
 	}
 
 	if (!pid) {
-		/* child process */
-		char *fullpath;
-		char *script;
-		char *purl;
-
+		/* Child process */
 		xfunc_error_retval = 242;
 
 		if (accepted_socket > 1)
@@ -982,95 +1047,18 @@
 		xmove_fd(fromCgi.wr, 1);  /* replace stdout with the pipe */
 		close(fromCgi.rd);
 		close(toCgi.wr);
-		/* Huh? User seeing stderr can be a security problem.
+		/* User seeing stderr output can be a security problem.
 		 * If CGI really wants that, it can always do dup itself. */
 		/* dup2(1, 2); */
 
-		/*
-		 * Find PATH_INFO.
-		 */
-		purl = xstrdup(url);
-		script = purl;
-		while ((script = strchr(script + 1, '/')) != NULL) {
-			/* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */
-			struct stat sb;
-
-			*script = '\0';
-			if (!is_directory(purl + 1, 1, &sb)) {
-				/* not directory, found script.cgi/PATH_INFO */
-				*script = '/';
-				break;
-			}
-			*script = '/';          /* is directory, find next '/' */
-		}
-		setenv1("PATH_INFO", script);   /* set /PATH_INFO or "" */
-		setenv1("REQUEST_METHOD", request);
-		if (g_query) {
-			putenv(xasprintf("%s=%s?%s", "REQUEST_URI", purl, g_query));
-		} else {
-			setenv1("REQUEST_URI", purl);
-		}
-		if (script != NULL)
-			*script = '\0';         /* cut off /PATH_INFO */
-
-		/* SCRIPT_FILENAME required by PHP in CGI mode */
-		fullpath = concat_path_file(home_httpd, purl);
-		setenv1("SCRIPT_FILENAME", fullpath);
-		/* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
-		setenv1("SCRIPT_NAME", purl);
-		/* http://hoohoo.ncsa.uiuc.edu/cgi/env.html:
-		 * QUERY_STRING: The information which follows the ? in the URL
-		 * which referenced this script. This is the query information.
-		 * It should not be decoded in any fashion. This variable
-		 * should always be set when there is query information,
-		 * regardless of command line decoding. */
-		/* (Older versions of bbox seem to do some decoding) */
-		setenv1("QUERY_STRING", g_query);
-		putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER);
-		putenv((char*)"SERVER_PROTOCOL=HTTP/1.0");
-		putenv((char*)"GATEWAY_INTERFACE=CGI/1.1");
-		/* Having _separate_ variables for IP and port defeats
-		 * the purpose of having socket abstraction. Which "port"
-		 * are you using on Unix domain socket?
-		 * IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense.
-		 * Oh well... */
-		{
-			char *p = rmt_ip_str ? rmt_ip_str : (char*)"";
-			char *cp = strrchr(p, ':');
-			if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']'))
-				cp = NULL;
-			if (cp) *cp = '\0'; /* delete :PORT */
-			setenv1("REMOTE_ADDR", p);
-			if (cp) *cp = ':';
-		}
-		setenv1("HTTP_USER_AGENT", user_agent);
-#if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
-		setenv_long("REMOTE_PORT", tcp_port);
-#endif
-		if (bodyLen)
-			setenv_long("CONTENT_LENGTH", bodyLen);
-		if (cookie)
-			setenv1("HTTP_COOKIE", cookie);
-		if (content_type)
-			setenv1("CONTENT_TYPE", content_type);
-#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
-		if (remoteuser) {
-			setenv1("REMOTE_USER", remoteuser);
-			putenv((char*)"AUTH_TYPE=Basic");
-		}
-#endif
-		if (referer)
-			setenv1("HTTP_REFERER", referer);
-
-		/* set execve argp[0] without path */
-		argp[0] = (char*)bb_basename(purl);
-		/* but script argp[0] must have absolute path */
+		/* script must have absolute path */
 		script = strrchr(fullpath, '/');
 		if (!script)
 			goto error_execing_cgi;
 		*script = '\0';
 		/* chdiring to script's dir */
 		if (chdir(fullpath) == 0) {
+			char *argv[2];
 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
 			char *interpr = NULL;
 			char *suffix = strrchr(purl, '.');
@@ -1086,12 +1074,15 @@
 			}
 #endif
 			*script = '/';
+			/* set argv[0] to name without path */
+			argv[0] = (char*)bb_basename(purl);
+			argv[1] = NULL;
 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
 			if (interpr)
-				execv(interpr, argp);
+				execv(interpr, argv);
 			else
 #endif
-				execv(fullpath, argp);
+				execv(fullpath, argv);
 		}
  error_execing_cgi:
 		/* send to stdout
@@ -1100,7 +1091,13 @@
 		send_headers_and_exit(HTTP_NOT_FOUND);
 	} /* end child */
 
-	/* parent process */
+	/* Parent process */
+
+	/* First, restore variables possibly changed by child */
+	xfunc_error_retval = 0;
+	accepted_socket = sv_accepted_socket;
+
+	/* Prepare for pumping data */
 	buf_count = 0;
 	post_read_size = 0;
 	post_read_idx = 0; /* for gcc */




More information about the busybox-cvs mailing list