libthttpd.c now longer used fork() and execve()

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1980 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-07-12 18:46:11 +00:00
parent 29899e1069
commit 1235ab92c5
5 changed files with 612 additions and 433 deletions

102
include/net/uip/thttpd.h Normal file
View File

@ -0,0 +1,102 @@
/****************************************************************************
* net/uip/thttpd.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __NET_UIP_THTTPD_H
#define __NET_UIP_THTTPD_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/symtab.h>
/****************************************************************************
* Public Data
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C" {
#else
#define EXTERN extern
#endif
/* These values must be provided by the user before the THTTPD task daemon
* is started:
*
* g_thttpdsymtab: A symbol table describing all of the symbols exported
* from the base system. These symbols are used to bind address references
* in CGI programs to NuttX.
* g_nsymbols: The number of symbols in g_thttpdsymtab[].
*
* (See examples/nxflat and examples/thttpd for examples of how such a symbol
* table may be created.)
*/
EXTERN FAR const struct symtab_s *g_thttpdsymtab;
EXTERN int g_thttpdnsymbols;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Function: thttpd_main
*
* Description:
* This function is the entrypoint into the THTTPD server. It does not
* return. It may be called, the normal mechanism for starting the server
* is:
*
* 1) Set is g_thttpdsymtab and g_thttpdnsymbols. The user is required
* to provide a symbol table to use for binding CGI programs (if CGI
* is enabled. See examples/nxflat and examples/thttpd for examples of
* how such a symbol table may be created.)
* 2) Call task_create() to start thttpd_main()
*
****************************************************************************/
EXTERN int thttpd_main(int argc, char **argv);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __NET_UIP_THTTPD_H */

View File

@ -43,7 +43,8 @@
/* Make sure that the system is configured to handle THTTPD */
#undef CONFIG_THTTPD
#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCPBACKLOG)
#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) && \
defined(CONFIG_NET_TCPBACKLOG) && !defined(CONFIG_DISABLE_ENVIRONMENT)
# define CONFIG_THTTPD
#else
# warning "THTTPD not built because dependenciesnot selected in configuration"
@ -96,6 +97,16 @@
# define CONFIG_THTTPD_CGI_PATTERN "/cgi-bin/*"
#endif
/* These provide the priority and stack size of the CGI child tasks */
#ifndef CONFIG_THTTPD_CGI_PRIORITY
# define CONFIG_THTTPD_CGI_PRIORITY 50
#endif
#ifndef CONFIG_THTTPD_CGI_STACKSIZE
# define CONFIG_THTTPD_CGI_STACKSIZE 2048
#endif
/* Byte output limit for CGI tasks */
#ifndef CONFIG_THTTPD_CGI_BYTECOUNT

View File

@ -52,10 +52,14 @@
#include <fcntl.h>
#include <dirent.h>
#include <signal.h>
#include <sched.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/regex.h>
#include <nuttx/symtab.h>
#include <nuttx/binfmt.h>
#include <net/uip/thttpd.h>
#include "config.h"
#include "libhttpd.h"
@ -150,6 +154,7 @@ static void cgi_kill2(ClientData client_data, struct timeval *nowP);
static void cgi_kill(ClientData client_data, struct timeval *nowP);
#endif
#ifdef GENERATE_INDEXES
static void ls_child(int argc, char **argv);
static int ls(httpd_conn *hc);
#endif
#ifdef SERVER_NAME_LIST
@ -159,13 +164,12 @@ static char *hostname_map(char *hostname);
/* CGI Support */
#ifdef CONFIG_THTTPD_CGI_PATTERN
static char *build_env(char *fmt, char *arg);
static char **make_envp(httpd_conn * hc);
static void create_environment(httpd_conn *hc);
static char **make_argp(httpd_conn *hc);
static void cgi_interpose_input(httpd_conn *hc, int wfd);
static void post_post_garbage_hack(httpd_conn *hc);
static void cgi_interpose_output(httpd_conn *hc, int rfd);
static void cgi_child(httpd_conn * hc);
static void cgi_child(int argc, char **argv);
static int cgi(httpd_conn *hc);
#endif
@ -1624,8 +1628,9 @@ static int name_compare(char **a, char **b)
return strcmp(*a, *b);
}
static int ls(httpd_conn * hc)
static void ls_child(int argc, char **argv)
{
FAR httpd_conn *hc = (FAR httpd_conn*)strtoul(argv[1], NULL, 16);
DIR *dirp;
struct dirent *de;
int namlen;
@ -1651,46 +1656,6 @@ static int ls(httpd_conn * hc)
char *timestr;
ClientData client_data;
dirp = opendir(hc->expnfilename);
if (dirp == (DIR *) 0)
{
ndbg("opendir %s: %d\n", hc->expnfilename, errno);
httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl);
return -1;
}
if (hc->method == METHOD_HEAD)
{
closedir(dirp);
send_mime(hc, 200, ok200title, "", "", "text/html; charset=%s",
(off_t) - 1, hc->sb.st_mtime);
}
else if (hc->method == METHOD_GET)
{
#ifdef CONFIG_THTTPD_CGILIMIT
if (hc->hs->cgi_count >= CONFIG_THTTPD_CGILIMIT)
{
closedir(dirp);
httpd_send_err(hc, 503, httpd_err503title, "", httpd_err503form,
hc->encodedurl);
return -1;
}
#endif
++hc->hs->cgi_count;
r = fork();
if (r < 0)
{
ndbg("fork: %d\n", errno);
closedir(dirp);
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
return -1;
}
if (r == 0)
{
/* Child process. */
httpd_unlisten(hc->hs);
send_mime(hc, 200, ok200title, "", "", "text/html; charset=%s",
(off_t) - 1, hc->sb.st_mtime);
@ -1748,8 +1713,10 @@ mode links bytes last-changed name\n\
}
for (i = 0; i < maxnames; ++i)
{
nameptrs[i] = &names[i * (MAXPATHLEN + 1)];
}
}
namlen = NAMLEN(de);
(void)strncpy(nameptrs[nnames], de->d_name, namlen);
@ -1772,6 +1739,7 @@ mode links bytes last-changed name\n\
httpd_realloc_str(&rname, &maxrname,
strlen(hc->origfilename) + 1 +
strlen(nameptrs[i]));
if (hc->expnfilename[0] == '\0' ||
strcmp(hc->expnfilename, ".") == 0)
{
@ -1911,15 +1879,90 @@ mode links bytes last-changed name\n\
exit(0);
}
/* Parent process. */
static int ls(httpd_conn *hc)
{
DIR *dirp;
struct dirent *de;
int namlen;
static int maxnames = 0;
int nnames;
static char *names;
static char **nameptrs;
static char *name;
static size_t maxname = 0;
static char *rname;
static size_t maxrname = 0;
static char *encrname;
static size_t maxencrname = 0;
FILE *fp;
int i, child;
struct stat sb;
struct stat lsb;
char modestr[20];
char *linkprefix;
char link[MAXPATHLEN + 1];
char *fileclass;
time_t now;
char *timestr;
char arg[16];
char *argv[1];
ClientData client_data;
dirp = opendir(hc->expnfilename);
if (dirp == (DIR *) 0)
{
ndbg("opendir %s: %d\n", hc->expnfilename, errno);
httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl);
return -1;
}
if (hc->method == METHOD_HEAD)
{
closedir(dirp);
send_mime(hc, 200, ok200title, "", "", "text/html; charset=%s",
(off_t) - 1, hc->sb.st_mtime);
}
else if (hc->method == METHOD_GET)
{
#ifdef CONFIG_THTTPD_CGILIMIT
if (hc->hs->cgi_count >= CONFIG_THTTPD_CGILIMIT)
{
closedir(dirp);
httpd_send_err(hc, 503, httpd_err503title, "", httpd_err503form,
hc->encodedurl);
return -1;
}
#endif
++hc->hs->cgi_count;
/* Start the child task. */
snprintf(arg, 16, "%p", hc); /* task_create doesn't handle binary arguments. */
argv[0] = arg;
#ifndef CONFIG_CUSTOM_STACK
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
CONFIG_THTTPD_CGI_STACKSIZE,
(main_t)ls_child, (const char **)argv);
#else
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
(main_t)ls_child, (const char **)argv);
#endif
if (child < 0)
{
ndbg("task_create: %d\n", errno);
closedir(dirp);
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
return -1;
}
closedir(dirp);
ndbg("spawned indexing process %d for directory '%s'\n", r, hc->expnfilename);
ndbg("spawned indexing process %d for directory '%s'\n", child, hc->expnfilename);
/* Schedule a kill for the child process, in case it runs too long */
#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
client_data.i = r;
client_data.i = child;
if (tmr_create((struct timeval *)0, cgi_kill, client_data, CONFIG_THTTPD_CGI_TIMELIMIT * 1000L, 0) == (Timer *) 0)
{
ndbg("tmr_create(cgi_kill ls) failed\n");
@ -1942,50 +1985,24 @@ mode links bytes last-changed name\n\
}
#endif /* GENERATE_INDEXES */
#ifdef CONFIG_THTTPD_CGI_PATTERN
static char *build_env(char *fmt, char *arg)
{
char *cp;
size_t size;
static char *buf;
static size_t maxbuf = 0;
size = strlen(fmt) + strlen(arg);
if (size > maxbuf)
{
httpd_realloc_str(&buf, &maxbuf, size);
}
(void)snprintf(buf, maxbuf, fmt, arg);
cp = strdup(buf);
if (!cp)
{
ndbg("out of memory copying environment variable\n");
exit(1);
}
return cp;
}
#endif
/* Set up environment variables. Be real careful here to avoid
* letting malicious clients overrun a buffer. We don't have
* to worry about freeing stuff since we're a sub-process.
*/
#ifdef CONFIG_THTTPD_CGI_PATTERN
static char **make_envp(httpd_conn * hc)
static void create_environment(httpd_conn *hc)
{
static char *envp[50];
int envn;
char *cp;
char buf[256];
envn = 0;
envp[envn++] = build_env("PATH=%s", CONFIG_THTTPD_CGI_PATH);
setenv("PATH", CONFIG_THTTPD_CGI_PATH, TRUE);
#ifdef CGI_LD_LIBRARY_PATH
envp[envn++] = build_env("LD_LIBRARY_PATH=%s", CGI_LD_LIBRARY_PATH);
setenv("LD_LIBRARY_PATH", CGI_LD_LIBRARY_PATH, TRUE);
#endif /* CGI_LD_LIBRARY_PATH */
envp[envn++] = build_env("SERVER_SOFTWARE=%s", CONFIG_THTTPD_SERVER_SOFTWARE);
setenv("SERVER_SOFTWARE", CONFIG_THTTPD_SERVER_SOFTWARE, TRUE);
/* If vhosting, use that server-name here. */
#ifdef CONFIG_THTTPD_VHOST
if (hc->vhostname)
@ -2000,116 +2017,116 @@ static char **make_envp(httpd_conn * hc)
if (cp)
{
envp[envn++] = build_env("SERVER_NAME=%s", cp);
setenv("SERVER_NAME", cp, TRUE);
}
envp[envn++] = "GATEWAY_INTERFACE=CGI/1.1";
envp[envn++] = build_env("SERVER_PROTOCOL=%s", hc->protocol);
setenv("GATEWAY_INTERFACE", "CGI/1.1", TRUE);
setenv("SERVER_PROTOCOL", hc->protocol, TRUE);
(void)snprintf(buf, sizeof(buf), "%d", (int)CONFIG_THTTPD_PORT);
envp[envn++] = build_env("SERVER_PORT=%s", buf);
envp[envn++] = build_env("REQUEST_METHOD=%s", httpd_method_str(hc->method));
setenv("SERVER_PORT", buf, TRUE);
setenv("REQUEST_METHOD", httpd_method_str(hc->method), TRUE);
if (hc->pathinfo[0] != '\0')
{
char *cp2;
size_t l;
envp[envn++] = build_env("PATH_INFO=/%s", hc->pathinfo);
(void)snprintf(buf, sizeof(buf), "/%s", hc->pathinfo);
setenv("PATH_INFO", buf, TRUE);
l = strlen(hc->hs->cwd) + strlen(hc->pathinfo) + 1;
cp2 = NEW(char, l);
if (cp2)
{
(void)snprintf(cp2, l, "%s%s", hc->hs->cwd, hc->pathinfo);
envp[envn++] = build_env("PATH_TRANSLATED=%s", cp2);
setenv("PATH_TRANSLATED", cp2, TRUE);
}
}
envp[envn++] =
build_env("SCRIPT_NAME=/%s",
strcmp(hc->origfilename, ".") == 0 ? "" : hc->origfilename);
(void)snprintf(buf, sizeof(buf), "/%s",strcmp(hc->origfilename, ".") == 0 ? "" : hc->origfilename);
setenv("SCRIPT_NAME", buf, TRUE);
if (hc->query[0] != '\0')
{
envp[envn++] = build_env("QUERY_STRING=%s", hc->query);
setenv("QUERY_STRING", hc->query, TRUE);
}
envp[envn++] = build_env("REMOTE_ADDR=%s", httpd_ntoa(&hc->client_addr));
setenv("REMOTE_ADDR", httpd_ntoa(&hc->client_addr), TRUE);
if (hc->referer[0] != '\0')
{
envp[envn++] = build_env("HTTP_REFERER=%s", hc->referer);
setenv("HTTP_REFERER", hc->referer, TRUE);
}
if (hc->useragent[0] != '\0')
{
envp[envn++] = build_env("HTTP_USER_AGENT=%s", hc->useragent);
setenv("HTTP_USER_AGENT", hc->useragent, TRUE);
}
if (hc->accept[0] != '\0')
{
envp[envn++] = build_env("HTTP_ACCEPT=%s", hc->accept);
setenv("HTTP_ACCEPT", hc->accept, TRUE);
}
if (hc->accepte[0] != '\0')
{
envp[envn++] = build_env("HTTP_ACCEPT_ENCODING=%s", hc->accepte);
setenv("HTTP_ACCEPT_ENCODING", hc->accepte, TRUE);
}
if (hc->acceptl[0] != '\0')
{
envp[envn++] = build_env("HTTP_ACCEPT_LANGUAGE=%s", hc->acceptl);
setenv("HTTP_ACCEPT_LANGUAGE", hc->acceptl, TRUE);
}
if (hc->cookie[0] != '\0')
{
envp[envn++] = build_env("HTTP_COOKIE=%s", hc->cookie);
setenv("HTTP_COOKIE", hc->cookie, TRUE);
}
if (hc->contenttype[0] != '\0')
{
envp[envn++] = build_env("CONTENT_TYPE=%s", hc->contenttype);
setenv("CONTENT_TYPE", hc->contenttype, TRUE);
}
if (hc->hdrhost[0] != '\0')
{
envp[envn++] = build_env("HTTP_HOST=%s", hc->hdrhost);
setenv("HTTP_HOST", hc->hdrhost, TRUE);
}
if (hc->contentlength != -1)
{
(void)snprintf(buf, sizeof(buf), "%lu", (unsigned long)hc->contentlength);
envp[envn++] = build_env("CONTENT_LENGTH=%s", buf);
setenv("CONTENT_LENGTH", buf, TRUE);
}
if (hc->remoteuser[0] != '\0')
{
envp[envn++] = build_env("REMOTE_USER=%s", hc->remoteuser);
setenv("REMOTE_USER", hc->remoteuser, TRUE);
}
if (hc->authorization[0] != '\0')
{
envp[envn++] = build_env("AUTH_TYPE=%s", "Basic");
setenv("AUTH_TYPE", "Basic", TRUE);
}
/* We only support Basic auth at the moment. */
if (getenv("TZ") != NULL)
{
envp[envn++] = build_env("TZ=%s", getenv("TZ"));
setenv("TZ", getenv("TZ"), TRUE);
}
envp[envn++] = build_env("CGI_PATTERN=%s", CONFIG_THTTPD_CGI_PATTERN);
envp[envn] = (char *)0;
return envp;
setenv("CGI_PATTERN", CONFIG_THTTPD_CGI_PATTERN, TRUE);
}
#endif
/* Set up argument vector. Again, we don't have to worry about freeing stuff
* since we're a sub-process. This gets done after make_envp() because we
* scribble on hc->query.
*/
/* Set up argument vector */
#ifdef CONFIG_THTTPD_CGI_PATTERN
static char **make_argp(httpd_conn * hc)
static FAR char **make_argp(httpd_conn *hc)
{
char **argp;
FAR char **argp;
int argn;
char *cp1;
char *cp2;
@ -2424,13 +2441,13 @@ static void cgi_interpose_output(httpd_conn * hc, int rfd)
/* CGI child process. */
#ifdef CONFIG_THTTPD_CGI_PATTERN
static void cgi_child(httpd_conn * hc)
static void cgi_child(int argc, char **argv)
{
int r;
char **argp;
char **envp;
FAR httpd_conn *hc = (FAR httpd_conn*)strtoul(argv[1], NULL, 16);
FAR char **argp;
char *binary;
char *directory;
int child;
/* Unset close-on-exec flag for this socket. This actually shouldn't be
* necessary, according to POSIX a dup()'d file descriptor does *not*
@ -2463,9 +2480,11 @@ static void cgi_child(httpd_conn * hc)
*/
}
/* Make the environment vector. */
/* Update all of the environment variable settings, these will be inherited
* by the CGI task.
*/
envp = make_envp(hc);
create_environment(hc);
/* Make the argument vector. */
@ -2478,6 +2497,9 @@ static void cgi_child(httpd_conn * hc)
if (hc->method == METHOD_POST && hc->read_idx > hc->checked_idx)
{
char child_arg1[16];
char child_arg2[16];
char *child_argv[2];
int p[2];
if (pipe(p) < 0)
@ -2488,25 +2510,30 @@ static void cgi_child(httpd_conn * hc)
exit(1);
}
r = fork();
if (r < 0)
/* Start the cig_interpose_input task */
snprintf(child_arg1, 16, "%p", hc); /* task_create doesn't handle binary arguments. */
child_argv[0] = child_arg1;
snprintf(child_arg2, 16, "%08x", p[1]); /* task_create doesn't handle binary arguments. */
child_argv[1] = child_arg2;
#ifndef CONFIG_CUSTOM_STACK
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
CONFIG_THTTPD_CGI_STACKSIZE,
(main_t)cgi_interpose_input, (const char **)child_argv);
#else
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
(main_t)cgi_interpose_input, (const char **)child_argv);
#endif
if (child < 0)
{
ndbg("fork: %d\n", errno);
ndbg("task_create: %d\n", errno);
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
httpd_write_response(hc);
exit(1);
}
if (r == 0)
{
/* Interposer process. */
(void)close(p[0]);
cgi_interpose_input(hc, p[1]);
exit(0);
}
/* Need to schedule a kill for process r; but in the main process! */
/* Need to schedule a kill for process child; but in the main process! */
(void)close(p[1]);
if (p[0] != STDIN_FILENO)
@ -2531,6 +2558,9 @@ static void cgi_child(httpd_conn * hc)
if (strncmp(argp[0], "nph-", 4) != 0 && hc->mime_flag)
{
char child_arg1[16];
char child_arg2[16];
char *child_argv[2];
int p[2];
if (pipe(p) < 0)
@ -2541,8 +2571,22 @@ static void cgi_child(httpd_conn * hc)
exit(1);
}
r = fork();
if (r < 0)
/* Start the cgi_interpose_output task */
snprintf(child_arg1, 16, "%p", hc); /* task_create doesn't handle binary arguments. */
child_argv[0] = child_arg1;
snprintf(child_arg2, 16, "%08x", p[0]); /* task_create doesn't handle binary arguments. */
child_argv[1] = child_arg2;
#ifndef CONFIG_CUSTOM_STACK
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
CONFIG_THTTPD_CGI_STACKSIZE,
(main_t)cgi_interpose_output, (const char **)child_argv);
#else
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
(main_t)cgi_interpose_output, (const char **)child_argv);
#endif
if (child < 0)
{
ndbg("fork: %d\n", errno);
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
@ -2550,16 +2594,7 @@ static void cgi_child(httpd_conn * hc)
exit(1);
}
if (r == 0)
{
/* Interposer process. */
(void)close(p[1]);
cgi_interpose_output(hc, p[0]);
exit(0);
}
/* Need to schedule a kill for process r; but in the main process! */
/* Need to schedule a kill for process child; but in the main process! */
(void)close(p[0]);
if (p[1] != STDOUT_FILENO)
@ -2629,8 +2664,9 @@ static void cgi_child(httpd_conn * hc)
/* Run the program. */
(void)execve(binary, argp, envp);
child = exec(binary, (FAR const char **)argp, g_thttpdsymtab, g_thttpdnsymbols);
if (child < 0)
{
/* Something went wrong. */
ndbg("execve %s: %d\n", hc->expnfilename, errno);
@ -2638,6 +2674,7 @@ static void cgi_child(httpd_conn * hc)
httpd_write_response(hc);
exit(1);
}
}
#endif /* CONFIG_THTTPD_CGI_PATTERN */
#ifdef CONFIG_THTTPD_CGI_PATTERN
@ -2646,7 +2683,9 @@ static int cgi(httpd_conn * hc)
#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
ClientData client_data;
#endif
int r;
char arg[16];
char *argv[1];
pid_t child;
if (hc->method == METHOD_GET || hc->method == METHOD_POST)
{
@ -2661,30 +2700,40 @@ static int cgi(httpd_conn * hc)
++hc->hs->cgi_count;
httpd_clear_ndelay(hc->conn_fd);
r = fork();
if (r < 0)
/* Start the child task. We use a trampoline task here so that we can
* safely muck with the file descriptors before actually started the CGI
* task.
*/
snprintf(arg, 16, "%p", hc); /* task_create doesn't handle binary arguments. */
argv[0] = arg;
#ifndef CONFIG_CUSTOM_STACK
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
CONFIG_THTTPD_CGI_STACKSIZE,
(main_t)cgi_child, (const char **)argv);
#else
child = task_create("CGI child", CONFIG_THTTPD_CGI_PRIORITY,
(main_t)cgi_child, (const char **)argv);
#endif
if (child < 0)
{
ndbg("fork: %d\n", errno);
ndbg("task_create: %d\n", errno);
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
return -1;
}
else if (r == 0)
{
/* Child process. */
httpd_unlisten(hc->hs);
cgi_child(hc);
}
ndbg("started CGI process %d for file '%s'\n", child, hc->expnfilename);
/* Parent process. */
ndbg("spawned CGI process %d for file '%s'\n", r, hc->expnfilename);
/* Schedule a kill for the child process, in case it runs too long.
* Unfortunately, the returned value in 'child' is the pid of the trampoline
* task -- NOT the pid of the CGI task. So the following cannot work.
*/
#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
/* Schedule a kill for the child process, in case it runs too long */
client_data.i = r;
if (tmr_create((struct timeval *)0, cgi_kill, client_data, CONFIG_THTTPD_CGI_TIMELIMIT * 1000L, 0) == (Timer *) 0)
client_data.i = child;
if (tmr_create((struct timeval *)0, cgi_kill, client_data,
CONFIG_THTTPD_CGI_TIMELIMIT * 1000L, 0) == (Timer *) 0)
{
ndbg("tmr_create(cgi_kill child) failed\n");
exit(1);
@ -3012,7 +3061,7 @@ static int check_referer(httpd_conn * hc)
int r;
char *cp;
r = really_check_referer(hc);
child = really_check_referer(hc);
if (!r)
{
@ -3189,9 +3238,9 @@ static size_t sockaddr_len(httpd_sockaddr * saP)
* Public Functions
****************************************************************************/
httpd_server *httpd_initialize(httpd_sockaddr *sa, char *cwd)
FAR httpd_server *httpd_initialize(FAR httpd_sockaddr *sa, FAR const char *cwd)
{
httpd_server *hs;
FAR httpd_server *hs;
/* Save the PID of the main thread */
@ -3200,10 +3249,10 @@ httpd_server *httpd_initialize(httpd_sockaddr *sa, char *cwd)
/* Allocate the server structure */
hs = NEW(httpd_server, 1);
if (hs == (httpd_server *) 0)
if (!hs)
{
ndbg("out of memory allocating an httpd_server\n");
return (httpd_server *) 0;
return NULL;
}
#ifdef CONFIG_THTTPD_HOSTNAME
@ -3516,6 +3565,7 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn * hc)
* have checked so far; and hc->checked_state is the current state of the
* finite state machine.
*/
int httpd_got_request(httpd_conn *hc)
{
char c;

View File

@ -192,7 +192,7 @@ typedef struct
* Return (httpd_server*) 0 on error.
*/
extern httpd_server *httpd_initialize(httpd_sockaddr *sa, char *cwd);
extern FAR httpd_server *httpd_initialize(FAR httpd_sockaddr *sa, FAR const char *cwd);
/* Call to unlisten/close socket(s) listening for new connections. */
@ -247,9 +247,7 @@ extern int httpd_start_request(httpd_conn * hc, struct timeval *nowP);
extern void httpd_write_response(httpd_conn *hc);
/* Call this to close down a connection and free the data. A fine point,
* if you fork() with a connection open you should still call this in the
* parent process - the connection will stay open in the child.
/* Call this to close down a connection and free the data.
* If you don't have a current timeval handy just pass in 0.
*/

View File

@ -53,6 +53,8 @@
#include <debug.h>
#include <nuttx/compiler.h>
#include <nuttx/symtab.h>
#include <net/uip/thttpd.h>
#include "config.h"
#include "fdwatch.h"
@ -709,13 +711,29 @@ static void thttpd_logstats(long secs)
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: thttpd_main
*
* Description:
* This function is the entrypoint into the THTTPD server. It does not
* return. It may be called, the normal mechanism for starting the server
* is:
*
* 1) Set is g_thttpdsymtab and g_thttpdnsymbols. The user is required
* to provide a symbol table to use for binding CGI programs (if CGI
* is enabled. See examples/nxflat and examples/thttpd for examples of
* how such a symbol table may be created.
* 2) Call task_create() to start thttpd_main()
*
****************************************************************************/
int thttpd_main(int argc, char **argv)
{
char cwd[MAXPATHLEN + 1];
int num_ready;
int cnum;
struct connect_s *conn;
httpd_conn *hc;
FAR struct connect_s *conn;
FAR httpd_conn *hc;
#ifdef CONFIG_NET_IPv6
struct sockaddr_in6 sa;
#else