summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/netutils/thttpd/Makefile34
-rw-r--r--nuttx/netutils/thttpd/cgi-src/Makefile136
-rw-r--r--nuttx/netutils/thttpd/cgi-src/phf.c86
-rw-r--r--nuttx/netutils/thttpd/cgi-src/redirect.c288
-rw-r--r--nuttx/netutils/thttpd/cgi-src/ssi.c979
-rw-r--r--nuttx/netutils/thttpd/config.h18
-rw-r--r--nuttx/netutils/thttpd/libhttpd.c68
-rw-r--r--nuttx/netutils/thttpd/libhttpd.h4
-rw-r--r--nuttx/netutils/thttpd/tdate_parse.c4
9 files changed, 1574 insertions, 43 deletions
diff --git a/nuttx/netutils/thttpd/Makefile b/nuttx/netutils/thttpd/Makefile
index 0840fdd35..6ff882dc4 100644
--- a/nuttx/netutils/thttpd/Makefile
+++ b/nuttx/netutils/thttpd/Makefile
@@ -37,7 +37,15 @@
-include $(TOPDIR)/Make.defs
CGIBINDIR = $(TOPDIR)/netutils/thttpd/cgi-bin
+
+SUBDIRS =
+ifeq ($(CONFIG_NXFLAT),y)
SUBDIRS = cgi-src
+SUBDIR_BIN1 = phf
+SUBDIR_BIN2 = redirect
+SUBDIR_BIN3 = ssi
+SUBDIR_BIN += cgi-bin/$(SUBDIR_BIN1) cgi-bin/$(SUBDIR_BIN2) cgi-bin/$(SUBDIR_BIN3)
+endif
ASRCS =
AOBJS = $(ASRCS:.S=$(OBJEXT))
@@ -50,7 +58,7 @@ OBJS = $(AOBJS) $(COBJS)
BIN = libthttpd$(LIBEXT)
-all: $(BIN)
+all: $(BIN) $(SUBDIR_BIN)
$(AOBJS): %$(OBJEXT): %.S
$(call ASSEMBLE, $<, $@)
@@ -63,6 +71,29 @@ $(BIN): $(OBJS)
$(call ARCHIVE, $@, $${obj}); \
done ; )
+ifeq ($(CONFIG_NXFLAT),y)
+cgi-bin:
+ @mkdir cgi-bin
+
+cgi-src/$(SUBDIR_BIN1):
+ @$(MAKE) -C cgi-src $(SUBDIR_BIN1)
+
+cgi-bin/$(SUBDIR_BIN1): cgi-bin cgi-src/$(SUBDIR_BIN1)
+ @cp -a cgi-src/$(SUBDIR_BIN1) $@
+
+cgi-src/$(SUBDIR_BIN2):
+ @$(MAKE) -C cgi-src $(SUBDIR_BIN2)
+
+cgi-bin/$(SUBDIR_BIN2): cgi-bin cgi-src/$(SUBDIR_BIN2)
+ @cp -a cgi-src/$(SUBDIR_BIN2) $@
+
+cgi-src/$(SUBDIR_BIN3):
+ @$(MAKE) -C cgi-src $(SUBDIR_BIN3)
+
+cgi-bin/$(SUBDIR_BIN3): cgi-bin cgi-src/$(SUBDIR_BIN3)
+ @cp -a cgi-src/$(SUBDIR_BIN3) $@
+endif
+
.depend: Makefile $(SRCS)
@$(MKDEP) --dep-path . $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
@touch $@
@@ -71,6 +102,7 @@ depend: .depend
clean:
@rm -f $(BIN) *~ .*.swp
+ @rm -rf cgi-bin
$(call CLEAN)
@( for dir in $(SUBDIRS); do \
rm -f $${dir}/*~ $${dir}/.*.swp; \
diff --git a/nuttx/netutils/thttpd/cgi-src/Makefile b/nuttx/netutils/thttpd/cgi-src/Makefile
new file mode 100644
index 000000000..79814fb80
--- /dev/null
+++ b/nuttx/netutils/thttpd/cgi-src/Makefile
@@ -0,0 +1,136 @@
+############################################################################
+# examples/nxflat/tests/hello/Makefile
+#
+# 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.
+#
+############################################################################
+
+-include $(TOPDIR)/.config # Current configuration
+-include $(TOPDIR)/Make.defs # Basic make info
+
+CFLAGS += -I$(TOPDIR)/netutils/thttpd -I$(TOPDIR)/netutils/thttpd/cgi-src
+CGIBINDIR = $(TOPDIR)/netutils/thttpd/cgi-bin
+CLEANFILES = *.o redirect ssi phf
+
+BIN1 = phf
+BIN2 = redirect
+BIN3 = ssi
+BIN = $(BIN1) $(BIN2) $(BIN3)
+
+R1SRCS1 = $(BIN1).c
+R1OBJS1 = $(R1SRCS1:.c=.o)
+R2SRC1 = $(BIN1)-thunk.S
+R2OBJ1 = $(R2SRC1:.S=.o)
+
+R1SRCS2 = $(BIN2).c
+R1OBJS2 = $(R1SRCS2:.c=.o)
+R2SRC2 = $(BIN2)-thunk.S
+R2OBJ2 = $(R2SRC2:.S=.o)
+
+R1SRCS3 = $(BIN3).c
+R1OBJS3 = $(R1SRCS3:.c=.o)
+R2SRC3 = $(BIN3)-thunk.S
+R2OBJ3 = $(R2SRC3:.S=.o)
+
+DERIVED = $(R2SRC1) $(R2SRC2) $(R2SRC3)
+
+R1COBJS = $(R1OBJS1) $(R1OBJS2) $(R1OBJS3)
+R2AOBJS = $(R2OBJ1) $(R2OBJ2) $(R2OBJ3)
+
+all: $(BIN1) $(BIN2) $(BIN3)
+
+$(R1COBJS): %.o: %.c
+ @echo "CC: $<"
+ @$(CC) -c $(CPICFLAGS) $< -o $@
+
+$(R2AOBJS): %.o: %.S
+ @echo "AS: $<"
+ @$(CC) -c $(CPICFLAGS) $< -o $@
+
+# BIN1
+
+$(BIN1).r1: $(R1OBJS1)
+ @echo "LD: $<"
+ @$(LD) $(NXFLATLDFLAGS1) -o $@ $^
+
+$(R2SRC1): $(BIN1).r1
+ @echo "MK: $<"
+ @$(MKNXFLAT) -o $@ $^
+
+$(BIN1).r2: $(R2OBJ1)
+ @echo "LD: $<"
+ @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS1) $(R2OBJ1)
+
+$(BIN1): $(BIN1).r2
+ @echo "LD: $<"
+ @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^
+
+#BIN2
+
+$(BIN2).r1: $(R1OBJS2)
+ @echo "LD: $<"
+ @$(LD) $(NXFLATLDFLAGS1) -o $@ $^
+
+$(R2SRC2): $(BIN2).r1
+ @echo "MK: $<"
+ @$(MKNXFLAT) -o $@ $^
+
+$(BIN2).r2: $(R2OBJ2)
+ @echo "LD: $<"
+ @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS2) $(R2OBJ2)
+
+$(BIN2): $(BIN2).r2
+ @echo "LD: $<"
+ @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^
+# BIN3
+
+$(BIN3).r1: $(R1OBJS3)
+ @echo "LD: $<"
+ @$(LD) $(NXFLATLDFLAGS1) -o $@ $^
+
+$(R2SRC3): $(BIN3).r1
+ @echo "MK: $<"
+ @$(MKNXFLAT) -o $@ $^
+
+$(BIN3).r2: $(R2OBJ3)
+ @echo "LD: $<"
+ @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS3) $(R2OBJ3)
+
+$(BIN3): $(BIN3).r2
+ @echo "LD: $<"
+ @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^
+
+clean:
+ @rm -f $(BIN1) $(BIN2) $(BIN3) *.r1 *.r2 *-thunk.S *~ .*.swp
+ $(call CLEAN)
+
+distclean: clean
+
diff --git a/nuttx/netutils/thttpd/cgi-src/phf.c b/nuttx/netutils/thttpd/cgi-src/phf.c
new file mode 100644
index 000000000..16ea2fefe
--- /dev/null
+++ b/nuttx/netutils/thttpd/cgi-src/phf.c
@@ -0,0 +1,86 @@
+/****************************************************************************
+ * netutils/thttpd/cgi-src/phf.c
+ * Cracker trap
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1996 by Jef Poskanzer <jef@mail.acme.com>.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/* Old distributions of the NCSA and Apache web servers included a
+ * version of the phf program that had a bug. The program could
+ * easily be made to run arbitrary shell commands. There is no real
+ * legitimate use for phf, so any attempts to run it must be considered
+ * to be attacks. Accordingly, this version of phf logs the attack
+ * on stderr and then returns a page on CONFIG_THTTPD_CGI_OUTFD indicating
+ * that phf doesn't exist.
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+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,
+"\
+Content-type: text/html\n\
+Status: 404/html\n\
+\n\
+<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n\
+<BODY><H2>404 Not Found</H2>\n\
+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
new file mode 100644
index 000000000..5aa099d59
--- /dev/null
+++ b/nuttx/netutils/thttpd/cgi-src/redirect.c
@@ -0,0 +1,288 @@
+/****************************************************************************
+ * netutils/thttpd/cgi-src/redirect.c
+ * Simple redirection CGI program
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/* Three steps to set up a redirection:
+ *
+ * 1. Make sure your web server is set up to allow CGI programs.
+ * 2. Make a symbolic link from the file you want to redirect,
+ * pointing at this program in the CGI bin directory.
+ * 3. Add an entry to the file ".redirects" in the directory where your
+ * http server runs CGI programs. For most servers, this is the
+ * directory where the given CGI program lives. The format of the
+ * file is a bunch of lines with a filename, whitespace, and the new
+ * URL. For example:
+ *
+ * /test/oldfile.html http://www.acme.com/test/newfile.html
+ *
+ * The easiest way to figure out precisely what filename to put into
+ * .redirects is to set up the symlink and then click on it. You'll get
+ * back a "404 Not Found" page which includes the filename as received by
+ * the redirect program, and that's what you want to use.
+ *
+ * Note: this is designed for thttpd (http://www.acme.com/software/thttpd/)
+ * and using it with other web servers may require some hacking. A possible
+ * gotcha is with the symbolic link from the old file pointing at this
+ * script - servers other than thttpd may not allow that link to be run
+ * as a CGI program, because they don't check the link to see that it
+ * points into the allowed CGI directory.
+ *
+ * Note two: It would be really cool to have this program look for
+ * the .redirects file in the same directory as the file being redirected,
+ * instead of in the binaries directory. Unfortunately, this appears
+ * to be impossible with the information CGI gives, plus the non-standardized
+ * but widespread practice of running CGI programs in the directory where
+ * the binary lives. Perhaps CGI 1.2 will address this.
+ */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "config.h"
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+#define LINE_SIZE 80
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static char g_iobuffer[LINE_SIZE];
+static char g_file[LINE_SIZE];
+static char g_url[LINE_SIZE];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void internal_error(FILE *outstream, char *reason)
+{
+ char *title = "500 Internal Error";
+
+ (void)fprintf(outstream,
+"\
+Status: %s\n\
+Content-type: text/html\n\
+\n\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+Something unusual went wrong during a redirection request:\n\
+<BLOCKQUOTE>\n\
+%s\n\
+</BLOCKQUOTE>\n\
+</BODY></HTML>\n", title, title, title, reason);
+}
+
+static void not_found(FILE *outstream, char *script_name)
+{
+ char *title = "404 Not Found";
+
+ (void)fprintf(outstream,
+"\
+Status: %s\n\
+Content-type: text/html\n\
+\n\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+The requested filename, %s, is set up to be redirected to another URL;\n\
+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)
+{
+ char *title = "Moved";
+
+ (void)fprintf(outstream,
+"\
+Location: %s\n\
+Content-type: text/html\n\
+\n\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+The requested filename, %s, has moved to a new URL:\n\
+<A HREF=\"%s\">%s</A>.\n\
+</BODY></HTML>\n", url, title, title, script_name, url, url);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, char **argv)
+{
+ FILE *outstream;
+ char *script_name;
+ char *path_info;
+ char *cp = 0;
+ FILE *fp;
+ 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.
+ */
+
+ script_name = getenv("SCRIPT_NAME");
+ if (!script_name)
+ {
+ internal_error(outstream, "Couldn't get SCRIPT_NAME environment variable.");
+ err = 2;
+ goto errout_with_outstream;
+ }
+
+ /* Append the PATH_INFO, if any. This allows redirection of whole **
+ * directories.
+ */
+
+ path_info = getenv("PATH_INFO");
+ if (path_info)
+ {
+ cp = (char *)malloc(strlen(script_name) + strlen(path_info) + 1);
+ if (!cp)
+ {
+ internal_error(outstream, "Out of memory.");
+ err = 3;
+ goto errout_with_outstream;
+ }
+
+ (void)sprintf(cp, "%s%s", script_name, path_info);
+ script_name = cp;
+ }
+
+ /* Open the redirects file. */
+
+ fp = fopen(".redirects", "r");
+ if (fp == (FILE *) 0)
+ {
+ internal_error(outstream, "Couldn't open .redirects file.");
+ err = 4;
+ goto errout_with_cp;
+ }
+
+ /* Search the file for a matching entry. */
+
+ while (fgets(g_iobuffer, LINE_SIZE, fp) != NULL)
+ {
+ /* Remove comments. */
+
+ cp = strchr(g_iobuffer, '#');
+ if (cp)
+ {
+ *cp = '\0';
+ }
+
+ /* Skip leading whitespace. */
+
+ cp = g_iobuffer;
+ cp += strspn(cp, " \t");
+
+ /* Check for blank line. */
+
+ if (*cp != '\0')
+ {
+ /* Parse line. */
+
+ if (sscanf(cp, "%[^ \t\n] %[^ \t\n]", g_file, g_url) == 2)
+ {
+ /* Check for wildcard match. */
+
+ star = strchr(g_file, '*');
+ if (star != (char *)0)
+ {
+ /* Check for leading match. */
+
+ if (strncmp(g_file, script_name, star - g_file) == 0)
+ {
+ /* Got it; put together the full name. */
+
+ strcat(g_url, script_name + (star - g_file));
+
+ /* XXX Whack the script_name, too? */
+
+ moved(outstream, script_name, g_url);
+ goto success_out;
+ }
+ }
+
+ /* Check for exact match. */
+
+ if (strcmp(g_file, script_name) == 0)
+ {
+ /* Got it. */
+
+ moved(outstream, script_name, g_url);
+ goto success_out;
+ }
+ }
+ }
+ }
+
+ /* No match found. */
+
+ not_found(outstream, script_name);
+ err = 5;
+
+success_out:
+ fclose(fp);
+errout_with_cp:
+ if (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
new file mode 100644
index 000000000..042f43b65
--- /dev/null
+++ b/nuttx/netutils/thttpd/cgi-src/ssi.c
@@ -0,0 +1,979 @@
+/****************************************************************************
+ * netutils/thttpd/cgi-src/ssi.c
+ * Server-side-includes CGI program
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <nuttx/regex.h>
+
+#include "config.h"
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+#define ST_GROUND 0
+#define ST_LESSTHAN 1
+#define ST_BANG 2
+#define ST_MINUS1 3
+#define ST_MINUS2 4
+
+#define SF_BYTES 0
+#define SF_ABBREV 1
+
+#define DI_CONFIG 0
+#define DI_INCLUDE 1
+#define DI_ECHO 2
+#define DI_FSIZE 3
+#define DI_FLASTMOD 4
+
+#define BUFFER_SIZE 512
+#define TIMEFMT_SIZE 80
+#define MAX_TAGS 32
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *filename);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static char *g_url;
+static char g_timeformat[TIMEFMT_SIZE];
+static char g_iobuffer1[BUFFER_SIZE];
+static char g_iobuffer2[BUFFER_SIZE];
+static char *g_tags[MAX_TAGS];
+static int g_sizefmt;
+static struct stat g_sb;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void internal_error(FILE *outstream, char *reason)
+{
+ char *title = "500 Internal Error";
+
+ (void)fprintf(outstream,
+"\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+Something unusual went wrong during a server-side-includes request:\n\
+<BLOCKQUOTE>\n\
+%s\n\
+</BLOCKQUOTE>\n\
+</BODY></HTML>\n", title, title, reason);
+}
+
+static void not_found(FILE *outstream, char *filename)
+{
+ char *title = "404 Not Found";
+
+ (void)fprintf(outstream,
+"\
+<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
+<BODY><H2>%s</H2>\n\
+The requested server-side-includes filename, %s,\n\
+does not seem to exist.\n\
+</BODY></HTML>\n", title, title, filename);
+}
+
+static void not_found2(FILE *outstream, char *directive, char *tag, char *filename)
+{
+ char *title = "Not Found";
+
+ (void)fprintf(outstream,
+"\
+<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)
+{
+ char *title = "Not Permitted";
+
+ (void)fprintf(outstream,
+"\
+<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)
+{
+ char *title = "Unknown Directive";
+
+ (void)fprintf(outstream,
+"\
+<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)
+{
+ char *title = "Unknown Tag";
+
+ (void)fprintf(outstream,
+"\
+<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)
+{
+ char *title = "Unknown Value";
+
+ (void)fprintf(outstream,
+"\
+<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,
+ char *directive, char *tag, char *val, char *fn,
+ int fnsize)
+{
+ char *cp;
+ int vl;
+ int fl;
+
+ /* Used for the various commands that accept a file name. These commands
+ * accept two tags: virtual Gives a virtual path to a document on the
+ * server. file Gives a pathname relative to the current directory. ../
+ * cannot be used in this pathname, nor can absolute paths be used.
+ */
+
+ vl = strlen(vfilename);
+ fl = strlen(filename);
+
+ if (strcmp(tag, "virtual") == 0)
+ {
+ if (strstr(val, "../") != (char *)0)
+ {
+ not_permitted(outstream, directive, tag, val);
+ return -1;
+ }
+
+ /* Figure out root using difference between vfilename and filename. */
+
+ if (vl > fl || strcmp(vfilename, &filename[fl - vl]) != 0)
+ {
+ return -1;
+ }
+
+ if (fl - vl + strlen(val) >= fnsize)
+ {
+ return -1;
+ }
+
+ (void)strncpy(fn, filename, fl - vl);
+ (void)strcpy(&fn[fl - vl], val);
+ }
+ else if (strcmp(tag, "file") == 0)
+ {
+ if (val[0] == '/' || strstr(val, "../") != (char *)0)
+ {
+ not_permitted(outstream, directive, tag, val);
+ return -1;
+ }
+ if (fl + 1 + strlen(val) >= fnsize)
+ {
+ return -1;
+ }
+
+ (void)strcpy(fn, filename);
+ cp = strrchr(fn, '/');
+ if (cp == (char *)0)
+ {
+ cp = &fn[strlen(fn)];
+ *cp = '/';
+ }
+ (void)strcpy(++cp, val);
+ }
+ else
+ {
+ unknown_tag(outstream, filename, directive, tag);
+ return -1;
+ }
+ return 0;
+}
+
+static int check_filename(char *filename)
+{
+ static int inited = 0;
+ static char *cgi_pattern;
+#ifdef CONFIG_AUTH_FILE
+ struct stat sb;
+ char *dirname;
+ char *authname;
+ char *cp;
+ int fnl;
+ int r;
+#endif
+
+ if (!inited)
+ {
+ /* Get the cgi pattern. */
+
+ cgi_pattern = getenv("CGI_PATTERN");
+#ifdef CGI_PATTERN
+ if (cgi_pattern == (char *)0)
+ {
+ cgi_pattern = CGI_PATTERN;
+ }
+#endif /* CGI_PATTERN */
+ inited = 1;
+ }
+
+ /* ../ is not permitted. */
+
+ if (strstr(filename, "../") !=NULL)
+ {
+ return 0;
+ }
+
+ /* Ensure that we are not reading a basic auth password file. */
+
+#ifdef CONFIG_AUTH_FILE
+ fnl = strlen(filename);
+ if (strcmp(filename, CONFIG_AUTH_FILE) == 0 ||
+ (fnl >= sizeof(CONFIG_AUTH_FILE) &&
+ strcmp(&filename[fnl - sizeof(CONFIG_AUTH_FILE) + 1], CONFIG_AUTH_FILE) == 0 &&
+ filename[fnl - sizeof(CONFIG_AUTH_FILE)] == '/'))
+ {
+ return 0;
+ }
+
+ /* Check for an auth file in the same directory. We can't do an actual **
+ * auth password check here because CGI programs are not given the **
+ * authorization header, for security reasons. So instead we just **
+ * prohibit access to all auth-protected files.
+ */
+
+ dirname = strdup(filename);
+ if (dirname == (char *)0)
+ {
+ /* out of memory */
+
+ return 0;
+ }
+
+ cp = strrchr(dirname, '/');
+ if (cp == (char *)0)
+ {
+ (void)strcpy(dirname, ".");
+ }
+ else
+ {
+ *cp = '\0';
+ }
+
+ authname = malloc(strlen(dirname) + 1 + sizeof(CONFIG_AUTH_FILE));
+ if (!authname)
+ {
+ /* out of memory */
+
+ free(dirname);
+ return 0;
+ }
+
+ (void)sprintf(authname, "%s/%s", dirname, CONFIG_AUTH_FILE);
+ r = stat(authname, &sb);
+
+ free(dirname);
+ free(authname);
+
+ if (r == 0)
+ {
+ return 0;
+ }
+#endif /* CONFIG_AUTH_FILE */
+
+ /* Ensure that we are not reading a CGI file. */
+
+ if (cgi_pattern != (char *)0 && match(cgi_pattern, filename))
+ {
+ return 0;
+ }
+ return 1;
+}
+
+static void show_time(FILE *outstream, time_t t, int gmt)
+{
+ struct tm *tmP;
+
+ if (gmt)
+ {
+ tmP = gmtime(&t);
+ }
+ else
+ {
+ tmP = localtime(&t);
+ }
+
+ if (strftime(g_iobuffer2, BUFFER_SIZE, g_timeformat, tmP) > 0)
+ {
+ (void)fputs(g_iobuffer2, outstream);
+ }
+}
+
+static void show_size(FILE *outstream, off_t size)
+{
+ switch (g_sizefmt)
+ {
+ case SF_BYTES:
+ (void)fprintf(outstream, "%ld", (long)size); /* spec says should have commas */
+ break;
+
+ case SF_ABBREV:
+ if (size < 1024)
+ {
+ (void)fprintf(outstream, "%ld", (long)size);
+ }
+ else if (size < 1024)
+ {
+ (void)fprintf(outstream, "%ldK", (long)size / 1024L);
+ }
+ else if (size < 1024 * 1024)
+ {
+ (void)fprintf(outstream, "%ldM", (long)size / (1024L * 1024L));
+ }
+ else
+ {
+ (void)fprintf(outstream, "%ldG", (long)size / (1024L * 1024L * 1024L));
+ }
+ break;
+ }
+}
+
+static void do_config(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+ char *directive, char *tag, char *val)
+{
+ /* The config directive controls various aspects of the file parsing. **
+ * There are two valid tags: g_timeformat Gives the server a new format to
+ * use when providing dates. This is a string compatible with the
+ * strftime library call. g_sizefmt Determines the formatting to be used
+ * when displaying the size of a file. Valid choices are bytes, for a
+ * formatted byte count (formatted as 1,234,567), or abbrev for an
+ * abbreviated version displaying the number of kilobytes or megabytes the
+ * file occupies.
+ */
+
+ if (strcmp(tag, "g_timeformat") == 0)
+ {
+ (void)strncpy(g_timeformat, val, TIMEFMT_SIZE - 1);
+ g_timeformat[TIMEFMT_SIZE - 1] = '\0';
+ }
+ else if (strcmp(tag, "g_sizefmt") == 0)
+ {
+ if (strcmp(val, "bytes") == 0)
+ {
+ g_sizefmt = SF_BYTES;
+ }
+ else if (strcmp(val, "abbrev") == 0)
+ {
+ g_sizefmt = SF_ABBREV;
+ }
+ else
+ {
+ unknown_value(outstream, filename, directive, tag, val);
+ }
+ }
+ else
+ {
+ unknown_tag(outstream, filename, directive, tag);
+ }
+}
+
+static void do_include(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+ char *directive, char *tag, char *val)
+{
+ FILE *instream2;
+ int ret;
+
+ /* Inserts the text of another document into the parsed document. */
+
+ ret = get_filename(outstream, vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
+ if (ret < 0)
+ {
+ return;
+ }
+
+ if (!check_filename(g_iobuffer1))
+ {
+ not_permitted(outstream, directive, tag, g_iobuffer1);
+ return;
+ }
+
+ instream2 = fopen(g_iobuffer1, "r");
+ if (instream2 == (FILE *) 0)
+ {
+ not_found2(outstream, directive, tag, g_iobuffer1);
+ return;
+ }
+
+ if (strcmp(tag, "virtual") == 0)
+ {
+ if (strlen(val) <BUFFER_SIZE)
+ {
+ (void)strcpy(g_iobuffer2, val);
+ }
+ else
+ {
+ (void)strcpy(g_iobuffer2, g_iobuffer1); /* same size, has to fit */
+ }
+ }
+ else
+ {
+ if (strlen(vfilename) + 1 + strlen(val) < BUFFER_SIZE)
+ {
+ char *cp;
+ (void)strcpy(g_iobuffer2, vfilename);
+ cp = strrchr(g_iobuffer2, '/');
+ if (cp == (char *)0)
+ {
+ cp = &g_iobuffer2[strlen(g_iobuffer2)];
+ *cp = '/';
+ }
+ (void)strcpy(++cp, val);
+ }
+ else
+ {
+ (void)strcpy(g_iobuffer2, g_iobuffer1); /* same size, has to fit */
+ }
+ }
+
+ read_file(outstream, instream2, g_iobuffer2, g_iobuffer1);
+ (void)fclose(instream2);
+}
+
+static void do_echo(FILE *outstream, FILE *instream, char *vfilename, char *filename,
+ char *directive, char *tag, char *val)
+{
+ char *cp;
+ time_t t;
+
+ /* Prints the value of one of the include variables. Any dates are
+ * printed subject to the currently configured g_timeformat. The only valid
+ * tag is var, whose value is the name of the variable you wish to echo.
+ */
+
+ if (strcmp(tag, "var") != 0)
+ {
+ unknown_tag(outstream, filename, directive, tag);
+ }
+ else
+ {
+ if (strcmp(val, "DOCUMENT_NAME") == 0)
+ {
+ /* The current filename. */
+
+ (void)fputs(filename, outstream);
+ }
+ else if (strcmp(val, "DOCUMENT_URI") == 0)
+ {
+ /* The virtual path to this file (such as /~robm/foo.shtml). */
+
+ (void)fputs(vfilename, outstream);
+ }
+ else if (strcmp(val, "QUERY_STRING_UNESCAPED") == 0)
+ {
+ /* The unescaped version of any search query the client sent. */
+
+ cp = getenv("QUERY_STRING");
+ if (cp != (char *)0)
+ {
+ (void)fputs(cp, outstream);
+ }
+ }
+ else if (strcmp(val, "DATE_LOCAL") == 0)
+ {
+ struct timeval tm;
+
+ /* The current date, local time zone. */
+
+ gettimeofday(&tm, NULL);
+ show_time(outstream, tm.tv_sec, 0);
+ }
+ else if (strcmp(val, "DATE_GMT") == 0)
+ {
+ struct timeval tm;
+
+ /* Same as DATE_LOCAL but in Greenwich mean time. */
+
+ gettimeofday(&tm, NULL);
+ show_time(outstream, t, 1);
+ }
+ else if (strcmp(val, "LAST_MODIFIED") == 0)
+ {
+ /* The last modification date of the current document. */
+
+ if (fstat(fileno(instream), &g_sb) >= 0)
+ {
+ show_time(outstream, g_sb.st_mtime, 0);
+ }
+ }
+ else
+ {
+ /* Try an environment variable. */
+
+ cp = getenv(val);
+ if (cp == (char *)0)
+ {
+ unknown_value(outstream, filename, directive, tag, val);
+ }
+ else
+ {
+ (void)fputs(cp, outstream);
+ }
+ }
+ }
+}
+
+static void do_fsize(FILE *outstream, 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);
+ if (ret < 0)
+ {
+ return;
+ }
+
+ if (stat(g_iobuffer1, &g_sb) < 0)
+ {
+ not_found2(outstream, directive, tag, g_iobuffer1);
+ return;
+ }
+
+ show_size(outstream, g_sb.st_size);
+}
+
+static void do_flastmod(FILE *outstream, 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);
+ if (ret < 0)
+ {
+ return;
+ }
+
+ if (stat(g_iobuffer1, &g_sb) < 0)
+ {
+ not_found2(outstream, directive, tag, g_iobuffer1);
+ return;
+ }
+ show_time(outstream, g_sb.st_mtime, 0);
+}
+
+static void parse(FILE *outstream, FILE *instream, char *vfilename, char *filename, char *str)
+{
+ char *directive;
+ char *cp;
+ int ntags;
+ int dirn;
+ int i;
+ char *val;
+
+ directive = str;
+ directive += strspn(directive, " \t\n\r");
+
+ ntags = 0;
+ cp = directive;
+ for (;;)
+ {
+ cp = strpbrk(cp, " \t\n\r\"");
+ if (cp == (char *)0)
+ {
+ break;
+ }
+
+ if (*cp == '"')
+ {
+ cp = strpbrk(cp + 1, "\"");
+ cp++;
+ if (*cp == '\0')
+ {
+ break;
+ }
+ }
+
+ *cp++ = '\0';
+ cp += strspn(cp, " \t\n\r");
+ if (*cp == '\0')
+ {
+ break;
+ }
+
+ if (ntags < MAX_TAGS)
+ {
+ g_tags[ntags++] = cp;
+ }
+ }
+
+ if (strcmp(directive, "config") == 0)
+ {
+ dirn = DI_CONFIG;
+ }
+ else if (strcmp(directive, "include") == 0)
+ {
+ dirn = DI_INCLUDE;
+ }
+ else if (strcmp(directive, "echo") == 0)
+ {
+ dirn = DI_ECHO;
+ }
+ else if (strcmp(directive, "fsize") == 0)
+ {
+ dirn = DI_FSIZE;
+ }
+ else if (strcmp(directive, "flastmod") == 0)
+ {
+ dirn = DI_FLASTMOD;
+ }
+ else
+ {
+ unknown_directive(outstream, filename, directive);
+ return;
+ }
+
+ for (i = 0; i < ntags; ++i)
+ {
+ if (i > 0)
+ {
+ putc(' ', outstream);
+ }
+
+ val = strchr(g_tags[i], '=');
+ if (val == (char *)0)
+ {
+ val = "";
+ }
+ else
+ {
+ *val++ = '\0';
+ }
+
+ if (*val == '"' && val[strlen(val) - 1] == '"')
+ {
+ val[strlen(val) - 1] = '\0';
+ ++val;
+ }
+
+ switch (dirn)
+ {
+ case DI_CONFIG:
+ do_config(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ break;
+
+ case DI_INCLUDE:
+ do_include(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ break;
+
+ case DI_ECHO:
+ do_echo(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ break;
+
+ case DI_FSIZE:
+ do_fsize(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ break;
+
+ case DI_FLASTMOD:
+ do_flastmod(outstream, instream, vfilename, filename, directive, g_tags[i], val);
+ break;
+ }
+ }
+}
+
+static void slurp(FILE *outstream, FILE *instream, char *vfilename, char *filename)
+{
+ int state;
+ int ich;
+ int i;
+
+ /* Now slurp in the rest of the comment from the input file. */
+
+ i = 0;
+ state = ST_GROUND;
+ while ((ich = getc(instream)) != EOF)
+ {
+ switch (state)
+ {
+ case ST_GROUND:
+ if (ich == '-')
+ {
+ state = ST_MINUS1;
+ }
+ break;
+
+ case ST_MINUS1:
+ if (ich == '-')
+ {
+ state = ST_MINUS2;
+ }
+ else
+ {
+ state = ST_GROUND;
+ }
+ break;
+
+ case ST_MINUS2:
+ if (ich == '>')
+ {
+ g_iobuffer1[i - 2] = '\0';
+ parse(outstream, instream, vfilename, filename, g_iobuffer1);
+ return;
+ }
+ else if (ich != '-')
+ {
+ state = ST_GROUND;
+ }
+ break;
+ }
+
+ if (i < BUFFER_SIZE - 1)
+ {
+ g_iobuffer1[i++] = (char)ich;
+ }
+ }
+}
+
+static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *filename)
+{
+ int ich;
+ int state;
+
+ /* Copy it to output, while running a state-machine to look for SSI
+ * directives.
+ */
+
+ state = ST_GROUND;
+ while ((ich = getc(instream)) != EOF)
+ {
+ switch (state)
+ {
+ case ST_GROUND:
+ if (ich == '<')
+ {
+ state = ST_LESSTHAN;
+ continue;
+ }
+ break;
+
+ case ST_LESSTHAN:
+ if (ich == '!')
+ {
+ state = ST_BANG;
+ continue;
+ }
+ else
+ {
+ state = ST_GROUND;
+ putc('<', outstream);
+ }
+ break;
+
+ case ST_BANG:
+ if (ich == '-')
+ {
+ state = ST_MINUS1;
+ continue;
+ }
+ else
+ {
+ state = ST_GROUND;
+ (void)fputs("<!", outstream);
+ }
+ break;
+
+ case ST_MINUS1:
+ if (ich == '-')
+ {
+ state = ST_MINUS2;
+ continue;
+ }
+ else
+ {
+ state = ST_GROUND;
+ (void)fputs("<!-", outstream);
+ }
+ break;
+
+ case ST_MINUS2:
+ if (ich == '#')
+ {
+ slurp(outstream, instream, vfilename, filename);
+ state = ST_GROUND;
+ continue;
+ }
+ else
+ {
+ state = ST_GROUND;
+ (void)fputs("<!--", outstream);
+ }
+ break;
+ }
+
+ putc((char)ich, outstream);
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+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");
+ g_sizefmt = SF_BYTES;
+
+ /* The MIME type has to be text/html. */
+
+ (void)fputs("Content-type: text/html\n\n", outstream);
+
+ /* 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;
+ }
+
+ /* Append the PATH_INFO, if any, to get the full URL. */
+
+ path_info = getenv("PATH_INFO");
+ if (!path_info)
+ {
+ path_info = "";
+ }
+
+ 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;
+ }
+ (void)sprintf(g_url, "%s%s", script_name, path_info);
+
+ /* Get the name of the file to parse. */
+
+ path_translated = getenv("PATH_TRANSLATED");
+ if (!path_translated)
+ {
+ internal_error(outstream, "Couldn't get PATH_TRANSLATED environment variable.");
+ err = 4;
+ goto errout_with_g_url;
+ }
+
+ if (!check_filename(path_translated))
+ {
+ not_permitted(outstream, "initial", "PATH_TRANSLATED", path_translated);
+ err = 5;
+ goto errout_with_g_url;
+ }
+
+ /* Open it. */
+
+ instream = fopen(path_translated, "r");
+ if (!instream)
+ {
+ not_found(outstream, path_translated);
+ err = 6;
+ goto errout_with_g_url;
+ }
+
+ /* Read and handle the file. */
+
+ read_file(outstream, 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 241f67940..6ee5fa27d 100644
--- a/nuttx/netutils/thttpd/config.h
+++ b/nuttx/netutils/thttpd/config.h
@@ -119,6 +119,14 @@
# 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
@@ -189,15 +197,15 @@
* You can also leave both options undefined, and thttpd will not do anything special
* about tildes. Enabling both options is an error.
*
- * Typical values, if they're defined, are "users" for TILDE_MAP_1 and "public_html"
- * for TILDE_MAP_2.
+ * Typical values, if they're defined, are "users" for CONFIG_THTTPD_TILDE_MAP1 and "public_html"
+ * for CONFIG_THTTPD_TILDE_MAP2.
*/
-#if defined(TILDE_MAP_1) && defined(TILDE_MAP_2)
-# error "Both TILDE_MAP_1 and TILDE_MAP_2 are defined"
+#if defined(CONFIG_THTTPD_TILDE_MAP1) && defined(CONFIG_THTTPD_TILDE_MAP2)
+# error "Both CONFIG_THTTPD_TILDE_MAP1 andCONFIG_THTTPD_TILDE_MAP2 are defined"
#endif
-/* If CONFIG_THTTPD_URLPATTERN is not defined, then it will be used to match and verify
+/* If CONFIG_THTTPD_URLPATTERN is defined, then it will be used to match and verify
* referrers.
*/
diff --git a/nuttx/netutils/thttpd/libhttpd.c b/nuttx/netutils/thttpd/libhttpd.c
index cc3401fa2..ed49a4aee 100644
--- a/nuttx/netutils/thttpd/libhttpd.c
+++ b/nuttx/netutils/thttpd/libhttpd.c
@@ -132,14 +132,14 @@ static int auth_check2(httpd_conn *hc, char *dirname);
static void send_dirredirect(httpd_conn *hc);
static int hexit(char c);
static void strdecode(char *to, char *from);
-#ifdef GENERATE_INDEXES
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
static void strencode(char *to, int tosize, char *from);
#endif
-#ifdef TILDE_MAP_1
-static int tilde_map_1(httpd_conn *hc);
+#ifdef CONFIG_THTTPD_TILDE_MAP1
+static int CONFIG_THTTPD_TILDE_MAP1(httpd_conn *hc);
#endif
-#ifdef TILDE_MAP_2
-static int tilde_map_2(httpd_conn *hc);
+#ifdef CONFIG_THTTPD_TILDE_MAP2
+static int CONFIG_THTTPD_TILDE_MAP2(httpd_conn *hc);
#endif
#ifdef CONFIG_THTTPD_VHOST
static int vhost_map(httpd_conn *hc);
@@ -153,7 +153,7 @@ static void figure_mime(httpd_conn *hc);
static void cgi_kill2(ClientData client_data, struct timeval *nowP);
static void cgi_kill(ClientData client_data, struct timeval *nowP);
#endif
-#ifdef GENERATE_INDEXES
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
static void ls_child(int argc, char **argv);
static int ls(httpd_conn *hc);
#endif
@@ -941,7 +941,7 @@ static void strdecode(char *to, char *from)
/* Copies and encodes a string. */
-#ifdef GENERATE_INDEXES
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
static void strencode(char *to, int tosize, char *from)
{
int tolen;
@@ -963,17 +963,17 @@ static void strencode(char *to, int tosize, char *from)
}
*to = '\0';
}
-#endif /* GENERATE_INDEXES */
+#endif /* CONFIG_THTTPD_GENERATE_INDICES */
/* Map a ~username/whatever URL into <prefix>/username. */
-#ifdef TILDE_MAP_1
-static int tilde_map_1(httpd_conn *hc)
+#ifdef CONFIG_THTTPD_TILDE_MAP1
+static intCONFIG_THTTPD_TILDE_MAP1(httpd_conn *hc)
{
static char *temp;
static size_t maxtemp = 0;
int len;
- static char *prefix = TILDE_MAP_1;
+ static char *prefix =CONFIG_THTTPD_TILDE_MAP1;
len = strlen(hc->expnfilename) - 1;
httpd_realloc_str(&temp, &maxtemp, len);
@@ -990,16 +990,16 @@ static int tilde_map_1(httpd_conn *hc)
(void)strcat(hc->expnfilename, temp);
return 1;
}
-#endif /* TILDE_MAP_1 */
+#endif /*CONFIG_THTTPD_TILDE_MAP1 */
/* Map a ~username/whatever URL into <user's homedir>/<postfix>. */
-#ifdef TILDE_MAP_2
-static int tilde_map_2(httpd_conn *hc)
+#ifdef CONFIG_THTTPD_TILDE_MAP2
+static intCONFIG_THTTPD_TILDE_MAP2(httpd_conn *hc)
{
static char *temp;
static size_t maxtemp = 0;
- static char *postfix = TILDE_MAP_2;
+ static char *postfix =CONFIG_THTTPD_TILDE_MAP2;
char *cp;
struct passwd *pw;
char *alt;
@@ -1057,7 +1057,7 @@ static int tilde_map_2(httpd_conn *hc)
hc->tildemapped = TRUE;
return 1;
}
-#endif /* TILDE_MAP_2 */
+#endif /*CONFIG_THTTPD_TILDE_MAP2 */
/* Virtual host mapping. */
@@ -1622,7 +1622,7 @@ static void cgi_kill(ClientData client_data, struct timeval *nowP)
/* qsort comparison routine. */
-#ifdef GENERATE_INDEXES
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
static int name_compare(char **a, char **b)
{
return strcmp(*a, *b);
@@ -1985,7 +1985,7 @@ static int ls(httpd_conn *hc)
return 0;
}
-#endif /* GENERATE_INDEXES */
+#endif /* CONFIG_THTTPD_GENERATE_INDICES */
/* Set up environment variables. Be real careful here to avoid
* letting malicious clients overrun a buffer. We don't have
@@ -2843,7 +2843,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP)
}
/* Nope, no index file, so it's an actual directory request. */
-#ifdef GENERATE_INDEXES
+#ifdef CONFIG_THTTPD_GENERATE_INDICES
/* Directories must be readable for indexing. */
if (!(hc->sb.st_mode & S_IROTH))
{
@@ -2873,7 +2873,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP)
/* Ok, generate an index. */
return ls(hc);
-#else /* GENERATE_INDEXES */
+#else /* CONFIG_THTTPD_GENERATE_INDICES */
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 +2881,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 /* GENERATE_INDEXES */
+#endif /* CONFIG_THTTPD_GENERATE_INDICES */
got_one:
@@ -3449,9 +3449,9 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc)
hc->maxpathinfo = hc->maxquery = hc->maxaccept =
hc->maxaccepte = hc->maxreqhost = hc->maxhostdir =
hc->maxremoteuser = 0;
-#ifdef TILDE_MAP_2
+#ifdef CONFIG_THTTPD_TILDE_MAP2
hc->maxaltdir = 0;
-#endif /* TILDE_MAP_2 */
+#endif /*CONFIG_THTTPD_TILDE_MAP2 */
httpd_realloc_str(&hc->decodedurl, &hc->maxdecodedurl, 1);
httpd_realloc_str(&hc->origfilename, &hc->maxorigfilename, 1);
httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, 0);
@@ -3463,7 +3463,7 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc)
httpd_realloc_str(&hc->reqhost, &hc->maxreqhost, 0);
httpd_realloc_str(&hc->hostdir, &hc->maxhostdir, 0);
httpd_realloc_str(&hc->remoteuser, &hc->maxremoteuser, 0);
-#ifdef TILDE_MAP_2
+#ifdef CONFIG_THTTPD_TILDE_MAP2
httpd_realloc_str(&hc->altdir, &hc->maxaltdir, 0);
#endif
hc->initialized = 1;
@@ -3524,9 +3524,9 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc)
hc->authorization = "";
hc->remoteuser[0] = '\0';
hc->buffer[0] = '\0';
-#ifdef TILDE_MAP_2
+#ifdef CONFIG_THTTPD_TILDE_MAP2
hc->altdir[0] = '\0';
-#endif /* TILDE_MAP_2 */
+#endif /*CONFIG_THTTPD_TILDE_MAP2 */
hc->buflen = 0;
hc->if_modified_since = (time_t) - 1;
hc->range_if = (time_t) - 1;
@@ -4149,20 +4149,20 @@ int httpd_parse_request(httpd_conn *hc)
if (hc->expnfilename[0] == '~')
{
-#ifdef TILDE_MAP_1
+#ifdef CONFIG_THTTPD_TILDE_MAP1
if (!tilde_map_1(hc))
{
httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl);
return -1;
}
-#endif /* TILDE_MAP_1 */
-#ifdef TILDE_MAP_2
+#endif /*CONFIG_THTTPD_TILDE_MAP1 */
+#ifdef CONFIG_THTTPD_TILDE_MAP2
if (!tilde_map_2(hc))
{
httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl);
return -1;
}
-#endif /* TILDE_MAP_2 */
+#endif /*CONFIG_THTTPD_TILDE_MAP2 */
}
/* Virtual host mapping. */
@@ -4215,7 +4215,7 @@ int httpd_parse_request(httpd_conn *hc)
(void)strcpy(hc->expnfilename, &hc->expnfilename[strlen(hc->hs->cwd)]);
}
-#ifdef TILDE_MAP_2
+#ifdef CONFIG_THTTPD_TILDE_MAP2
else if (hc->altdir[0] != '\0' &&
(strncmp(hc->expnfilename, hc->altdir,
strlen(hc->altdir)) == 0 &&
@@ -4223,7 +4223,7 @@ int httpd_parse_request(httpd_conn *hc)
hc->expnfilename[strlen(hc->altdir)] == '/')))
{
}
-#endif /* TILDE_MAP_2 */
+#endif /*CONFIG_THTTPD_TILDE_MAP2 */
else
{
ndbg("%s URL \"%s\" goes outside the web tree\n",
@@ -4271,9 +4271,9 @@ void httpd_destroy_conn(httpd_conn *hc)
free((void *)hc->hostdir);
free((void *)hc->remoteuser);
free((void *)hc->buffer);
-#ifdef TILDE_MAP_2
+#ifdef CONFIG_THTTPD_TILDE_MAP2
free((void *)hc->altdir);
-#endif /* TILDE_MAP_2 */
+#endif /*CONFIG_THTTPD_TILDE_MAP2 */
hc->initialized = 0;
}
}
diff --git a/nuttx/netutils/thttpd/libhttpd.h b/nuttx/netutils/thttpd/libhttpd.h
index 87804eb2a..c5829614c 100644
--- a/nuttx/netutils/thttpd/libhttpd.h
+++ b/nuttx/netutils/thttpd/libhttpd.h
@@ -155,10 +155,10 @@ typedef struct
size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings,
maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir,
maxremoteuser, maxresponse;
-#ifdef TILDE_MAP_2
+#ifdef CONFIG_THTTPD_TILDE_MAP2
char *altdir;
size_t maxaltdir;
-#endif /* TILDE_MAP_2 */
+#endif /*CONFIG_THTTPD_TILDE_MAP2 */
time_t if_modified_since, range_if;
size_t contentlength;
char *type; /* not malloc()ed */
diff --git a/nuttx/netutils/thttpd/tdate_parse.c b/nuttx/netutils/thttpd/tdate_parse.c
index fcd2cfbda..f1e657029 100644
--- a/nuttx/netutils/thttpd/tdate_parse.c
+++ b/nuttx/netutils/thttpd/tdate_parse.c
@@ -190,7 +190,9 @@ time_t tdate_parse(char *str)
/* Skip initial whitespace ourselves - sscanf is clumsy at this. */
for (cp = str; *cp == ' ' || *cp == '\t'; ++cp)
- continue;
+ {
+ continue;
+ }
/* And do the sscanfs. WARNING: you can add more formats here, but be
* careful! You can easily screw up the parsing of existing formats when