summaryrefslogtreecommitdiff
path: root/nuttx/netutils/thttpd
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-07-18 18:04:05 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-07-18 18:04:05 +0000
commit0ae84141bbd645eff4c096b608a2aee7704ea17a (patch)
tree8f69951d409be32bcb4b4895ddb3d3a4d8171e42 /nuttx/netutils/thttpd
parent9b9e5bbafa1f5d03f903a4ec0985f68af7164792 (diff)
downloadpx4-nuttx-0ae84141bbd645eff4c096b608a2aee7704ea17a.tar.gz
px4-nuttx-0ae84141bbd645eff4c096b608a2aee7704ea17a.tar.bz2
px4-nuttx-0ae84141bbd645eff4c096b608a2aee7704ea17a.zip
Fix CGI I/O redirection and interposer tasks
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1988 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/netutils/thttpd')
-rw-r--r--nuttx/netutils/thttpd/cgi-src/phf.c9
-rw-r--r--nuttx/netutils/thttpd/cgi-src/redirect.c49
-rw-r--r--nuttx/netutils/thttpd/cgi-src/ssi.c185
-rw-r--r--nuttx/netutils/thttpd/config.h8
-rw-r--r--nuttx/netutils/thttpd/fdwatch.c213
-rw-r--r--nuttx/netutils/thttpd/fdwatch.h43
-rw-r--r--nuttx/netutils/thttpd/libhttpd.c912
-rw-r--r--nuttx/netutils/thttpd/thttpd.c38
8 files changed, 770 insertions, 687 deletions
diff --git a/nuttx/netutils/thttpd/cgi-src/phf.c b/nuttx/netutils/thttpd/cgi-src/phf.c
index 16ea2fefe..a108468a8 100644
--- a/nuttx/netutils/thttpd/cgi-src/phf.c
+++ b/nuttx/netutils/thttpd/cgi-src/phf.c
@@ -61,15 +61,9 @@
int main(int argc, char *argv[])
{
- FILE *outstream;
-
fprintf(stderr, "phf CGI probe from %s\n", getenv("REMOTE_ADDR"));
- outstream = fdopen(CONFIG_THTTPD_CGI_OUTFD, "w");
- if (outstream)
- {
- (void)fprintf(outstream,
-"\
+ (void)printf("\
Content-type: text/html\n\
Status: 404/html\n\
\n\
@@ -79,7 +73,6 @@ The requested object does not exist on this server.\n\
The link you followed is either outdated, inaccurate,\n\
or the server has been instructed not to let you have it.\n\
</BODY></HTML>\n");
- fclose(outstream);
return 0;
}
return 1;
diff --git a/nuttx/netutils/thttpd/cgi-src/redirect.c b/nuttx/netutils/thttpd/cgi-src/redirect.c
index 5aa099d59..8177b8df9 100644
--- a/nuttx/netutils/thttpd/cgi-src/redirect.c
+++ b/nuttx/netutils/thttpd/cgi-src/redirect.c
@@ -98,12 +98,11 @@ static char g_url[LINE_SIZE];
* Private Functions
****************************************************************************/
-static void internal_error(FILE *outstream, char *reason)
+static void internal_error(char *reason)
{
char *title = "500 Internal Error";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
Status: %s\n\
Content-type: text/html\n\
\n\
@@ -116,12 +115,11 @@ Something unusual went wrong during a redirection request:\n\
</BODY></HTML>\n", title, title, title, reason);
}
-static void not_found(FILE *outstream, char *script_name)
+static void not_found(char *script_name)
{
char *title = "404 Not Found";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
Status: %s\n\
Content-type: text/html\n\
\n\
@@ -132,12 +130,11 @@ however, the new URL has not yet been specified.\n\
</BODY></HTML>\n", title, title, title, script_name);
}
-static void moved(FILE *outstream, char *script_name, char *url)
+static void moved(char *script_name, char *url)
{
char *title = "Moved";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
Location: %s\n\
Content-type: text/html\n\
\n\
@@ -154,7 +151,6 @@ The requested filename, %s, has moved to a new URL:\n\
int main(int argc, char **argv)
{
- FILE *outstream;
char *script_name;
char *path_info;
char *cp = 0;
@@ -162,14 +158,6 @@ int main(int argc, char **argv)
char *star;
int err = 0;
- outstream = fdopen(CONFIG_THTTPD_CGI_OUTFD, "w");
- if (!outstream)
- {
- fprintf(stderr, "fdopen failed: %d\n", errno);
- err = 1;
- goto errout;
- }
-
/* Get the name that we were run as, which is the filename being **
* redirected.
*/
@@ -177,9 +165,8 @@ int main(int argc, char **argv)
script_name = getenv("SCRIPT_NAME");
if (!script_name)
{
- internal_error(outstream, "Couldn't get SCRIPT_NAME environment variable.");
- err = 2;
- goto errout_with_outstream;
+ internal_error("Couldn't get SCRIPT_NAME environment variable.");
+ return 1;
}
/* Append the PATH_INFO, if any. This allows redirection of whole **
@@ -192,9 +179,8 @@ int main(int argc, char **argv)
cp = (char *)malloc(strlen(script_name) + strlen(path_info) + 1);
if (!cp)
{
- internal_error(outstream, "Out of memory.");
- err = 3;
- goto errout_with_outstream;
+ internal_error("Out of memory.");
+ return 2;
}
(void)sprintf(cp, "%s%s", script_name, path_info);
@@ -206,8 +192,8 @@ int main(int argc, char **argv)
fp = fopen(".redirects", "r");
if (fp == (FILE *) 0)
{
- internal_error(outstream, "Couldn't open .redirects file.");
- err = 4;
+ internal_error("Couldn't open .redirects file.");
+ err = 3;
goto errout_with_cp;
}
@@ -251,7 +237,7 @@ int main(int argc, char **argv)
/* XXX Whack the script_name, too? */
- moved(outstream, script_name, g_url);
+ moved(script_name, g_url);
goto success_out;
}
}
@@ -262,7 +248,7 @@ int main(int argc, char **argv)
{
/* Got it. */
- moved(outstream, script_name, g_url);
+ moved(script_name, g_url);
goto success_out;
}
}
@@ -271,8 +257,8 @@ int main(int argc, char **argv)
/* No match found. */
- not_found(outstream, script_name);
- err = 5;
+ not_found(script_name);
+ err = 4;
success_out:
fclose(fp);
@@ -281,8 +267,5 @@ errout_with_cp:
{
free(cp);
}
-errout_with_outstream:
- fclose(outstream);
-errout:
return err;
}
diff --git a/nuttx/netutils/thttpd/cgi-src/ssi.c b/nuttx/netutils/thttpd/cgi-src/ssi.c
index 042f43b65..befb7f769 100644
--- a/nuttx/netutils/thttpd/cgi-src/ssi.c
+++ b/nuttx/netutils/thttpd/cgi-src/ssi.c
@@ -78,7 +78,7 @@
* Private Function Prototypes
****************************************************************************/
-static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *filename);
+static void read_file(FILE *instream, char *vfilename, char *filename);
/****************************************************************************
* Private Data
@@ -96,12 +96,11 @@ static struct stat g_sb;
* Private Functions
****************************************************************************/
-static void internal_error(FILE *outstream, char *reason)
+static void internal_error(char *reason)
{
char *title = "500 Internal Error";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
<BODY><H2>%s</H2>\n\
Something unusual went wrong during a server-side-includes request:\n\
@@ -111,12 +110,11 @@ Something unusual went wrong during a server-side-includes request:\n\
</BODY></HTML>\n", title, title, reason);
}
-static void not_found(FILE *outstream, char *filename)
+static void not_found(char *filename)
{
char *title = "404 Not Found";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
<BODY><H2>%s</H2>\n\
The requested server-side-includes filename, %s,\n\
@@ -124,67 +122,62 @@ does not seem to exist.\n\
</BODY></HTML>\n", title, title, filename);
}
-static void not_found2(FILE *outstream, char *directive, char *tag, char *filename)
+static void not_found2(char *directive, char *tag, char *filename)
{
char *title = "Not Found";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
<HR><H2>%s</H2>\n\
The filename requested in a %s %s directive, %s,\n\
does not seem to exist.\n\
<HR>\n", title, directive, tag, filename);
}
-static void not_permitted(FILE *outstream, char *directive, char *tag, char *val)
+static void not_permitted(char *directive, char *tag, char *val)
{
char *title = "Not Permitted";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
<HR><H2>%s</H2>\n\
The filename requested in the %s %s=%s directive\n\
may not be fetched.\n\
<HR>\n", title, directive, tag, val);
}
-static void unknown_directive(FILE *outstream, char *filename, char *directive)
+static void unknown_directive(char *filename, char *directive)
{
char *title = "Unknown Directive";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
<HR><H2>%s</H2>\n\
The requested server-side-includes filename, %s,\n\
tried to use an unknown directive, %s.\n\
<HR>\n", title, filename, directive);
}
-static void unknown_tag(FILE *outstream, char *filename, char *directive, char *tag)
+static void unknown_tag(char *filename, char *directive, char *tag)
{
char *title = "Unknown Tag";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
<HR><H2>%s</H2>\n\
The requested server-side-includes filename, %s,\n\
tried to use the directive %s with an unknown tag, %s.\n\
<HR>\n", title, filename, directive, tag);
}
-static void unknown_value(FILE *outstream, char *filename, char *directive, char *tag, char *val)
+static void unknown_value(char *filename, char *directive, char *tag, char *val)
{
char *title = "Unknown Value";
- (void)fprintf(outstream,
-"\
+ (void)printf("\
<HR><H2>%s</H2>\n\
The requested server-side-includes filename, %s,\n\
tried to use the directive %s %s with an unknown value, %s.\n\
<HR>\n", title, filename, directive, tag, val);
}
-static int get_filename(FILE *outstream, char *vfilename, char *filename,
+static int get_filename(char *vfilename, char *filename,
char *directive, char *tag, char *val, char *fn,
int fnsize)
{
@@ -205,7 +198,7 @@ static int get_filename(FILE *outstream, char *vfilename, char *filename,
{
if (strstr(val, "../") != (char *)0)
{
- not_permitted(outstream, directive, tag, val);
+ not_permitted(directive, tag, val);
return -1;
}
@@ -228,7 +221,7 @@ static int get_filename(FILE *outstream, char *vfilename, char *filename,
{
if (val[0] == '/' || strstr(val, "../") != (char *)0)
{
- not_permitted(outstream, directive, tag, val);
+ not_permitted(directive, tag, val);
return -1;
}
if (fl + 1 + strlen(val) >= fnsize)
@@ -247,7 +240,7 @@ static int get_filename(FILE *outstream, char *vfilename, char *filename,
}
else
{
- unknown_tag(outstream, filename, directive, tag);
+ unknown_tag(filename, directive, tag);
return -1;
}
return 0;
@@ -353,7 +346,7 @@ static int check_filename(char *filename)
return 1;
}
-static void show_time(FILE *outstream, time_t t, int gmt)
+static void show_time(time_t t, int gmt)
{
struct tm *tmP;
@@ -368,40 +361,40 @@ static void show_time(FILE *outstream, time_t t, int gmt)
if (strftime(g_iobuffer2, BUFFER_SIZE, g_timeformat, tmP) > 0)
{
- (void)fputs(g_iobuffer2, outstream);
+ (void)puts(g_iobuffer2);
}
}
-static void show_size(FILE *outstream, off_t size)
+static void show_size(off_t size)
{
switch (g_sizefmt)
{
case SF_BYTES:
- (void)fprintf(outstream, "%ld", (long)size); /* spec says should have commas */
+ (void)printf("%ld", (long)size); /* spec says should have commas */
break;
case SF_ABBREV:
if (size < 1024)
{
- (void)fprintf(outstream, "%ld", (long)size);
+ (void)printf("%ld", (long)size);
}
else if (size < 1024)
{
- (void)fprintf(outstream, "%ldK", (long)size / 1024L);
+ (void)printf("%ldK", (long)size / 1024L);
}
else if (size < 1024 * 1024)
{
- (void)fprintf(outstream, "%ldM", (long)size / (1024L * 1024L));
+ (void)printf("%ldM", (long)size / (1024L * 1024L));
}
else
{
- (void)fprintf(outstream, "%ldG", (long)size / (1024L * 1024L * 1024L));
+ (void)printf("%ldG", (long)size / (1024L * 1024L * 1024L));
}
break;
}
}
-static void do_config(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+static void do_config(FILE *instream, char *vfilename, char *filename,
char *directive, char *tag, char *val)
{
/* The config directive controls various aspects of the file parsing. **
@@ -431,16 +424,16 @@ static void do_config(FILE *outstream, FILE *instream, char *vfilename, char *fi
}
else
{
- unknown_value(outstream, filename, directive, tag, val);
+ unknown_value(filename, directive, tag, val);
}
}
else
{
- unknown_tag(outstream, filename, directive, tag);
+ unknown_tag(filename, directive, tag);
}
}
-static void do_include(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+static void do_include(FILE *instream, char *vfilename, char *filename,
char *directive, char *tag, char *val)
{
FILE *instream2;
@@ -448,7 +441,7 @@ static void do_include(FILE *outstream, FILE *instream, char *vfilename, char *f
/* Inserts the text of another document into the parsed document. */
- ret = get_filename(outstream, vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
+ ret = get_filename(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
if (ret < 0)
{
return;
@@ -456,14 +449,14 @@ static void do_include(FILE *outstream, FILE *instream, char *vfilename, char *f
if (!check_filename(g_iobuffer1))
{
- not_permitted(outstream, directive, tag, g_iobuffer1);
+ not_permitted(directive, tag, g_iobuffer1);
return;
}
instream2 = fopen(g_iobuffer1, "r");
if (instream2 == (FILE *) 0)
{
- not_found2(outstream, directive, tag, g_iobuffer1);
+ not_found2(directive, tag, g_iobuffer1);
return;
}
@@ -498,11 +491,11 @@ static void do_include(FILE *outstream, FILE *instream, char *vfilename, char *f
}
}
- read_file(outstream, instream2, g_iobuffer2, g_iobuffer1);
+ read_file(instream2, g_iobuffer2, g_iobuffer1);
(void)fclose(instream2);
}
-static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+static void do_echo(FILE *instream, char *vfilename, char *filename,
char *directive, char *tag, char *val)
{
char *cp;
@@ -515,7 +508,7 @@ static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *file
if (strcmp(tag, "var") != 0)
{
- unknown_tag(outstream, filename, directive, tag);
+ unknown_tag(filename, directive, tag);
}
else
{
@@ -523,13 +516,13 @@ static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *file
{
/* The current filename. */
- (void)fputs(filename, outstream);
+ (void)puts(filename);
}
else if (strcmp(val, "DOCUMENT_URI") == 0)
{
/* The virtual path to this file (such as /~robm/foo.shtml). */
- (void)fputs(vfilename, outstream);
+ (void)puts(vfilename);
}
else if (strcmp(val, "QUERY_STRING_UNESCAPED") == 0)
{
@@ -538,7 +531,7 @@ static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *file
cp = getenv("QUERY_STRING");
if (cp != (char *)0)
{
- (void)fputs(cp, outstream);
+ (void)puts(cp);
}
}
else if (strcmp(val, "DATE_LOCAL") == 0)
@@ -548,7 +541,7 @@ static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *file
/* The current date, local time zone. */
gettimeofday(&tm, NULL);
- show_time(outstream, tm.tv_sec, 0);
+ show_time(tm.tv_sec, 0);
}
else if (strcmp(val, "DATE_GMT") == 0)
{
@@ -557,7 +550,7 @@ static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *file
/* Same as DATE_LOCAL but in Greenwich mean time. */
gettimeofday(&tm, NULL);
- show_time(outstream, t, 1);
+ show_time(t, 1);
}
else if (strcmp(val, "LAST_MODIFIED") == 0)
{
@@ -565,7 +558,7 @@ static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *file
if (fstat(fileno(instream), &g_sb) >= 0)
{
- show_time(outstream, g_sb.st_mtime, 0);
+ show_time(g_sb.st_mtime, 0);
}
}
else
@@ -575,24 +568,24 @@ static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *file
cp = getenv(val);
if (cp == (char *)0)
{
- unknown_value(outstream, filename, directive, tag, val);
+ unknown_value(filename, directive, tag, val);
}
else
{
- (void)fputs(cp, outstream);
+ (void)puts(cp);
}
}
}
}
-static void do_fsize(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+static void do_fsize(FILE *instream, char *vfilename, char *filename,
char *directive, char *tag, char *val)
{
int ret;
/* Prints the size of the specified file. */
- ret = get_filename(outstream, vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
+ ret = get_filename(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
if (ret < 0)
{
return;
@@ -600,21 +593,21 @@ static void do_fsize(FILE *outstream, FILE *instream, char *vfilename, char *fil
if (stat(g_iobuffer1, &g_sb) < 0)
{
- not_found2(outstream, directive, tag, g_iobuffer1);
+ not_found2(directive, tag, g_iobuffer1);
return;
}
- show_size(outstream, g_sb.st_size);
+ show_size(g_sb.st_size);
}
-static void do_flastmod(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+static void do_flastmod(FILE *instream, char *vfilename, char *filename,
char *directive, char *tag, char *val)
{
int ret;
/* Prints the last modification date of the specified file. */
- ret = get_filename(outstream, vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
+ ret = get_filename(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
if (ret < 0)
{
return;
@@ -622,13 +615,13 @@ static void do_flastmod(FILE *outstream, FILE *instream, char *vfilename, char *
if (stat(g_iobuffer1, &g_sb) < 0)
{
- not_found2(outstream, directive, tag, g_iobuffer1);
+ not_found2(directive, tag, g_iobuffer1);
return;
}
- show_time(outstream, g_sb.st_mtime, 0);
+ show_time(g_sb.st_mtime, 0);
}
-static void parse(FILE *outstream, FILE *instream, char *vfilename, char *filename, char *str)
+static void parse(FILE *instream, char *vfilename, char *filename, char *str)
{
char *directive;
char *cp;
@@ -695,7 +688,7 @@ static void parse(FILE *outstream, FILE *instream, char *vfilename, char *filena
}
else
{
- unknown_directive(outstream, filename, directive);
+ unknown_directive(filename, directive);
return;
}
@@ -703,7 +696,7 @@ static void parse(FILE *outstream, FILE *instream, char *vfilename, char *filena
{
if (i > 0)
{
- putc(' ', outstream);
+ putchar(' ');
}
val = strchr(g_tags[i], '=');
@@ -725,29 +718,29 @@ static void parse(FILE *outstream, FILE *instream, char *vfilename, char *filena
switch (dirn)
{
case DI_CONFIG:
- do_config(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ do_config(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_INCLUDE:
- do_include(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ do_include(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_ECHO:
- do_echo(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ do_echo(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_FSIZE:
- do_fsize(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ do_fsize(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_FLASTMOD:
- do_flastmod(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ do_flastmod(instream, vfilename, filename, directive, g_tags[i], val);
break;
}
}
}
-static void slurp(FILE *outstream, FILE *instream, char *vfilename, char *filename)
+static void slurp(FILE *instream, char *vfilename, char *filename)
{
int state;
int ich;
@@ -783,7 +776,7 @@ static void slurp(FILE *outstream, FILE *instream, char *vfilename, char *filena
if (ich == '>')
{
g_iobuffer1[i - 2] = '\0';
- parse(outstream, instream, vfilename, filename, g_iobuffer1);
+ parse(instream, vfilename, filename, g_iobuffer1);
return;
}
else if (ich != '-')
@@ -800,7 +793,7 @@ static void slurp(FILE *outstream, FILE *instream, char *vfilename, char *filena
}
}
-static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *filename)
+static void read_file(FILE *instream, char *vfilename, char *filename)
{
int ich;
int state;
@@ -831,7 +824,7 @@ static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *fi
else
{
state = ST_GROUND;
- putc('<', outstream);
+ putchar('<');
}
break;
@@ -844,7 +837,7 @@ static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *fi
else
{
state = ST_GROUND;
- (void)fputs("<!", outstream);
+ (void)puts("<!");
}
break;
@@ -857,26 +850,26 @@ static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *fi
else
{
state = ST_GROUND;
- (void)fputs("<!-", outstream);
+ (void)puts("<!-");
}
break;
case ST_MINUS2:
if (ich == '#')
{
- slurp(outstream, instream, vfilename, filename);
+ slurp(instream, vfilename, filename);
state = ST_GROUND;
continue;
}
else
{
state = ST_GROUND;
- (void)fputs("<!--", outstream);
+ (void)puts("<!--");
}
break;
}
- putc((char)ich, outstream);
+ putcchar((char)ich);
}
}
@@ -886,21 +879,12 @@ static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *fi
int main(int argc, char **argv)
{
- FILE *outstream;
FILE *instream;
char *script_name;
char *path_info;
char *path_translated;
int err = 0;
- outstream = fdopen(CONFIG_THTTPD_CGI_OUTFD, "w");
- if (!outstream)
- {
- fprintf(stderr, "fdopen failed: %d\n", errno);
- err = 1;
- goto errout;
- }
-
/* Default formats. */
(void)strcpy(g_timeformat, "%a %b %e %T %Z %Y");
@@ -908,16 +892,15 @@ int main(int argc, char **argv)
/* The MIME type has to be text/html. */
- (void)fputs("Content-type: text/html\n\n", outstream);
+ (voidfputs("Content-type: text/html\n\n");
/* Get the name that we were run as. */
script_name = getenv("SCRIPT_NAME");
if (!script_name)
{
- internal_error(outstream, "Couldn't get SCRIPT_NAME environment variable.");
- err = 2;
- goto errout_with_outstream;
+ internal_error("Couldn't get SCRIPT_NAME environment variable.");
+ return 1;
}
/* Append the PATH_INFO, if any, to get the full URL. */
@@ -931,9 +914,8 @@ int main(int argc, char **argv)
g_url = (char*)malloc(strlen(script_name) + strlen(path_info) + 1);
if (!g_url)
{
- internal_error(outstream, "Out of memory.");
- err = 3;
- goto errout_with_outstream;
+ internal_error("Out of memory.");
+ return 2;
}
(void)sprintf(g_url, "%s%s", script_name, path_info);
@@ -942,15 +924,15 @@ int main(int argc, char **argv)
path_translated = getenv("PATH_TRANSLATED");
if (!path_translated)
{
- internal_error(outstream, "Couldn't get PATH_TRANSLATED environment variable.");
- err = 4;
+ internal_error("Couldn't get PATH_TRANSLATED environment variable.");
+ err = 3;
goto errout_with_g_url;
}
if (!check_filename(path_translated))
{
- not_permitted(outstream, "initial", "PATH_TRANSLATED", path_translated);
- err = 5;
+ not_permitted("initial", "PATH_TRANSLATED", path_translated);
+ err = 4;
goto errout_with_g_url;
}
@@ -959,21 +941,18 @@ int main(int argc, char **argv)
instream = fopen(path_translated, "r");
if (!instream)
{
- not_found(outstream, path_translated);
- err = 6;
+ not_found(path_translated);
+ err = 5;
goto errout_with_g_url;
}
/* Read and handle the file. */
- read_file(outstream, instream, path_info, path_translated);
+ read_file(instream, path_info, path_translated);
(void)fclose(instream);
errout_with_g_url:
free(g_url);
-errout_with_outstream:
- fclose(outstream);
-errout:
return err;
}
diff --git a/nuttx/netutils/thttpd/config.h b/nuttx/netutils/thttpd/config.h
index 6ee5fa27d..c40510918 100644
--- a/nuttx/netutils/thttpd/config.h
+++ b/nuttx/netutils/thttpd/config.h
@@ -119,14 +119,6 @@
# define CONFIG_THTTPD_CGI_TIMELIMIT 0 /* No time limit */
#endif
-/* In NuttX, CGI cannot use stdout for output. Rather, it must use
- * the following file descriptor number.
- */
-
-#ifndef CONFIG_THTTPD_CGI_OUTFD
-# define CONFIG_THTTPD_CGI_OUTFD CONFIG_NFILE_DESCRIPTORS
-#endif
-
/* The default character set name to use with text MIME types. */
#ifndef CONFIG_THTTPD_CHARSET
diff --git a/nuttx/netutils/thttpd/fdwatch.c b/nuttx/netutils/thttpd/fdwatch.c
index 2f82fc19c..724631918 100644
--- a/nuttx/netutils/thttpd/fdwatch.c
+++ b/nuttx/netutils/thttpd/fdwatch.c
@@ -71,18 +71,9 @@
****************************************************************************/
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
-static long nwatches;
+static long nwatches = 0;
#endif
-static int *fd_rw;
-static void **fd_data;
-static struct pollfd *pollfds;
-static int *poll_pollndx;
-static int *poll_rfdidx;
-static int npoll_fds;
-static int nreturned;
-static int next_rfndx;
-
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@@ -97,87 +88,123 @@ static int next_rfndx;
/* Initialize the fdwatch data structures. Returns -1 on failure. */
-int fdwatch_initialize(void)
+struct fdwatch_s *fdwatch_initialize(int nfds)
{
+ struct fdwatch_s *fw;
int i;
+ /* Allocate the fdwatch data structure */
+
+ fw = (struct fdwatch_s*)zalloc(sizeof(struct fdwatch_s));
+ if (!fw)
+ {
+ ndbg("Failed to allocate fdwatch\n");
+ return NULL;
+ }
+
/* Initialize the fdwatch data structures. */
-#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
- nwatches = 0;
-#endif
+ fw->nfds = nfds;
- fd_rw = (int *)malloc(sizeof(int) * CONFIG_NSOCKET_DESCRIPTORS);
- if (!fd_rw)
+ fw->fd_rw = (int*)malloc(sizeof(int) * nfds);
+ if (!fw->fd_rw)
{
- goto errout;
+ goto errout_with_allocations;
}
- fd_data = (void **)malloc(sizeof(void*) * CONFIG_NSOCKET_DESCRIPTORS);
- if (!fd_data)
+ fw->fd_data = (void**)malloc(sizeof(void*) * nfds);
+ if (!fw->fd_data)
{
- goto errout_with_fd_rw;
+ goto errout_with_allocations;
}
- for (i = 0; i < CONFIG_NSOCKET_DESCRIPTORS; ++i)
+ for (i = 0; i < nfds; ++i)
{
- fd_rw[i] = -1;
+ fw->fd_rw[i] = -1;
}
- pollfds = (struct pollfd *)malloc(sizeof(struct pollfd) * CONFIG_NSOCKET_DESCRIPTORS);
- if (!pollfds)
+ fw->pollfds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds);
+ if (!fw->pollfds)
{
- goto errout_with_fd_data;
+ goto errout_with_allocations;
}
- poll_pollndx = (int *)malloc(sizeof(int) * CONFIG_NSOCKET_DESCRIPTORS);
- if (!poll_pollndx)
+ fw->poll_pollndx = (int*)malloc(sizeof(int) * nfds);
+ if (!fw->poll_pollndx)
{
- goto errout_with_pollfds;
+ goto errout_with_allocations;
}
- poll_rfdidx = (int *)malloc(sizeof(int) * CONFIG_NSOCKET_DESCRIPTORS);
- if (!poll_rfdidx)
+ fw->poll_rfdidx = (int*)malloc(sizeof(int) * nfds);
+ if (!fw->poll_rfdidx)
{
- goto errout_with_poll_pollndx;
+ goto errout_with_allocations;
}
- for (i = 0; i < CONFIG_NSOCKET_DESCRIPTORS; i++)
+ for (i = 0; i < nfds; i++)
{
- pollfds[i].fd = poll_pollndx[i] = -1;
+ fw->pollfds[i].fd = fw->poll_pollndx[i] = -1;
}
- return OK;
-
-errout_with_poll_pollndx:
- free(poll_pollndx);
-errout_with_pollfds:
- free(pollfds);
-errout_with_fd_data:
- free(fd_data);
-errout_with_fd_rw:
- free(fd_rw);
-errout:
- return ERROR;
+ return fw;
+
+errout_with_allocations:
+ fdwatch_uninitialize(fw);
+ return NULL;
+}
+
+/* Uninitialize the fwdatch data structure */
+
+void fdwatch_uninitialize(struct fdwatch_s *fw)
+{
+ if (fw)
+ {
+ if (fw->fd_rw)
+ {
+ free(fw->fd_rw);
+ }
+
+ if (fw->fd_data)
+ {
+ free(fw->fd_data);
+ }
+
+ if (fw->pollfds)
+ {
+ free(fw->pollfds);
+ }
+
+ if (fw->poll_pollndx)
+ {
+ free(fw->poll_pollndx);
+ }
+
+ if (fw->poll_rfdidx)
+ {
+ free(fw->poll_rfdidx);
+ }
+
+ free(fw);
+ }
}
/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */
-void fdwatch_add_fd(int fd, void *client_data, int rw)
+void fdwatch_add_fd(struct fdwatch_s *fw, int fd, void *client_data, int rw)
{
int fdndx;
#ifdef CONFIG_DEBUG
if (fd < CONFIG_NFILE_DESCRIPTORS ||
- fd >= CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS ||
- fd_rw[fd-CONFIG_NFILE_DESCRIPTORS] != -1)
+ fd >= CONFIG_NFILE_DESCRIPTORS+fw->nfds ||
+ fw->fd_rw[fd-CONFIG_NFILE_DESCRIPTORS] != -1)
{
ndbg("Received bad fd (%d)\n", fd);
return;
}
#endif
- if (npoll_fds >= CONFIG_NSOCKET_DESCRIPTORS)
+ if (fw->npoll_fds >= fw->nfds)
{
ndbg("too many fds\n");
return;
@@ -189,31 +216,31 @@ void fdwatch_add_fd(int fd, void *client_data, int rw)
/* Save the new fd at the end of the list */
- pollfds[npoll_fds].fd = fd;
+ fw->pollfds[fw->npoll_fds].fd = fd;
switch (rw)
{
default:
case FDW_READ:
- pollfds[npoll_fds].events = POLLIN;
+ fw->pollfds[fw->npoll_fds].events = POLLIN;
break;
case FDW_WRITE:
- pollfds[npoll_fds].events = POLLOUT;
+ fw->pollfds[fw->npoll_fds].events = POLLOUT;
break;
}
/* Save the new index and increment the cound of watched descriptors */
- poll_pollndx[fdndx] = npoll_fds;
- npoll_fds++;
+ fw->poll_pollndx[fdndx] = fw->npoll_fds;
+ fw->npoll_fds++;
- fd_rw[fdndx] = rw;
- fd_data[fdndx] = client_data;
+ fw->fd_rw[fdndx] = rw;
+ fw->fd_data[fdndx] = client_data;
}
/* Remove a descriptor from the watch list. */
-void fdwatch_del_fd(int fd)
+void fdwatch_del_fd(struct fdwatch_s *fw, int fd)
{
int fdndx;
int pollndx;
@@ -221,8 +248,8 @@ void fdwatch_del_fd(int fd)
#ifdef CONFIG_DEBUG
if (fd < CONFIG_NFILE_DESCRIPTORS ||
- fd >= CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS ||
- fd_rw[fd-CONFIG_NFILE_DESCRIPTORS] == -1)
+ fd >= CONFIG_NFILE_DESCRIPTORS+fw->nfds ||
+ fw->fd_rw[fd-CONFIG_NFILE_DESCRIPTORS] == -1)
{
ndbg("Received bad fd: %d\n", fd);
return;
@@ -234,10 +261,10 @@ void fdwatch_del_fd(int fd)
*/
fdndx = fd-CONFIG_NFILE_DESCRIPTORS;
- pollndx = poll_pollndx[fdndx];
+ pollndx = fw->poll_pollndx[fdndx];
#ifdef CONFIG_DEBUG
- if (pollndx < 0 || pollndx >= CONFIG_NSOCKET_DESCRIPTORS)
+ if (pollndx < 0 || pollndx >= fw->nfds)
{
ndbg("Bad poll index: %d\n", pollndx);
return;
@@ -246,20 +273,20 @@ void fdwatch_del_fd(int fd)
/* Decrement the number of fds in the poll table */
- npoll_fds--;
+ fw->npoll_fds--;
/* Replace the deleted one with the one at the the end
* of the list.
*/
- tmpndx = pollfds[pollndx].fd - CONFIG_NFILE_DESCRIPTORS;
- pollfds[pollndx] = pollfds[npoll_fds];
- poll_pollndx[tmpndx] = poll_pollndx[fdndx];;
- pollfds[npoll_fds].fd = -1;
- poll_pollndx[fdndx] = -1;
+ tmpndx = fw->pollfds[pollndx].fd - CONFIG_NFILE_DESCRIPTORS;
+ fw->pollfds[pollndx] = fw->pollfds[fw->npoll_fds];
+ fw->poll_pollndx[tmpndx] = fw->poll_pollndx[fdndx];;
+ fw->pollfds[fw->npoll_fds].fd = -1;
+ fw->poll_pollndx[fdndx] = -1;
- fd_rw[fdndx] = -1;
- fd_data[fdndx] = NULL;
+ fw->fd_rw[fdndx] = -1;
+ fw->fd_data[fdndx] = NULL;
}
/* Do the watch. Return value is the number of descriptors that are ready,
@@ -267,7 +294,7 @@ void fdwatch_del_fd(int fd)
* wait indefinitely.
*/
-int fdwatch(long timeout_msecs)
+int fdwatch(struct fdwatch_s *fw, long timeout_msecs)
{
int rfndx;
int ret;
@@ -277,18 +304,18 @@ int fdwatch(long timeout_msecs)
nwatches++;
#endif
- ret = poll(pollfds, npoll_fds, (int)timeout_msecs);
+ ret = poll(fw->pollfds, fw->npoll_fds, (int)timeout_msecs);
if (ret <= 0)
{
return ret;
}
rfndx = 0;
- for (i = 0; i < npoll_fds; i++)
+ for (i = 0; i < fw->npoll_fds; i++)
{
- if (pollfds[i].revents & (POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL))
+ if (fw->pollfds[i].revents & (POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL))
{
- poll_rfdidx[rfndx++] = pollfds[i].fd;
+ fw->poll_rfdidx[rfndx++] = fw->pollfds[i].fd;
if (rfndx == ret)
{
break;
@@ -296,21 +323,20 @@ int fdwatch(long timeout_msecs)
}
}
- next_rfndx = 0;
return rfndx;
}
/* Check if a descriptor was ready. */
-int fdwatch_check_fd(int fd)
+int fdwatch_check_fd(struct fdwatch_s *fw, int fd)
{
int fdndx;
int pollndx;
#ifdef CONFIG_DEBUG
if (fd < CONFIG_NFILE_DESCRIPTORS ||
- fd >= CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS ||
- fd_rw[fd-CONFIG_NFILE_DESCRIPTORS] == -1)
+ fd >= CONFIG_NFILE_DESCRIPTORS+fw->nfds ||
+ fw->fd_rw[fd-CONFIG_NFILE_DESCRIPTORS] == -1)
{
ndbg("Bad fd: %d\n", fd);
return 0;
@@ -322,28 +348,28 @@ int fdwatch_check_fd(int fd)
*/
fdndx = fd-CONFIG_NFILE_DESCRIPTORS;
- pollndx = poll_pollndx[fdndx];
+ pollndx = fw->poll_pollndx[fdndx];
#ifdef CONFIG_DEBUG
- if (pollndx < 0 || pollndx >= CONFIG_NSOCKET_DESCRIPTORS)
+ if (pollndx < 0 || pollndx >= fw->nfds)
{
ndbg("Bad poll index: %d\n", pollndx);
return 0;
}
#endif
- if (pollfds[pollndx].revents & POLLERR)
+ if (fw->pollfds[pollndx].revents & POLLERR)
{
return 0;
}
- switch (fd_rw[fdndx])
+ switch (fw->fd_rw[fdndx])
{
case FDW_READ:
- return pollfds[pollndx].revents & (POLLIN | POLLHUP | POLLNVAL);
+ return fw->pollfds[pollndx].revents & (POLLIN | POLLHUP | POLLNVAL);
case FDW_WRITE:
- return pollfds[pollndx].revents & (POLLOUT | POLLHUP | POLLNVAL);
+ return fw->pollfds[pollndx].revents & (POLLOUT | POLLHUP | POLLNVAL);
default:
break;
@@ -351,40 +377,33 @@ int fdwatch_check_fd(int fd)
return 0;
}
-void *fdwatch_get_next_client_data(void)
+void *fdwatch_get_next_client_data(struct fdwatch_s *fw)
{
int rfndx;
int fdndx;
int fd;
- if (next_rfndx >= nreturned)
- {
- return (void*)-1;
- }
-
- rfndx = next_rfndx++;
-
#ifdef CONFIG_DEBUG
- if (rfndx < 0 || rfndx >= CONFIG_NSOCKET_DESCRIPTORS)
+ if (rfndx < 0 || rfndx >= fw->nfds)
{
ndbg("Bad rfndx: %d\n", rfndx);
return NULL;
}
#endif
- fd = poll_rfdidx[rfndx];
+ fd = fw->poll_rfdidx[rfndx];
fdndx = fd-CONFIG_NFILE_DESCRIPTORS;
- if (fdndx < 0 || fdndx >= CONFIG_NSOCKET_DESCRIPTORS)
+ if (fdndx < 0 || fdndx >= fw->nfds)
{
return NULL;
}
- return fd_data[fdndx];
+ return fw->fd_data[fdndx];
}
/* Generate debugging statistics ndbg message. */
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
-void fdwatch_logstats(long secs)
+void fdwatch_logstats(struct fdwatch_s *fw, long secs)
{
if (secs > 0)
ndbg("fdwatch - %ld polls (%g/sec)\n", nwatches, (float)nwatches / secs);
diff --git a/nuttx/netutils/thttpd/fdwatch.h b/nuttx/netutils/thttpd/fdwatch.h
index cf6bd551e..65a6704ce 100644
--- a/nuttx/netutils/thttpd/fdwatch.h
+++ b/nuttx/netutils/thttpd/fdwatch.h
@@ -40,6 +40,10 @@
#ifndef __NETUTILS_THTTPD_FDWATCH_H
#define __NETUTILS_THTTPD_FDWATCH_H
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
#define FDW_READ 0
#define FDW_WRITE 1
@@ -47,39 +51,62 @@
# define INFTIM -1
#endif
-/* initialize the fdwatch data structures. Returns -1 on failure. */
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct fdwatch_s
+{
+ int *fd_rw;
+ void **fd_data;
+ struct pollfd *pollfds;
+ int *poll_pollndx;
+ int *poll_rfdidx;
+ int nfds;
+ int npoll_fds;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* Initialize the fdwatch data structures. Returns NULL on failure. */
+
+extern struct fdwatch_s *fdwatch_initialize(int nfds);
+
+/* Uninitialize the fwdatch data structure */
-extern int fdwatch_initialize(void);
+extern void fdwatch_uninitialize(struct fdwatch_s *fw);
/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */
-extern void fdwatch_add_fd(int fd, void *client_data, int rw);
+extern void fdwatch_add_fd(struct fdwatch_s *fw, int fd, void *client_data, int rw);
/* Delete a descriptor from the watch list. */
-extern void fdwatch_del_fd(int fd);
+extern void fdwatch_del_fd(struct fdwatch_s *fw, int fd);
/* Do the watch. Return value is the number of descriptors that are ready,
* or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means
* wait indefinitely.
*/
-extern int fdwatch(long timeout_msecs);
+extern int fdwatch(struct fdwatch_s *fw, long timeout_msecs);
/* Check if a descriptor was ready. */
-extern int fdwatch_check_fd(int fd);
+extern int fdwatch_check_fd(struct fdwatch_s *fw, int fd);
/* Get the client data for the next returned event. Returns -1 when there
* are no more events.
*/
-extern void *fdwatch_get_next_client_data(void);
+extern void *fdwatch_get_next_client_data(struct fdwatch_s *fw);
/* Generate debugging statistics syslog message. */
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
-extern void fdwatch_logstats(long secs);
+extern void fdwatch_logstats(struct fdwatch_s *fw, long secs);
#endif
#endif /* __NETUTILS_THTTPD_FDWATCH_H */
diff --git a/nuttx/netutils/thttpd/libhttpd.c b/nuttx/netutils/thttpd/libhttpd.c
index ed49a4aee..b9b2508ba 100644
--- a/nuttx/netutils/thttpd/libhttpd.c
+++ b/nuttx/netutils/thttpd/libhttpd.c
@@ -65,6 +65,7 @@
#include "libhttpd.h"
#include "timers.h"
#include "tdate_parse.h"
+#include "fdwatch.h"
#ifdef CONFIG_THTTPD
@@ -107,6 +108,29 @@ extern char *crypt(const char *key, const char *setting);
#endif
/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#ifdef CONFIG_THTTPD_CGI_PATTERN
+enum cgi_outbuffer_e
+{
+ CGI_OUTBUFFER_READHEADER = 0,
+ CGI_OUTBUFFER_HEADERREAD,
+ CGI_OUTBUFFER_HEADERSENT,
+ CGI_OUTBUFFER_READDATA,
+ CGI_OUTBUFFER_DONE,
+};
+
+struct cgi_outbuffer_s
+{
+ enum cgi_outbuffer_e state;
+ char *buffer;
+ size_t size;
+ size_t len;
+};
+#endif
+
+/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@@ -166,10 +190,10 @@ static char *hostname_map(char *hostname);
#ifdef CONFIG_THTTPD_CGI_PATTERN
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(int argc, char **argv);
+static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer);
+static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
+ struct cgi_outbuffer_s *hdr);
+static int cgi_child(int argc, char **argv);
static int cgi(httpd_conn *hc);
#endif
@@ -198,37 +222,6 @@ static pid_t main_thread;
static int str_alloc_count = 0;
static size_t str_alloc_size = 0;
-/* Base-64 decoding. This represents binary data as printable ASCII
- * characters. Three 8-bit binary bytes are turned into four 6-bit
- * values, like so:
- *
- * [11111111][22222222][33333333] -> [111111][112222][222233][333333]
- *
- * Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
- */
-
-#ifdef CONFIG_THTTPD_AUTH_FILE
-static const int b64_decode_table[256] =
-{
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00-0F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10-1F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20-2F */
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 30-3F */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40-4F */
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50-5F */
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60-6F */
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 70-7F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80-8F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90-9F */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0-AF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0-BF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0-CF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0-DF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0-EF */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* F0-FF */
-};
-#endif
-
/* Include MIME encodings and types */
#include "mime_types.h"
@@ -313,7 +306,6 @@ static int initialize_listen_socket(httpd_sockaddr *saP)
ndbg("socket %s: %d\n", httpd_ntoa(saP), errno);
return -1;
}
- (void)fcntl(listen_fd, F_SETFD, 1);
/* Allow reuse of local addresses. */
@@ -590,7 +582,7 @@ static int send_err_file(httpd_conn *hc, int status, char *title, char *extrahea
return 1;
}
-#endif /* CONFIG_THTTPD_ERROR_DIRECTORY */
+#endif
#ifdef CONFIG_THTTPD_AUTH_FILE
static void send_authenticate(httpd_conn *hc, char *realm)
@@ -613,6 +605,52 @@ static void send_authenticate(httpd_conn *hc, char *realm)
}
}
+/* Base-64 decoding. This represents binary data as printable ASCII
+ * characters. Three 8-bit binary bytes are turned into four 6-bit
+ * values, like so:
+ *
+ * [11111111][22222222][33333333] -> [111111][112222][222233][333333]
+ *
+ * Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
+ */
+
+static inline b64_charmap(char *ch)
+{
+ char bin6;
+
+ bin6 = -1;
+ if (c == 0x20) /* ' ' */
+ {
+ bin6 = 62; /* ' ' maps to 62 */
+ }
+ elseif (c == 0x2f) /* '/' */
+ {
+ bin6 = 63; /* '/' maps to 63 */
+ }
+ else if (c >= 0x30) /* '0' */
+ {
+ else if (c <= 0x39) /* '9' */
+ {
+ bin6 = (c - 0x39 + 52); /* '0'-'9' maps to 52-61 */
+ }
+ else if (c >= 0x41) /* 'A' */
+ {
+ if (c <= 0x5a) /* 'Z' */
+ {
+ bin6 = c - 0x41; /* 'A'-'Z' map to 0 - 25 */
+ }
+ else if (c >= 0x61) /* 'a' */
+ {
+ if (c <= 0x7a) /* 'z' */
+ {
+ bin6 = c - 0x61 + 26; /* 'a'-'z' map to 0 - 25 */
+ }
+ }
+ }
+ }
+
+}
+
/* Do base-64 decoding on a string. Ignore any non-base64 bytes.
* Return the actual number of bytes generated. The decoded size will
* be at most 3/4 the size of the encoded, and may be smaller if there
@@ -622,45 +660,46 @@ static void send_authenticate(httpd_conn *hc, char *realm)
static int b64_decode(const char *str, unsigned char *space, int size)
{
const char *cp;
- int space_idx, phase;
- int d, prev_d = 0;
- unsigned char c;
+ int ndx;
+ int phase;
+ int decoded;
+ int prev_decoded = 0;
+ unsigned char packed;
- space_idx = 0;
+ ndx = 0;
phase = 0;
- for (cp = str; *cp != '\0'; ++cp)
+ for (cp = str; *cp != '\0', ndx < size; cp++)
{
- d = b64_decode_table[(int)*cp];
- if (d != -1)
+ /* Decode base-64 */
+
+ decoded = b64_charmap(*cp); /* Decode ASCII representations to 6-bit binary */
+ if (decoded != -1)
{
switch (phase)
{
case 0:
- ++phase;
+ phase = 1;
break;
+
case 1:
- c = ((prev_d << 2) | ((d & 0x30) >> 4));
- if (space_idx < size)
- space[space_idx++] = c;
- ++phase;
+ space[ndx++] = ((prev_decoded << 2) | ((decoded & 0x30) >> 4));
+ phase = 2;
break;
+
case 2:
- c = (((prev_d & 0xf) << 4) | ((d & 0x3c) >> 2));
- if (space_idx < size)
- space[space_idx++] = c;
- ++phase;
+ space[ndx++] =(((prev_decoded & 0xf) << 4) | ((decoded & 0x3packed) >> 2));
+ phase = 3;
break;
+
case 3:
- c = (((prev_d & 0x03) << 6) | d);
- if (space_idx < size)
- space[space_idx++] = c;
+ space[ndx++] =(((prev_decoded & 0x03) << 6) | decoded);
phase = 0;
break;
}
- prev_d = d;
+ prev_decoded = decoded;
}
}
- return space_idx;
+ return ndx;
}
/* Returns -1 == unauthorized, 0 == no auth file, 1 = authorized. */
@@ -901,19 +940,19 @@ static void send_dirredirect(httpd_conn *hc)
send_response(hc, 302, err302title, header, err302form, location);
}
-static int hexit(char c)
+static int hexit(char nibble)
{
- if (c >= '0' && c <= '9')
+ if (nibble >= '0' && nibble <= '9')
{
- return c - '0';
+ return nibble - '0';
}
- else if (c >= 'a' && c <= 'f')
+ else if (nibble >= 'a' && nibble <= 'f')
{
- return c - 'a' + 10;
+ return nibble - 'a' + 10;
}
- else if (c >= 'A' && c <= 'F')
+ else if (nibble >= 'A' && nibble <= 'F')
{
- return c - 'A' + 10;
+ return nibble - 'A' + 10;
}
return 0;
}
@@ -990,7 +1029,7 @@ static intCONFIG_THTTPD_TILDE_MAP1(httpd_conn *hc)
(void)strcat(hc->expnfilename, temp);
return 1;
}
-#endif /*CONFIG_THTTPD_TILDE_MAP1 */
+#endif
/* Map a ~username/whatever URL into <user's homedir>/<postfix>. */
@@ -1057,7 +1096,7 @@ static intCONFIG_THTTPD_TILDE_MAP2(httpd_conn *hc)
hc->tildemapped = TRUE;
return 1;
}
-#endif /*CONFIG_THTTPD_TILDE_MAP2 */
+#endif
/* Virtual host mapping. */
@@ -1073,7 +1112,7 @@ static int vhost_map(httpd_conn *hc)
#ifdef VHOST_DIRLEVELS
int i;
char *cp2;
-#endif /* VHOST_DIRLEVELS */
+#endif
/* Figure out the virtual hostname. */
@@ -2186,80 +2225,74 @@ static FAR char **make_argp(httpd_conn *hc)
}
#endif
-/* This routine is used only for POST requests. It reads the data
- * from the request and sends it to the child process. The only reason
- * we need to do it this way instead of just letting the child read
- * directly is that we have already read part of the data into our
- * buffer.
+/* Data is available from the client socket. This routine is used only for POST
+ * requests. It reads the data from the client and sends it to the child thread.
*/
#ifdef CONFIG_THTTPD_CGI_PATTERN
-static void cgi_interpose_input(httpd_conn *hc, int wfd)
+static inline int cgi_interpose_input(httpd_conn *hc, int wfd, char *buffer)
{
- size_t c;
- ssize_t r;
- char buf[1024];
+ size_t nbytes;
+ ssize_t nbytes_read;
+ ssize_t nbytes_written;
- c = hc->read_idx - hc->checked_idx;
- if (c > 0)
+ nbytes = hc->read_idx - hc->checked_idx;
+ if (nbytes > 0)
{
- if (httpd_write(wfd, &(hc->read_buf[hc->checked_idx]), c) != c)
+ if (httpd_write(wfd, &(hc->read_buf[hc->checked_idx]), nbytes) != nbytes)
{
- return;
+ return 1;
}
}
- while (c < hc->contentlength)
+
+ if (nbytes < hc->contentlength)
{
- r = read(hc->conn_fd, buf, MIN(sizeof(buf), hc->contentlength - c));
- if (r < 0 && (errno == EINTR || errno == EAGAIN))
- {
- sleep(1);
- continue;
- }
- if (r <= 0)
+ do
{
- return;
+ nbytes_read = read(hc->conn_fd, buffer, MIN(sizeof(buffer), hc->contentlength - nbytes));
+ if (nbytes_read < 0)
+ {
+ if (errno != EINTR)
+ {
+ return 1;
+ }
+ }
}
+ while (nbytes_read < 0);
- if (httpd_write(wfd, buf, r) != r)
+ if (nbytes_read > 0)
{
- return;
+ nbytes_written = httpd_write(wfd, buffer, nbytes_read);
+ if (nbytes_written != nbytes_read)
+ {
+ return 1;
+ }
}
-
- c += r;
}
- post_post_garbage_hack(hc);
-}
-#endif
-
-/* Special hack to deal with broken browsers that send a LF or CRLF
- * after POST data, causing TCP resets - we just read and discard up
- * to 2 bytes. Unfortunately this doesn't fix the problem for CGIs
- * which avoid the interposer process due to their POST data being
- * short. Creating an interposer process for all POST CGIs is
- * unacceptably expensive. The eventual fix will come when interposing
- * gets integrated into the main loop as a tasklet instead of a process.
- */
-#ifdef CONFIG_THTTPD_CGI_PATTERN
-static void post_post_garbage_hack(httpd_conn *hc)
-{
- char buf[2];
+ if (nbytes >= hc->contentlength)
+ {
+ /* Special hack to deal with broken browsers that send a LF or CRLF
+ * after POST data, causing TCP resets - we just read and discard up
+ * to 2 bytes. Unfortunately this doesn't fix the problem for CGIs
+ * which avoid the interposer process due to their POST data being
+ * short. Creating an interposer process for all POST CGIs is
+ * unacceptably expensive. The eventual fix will come when interposing
+ * gets integrated into the main loop as a tasklet instead of a process.
+ */
- /* If we are in a sub-process, turn on no-delay mode in case we previously
- * cleared it.
- */
+ /* Turn on no-delay mode in case we previously cleared it. */
- if (main_thread != getpid())
- {
httpd_set_ndelay(hc->conn_fd);
- }
- /* And read up to 2 bytes. */
+ /* And read up to 2 bytes. */
- (void)read(hc->conn_fd, buf, sizeof(buf));
+ (void)read(hc->conn_fd, buffer, sizeof(buffer));
+ return 1;
+ }
+ return 0;
}
-#endif /* CONFIG_THTTPD_CGI_PATTERN */
+#endif
/* This routine is used for parsed-header CGIs. The idea here is that the
* CGI can return special headers such as "Status:" and "Location:" which
@@ -2270,12 +2303,10 @@ static void post_post_garbage_hack(httpd_conn *hc)
*/
#ifdef CONFIG_THTTPD_CGI_PATTERN
-static void cgi_interpose_output(httpd_conn *hc, int rfd)
+static inline int cgi_interpose_output(httpd_conn *hc, int rfd, char *inbuffer,
+ struct cgi_outbuffer_s *hdr)
{
- int r;
- char buf[1024];
- size_t headers_size, headers_len;
- char *headers;
+ ssize_t nbytes_read;
char *br;
int status;
char *title;
@@ -2287,203 +2318,251 @@ static void cgi_interpose_output(httpd_conn *hc, int rfd)
httpd_clear_ndelay(hc->conn_fd);
- /* Slurp in all headers. */
+ /* Loop while there are things we can do without waiting for more input */
- headers_size = 0;
- httpd_realloc_str(&headers, &headers_size, 500);
- headers_len = 0;
- for (;;)
+ switch (hdr->state)
{
- r = read(rfd, buf, sizeof(buf));
- if (r < 0 && (errno == EINTR || errno == EAGAIN))
+ case CGI_OUTBUFFER_READHEADER:
{
- sleep(1);
- continue;
- }
+ /* Slurp in all headers as they become available from the CGI program. */
- if (r <= 0)
- {
- br = &(headers[headers_len]);
- break;
- }
+ do
+ {
+ /* Read until we successfully read data or until an error occurs.
+ * EAGAIN is not an error, but it is still cause to return.
+ */
- httpd_realloc_str(&headers, &headers_size, headers_len + r);
- (void)memmove(&(headers[headers_len]), buf, r);
- headers_len += r;
- headers[headers_len] = '\0';
+ nbytes_read = read(rfd, inbuffer, sizeof(inbuffer));
+ if (nbytes_read < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (errno != EAGAIN)
+ {
+ ndbg("read: %d\n", errno);
+ }
+ return 1;
+ }
+ }
+ }
+ while (nbytes_read < 0);
- if ((br = strstr(headers, "\015\012\015\012")) != NULL ||
- (br = strstr(headers, "\012\012")) != NULL)
- {
- break;
+ /* Check for end-of-file */
+
+ if (nbytes_read <= 0)
+ {
+ br = &(hdr->buffer[hdr->len]);
+ hdr->state = CGI_OUTBUFFER_HEADERREAD;
+ }
+ else
+ {
+ /* Accumulate more header data */
+
+ httpd_realloc_str(&hdr->buffer, &hdr->size, hdr->len + nbytes_read);
+ (void)memcpy(&(hdr->buffer[hdr->len]), inbuffer, nbytes_read);
+ hdr->len += nbytes_read;
+ hdr->buffer[hdr->len] = '\0';
+
+ /* Check for end of header */
+
+ if ((br = strstr(hdr->buffer, "\015\012\015\012")) != NULL ||
+ (br = strstr(hdr->buffer, "\012\012")) != NULL)
+ {
+ hdr->state = CGI_OUTBUFFER_HEADERREAD;
+ }
+ else
+ {
+ /* Return. We will be called again when more data is available
+ * on the pipe.
+ */
+
+ return 0;
+ }
+ }
}
- }
+ break;
- /* If there were no headers, bail. */
+ case CGI_OUTBUFFER_HEADERREAD:
+ {
+ /* If there were no headers, bail. */
- if (headers[0] == '\0')
- {
- return;
- }
+ if (hdr->buffer[0] == '\0')
+ {
+ hdr->state = CGI_OUTBUFFER_DONE;
+ return 1;
+ }
- /* Figure out the status. Look for a Status: or Location: header; else if
- * there's an HTTP header line, get it from there; else default to 200.
- */
+ /* Figure out the status. Look for a Status: or Location: header; else if
+ * there's an HTTP header line, get it from there; else default to 200.
+ */
- status = 200;
- if (strncmp(headers, "HTTP/", 5) == 0)
- {
- cp = headers;
- cp += strcspn(cp, " \t");
- status = atoi(cp);
- }
+ status = 200;
+ if (strncmp(hdr->buffer, "HTTP/", 5) == 0)
+ {
+ cp = hdr->buffer;
+ cp += strcspn(cp, " \t");
+ status = atoi(cp);
+ }
- if ((cp = strstr(headers, "Status:")) != (char *)0 &&
- cp < br && (cp == headers || *(cp - 1) == '\012'))
- {
- cp += 7;
- cp += strspn(cp, " \t");
- status = atoi(cp);
- }
+ if ((cp = strstr(hdr->buffer, "Status:")) != (char *)0 &&
+ cp < br && (cp == hdr->buffer || *(cp - 1) == '\012'))
+ {
+ cp += 7;
+ cp += strspn(cp, " \t");
+ status = atoi(cp);
+ }
- if ((cp = strstr(headers, "Location:")) != (char *)0 &&
- cp < br && (cp == headers || *(cp - 1) == '\012'))
- {
- status = 302;
- }
+ if ((cp = strstr(hdr->buffer, "Location:")) != (char *)0 &&
+ cp < br && (cp == hdr->buffer || *(cp - 1) == '\012'))
+ {
+ status = 302;
+ }
- /* Write the status line. */
+ /* Write the status line. */
- switch (status)
- {
- case 200:
- title = ok200title;
- break;
+ switch (status)
+ {
+ case 200:
+ title = ok200title;
+ break;
- case 302:
- title = err302title;
- break;
+ case 302:
+ title = err302title;
+ break;
- case 304:
- title = err304title;
- break;
+ case 304:
+ title = err304title;
+ break;
- case 400:
- title = httpd_err400title;
- break;
+ case 400:
+ title = httpd_err400title;
+ break;
#ifdef CONFIG_THTTPD_AUTH_FILE
- case 401:
- title = err401title;
- break;
-#endif /* CONFIG_THTTPD_AUTH_FILE */
+ case 401:
+ title = err401title;
+ break;
+#endif
- case 403:
- title = err403title;
- break;
+ case 403:
+ title = err403title;
+ break;
- case 404:
- title = err404title;
- break;
+ case 404:
+ title = err404title;
+ break;
- case 408:
- title = httpd_err408title;
- break;
+ case 408:
+ title = httpd_err408title;
+ break;
- case 500:
- title = err500title;
- break;
+ case 500:
+ title = err500title;
+ break;
- case 501:
- title = err501title;
- break;
+ case 501:
+ title = err501title;
+ break;
- case 503:
- title = httpd_err503title;
- break;
+ case 503:
+ title = httpd_err503title;
+ break;
- default:
- title = "Something";
- break;
- }
+ default:
+ title = "Something";
+ break;
+ }
- (void)snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\015\012", status, title);
- (void)httpd_write(hc->conn_fd, buf, strlen(buf));
+ (void)snprintf(inbuffer, sizeof(inbuffer), "HTTP/1.0 %d %s\015\012", status, title);
+ (void)httpd_write(hc->conn_fd, inbuffer, strlen(inbuffer));
- /* Write the saved headers. */
+ /* Write the saved hdr->buffer. */
- (void)httpd_write(hc->conn_fd, headers, headers_len);
+ (void)httpd_write(hc->conn_fd, hdr->buffer, hdr->len);
+ }
- /* Echo the rest of the output. */
+ /* Then set up to read the data following the header from the CGI program.
+ * We return here; we will be called again when data is available on the pipe.
+ */
- for (;;)
- {
- r = read(rfd, buf, sizeof(buf));
- if (r < 0 && (errno == EINTR || errno == EAGAIN))
- {
- sleep(1);
- continue;
- }
+ hdr->state = CGI_OUTBUFFER_READDATA;
+ return 0;
- if (r <= 0)
+ case CGI_OUTBUFFER_READDATA:
{
- break;
- }
+ /* Read data from the pipe. */
- if (httpd_write(hc->conn_fd, buf, r) != r)
- {
- break;
+ do
+ {
+ /* Read until we successfully read data or until an error occurs.
+ * EAGAIN is not an error, but it is still cause to return.
+ */
+
+ nbytes_read = read(rfd, inbuffer, sizeof(inbuffer));
+ if (nbytes_read < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (errno != EAGAIN)
+ {
+ ndbg("read: %d\n", errno);
+ }
+ return 1;
+ }
+ }
+ }
+ while (nbytes_read < 0);
+
+ /* Check for end of file */
+
+ if (nbytes_read == 0)
+ {
+ close(hc->conn_fd);
+ close(rfd);
+ hdr->state = CGI_OUTBUFFER_DONE;
+ return 1;
+ }
+ else
+ {
+ /* Forward the data from the CGI program to the client */
+
+ (void)httpd_write(hc->conn_fd, inbuffer, strlen(inbuffer));
+ }
}
- }
+ break;
- close(hc->conn_fd);
+ case CGI_OUTBUFFER_DONE:
+ default:
+ return 1;
+ }
+ return 0;
}
#endif
/* CGI child process. */
#ifdef CONFIG_THTTPD_CGI_PATTERN
-static void cgi_child(int argc, char **argv)
+static int cgi_child(int argc, char **argv)
{
FAR httpd_conn *hc = (FAR httpd_conn*)strtoul(argv[1], NULL, 16);
#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
ClientData client_data;
#endif
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*
- * inherit the close-on-exec flag, its flag is always clear. However,
- * Linux messes this up and does copy the flag to the dup()'d descriptor,
- * so we have to clear it. This could be ifdeffed for Linux only.
- */
-
- (void)fcntl(hc->conn_fd, F_SETFD, 0);
-
- /* If the socket happens to be using one of the stdin/stdout/stderr
- * descriptors, move it to another descriptor so that the dup2 calls below
- * don't screw things up. We arbitrarily pick fd 3 - if there was already
- * something on it, we clobber it, but that doesn't matter since at this
- * point the only fd of interest is the connection. All others will be
- * closed on exec.
- */
-
- if (hc->conn_fd == STDIN_FILENO || hc->conn_fd == STDOUT_FILENO ||
- hc->conn_fd == STDERR_FILENO)
- {
- int newfd = dup2(hc->conn_fd, STDERR_FILENO + 1);
- if (newfd >= 0)
- {
- hc->conn_fd = newfd;
- }
-
- /* If the dup2 fails, shrug. We'll just take our chances. Shouldn't
- * happen though.
- */
- }
+ struct cgi_outbuffer_s hdr;
+ struct fdwatch_s *fw;
+ char *buffer;
+ char *binary;
+ char *directory;
+ boolean indone;
+ boolean outdone;
+ int child;
+ int pipefd[2];
+ int wfd;
+ int rfd;
+ int fd;
+ int ret;
+ int err = 1;
/* Update all of the environment variable settings, these will be inherited
* by the CGI task.
@@ -2495,140 +2574,80 @@ static void cgi_child(int argc, char **argv)
argp = make_argp(hc);
- /* Set up stdin. For POSTs we may have to set up a pipe from an
- * interposer process, depending on if we've read some of the data into
- * our buffer.
+ /* Close all file descriptors (including stdio, stdin, stdout) EXCEPT for
+ * stderr and hc->conn_fd
*/
- if (hc->method == METHOD_POST && hc->read_idx > hc->checked_idx)
+ for (fd = 0; fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS); fd++)
{
- char child_arg1[16];
- char child_arg2[16];
- char *child_argv[2];
- int p[2];
-
- if (pipe(p) < 0)
- {
- ndbg("pipe: %d\n", errno);
- httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
- httpd_write_response(hc);
- exit(1);
- }
-
- /* 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;
+ /* Keep stderr open for debug; keep hc->conn_fd open for obvious reasons */
-#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("task_create: %d\n", errno);
- httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
- httpd_write_response(hc);
- exit(1);
- }
+ if (fd != 2 && fd != hc->conn_fd)
+ {
+ close(fd);
+ }
+ }
- /* Need to schedule a kill for process child; but in the main process! */
+ /* Create pipes that will be interposed between the CGI task's stdin or
+ * stdout and the socket.
+ *
+ *
+ * Setup up the STDIN pipe - a pipe to transfer data received on the
+ * socket to the CGI program.
+ */
- (void)close(p[1]);
- if (p[0] != STDIN_FILENO)
- {
- (void)dup2(p[0], STDIN_FILENO);
- (void)close(p[0]);
- }
+ ret = pipe(pipefd);
+ if (ret < 0)
+ {
+ ndbg("STDIN pipe: %d\n", errno);
+ goto errout_with_descriptors;
}
else
{
- /* Otherwise, the request socket is stdin. */
+ /* Then map the receiving end the pipe to stdin, save the sending end, and
+ * closing the original receiving end
+ */
- if (hc->conn_fd != STDIN_FILENO)
+ ret = dup2(pipefd[0], 0);
+ if (ret < 0)
{
- (void)dup2(hc->conn_fd, STDIN_FILENO);
+ ndbg("STDIN dup2: %d\n", errno);
+ close(pipefd[1]);
+ goto errout_with_descriptors;
}
+
+ wfd = pipefd[1];
+ close(pipefd[0]);
}
- /* Set up stdout/stderr. If we're doing CGI header parsing, we need an
- * output interposer too.
+ /* Set up the STDOUT pipe - a pipe to transfer data received from the CGI program
+ * to the client.
*/
- if (strncmp(argp[0], "nph-", 4) != 0 && hc->mime_flag)
+ if (ret == 0)
{
- char child_arg1[16];
- char child_arg2[16];
- char *child_argv[2];
- int p[2];
-
- if (pipe(p) < 0)
- {
- ndbg("pipe: %d\n", errno);
- httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
- httpd_write_response(hc);
- exit(1);
- }
-
- /* 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)
+ ret = pipe(pipefd);
+ if (ret < 0)
{
- ndbg("fork: %d\n", errno);
- httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
- httpd_write_response(hc);
- exit(1);
+ ndbg("STDOUT pipe: %d\n", errno);
+ goto errout_with_descriptors;
}
-
- /* Need to schedule a kill for process child; but in the main process! */
-
- (void)close(p[0]);
- if (p[1] != STDOUT_FILENO)
- {
- (void)dup2(p[1], STDOUT_FILENO);
- }
-
- if (p[1] != STDERR_FILENO)
- {
- (void)dup2(p[1], STDERR_FILENO);
- }
-
- if (p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO)
+ else
{
- (void)close(p[1]);
- }
- }
- else
- {
- /* Otherwise, the request socket is stdout/stderr. */
+ /* Then map the sending end the pipe to stdout, save the receiving end, and
+ * closing the original sending end
+ */
- if (hc->conn_fd != STDOUT_FILENO)
- {
- (void)dup2(hc->conn_fd, STDOUT_FILENO);
- }
+ ret = dup2(pipefd[1], 1);
+ if (ret < 0)
+ {
+ ndbg("STDOUT dup2: %d\n", errno);
+ close(pipefd[1]);
+ goto errout_with_descriptors;
+ }
- if (hc->conn_fd != STDERR_FILENO)
- {
- (void)dup2(hc->conn_fd, STDERR_FILENO);
+ rfd = pipefd[0];
+ close(pipefd[1]);
}
}
@@ -2656,7 +2675,38 @@ static void cgi_child(int argc, char **argv)
}
}
- /* Run the program. */
+ /* Allocate memory for buffering */
+
+ memset(&hdr, 0, sizeof(struct cgi_outbuffer_s));
+ httpd_realloc_str(&hdr.buffer, &hdr.size, 500);
+ if (!hdr.buffer)
+ {
+ ndbg("hdr allocation failed\n");
+ goto errout_with_descriptors;
+ }
+
+ buffer = (char*)malloc(CONFIG_THTTPD_IOBUFFERSIZE);
+ if (!buffer)
+ {
+ ndbg("buffer allocation failed\n");
+ goto errout_with_header;
+ }
+
+ /* Create fdwatch structures */
+
+ fw = fdwatch_initialize(2);
+ if (!fw)
+ {
+ ndbg("fdwatch allocation failed\n");
+ goto errout_with_buffer;
+ }
+
+ /* Add the read descriptors to the watch */
+
+ fdwatch_add_fd(fw, hc->conn_fd, NULL, FDW_READ);
+ fdwatch_add_fd(fw, rfd, NULL, FDW_READ);
+
+ /* Run the CGI program. */
child = exec(binary, (FAR const char **)argp, g_thttpdsymtab, g_thttpdnsymbols);
if (child < 0)
@@ -2664,24 +2714,63 @@ static void cgi_child(int argc, char **argv)
/* Something went wrong. */
ndbg("execve %s: %d\n", hc->expnfilename, errno);
- httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
- httpd_write_response(hc);
- exit(1);
+ goto errout_with_watch;
}
- else
- {
- /* Schedule a kill for the child process, in case it runs too long. */
+
+ /* Schedule a kill for the child process, in case it runs too long. */
#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
- client_data.i = child;
- 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");
+ goto errout_with_watch;
+ }
+#endif
+
+ /* Then perform the interposition */
+
+ indone = FALSE;
+ outdone = FALSE;
+
+ do
+ {
+ if (!indone)
{
- ndbg("tmr_create(cgi_kill child) failed\n");
- exit(1);
+ indone = cgi_interpose_input(hc, wfd, buffer);
}
-#endif
- }
+
+ if (!outdone)
+ {
+ outdone = cgi_interpose_output(hc, rfd, buffer, &hdr);
+ }
+ }
+ while (!outdone);
+ err = 0;
+
+ /* Get rid of watch structures */
+
+errout_with_watch:
+ fdwatch_uninitialize(fw);
+
+ /* Free memory */
+
+errout_with_buffer:
+ free(buffer);
+errout_with_header:
+ free(hdr.buffer);
+
+ /* Close all descriptors */
+
+errout_with_descriptors:
+ close(wfd);
+ close(rfd);
+ close(hc->conn_fd);
+
+ httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
+ httpd_write_response(hc);
+ return err;
}
#endif /* CONFIG_THTTPD_CGI_PATTERN */
@@ -2873,7 +2962,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP)
/* Ok, generate an index. */
return ls(hc);
-#else /* CONFIG_THTTPD_GENERATE_INDICES */
+#else
ndbg("%s URL \"%s\" tried to index a directory\n",
httpd_ntoa(&hc->client_addr), hc->encodedurl);
httpd_send_err(hc, 403, err403title, "",
@@ -2881,7 +2970,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP)
"The requested URL '%s' is a directory, and directory indexing is disabled on this server.\n"),
hc->encodedurl);
return -1;
-#endif /* CONFIG_THTTPD_GENERATE_INDICES */
+#endif
got_one:
@@ -2962,7 +3051,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP)
hc->encodedurl);
return -1;
}
-#endif /* CONFIG_THTTPD_AUTH_FILE */
+#endif
/* Referer check. */
@@ -3169,7 +3258,7 @@ static int really_check_referer(httpd_conn *hc)
return 1;
}
-#endif /* CONFIG_THTTPD_VHOST */
+#endif
#endif /* CONFIG_THTTPD_LOCALPATTERN */
/* If the referer host doesn't match the local host pattern, and the
@@ -3187,7 +3276,7 @@ static int really_check_referer(httpd_conn *hc)
return 1;
}
-#endif /* CONFIG_THTTPD_URLPATTERN */
+#endif
static int sockaddr_check(httpd_sockaddr * saP)
{
@@ -3199,7 +3288,7 @@ static int sockaddr_check(httpd_sockaddr * saP)
#ifdef CONFIG_NET_IPv6
case AF_INET6:
return 1;
-#endif /* CONFIG_NET_IPv6 */
+#endif
default:
return 0;
@@ -3216,7 +3305,7 @@ static size_t sockaddr_len(httpd_sockaddr * saP)
#ifdef CONFIG_NET_IPv6
case AF_INET6:
return sizeof(struct sockaddr_in6);
-#endif /* CONFIG_NET_IPv6 */
+#endif
default:
break;
@@ -3410,11 +3499,11 @@ void httpd_send_err(httpd_conn *hc, int status, char *title, char *extraheads,
send_response(hc, status, title, extraheads, form, arg);
-#else /* CONFIG_THTTPD_ERROR_DIRECTORY */
+#else
send_response(hc, status, title, extraheads, form, arg);
-#endif /* CONFIG_THTTPD_ERROR_DIRECTORY */
+#endif
}
char *httpd_method_str(int method)
@@ -3492,7 +3581,6 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc)
return GC_FAIL;
}
- (void)fcntl(hc->conn_fd, F_SETFD, 1);
hc->hs = hs;
(void)memset(&hc->client_addr, 0, sizeof(hc->client_addr));
(void)memmove(&hc->client_addr, &sa, sockaddr_len(&sa));
@@ -3526,7 +3614,7 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc)
hc->buffer[0] = '\0';
#ifdef CONFIG_THTTPD_TILDE_MAP2
hc->altdir[0] = '\0';
-#endif /*CONFIG_THTTPD_TILDE_MAP2 */
+#endif
hc->buflen = 0;
hc->if_modified_since = (time_t) - 1;
hc->range_if = (time_t) - 1;
@@ -4108,7 +4196,7 @@ int httpd_parse_request(httpd_conn *hc)
{
ndbg("unknown request header: %s\n", buf);
}
-#endif /* LOG_UNKNOWN_HEADERS */
+#endif
}
}
@@ -4223,7 +4311,7 @@ int httpd_parse_request(httpd_conn *hc)
hc->expnfilename[strlen(hc->altdir)] == '/')))
{
}
-#endif /*CONFIG_THTTPD_TILDE_MAP2 */
+#endif
else
{
ndbg("%s URL \"%s\" goes outside the web tree\n",
@@ -4317,7 +4405,7 @@ char *httpd_ntoa(httpd_sockaddr *saP)
return inet_ntoa(saP->sin_addr);
-#endif /* CONFIG_NET_IPv6 */
+#endif
}
/* Read to requested buffer, accounting for interruptions and EOF */
diff --git a/nuttx/netutils/thttpd/thttpd.c b/nuttx/netutils/thttpd/thttpd.c
index cccacaf3b..8d26933fa 100644
--- a/nuttx/netutils/thttpd/thttpd.c
+++ b/nuttx/netutils/thttpd/thttpd.c
@@ -108,6 +108,7 @@ static struct connect_s *connects;
static int num_connects;
static int first_free_connect;
static int httpd_conn_count;
+static struct fdwatch_s *fw;
/****************************************************************************
* Public Data
@@ -180,7 +181,7 @@ static void shut_down(void)
hs = (httpd_server *) 0;
if (ths->listen_fd != -1)
{
- fdwatch_del_fd(ths->listen_fd);
+ fdwatch_del_fd(fw, ths->listen_fd);
}
httpd_terminate(ths);
}
@@ -271,7 +272,7 @@ static int handle_newconnect(struct timeval *tv, int listen_fd)
httpd_set_ndelay(conn->hc->conn_fd);
- fdwatch_add_fd(conn->hc->conn_fd, conn, FDW_READ);
+ fdwatch_add_fd(fw, conn->hc->conn_fd, conn, FDW_READ);
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
++stats_connections;
@@ -403,8 +404,8 @@ static void handle_read(struct connect_s *conn, struct timeval *tv)
conn->conn_state = CNST_SENDING;
client_data.p = conn;
- fdwatch_del_fd(hc->conn_fd);
- fdwatch_add_fd(hc->conn_fd, conn, FDW_WRITE);
+ fdwatch_del_fd(fw, hc->conn_fd);
+ fdwatch_add_fd(fw, hc->conn_fd, conn, FDW_WRITE);
return;
errout_with_400:
@@ -560,12 +561,12 @@ static void clear_connection(struct connect_s *conn, struct timeval *tv)
{
if (conn->conn_state != CNST_PAUSING)
{
- fdwatch_del_fd(conn->hc->conn_fd);
+ fdwatch_del_fd(fw, conn->hc->conn_fd);
}
conn->conn_state = CNST_LINGERING;
close(conn->hc->conn_fd);
- fdwatch_add_fd(conn->hc->conn_fd, conn, FDW_READ);
+ fdwatch_add_fd(fw, conn->hc->conn_fd, conn, FDW_READ);
client_data.p = conn;
if (conn->linger_timer != (Timer *) 0)
@@ -594,7 +595,7 @@ static void really_clear_connection(struct connect_s *conn, struct timeval *tv)
#endif
if (conn->conn_state != CNST_PAUSING)
{
- fdwatch_del_fd(conn->hc->conn_fd);
+ fdwatch_del_fd(fw, conn->hc->conn_fd);
}
httpd_close_conn(conn->hc, tv);
@@ -685,7 +686,7 @@ static void logstats(struct timeval *nowP)
thttpd_logstats(stats_secs);
httpd_logstats(stats_secs);
- fdwatch_logstats(stats_secs);
+ fdwatch_logstats(fw, stats_secs);
tmr_logstats(stats_secs);
}
#endif
@@ -742,7 +743,6 @@ int thttpd_main(int argc, char **argv)
struct sockaddr_in sa;
#endif
struct timeval tv;
- int ret;
/* Setup host address */
@@ -773,10 +773,12 @@ int thttpd_main(int argc, char **argv)
(void)strcat(cwd, "/");
}
- /* Initialize the fdwatch package */
+ /* Initialize the fdwatch package to handle all of the configured
+ * socket descriptors
+ */
- ret = fdwatch_initialize();
- if (ret < 0)
+ fw = fdwatch_initialize(CONFIG_NSOCKET_DESCRIPTORS);
+ if (!fw)
{
ndbg("fdwatch initialization failure\n");
exit(1);
@@ -860,7 +862,7 @@ int thttpd_main(int argc, char **argv)
if (hs != (httpd_server *) 0)
{
if (hs->listen_fd != -1)
- fdwatch_add_fd(hs->listen_fd, (void *)0, FDW_READ);
+ fdwatch_add_fd(fw, hs->listen_fd, (void *)0, FDW_READ);
}
/* Main loop */
@@ -870,7 +872,7 @@ int thttpd_main(int argc, char **argv)
{
/* Do the fd watch */
- num_ready = fdwatch(tmr_mstimeout(&tv));
+ num_ready = fdwatch(fw, tmr_mstimeout(&tv));
if (num_ready < 0)
{
if (errno == EINTR || errno == EAGAIN)
@@ -892,7 +894,7 @@ int thttpd_main(int argc, char **argv)
/* Is it a new connection? */
if (hs != (httpd_server *) 0 && hs->listen_fd != -1 &&
- fdwatch_check_fd(hs->listen_fd))
+ fdwatch_check_fd(fw, hs->listen_fd))
{
if (handle_newconnect(&tv, hs->listen_fd))
{
@@ -908,14 +910,14 @@ int thttpd_main(int argc, char **argv)
/* Find the connections that need servicing */
while ((conn =
- (struct connect_s *) fdwatch_get_next_client_data()) !=
- (struct connect_s *) - 1)
+ (struct connect_s*)fdwatch_get_next_client_data(fw)) !=
+ (struct connect_s*)- 1)
{
if (conn == (struct connect_s *) 0)
continue;
hc = conn->hc;
- if (!fdwatch_check_fd(hc->conn_fd))
+ if (!fdwatch_check_fd(fw, hc->conn_fd))
{
/* Something went wrong */