Resync new repository with old repo r5166

git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2012-09-17 18:18:44 +00:00
commit 57623d42eb
5691 changed files with 1361853 additions and 0 deletions
+240
View File
@@ -0,0 +1,240 @@
#
# For a description of the syntax of this configuration file,
# see misc/tools/kconfig-language.txt.
#
config NETUTILS_THTTPD
bool "THTTPD webserver"
default n
---help---
Enable support for the THTTPD webservert.
if NETUTILS_THTTPD
config THTTPD_PORT
int "THTTPD port number"
default 80
---help---
THTTPD Server port number. Default: 80
config THTTPD_IPADDR
hex "THTTPD IP address"
default 0x10000002
---help---
Server IP address (no host name). Default: 0x10000002
This is a 32-bit integer value in host order. So, as an example,
the default value of 0x10000002 would correspond to 10.0.0.2.
config THTTPD_SERVER_ADDRESS
string "Reported server URL"
default "http://www.nuttx.org"
---help---
SERVER_ADDRESS: response, Default: "http://www.nuttx.org"
config THTTPD_SERVER_SOFTWARE
string "Reporter server software string"
default "thttpd/2.25b 29dec2003-NuttX"
---help---
SERVER_SOFTWARE: response, Default: "thttpd/2.25b 29dec2003-NuttX"
config THTTPD_PATH
string "Path to the server content"
default "/mnt/www"
---help---
Server working directory. Default: "/mnt/www"
config THTTPD_CGI_PATH
string "Path to CGI content"
default "/mnt/www/cgi-bin"
---help---
Path to CGI executables. Default: "/mnt/www/cgi-bin"
config THTTPD_CGI_PATTERN
string "CGI match pattern"
default "/mnt/www/cgi-bin/*"
---help---
Only CGI programs matching this pattern will be executed. In
fact, if this value is not defined then no CGI logic will be built.
Default: "/mnt/www/cgi-bin/*"
config THTTPD_CGI_PRIORITY
int "CGI child priority"
default 50
---help---
Provides the priority of CGI child tasks. Default: 50
config THTTPD_CGI_STACKSIZE
int "CGI child stack size"
default 2048
---help---
Provides the default stack size of CGI child task (will be overridden
by the stack size in the NXFLAT header)
config THTTPD_CGI_BYTECOUNT
int "Byte output limit"
default 200000
---help---
Byte output limit for CGI tasks. Default: 200000
config THTTPD_CGI_TIMELIMIT
int "CGI time limit"
default 0
---help---
How many seconds to allow CGI programs to run before killing them.
Default: 0 (no time limit)
config THTTPD_CHARSET
string "Default character set"
default "iso-8859-1"
---help---
The default character set name to use with text MIME types.
Default: "iso-8859-1"
config THTTPD_IOBUFFERSIZE
int "Initial I/O buffer size"
default 256
---help---
Initial I/O buffer size. Default: 256
config THTTPD_MINSTRSIZE
int "Minimum string size"
default 64
---help---
Minimum string size. Default: 64
config THTTPD_REALLOCINCR
int "String reallocation increment"
default 64
---help---
String reallocation increment. Default: 64
config THTTPD_MAXREALLOC
int "Maximum string reallocation size"
default 4096
---help---
Maximum string reallocation size. Default: 4096
config THTTPD_CGIINBUFFERSIZ
int "CGI interpose input buffer size"
default 512
---help---
CGI interpose input buffer size. Default: 512
config THTTPD_CGIOUTBUFFERSIZE
int "CGI interpose output buffer size"
default 512
---help---
CGI interpose output buffer size. Default: 512
config THTTPD_INDEX_NAMES
string "Index file name list"
default "\"index.html\", \"index.htm\", \"index.cgi\""
---help---
A list of index filenames to check. The files are searched for
in this order. Default: "\"index.html\", \"index.htm\", \"index.cgi\""
config AUTH_FILE
string "Authorization file"
# default ".htpasswd"
---help---
The file to use for authentication. If this is defined then thttpd
checks for this file in the local directory before every fetch. If
the file exists then authentication is done, otherwise the fetch proceeds
as usual. If you leave this undefined then thttpd will not implement
authentication at all and will not check for auth files, which saves a
bit of CPU time. A typical value is ".htpasswd"
config THTTPD_LISTEN_BACKLOG
int "Listen backlog"
default 8
---help---
The listen() backlog queue length. Default: 8
config THTTPD_LINGER_MSEC
int "Linger time (msec)"
default 500
---help---
How many milliseconds to leave a connection open while doing a lingering
close. Default: 500
config THTTPD_OCCASIONAL_MSEC
int "Occasional clean-up time (msec)"
default 120
---help---
How often to run the occasional cleanup job in milliseconds.
Default: 120 (2 minutes)
config THTTPD_MEMDEBUG
bool "Enable memory debug"
default n
depends on DEBUG && DEBUG_NET
---help---
Enable THTTPD memory usage debug output. Default: n
config THTTPD_IDLE_READ_LIMIT_SEC
int "Idle read time limit (sec)"
default 300
---help---
How many seconds to allow for reading the initial request on a new connection.
Default: 300
config THTTPD_IDLE_SEND_LIMIT_SEC
int "Idle send time limit (sec)"
default 300
---help---
How many seconds before an idle connection gets closed.
Default: 300
config THTTPD_TILDE_MAP1
string "Tilde mapping"
---help---
Tilde mapping.
Many URLs use ~username to indicate a user's home directory. thttpd
provides two options for mapping this construct to an actual filename.
1) Map ~username to <prefix>/username. This is the recommended choice.
Each user gets a subdirectory in the main web tree, and the tilde
construct points there. The prefix could be something like "users",
or it could be empty.
2) Map ~username to <user's homedir>/<postfix>. The postfix would be
the name of a subdirectory off of the user's actual home dir,
something like "public_html".
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
config THTTPD_TILDE_MAP1 and "public_html" for THTTPD_TILDE_MAP2.
config THTTPD_TILDE_MAP2
string "Tilde mapping"
---help---
Tilde mapping.
Many URLs use ~username to indicate a user's home directory. thttpd
provides two options for mapping this construct to an actual filename.
1) Map ~username to <prefix>/username. This is the recommended choice.
Each user gets a subdirectory in the main web tree, and the tilde
construct points there. The prefix could be something like "users",
or it could be empty.
2) Map ~username to <user's homedir>/<postfix>. The postfix would be
the name of a subdirectory off of the user's actual home dir,
something like "public_html".
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
config THTTPD_TILDE_MAP1 and "public_html" for THTTPD_TILDE_MAP2.
config THTTPD_GENERATE_INDICES
bool "Generate name indices"
default n
---help---
config THTTPD_URLPATTERN
string "URL pattern"
---help---
If defined, then it will be used to match and verify referrers.
endif
+129
View File
@@ -0,0 +1,129 @@
#############################################################################
# apps/netutils/thttpd/Makefile
#
# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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
-include $(TOPDIR)/Make.defs
include $(APPDIR)/Make.defs
# THTTPD Library
ASRCS =
CSRCS =
ifeq ($(CONFIG_NET_TCP),y)
CSRCS += thttpd.c libhttpd.c thttpd_cgi.c thttpd_alloc.c thttpd_strings.c timers.c fdwatch.c tdate_parse.c
endif
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
SRCS = $(ASRCS) $(CSRCS)
OBJS = $(AOBJS) $(COBJS)
ifeq ($(WINTOOL),y)
BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}"
else
BIN = "$(APPDIR)/libapps$(LIBEXT)"
endif
ROOTDEPPATH = --dep-path .
# CGI binaries (examples only, not used in the build)
CGIBINDIR = $(APPDIR)/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
all: $(SUBDIR_BIN) .built
.PHONY: depend clean distclean
$(AOBJS): %$(OBJEXT): %.S
$(call ASSEMBLE, $<, $@)
$(COBJS): %$(OBJEXT): %.c
$(call COMPILE, $<, $@)
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
.built: $(OBJS)
@( for obj in $(OBJS) ; do \
$(call ARCHIVE, $(BIN), $${obj}); \
done ; )
@touch .built
context:
.depend: Makefile $(SRCS)
@$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
@touch $@
depend: .depend
clean:
@rm -f *.o *~ .*.swp .built
$(call CLEAN)
distclean: clean
@rm -f Make.dep .depend
-include Make.dep
+140
View File
@@ -0,0 +1,140 @@
############################################################################
# apps/netutils/cgi-src/Makefile
#
# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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
-include $(TOPDIR)/Make.defs
ifeq ($(WINTOOL),y)
INCDIROPT = -w
endif
CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" "$(APPDIR)/netutils/thttpd" "$(APPDIR)/netutils/thttpd/cgi-src"}
CGIBINDIR = $(APPDIR)/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
+77
View File
@@ -0,0 +1,77 @@
/****************************************************************************
* netutils/thttpd/cgi-src/phf.c
* Cracker trap
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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[])
{
fprintf(stderr, "phf CGI probe from %s\n", getenv("REMOTE_ADDR"));
(void)printf("\
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");
return 0;
}
+269
View File
@@ -0,0 +1,269 @@
/****************************************************************************
* netutils/thttpd/cgi-src/redirect.c
* Simple redirection CGI program
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <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(char *reason)
{
char *title = "500 Internal Error";
(void)printf("\
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(char *script_name)
{
char *title = "404 Not Found";
(void)printf("\
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(char *script_name, char *url)
{
char *title = "Moved";
(void)printf("\
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)
{
char *script_name;
char *path_info;
char *cp = 0;
FILE *fp;
char *star;
int err = 0;
/* Get the name that we were run as, which is the filename being **
* redirected.
*/
script_name = getenv("SCRIPT_NAME");
if (!script_name)
{
internal_error("Couldn't get SCRIPT_NAME environment variable.");
return 1;
}
/* 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("Out of memory.");
return 2;
}
(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("Couldn't open .redirects file.");
err = 3;
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(script_name, g_url);
goto success_out;
}
}
/* Check for exact match. */
if (strcmp(g_file, script_name) == 0)
{
/* Got it. */
moved(script_name, g_url);
goto success_out;
}
}
}
}
/* No match found. */
not_found(script_name);
err = 4;
success_out:
fclose(fp);
errout_with_cp:
if (cp)
{
free(cp);
}
return err;
}
+957
View File
@@ -0,0 +1,957 @@
/****************************************************************************
* netutils/thttpd/cgi-src/ssi.c
* Server-side-includes CGI program
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 *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(char *reason)
{
char *title = "500 Internal Error";
(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\
<BLOCKQUOTE>\n\
%s\n\
</BLOCKQUOTE>\n\
</BODY></HTML>\n", title, title, reason);
}
static void not_found(char *filename)
{
char *title = "404 Not Found";
(void)printf("\
<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(char *directive, char *tag, char *filename)
{
char *title = "Not Found";
(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(char *directive, char *tag, char *val)
{
char *title = "Not Permitted";
(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(char *filename, char *directive)
{
char *title = "Unknown Directive";
(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(char *filename, char *directive, char *tag)
{
char *title = "Unknown Tag";
(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(char *filename, char *directive, char *tag, char *val)
{
char *title = "Unknown Value";
(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(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(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(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(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(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)puts(g_iobuffer2);
}
}
static void show_size(off_t size)
{
switch (g_sizefmt)
{
case SF_BYTES:
(void)printf("%ld", (long)size); /* spec says should have commas */
break;
case SF_ABBREV:
if (size < 1024)
{
(void)printf("%ld", (long)size);
}
else if (size < 1024)
{
(void)printf("%ldK", (long)size / 1024L);
}
else if (size < 1024 * 1024)
{
(void)printf("%ldM", (long)size / (1024L * 1024L));
}
else
{
(void)printf("%ldG", (long)size / (1024L * 1024L * 1024L));
}
break;
}
}
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. **
* 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(filename, directive, tag, val);
}
}
else
{
unknown_tag(filename, directive, tag);
}
}
static void do_include(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(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
if (ret < 0)
{
return;
}
if (!check_filename(g_iobuffer1))
{
not_permitted(directive, tag, g_iobuffer1);
return;
}
instream2 = fopen(g_iobuffer1, "r");
if (instream2 == (FILE *) 0)
{
not_found2(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(instream2, g_iobuffer2, g_iobuffer1);
(void)fclose(instream2);
}
static void do_echo(FILE *instream, char *vfilename, char *filename,
char *directive, char *tag, char *val)
{
char *cp;
/* 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(filename, directive, tag);
}
else
{
if (strcmp(val, "DOCUMENT_NAME") == 0)
{
/* The current filename. */
(void)puts(filename);
}
else if (strcmp(val, "DOCUMENT_URI") == 0)
{
/* The virtual path to this file (such as /~robm/foo.shtml). */
(void)puts(vfilename);
}
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)puts(cp);
}
}
else if (strcmp(val, "DATE_LOCAL") == 0)
{
struct timeval tm;
/* The current date, local time zone. */
gettimeofday(&tm, NULL);
show_time(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(tm.tv_sec, 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(g_sb.st_mtime, 0);
}
}
else
{
/* Try an environment variable. */
cp = getenv(val);
if (cp == (char *)0)
{
unknown_value(filename, directive, tag, val);
}
else
{
(void)puts(cp);
}
}
}
}
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(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
if (ret < 0)
{
return;
}
if (stat(g_iobuffer1, &g_sb) < 0)
{
not_found2(directive, tag, g_iobuffer1);
return;
}
show_size(g_sb.st_size);
}
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(vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE);
if (ret < 0)
{
return;
}
if (stat(g_iobuffer1, &g_sb) < 0)
{
not_found2(directive, tag, g_iobuffer1);
return;
}
show_time(g_sb.st_mtime, 0);
}
static void parse(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(filename, directive);
return;
}
for (i = 0; i < ntags; ++i)
{
if (i > 0)
{
putchar(' ');
}
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(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_INCLUDE:
do_include(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_ECHO:
do_echo(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_FSIZE:
do_fsize(instream, vfilename, filename, directive, g_tags[i], val);
break;
case DI_FLASTMOD:
do_flastmod(instream, vfilename, filename, directive, g_tags[i], val);
break;
}
}
}
static void slurp(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(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 *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;
putchar('<');
}
break;
case ST_BANG:
if (ich == '-')
{
state = ST_MINUS1;
continue;
}
else
{
state = ST_GROUND;
(void)puts("<!");
}
break;
case ST_MINUS1:
if (ich == '-')
{
state = ST_MINUS2;
continue;
}
else
{
state = ST_GROUND;
(void)puts("<!-");
}
break;
case ST_MINUS2:
if (ich == '#')
{
slurp(instream, vfilename, filename);
state = ST_GROUND;
continue;
}
else
{
state = ST_GROUND;
(void)puts("<!--");
}
break;
}
putchar((char)ich);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, char **argv)
{
FILE *instream;
char *script_name;
char *path_info;
char *path_translated;
int err = 0;
/* 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)puts("Content-type: text/html\n\n");
/* Get the name that we were run as. */
script_name = getenv("SCRIPT_NAME");
if (!script_name)
{
internal_error("Couldn't get SCRIPT_NAME environment variable.");
return 1;
}
/* 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("Out of memory.");
return 2;
}
(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("Couldn't get PATH_TRANSLATED environment variable.");
err = 3;
goto errout_with_g_url;
}
if (!check_filename(path_translated))
{
not_permitted("initial", "PATH_TRANSLATED", path_translated);
err = 4;
goto errout_with_g_url;
}
/* Open it. */
instream = fopen(path_translated, "r");
if (!instream)
{
not_found(path_translated);
err = 5;
goto errout_with_g_url;
}
/* Read and handle the file. */
read_file(instream, path_info, path_translated);
(void)fclose(instream);
errout_with_g_url:
free(g_url);
return err;
}
+253
View File
@@ -0,0 +1,253 @@
/****************************************************************************
* netutils/thttpd/config.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_CONFIG_H
#define __NETUTILS_THTTPD_CONFIG_H
/****************************************************************************
* Included files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Make sure that the system is configured to handle THTTPD */
#undef CONFIG_THTTPD
#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) && \
defined(CONFIG_NET_TCPBACKLOG) && !defined(CONFIG_DISABLE_ENVIRONMENT) && \
!defined(CONFIG_SDCLONE_DISABLE) && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
# define CONFIG_THTTPD 1
/* Check all THTTPD configuration settings. Complain on any that should have
* been defined but were not. Supply some kind of reasonable value for all
* undefined settings.
*/
/* Server port number */
# ifndef CONFIG_THTTPD_PORT
# define CONFIG_THTTPD_PORT 80
# endif
/* Server IP address (no host name) */
# ifndef CONFIG_THTTPD_IPADDR
# ifdef CONFIG_CPP_HAVE_WARNING
# warning "CONFIG_THTTPD_IPADDR not defined"
# endif
# define CONFIG_THTTPD_IPADDR (10<<24|0<<16|0<<8|2)
# endif
/* SERVER_ADDRESS: response */
# ifndef CONFIG_THTTPD_SERVER_ADDRESS
# define CONFIG_THTTPD_SERVER_ADDRESS "http://www.nuttx.org"
# endif
/* SERVER_SOFTWARE: response */
# ifndef CONFIG_THTTPD_SERVER_SOFTWARE
# define CONFIG_THTTPD_SERVER_SOFTWARE "thttpd/2.25b 29dec2003-NuttX"
# endif
# ifndef CONFIG_THTTPD_PATH
# ifdef CONFIG_CPP_HAVE_WARNING
# warning "CONFIG_THTTPD_PATH not defined"
# endif
# define CONFIG_THTTPD_PATH "/mnt/www"
# endif
# ifndef CONFIG_THTTPD_CGI_PATH
# ifdef CONFIG_CPP_HAVE_WARNING
# warning "CONFIG_THTTPD_CGI_PATH not defined"
# endif
# define CONFIG_THTTPD_CGI_PATH "/mnt/www/cgi-bin"
# endif
/* Only CGI programs whose fully expanded pathes match this pattern will be executed. In fact,
* if this value is not defined then no CGI logic will be built.
*/
# ifndef CONFIG_THTTPD_CGI_PATTERN
# define CONFIG_THTTPD_CGI_PATTERN "/mnt/www/cgi-bin/*"
# endif
/* These provide the priority and stack size of the CGI child tasks */
# ifndef CONFIG_THTTPD_CGI_PRIORITY
# define CONFIG_THTTPD_CGI_PRIORITY 50
# endif
# ifndef CONFIG_THTTPD_CGI_STACKSIZE
# define CONFIG_THTTPD_CGI_STACKSIZE 2048
# endif
/* Byte output limit for CGI tasks */
# ifndef CONFIG_THTTPD_CGI_BYTECOUNT
# define CONFIG_THTTPD_CGI_BYTECOUNT 200000
# endif
/* How many seconds to allow CGI programs to run before killing them. */
# ifndef CONFIG_THTTPD_CGI_TIMELIMIT
# define CONFIG_THTTPD_CGI_TIMELIMIT 0 /* No time limit */
# endif
/* The default character set name to use with text MIME types. */
# ifndef CONFIG_THTTPD_CHARSET
# define CONFIG_THTTPD_CHARSET "iso-8859-1"
# endif
/* Initial buffer size, buffer reallocation increment, maximum buffer size */
# ifndef CONFIG_THTTPD_IOBUFFERSIZE
# define CONFIG_THTTPD_IOBUFFERSIZE 256
# endif
# ifndef CONFIG_THTTPD_MINSTRSIZE
# define CONFIG_THTTPD_MINSTRSIZE 64
# endif
# ifndef CONFIG_THTTPD_REALLOCINCR
# define CONFIG_THTTPD_REALLOCINCR 64
# endif
# ifndef CONFIG_THTTPD_MAXREALLOC
# define CONFIG_THTTPD_MAXREALLOC 4096
# endif
# ifndef CONFIG_THTTPD_CGIINBUFFERSIZE
# define CONFIG_THTTPD_CGIINBUFFERSIZE 512 /* Size of buffer to interpose input */
# endif
# ifndef CONFIG_THTTPD_CGIOUTBUFFERSIZE
# define CONFIG_THTTPD_CGIOUTBUFFERSIZE 512 /* Size of buffer to interpose output */
# endif
# if CONFIG_THTTPD_IOBUFFERSIZE > 65535
# error "Can't use uint16_t for buffer size"
# endif
/* A list of index filenames to check. The files are searched for in this order. */
# ifndef CONFIG_THTTPD_INDEX_NAMES
# define CONFIG_THTTPD_INDEX_NAMES "index.html", "index.htm", "index.cgi"
# endif
/* CONFIG_AUTH_FILE - The file to use for authentication. If this is defined then
* thttpd checks for this file in the local directory before every fetch. If the
* file exists then authentication is done, otherwise the fetch proceeds as usual.
* If you leave this undefined then thttpd will not implement authentication at
* all and will not check for auth files, which saves a bit of CPU time.
* A typical value is ".htpasswd"
*/
/* The listen() backlog queue length. */
# ifndef CONFIG_THTTPD_LISTEN_BACKLOG
# define CONFIG_THTTPD_LISTEN_BACKLOG 8
# endif
/* How many milliseconds to leave a connection open while doing a lingering close */
# ifndef CONFIG_THTTPD_LINGER_MSEC
# define CONFIG_THTTPD_LINGER_MSEC 500
# endif
/* How often to run the occasional cleanup job.*/
# ifndef CONFIG_THTTPD_OCCASIONAL_MSEC
# define CONFIG_THTTPD_OCCASIONAL_MSEC 120 /* Two minutes */
# endif
/* How many seconds to allow for reading the initial request on a new connection. */
# ifndef CONFIG_THTTPD_IDLE_READ_LIMIT_SEC
# define CONFIG_THTTPD_IDLE_READ_LIMIT_SEC 300
# endif
/* How many seconds before an idle connection gets closed. */
# ifndef CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC
# define CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC 300
# endif
/* Memory debug instrumentation depends on other debug options */
#if (!defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET)) && defined(CONFIG_THTTPD_MEMDEBUG)
# undef CONFIG_THTTPD_MEMDEBUG
#endif
/* Tilde mapping. Many URLs use ~username to indicate a user's home directory. thttpd
* provides two options for mapping this construct to an actual filename.
*
* 1) Map ~username to <prefix>/username. This is the recommended choice. Each user
* gets a subdirectory in the main web tree, and the tilde construct points there.
* The prefix could be something like "users", or it could be empty.
* 2) Map ~username to <user's homedir>/<postfix>. The postfix would be the name of
* a subdirectory off of the user's actual home dir, something like "public_html".
*
* 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 CONFIG_THTTPD_TILDE_MAP1 and "public_html"
* for CONFIG_THTTPD_TILDE_MAP2.
*/
# 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 defined, then it will be used to match and verify
* referrers.
*/
#else /* Dependencies not provided */
# ifdef CONFIG_CPP_HAVE_WARNING
# warning "THTTPD not built because dependencies not selected in configuration"
# endif
#endif /* Dependencies not provided */
#endif /* __NETUTILS_THTTPD_CONFIG_H */
+371
View File
@@ -0,0 +1,371 @@
/****************************************************************************
* netutils/thttpd/timers.c
* FD watcher routines for poll()
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1999,2000 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 <nuttx/config.h>
#include <stdint.h>
#include <stdlib.h>
#include <debug.h>
#include <poll.h>
#include <debug.h>
#include "config.h"
#include "thttpd_alloc.h"
#include "fdwatch.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
/* Debug output from this file is normally suppressed. If enabled, be aware
* that output to stdout will interfere with CGI programs (you could use the
* the low-level debug (lldbg) functions which probably do not use stdout
*/
#ifdef CONFIG_THTTPD_FDWATCH_DEBUG
# ifdef CONFIG_CPP_HAVE_VARARGS
# define fwdbg(format, arg...) ndbg(format, ##arg)
# define fwlldbg(format, arg...) nlldbg(format, ##arg)
# define fwvdbg(format, arg...) nvdbg(format, ##arg)
# define fwllvdbg(format, arg...) nllvdbg(format, ##arg)
# else
# define fwdbg ndbg
# define fwlldbg nlldbg
# define fwvdbg nvdbg
# define fwllvdbg nllvdbg
# endif
#else
# ifdef CONFIG_CPP_HAVE_VARARGS
# define fwdbg(x...)
# define fwlldbg(x...)
# define fwvdbg(x...)
# define fwllvdbg(x...)
# else
# define fwdbg (void)
# define fwlldbg (void)
# define fwvdbg (void)
# define fwllvdbg (void)
# endif
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
#ifdef CONFIG_THTTPD_FDWATCH_DEBUG
static void fdwatch_dump(const char *msg, FAR struct fdwatch_s *fw)
{
int i;
fwvdbg("%s\n", msg);
fwvdbg("nwatched: %d nfds: %d\n", fw->nwatched, fw->nfds);
for (i = 0; i < fw->nwatched; i++)
{
fwvdbg("%2d. pollfds: {fd: %d events: %02x revents: %02x} client: %p\n",
i+1, fw->pollfds[i].fd, fw->pollfds[i].events,
fw->pollfds[i].revents, fw->client[i]);
}
fwvdbg("nactive: %d next: %d\n", fw->nactive, fw->next);
for (i = 0; i < fw->nactive; i++)
{
fwvdbg("%2d. %d active\n", i, fw->ready[i]);
}
}
#else
# define fdwatch_dump(m,f)
#endif
static int fdwatch_pollndx(FAR struct fdwatch_s *fw, int fd)
{
int pollndx;
/* Get the index associated with the fd */
for (pollndx = 0; pollndx < fw->nwatched; pollndx++)
{
if (fw->pollfds[pollndx].fd == fd)
{
fwvdbg("pollndx: %d\n", pollndx);
return pollndx;
}
}
fwdbg("No poll index for fd %d: %d\n", fd);
return -1;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/* Initialize the fdwatch data structures. Returns -1 on failure. */
struct fdwatch_s *fdwatch_initialize(int nfds)
{
FAR struct fdwatch_s *fw;
/* Allocate the fdwatch data structure */
fw = (struct fdwatch_s*)zalloc(sizeof(struct fdwatch_s));
if (!fw)
{
fwdbg("Failed to allocate fdwatch\n");
return NULL;
}
/* Initialize the fdwatch data structures. */
fw->nfds = nfds;
fw->client = (void**)httpd_malloc(sizeof(void*) * nfds);
if (!fw->client)
{
goto errout_with_allocations;
}
fw->pollfds = (struct pollfd*)httpd_malloc(sizeof(struct pollfd) * nfds);
if (!fw->pollfds)
{
goto errout_with_allocations;
}
fw->ready = (uint8_t*)httpd_malloc(sizeof(uint8_t) * nfds);
if (!fw->ready)
{
goto errout_with_allocations;
}
fdwatch_dump("Initial state:", fw);
return fw;
errout_with_allocations:
fdwatch_uninitialize(fw);
return NULL;
}
/* Uninitialize the fwdatch data structure */
void fdwatch_uninitialize(struct fdwatch_s *fw)
{
if (fw)
{
fdwatch_dump("Uninitializing:", fw);
if (fw->client)
{
httpd_free(fw->client);
}
if (fw->pollfds)
{
httpd_free(fw->pollfds);
}
if (fw->ready)
{
httpd_free(fw->ready);
}
httpd_free(fw);
}
}
/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */
void fdwatch_add_fd(struct fdwatch_s *fw, int fd, void *client_data)
{
fwvdbg("fd: %d client_data: %p\n", fd, client_data);
fdwatch_dump("Before adding:", fw);
if (fw->nwatched >= fw->nfds)
{
fwdbg("too many fds\n");
return;
}
/* Save the new fd at the end of the list */
fw->pollfds[fw->nwatched].fd = fd;
fw->pollfds[fw->nwatched].events = POLLIN;
fw->client[fw->nwatched] = client_data;
/* Increment the count of watched descriptors */
fw->nwatched++;
fdwatch_dump("After adding:", fw);
}
/* Remove a descriptor from the watch list. */
void fdwatch_del_fd(struct fdwatch_s *fw, int fd)
{
int pollndx;
fwvdbg("fd: %d\n", fd);
fdwatch_dump("Before deleting:", fw);
/* Get the index associated with the fd */
pollndx = fdwatch_pollndx(fw, fd);
if (pollndx >= 0)
{
/* Decrement the number of fds in the poll table */
fw->nwatched--;
/* Replace the deleted one with the one at the the end
* of the list.
*/
if (pollndx != fw->nwatched)
{
fw->pollfds[pollndx] = fw->pollfds[fw->nwatched];
fw->client[pollndx] = fw->client[fw->nwatched];
}
}
fdwatch_dump("After deleting:", fw);
}
/* 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.
*/
int fdwatch(struct fdwatch_s *fw, long timeout_msecs)
{
int ret;
int i;
/* Wait for activity on any of the desciptors. When poll() returns, ret
* will hold the number of descriptors with activity (or zero on a timeout
* or <0 on an error.
*/
fdwatch_dump("Before waiting:", fw);
fwvdbg("Waiting... (timeout %d)\n", timeout_msecs);
fw->nactive = 0;
fw->next = 0;
ret = poll(fw->pollfds, fw->nwatched, (int)timeout_msecs);
fwvdbg("Awakened: %d\n", ret);
/* Look through all of the descriptors and make a list of all of them than
* have activity.
*/
if (ret > 0)
{
for (i = 0; i < fw->nwatched; i++)
{
/* Is there activity on this descriptor? */
if (fw->pollfds[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL))
{
/* Yes... save it in a shorter list */
fwvdbg("pollndx: %d fd: %d revents: %04x\n",
i, fw->pollfds[i].fd, fw->pollfds[i].revents);
fw->ready[fw->nactive++] = fw->pollfds[i].fd;
if (fw->nactive == ret)
{
/* We have all of them, break out early */
break;
}
}
}
}
/* Return the number of descriptors with activity */
fwvdbg("nactive: %d\n", fw->nactive);
fdwatch_dump("After wakeup:", fw);
return ret;
}
/* Check if a descriptor was ready. */
int fdwatch_check_fd(struct fdwatch_s *fw, int fd)
{
int pollndx;
fwvdbg("fd: %d\n", fd);
fdwatch_dump("Checking:", fw);
/* Get the index associated with the fd */
pollndx = fdwatch_pollndx(fw, fd);
if (pollndx >= 0 && (fw->pollfds[pollndx].revents & POLLERR) == 0)
{
return fw->pollfds[pollndx].revents & (POLLIN | POLLHUP | POLLNVAL);
}
fwvdbg("POLLERR fd: %d\n", fd);
return 0;
}
void *fdwatch_get_next_client_data(struct fdwatch_s *fw)
{
fdwatch_dump("Before getting client data:", fw);
if (fw->next >= fw->nwatched)
{
fwvdbg("All client data returned: %d\n", fw->next);
return (void*)-1;
}
fwvdbg("client_data[%d]: %p\n", fw->next, fw->client[fw->next]);
return fw->client[fw->next++];
}
#endif /* CONFIG_THTTPD */
+111
View File
@@ -0,0 +1,111 @@
/****************************************************************************
* netutils/thttpd/fdwatch.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in THTTPD:
*
* Copyright © 1999 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.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_FDWATCH_H
#define __NETUTILS_THTTPD_FDWATCH_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
/* Define to enable detailed FDWATCH debug output */
#undef CONFIG_THTTPD_FDWATCH_DEBUG
#ifndef INFTIM
# define INFTIM -1
#endif
/****************************************************************************
* Private Types
****************************************************************************/
struct fdwatch_s
{
struct pollfd *pollfds; /* Poll data (allocated) */
void **client; /* Client data (allocated) */
uint8_t *ready; /* The list of fds with activity (allocated) */
uint8_t nfds; /* The configured maximum number of fds */
uint8_t nwatched; /* The number of fds currently watched */
uint8_t nactive; /* The number of fds with activity */
uint8_t next; /* The index to the next client data */
};
/****************************************************************************
* 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 void fdwatch_uninitialize(struct fdwatch_s *fw);
/* Add a descriptor to the watch list */
extern void fdwatch_add_fd(struct fdwatch_s *fw, int fd, void *client_data);
/* Delete a descriptor from the watch list. */
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(struct fdwatch_s *fw, long timeout_msecs);
/* Check if a descriptor was ready. */
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(struct fdwatch_s *fw);
#endif /* __NETUTILS_THTTPD_FDWATCH_H */
File diff suppressed because it is too large Load Diff
+342
View File
@@ -0,0 +1,342 @@
/****************************************************************************
* netutils/thttpd/libhttpd.h
* HTTP Protocol Library Definitions
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,1998,1999,2000,2001 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.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_LIBHTTPD_H
#define __NETUTILS_THTTPD_LIBHTTPD_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <stdbool.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include "config.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* A few convenient defines. */
#ifndef MAX
# define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/* Enable special instrumentation to track down "400 Bad Request" problems */
#undef CONFIG_THTTPD_BADREQUEST /* Define to enable "Bad Request" instrumentation */
#ifdef CONFIG_THTTPD_BADREQUEST
# if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET)
# undef CONFIG_THTTPD_BADREQUEST
# else
# define BADREQUEST(s) nvdbg("Bad Request: \"%s\"\n", s)
# endif
#endif
#ifndef CONFIG_THTTPD_BADREQUEST
# undef BADREQUEST
# define BADREQUEST(s)
#endif
/* Enable special instrumentation to track down "501 Not Implemented" problems */
#undef CONFIG_THTTPD_NOTIMPLEMENTED /* Define to enable "Not Implemented" instrumentation */
#ifdef CONFIG_THTTPD_NOTIMPLEMENTED
# if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET)
# undef CONFIG_THTTPD_NOTIMPLEMENTED
# else
# define NOTIMPLEMENTED(s) nvdbg("Not Implemented: \"%s\"\n", s)
# endif
#endif
#ifndef CONFIG_THTTPD_NOTIMPLEMENTED
# undef NOTIMPLEMENTED
# define NOTIMPLEMENTED(s)
#endif
/* Enable special instrumentation to track down "500 Internal Error" problems */
#undef CONFIG_THTTPD_INTERNALERROR /* Define to enable "Internal Error" instrumentation */
#ifdef CONFIG_THTTPD_INTERNALERROR
# if !defined(CONFIG_DEBUG_VERBOSE) || !defined(CONFIG_DEBUG_NET)
# undef CONFIG_THTTPD_INTERNALERROR
# else
# define INTERNALERROR(s) nvdbg("Internal Error: \"%s\"\n", s)
# endif
#endif
#ifndef CONFIG_THTTPD_INTERNALERROR
# undef INTERNALERROR
# define INTERNALERROR(s)
#endif
/* Methods */
#define METHOD_UNKNOWN 0
#define METHOD_GET 1
#define METHOD_HEAD 2
#define METHOD_POST 3
/* States for checked_state. */
#define CHST_FIRSTWORD 0
#define CHST_FIRSTWS 1
#define CHST_SECONDWORD 2
#define CHST_SECONDWS 3
#define CHST_THIRDWORD 4
#define CHST_THIRDWS 5
#define CHST_LINE 6
#define CHST_LF 7
#define CHST_CR 8
#define CHST_CRLF 9
#define CHST_CRLFCR 10
#define CHST_BOGUS 11
#define GC_FAIL 0
#define GC_OK 1
#define GC_NO_MORE 2
#define GR_NO_REQUEST 0
#define GR_GOT_REQUEST 1
#define GR_BAD_REQUEST 2
/****************************************************************************
* Public Type Definitions
****************************************************************************/
/* A multi-family sockaddr. */
#ifdef CONFIG_NET_IPv6
typedef struct sockaddr_in6 httpd_sockaddr;
#else
typedef struct sockaddr_in httpd_sockaddr;
#endif
/* A server. */
typedef struct
{
char *hostname;
int cgi_count;
int listen_fd;
} httpd_server;
/* A connection. */
typedef struct
{
int initialized;
httpd_server *hs;
httpd_sockaddr client_addr;
char *read_buf;
size_t read_size, read_idx, checked_idx;
int checked_state;
int method;
off_t bytes_to_send;
off_t bytes_sent;
char *encodedurl;
char *decodedurl;
char *protocol;
char *origfilename;
char *expnfilename;
char *encodings;
char *pathinfo;
char *query;
char *referer;
char *useragent;
char *accept;
char *accepte;
char *acceptl;
char *cookie;
char *contenttype;
char *reqhost;
char *hdrhost;
char *hostdir;
char *authorization;
char *remoteuser;
size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings,
maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir,
maxremoteuser, maxresponse;
#ifdef CONFIG_THTTPD_TILDE_MAP2
char *altdir;
size_t maxaltdir;
#endif
time_t if_modified_since, range_if;
size_t contentlength;
char *type; /* not malloc()ed */
#ifdef CONFIG_THTTPD_VHOST
char *vhostname; /* not malloc()ed */
#endif
bool mime_flag;
bool one_one; /* HTTP/1.1 or better */
bool got_range;
bool tildemapped; /* this connection got tilde-mapped */
bool keep_alive;
bool should_linger;
int conn_fd; /* Connection to the client */
int file_fd; /* Descriptor for open, outgoing file */
off_t range_start; /* File range start from Range= */
off_t range_end; /* File range end from Range= */
struct stat sb;
/* This is the I/O buffer that is used to buffer portions of outgoing files */
uint16_t buflen; /* Index to first valid data in buffer */
uint8_t buffer[CONFIG_THTTPD_IOBUFFERSIZE];
} httpd_conn;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Initializes. Does the socket(), bind(), and listen(). Returns an
* httpd_server* which includes a socket fd that you can select() on.
* Return (httpd_server*) 0 on error.
*/
extern FAR httpd_server *httpd_initialize(FAR httpd_sockaddr *sa);
/* Call to unlisten/close socket(s) listening for new connections. */
extern void httpd_unlisten(httpd_server *hs);
/* Call to shut down. */
extern void httpd_terminate(httpd_server *hs);
/* When a listen fd is ready to read, call this. It does the accept() and
* returns an httpd_conn* which includes the fd to read the request from and
* write the response to. Returns an indication of whether the accept()
* failed, succeeded, or if there were no more connections to accept.
*
* In order to minimize malloc()s, the caller passes in the httpd_conn.
* The caller is also responsible for setting initialized to zero before the
* first call using each different httpd_conn.
*/
extern int httpd_get_conn(httpd_server *hs, int listen_fd, httpd_conn *hc);
/* Checks whether the data in hc->read_buf constitutes a complete request
* yet. The caller reads data into hc->read_buf[hc->read_idx] and advances
* hc->read_idx. This routine checks what has been read so far, using
* hc->checked_idx and hc->checked_state to keep track, and returns an
* indication of whether there is no complete request yet, there is a
* complete request, or there won't be a valid request due to a syntax error.
*/
extern int httpd_got_request(httpd_conn *hc);
/* Parses the request in hc->read_buf. Fills in lots of fields in hc,
* like the URL and the various headers.
*
* Returns -1 on error.
*/
extern int httpd_parse_request(httpd_conn *hc);
/* Starts sending data back to the client. In some cases (directories,
* CGI programs), finishes sending by itself - in those cases, hc->file_fd
* is negative. If there is more data to be sent, then hc->file_fd is a file
* stream for the file to send. If you don't have a current timeval
* handy just pass in 0.
*
* Returns -1 on error.
*/
extern int httpd_start_request(httpd_conn *hc, struct timeval *nowP);
/* Actually sends any buffered response text. */
extern void httpd_write_response(httpd_conn *hc);
/* Call this to close down a connection and free the data. */
extern void httpd_close_conn(httpd_conn *hc);
/* Call this to de-initialize a connection struct and *really* free the
* mallocced strings.
*/
extern void httpd_destroy_conn(httpd_conn *hc);
/* Send an error message back to the client. */
extern void httpd_send_err(httpd_conn *hc, int status, const char *title,
const char *extraheads, const char *form, const char *arg);
/* Generate a string representation of a method number. */
extern const char *httpd_method_str(int method);
/* Format a network socket to a string representation. */
extern char *httpd_ntoa(httpd_sockaddr * saP);
/* Set NDELAY mode on a socket. */
extern void httpd_set_ndelay(int fd);
/* Clear NDELAY mode on a socket. */
extern void httpd_clear_ndelay(int fd);
/* Read to requested buffer, accounting for interruptions and EOF */
extern int httpd_read(int fd, const void *buf, size_t nbytes);
/* Write the buffer completely, accounting for interruptions */
extern int httpd_write(int fd, const void *buf, size_t nbytes);
#endif /* CONFIG_THTTPD */
#endif /* __NETUTILS_THTTPD_LIBHTTPD_H */
+279
View File
@@ -0,0 +1,279 @@
/****************************************************************************
* netutils/thttpd/mime_types.h
* Provides mappings between filename extensions and MIME types and encodings.
*
* Based on mime_encodings.txt and mime_types.txt by Jef Poskanser which
* contained no copyright information.
*
* Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_MIME_TYPES_H
#define __NETUTILS_THTTPD_MIME_TYPES_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/types.h>
/****************************************************************************
* Private Types
****************************************************************************/
struct mime_entry
{
char *ext;
size_t ext_len;
char *val;
size_t val_len;
};
/****************************************************************************
* Private Data
****************************************************************************/
/* A list of file extensions followed by the corresponding MIME encoding.
* Extensions not found in the table proceed to the mime_types table.
* Must be ordered by extension so to support binary searches.
*/
static struct mime_entry enc_tab[] =
{
{ "Z", 0, "compress", 0 },
{ "gz", 0, "gzip", 0 },
{ "uu", 0, "x-uuencode", 0 },
};
static const int n_enc_tab = sizeof(enc_tab) / sizeof(*enc_tab);
/* A list of file extensions followed by the corresponding MIME type.
* Extensions not found in the table are returned as text/plain.
* Must be ordered by extension so to support binary searches.
*/
static struct mime_entry typ_tab[] =
{
{ "a", 0, "application/octet-stream", 0 },
{ "aab", 0, "application/x-authorware-bin", 0 },
{ "aam", 0, "application/x-authorware-map", 0 },
{ "aas", 0, "application/x-authorware-seg", 0 },
{ "ai", 0, "application/postscript", 0 },
{ "aif", 0, "audio/x-aiff", 0 },
{ "aifc", 0, "audio/x-aiff", 0 },
{ "aiff", 0, "audio/x-aiff", 0 },
{ "asc", 0, "text/plain", 0 },
{ "asf", 0, "video/x-ms-asf", 0 },
{ "asx", 0, "video/x-ms-asf", 0 },
{ "au", 0, "audio/basic", 0 },
{ "avi", 0, "video/x-msvideo", 0 },
{ "bcpio", 0, "application/x-bcpio", 0 },
{ "bin", 0, "application/octet-stream", 0 },
{ "bmp", 0, "image/bmp", 0 },
{ "cdf", 0, "application/x-netcdf", 0 },
{ "class", 0, "application/x-java-vm", 0 },
{ "cpio", 0, "application/x-cpio", 0 },
{ "cpt", 0, "application/mac-compactpro", 0 },
{ "crl", 0, "application/x-pkcs7-crl", 0 },
{ "crt", 0, "application/x-x509-ca-cert", 0 },
{ "csh", 0, "application/x-csh", 0 },
{ "css", 0, "text/css", 0 },
{ "dcr", 0, "application/x-director", 0 },
{ "dir", 0, "application/x-director", 0 },
{ "djv", 0, "image/vnd.djvu", 0 },
{ "djvu", 0, "image/vnd.djvu", 0 },
{ "dll", 0, "application/octet-stream", 0 },
{ "dms", 0, "application/octet-stream", 0 },
{ "doc", 0, "application/msword", 0 },
{ "dtd", 0, "text/xml", 0 },
{ "dump", 0, "application/octet-stream", 0 },
{ "dvi", 0, "application/x-dvi", 0 },
{ "dxr", 0, "application/x-director", 0 },
{ "eps", 0, "application/postscript", 0 },
{ "etx", 0, "text/x-setext", 0 },
{ "exe", 0, "application/octet-stream", 0 },
{ "ez", 0, "application/andrew-inset", 0 },
{ "fgd", 0, "application/x-director", 0 },
{ "fh", 0, "image/x-freehand", 0 },
{ "fh4", 0, "image/x-freehand", 0 },
{ "fh5", 0, "image/x-freehand", 0 },
{ "fh7", 0, "image/x-freehand", 0 },
{ "fhc", 0, "image/x-freehand", 0 },
{ "gif", 0, "image/gif", 0 },
{ "gtar", 0, "application/x-gtar", 0 },
{ "hdf", 0, "application/x-hdf", 0 },
{ "hqx", 0, "application/mac-binhex40", 0 },
{ "htm", 0, "text/html; charset=%s", 0 },
{ "html", 0, "text/html; charset=%s", 0 },
{ "ice", 0, "x-conference/x-cooltalk", 0 },
{ "ief", 0, "image/ief", 0 },
{ "iges", 0, "model/iges", 0 },
{ "igs", 0, "model/iges", 0 },
{ "iv", 0, "application/x-inventor", 0 },
{ "jar", 0, "application/x-java-archive", 0 },
{ "jfif", 0, "image/jpeg", 0 },
{ "jpe", 0, "image/jpeg", 0 },
{ "jpeg", 0, "image/jpeg", 0 },
{ "jpg", 0, "image/jpeg", 0 },
{ "js", 0, "application/x-javascript", 0 },
{ "kar", 0, "audio/midi", 0 },
{ "latex", 0, "application/x-latex", 0 },
{ "lha", 0, "application/octet-stream", 0 },
{ "lzh", 0, "application/octet-stream", 0 },
{ "m3u", 0, "audio/x-mpegurl", 0 },
{ "man", 0, "application/x-troff-man", 0 },
{ "mathml", 0, "application/mathml+xml", 0 },
{ "me", 0, "application/x-troff-me", 0 },
{ "mesh", 0, "model/mesh", 0 },
{ "mid", 0, "audio/midi", 0 },
{ "midi", 0, "audio/midi", 0 },
{ "mif", 0, "application/vnd.mif", 0 },
{ "mime", 0, "message/rfc822", 0 },
{ "mml", 0, "application/mathml+xml", 0 },
{ "mov", 0, "video/quicktime", 0 },
{ "movie", 0, "video/x-sgi-movie", 0 },
{ "mp2", 0, "audio/mpeg", 0 },
{ "mp3", 0, "audio/mpeg", 0 },
{ "mp4", 0, "video/mp4", 0 },
{ "mpe", 0, "video/mpeg", 0 },
{ "mpeg", 0, "video/mpeg", 0 },
{ "mpg", 0, "video/mpeg", 0 },
{ "mpga", 0, "audio/mpeg", 0 },
{ "ms", 0, "application/x-troff-ms", 0 },
{ "msh", 0, "model/mesh", 0 },
{ "mv", 0, "video/x-sgi-movie", 0 },
{ "mxu", 0, "video/vnd.mpegurl", 0 },
{ "nc", 0, "application/x-netcdf", 0 },
{ "o", 0, "application/octet-stream", 0 },
{ "oda", 0, "application/oda", 0 },
{ "ogg", 0, "application/x-ogg", 0 },
{ "pac", 0, "application/x-ns-proxy-autoconfig", 0 },
{ "pbm", 0, "image/x-portable-bitmap", 0 },
{ "pdb", 0, "chemical/x-pdb", 0 },
{ "pdf", 0, "application/pdf", 0 },
{ "pgm", 0, "image/x-portable-graymap", 0 },
{ "pgn", 0, "application/x-chess-pgn", 0 },
{ "png", 0, "image/png", 0 },
{ "pnm", 0, "image/x-portable-anymap", 0 },
{ "ppm", 0, "image/x-portable-pixmap", 0 },
{ "ppt", 0, "application/vnd.ms-powerpoint", 0 },
{ "ps", 0, "application/postscript", 0 },
{ "qt", 0, "video/quicktime", 0 },
{ "ra", 0, "audio/x-realaudio", 0 },
{ "ram", 0, "audio/x-pn-realaudio", 0 },
{ "ras", 0, "image/x-cmu-raster", 0 },
{ "rdf", 0, "application/rdf+xml", 0 },
{ "rgb", 0, "image/x-rgb", 0 },
{ "rm", 0, "audio/x-pn-realaudio", 0 },
{ "roff", 0, "application/x-troff", 0 },
{ "rpm", 0, "audio/x-pn-realaudio-plugin", 0 },
{ "rss", 0, "application/rss+xml", 0 },
{ "rtf", 0, "text/rtf", 0 },
{ "rtx", 0, "text/richtext", 0 },
{ "sgm", 0, "text/sgml", 0 },
{ "sgml", 0, "text/sgml", 0 },
{ "sh", 0, "application/x-sh", 0 },
{ "shar", 0, "application/x-shar", 0 },
{ "silo", 0, "model/mesh", 0 },
{ "sit", 0, "application/x-stuffit", 0 },
{ "skd", 0, "application/x-koan", 0 },
{ "skm", 0, "application/x-koan", 0 },
{ "skp", 0, "application/x-koan", 0 },
{ "skt", 0, "application/x-koan", 0 },
{ "smi", 0, "application/smil", 0 },
{ "smil", 0, "application/smil", 0 },
{ "snd", 0, "audio/basic", 0 },
{ "so", 0, "application/octet-stream", 0 },
{ "spl", 0, "application/x-futuresplash", 0 },
{ "src", 0, "application/x-wais-source", 0 },
{ "stc", 0, "application/vnd.sun.xml.calc.template", 0 },
{ "std", 0, "application/vnd.sun.xml.draw.template", 0 },
{ "sti", 0, "application/vnd.sun.xml.impress.template", 0 },
{ "stw", 0, "application/vnd.sun.xml.writer.template", 0 },
{ "sv4cpio", 0, "application/x-sv4cpio", 0 },
{ "sv4crc", 0, "application/x-sv4crc", 0 },
{ "svg", 0, "image/svg+xml", 0 },
{ "svgz", 0, "image/svg+xml", 0 },
{ "swf", 0, "application/x-shockwave-flash", 0 },
{ "sxc", 0, "application/vnd.sun.xml.calc", 0 },
{ "sxd", 0, "application/vnd.sun.xml.draw", 0 },
{ "sxg", 0, "application/vnd.sun.xml.writer.global", 0 },
{ "sxi", 0, "application/vnd.sun.xml.impress", 0 },
{ "sxm", 0, "application/vnd.sun.xml.math", 0 },
{ "sxw", 0, "application/vnd.sun.xml.writer", 0 },
{ "t", 0, "application/x-troff", 0 },
{ "tar", 0, "application/x-tar", 0 },
{ "tcl", 0, "application/x-tcl", 0 },
{ "tex", 0, "application/x-tex", 0 },
{ "texi", 0, "application/x-texinfo", 0 },
{ "texinfo", 0, "application/x-texinfo", 0 },
{ "tif", 0, "image/tiff", 0 },
{ "tiff", 0, "image/tiff", 0 },
{ "tr", 0, "application/x-troff", 0 },
{ "tsp", 0, "application/dsptype", 0 },
{ "tsv", 0, "text/tab-separated-values", 0 },
{ "txt", 0, "text/plain; charset=%s", 0 },
{ "ustar", 0, "application/x-ustar", 0 },
{ "vcd", 0, "application/x-cdlink", 0 },
{ "vrml", 0, "model/vrml", 0 },
{ "vx", 0, "video/x-rad-screenplay", 0 },
{ "wav", 0, "audio/x-wav", 0 },
{ "wax", 0, "audio/x-ms-wax", 0 },
{ "wbmp", 0, "image/vnd.wap.wbmp", 0 },
{ "wbxml", 0, "application/vnd.wap.wbxml", 0 },
{ "wm", 0, "video/x-ms-wm", 0 },
{ "wma", 0, "audio/x-ms-wma", 0 },
{ "wmd", 0, "application/x-ms-wmd", 0 },
{ "wml", 0, "text/vnd.wap.wml", 0 },
{ "wmlc", 0, "application/vnd.wap.wmlc", 0 },
{ "wmls", 0, "text/vnd.wap.wmlscript", 0 },
{ "wmlsc", 0, "application/vnd.wap.wmlscriptc", 0 },
{ "wmv", 0, "video/x-ms-wmv", 0 },
{ "wmx", 0, "video/x-ms-wmx", 0 },
{ "wmz", 0, "application/x-ms-wmz", 0 },
{ "wrl", 0, "model/vrml", 0 },
{ "wsrc", 0, "application/x-wais-source", 0 },
{ "wvx", 0, "video/x-ms-wvx", 0 },
{ "xbm", 0, "image/x-xbitmap", 0 },
{ "xht", 0, "application/xhtml+xml", 0 },
{ "xhtml", 0, "application/xhtml+xml", 0 },
{ "xls", 0, "application/vnd.ms-excel", 0 },
{ "xml", 0, "text/xml", 0 },
{ "xpm", 0, "image/x-xpixmap", 0 },
{ "xsl", 0, "text/xml", 0 },
{ "xwd", 0, "image/x-xwindowdump", 0 },
{ "xyz", 0, "chemical/x-xyz", 0 },
{ "zip", 0, "application/zip", 0 },
};
static const int n_typ_tab = sizeof(typ_tab) / sizeof(*typ_tab);
#endif /* __NETUTILS_THTTPD_MIME_TYPES_H */
+341
View File
@@ -0,0 +1,341 @@
/****************************************************************************
* netutils/thttpd/timers.c
* Parse string dates into internal form, stripped-down version
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <debug.h>
#include "tdate_parse.h"
/****************************************************************************
* Private Types
****************************************************************************/
#undef TDATE_PARSE_WORKS /* tdate_parse() doesn't work */
#undef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
/****************************************************************************
* Private Types
****************************************************************************/
struct strlong
{
char *s;
long l;
};
/****************************************************************************
* Private Functions
****************************************************************************/
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
static void pound_case(char *str)
{
for (; *str != '\0'; ++str)
{
if (isupper((int)*str))
{
*str = tolower((int)*str);
}
}
}
#endif
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
static int strlong_compare(const void *v1, const void *v2)
{
return strcmp(((struct strlong *)v1)->s, ((struct strlong *)v2)->s);
}
#endif
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
static int strlong_search(char *str, struct strlong *tab, int n, long *lP)
{
int i, h, l, r;
l = 0;
h = n - 1;
for (;;)
{
i = (h + l) / 2;
r = strcmp(str, tab[i].s);
if (r < 0)
{
h = i - 1;
}
else if (r > 0)
{
l = i + 1;
}
else
{
*lP = tab[i].l;
return 1;
}
if (h < l)
{
return 0;
}
}
}
#endif
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
static int scan_wday(char *str_wday, long *tm_wdayP)
{
static struct strlong wday_tab[] = {
{"sun", 0}, {"sunday", 0},
{"mon", 1}, {"monday", 1},
{"tue", 2}, {"tuesday", 2},
{"wed", 3}, {"wednesday", 3},
{"thu", 4}, {"thursday", 4},
{"fri", 5}, {"friday", 5},
{"sat", 6}, {"saturday", 6},
};
static int sorted = 0;
if (!sorted)
{
(void)qsort(wday_tab, sizeof(wday_tab) / sizeof(struct strlong),
sizeof(struct strlong), strlong_compare);
sorted = 1;
}
pound_case(str_wday);
return strlong_search(str_wday, wday_tab,
sizeof(wday_tab) / sizeof(struct strlong), tm_wdayP);
}
#endif /* Day of week not yet supported by NuttX */
#ifdef TDATE_PARSE_WORKS
static int scan_mon(char *str_mon, long *tm_monP)
{
static struct strlong mon_tab[] = {
{"jan", 0}, {"january", 0},
{"feb", 1}, {"february", 1},
{"mar", 2}, {"march", 2},
{"apr", 3}, {"april", 3},
{"may", 4},
{"jun", 5}, {"june", 5},
{"jul", 6}, {"july", 6},
{"aug", 7}, {"august", 7},
{"sep", 8}, {"september", 8},
{"oct", 9}, {"october", 9},
{"nov", 10}, {"november", 10},
{"dec", 11}, {"december", 11},
};
static int sorted = 0;
if (!sorted)
{
(void)qsort(mon_tab, sizeof(mon_tab) / sizeof(struct strlong),
sizeof(struct strlong), strlong_compare);
sorted = 1;
}
pound_case(str_mon);
return strlong_search(str_mon, mon_tab,
sizeof(mon_tab) / sizeof(struct strlong), tm_monP);
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
time_t tdate_parse(char *str)
{
#ifdef TDATE_PARSE_WORKS /* REVISIT -- doesn't work */
struct tm tm;
char *cp;
char str_mon[32];
int tm_year;
int tm_mday;
int tm_hour;
int tm_min;
int tm_sec;
long tm_mon;
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
char str_wday[32];
long tm_wday;
#endif
nvdbg("str: \"%s\"\n", str);
/* Initialize. */
(void)memset((char *)&tm, 0, sizeof(struct tm));
/* Skip initial whitespace ourselves - sscanf is clumsy at this. */
for (cp = str; *cp == ' ' || *cp == '\t'; ++cp)
{
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
* you add new ones. The order is important. */
/* DD-mth-YY HH:MM:SS GMT */
if (sscanf(cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
&tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 6 && scan_mon(str_mon, &tm_mon))
{
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
/* DD mth YY HH:MM:SS GMT */
else if (sscanf(cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
&tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 6 && scan_mon(str_mon, &tm_mon))
{
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
/* HH:MM:SS GMT DD-mth-YY */
else if (sscanf(cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
&tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
&tm_year) == 6 && scan_mon(str_mon, &tm_mon))
{
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
}
/* HH:MM:SS GMT DD mth YY */
else if (sscanf(cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
&tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
&tm_year) == 6 && scan_mon(str_mon, &tm_mon))
{
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
}
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
/* wdy, DD-mth-YY HH:MM:SS GMT */
else if (sscanf(cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 7 &&
scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon))
{
tm.tm_wday = tm_wday;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
#endif /* Day of week not yet supported by NuttX */
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
/* wdy, DD mth YY HH:MM:SS GMT */
else if (sscanf(cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 7 &&
scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon))
{
tm.tm_wday = tm_wday;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
#endif /* Day of week not yet supported by NuttX */
#ifdef HAVE_DAY_OF_WEEK /* Day of week not yet supported by NuttX */
/* wdy mth DD HH:MM:SS GMT YY */
else if (sscanf(cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
&tm_year) == 7 &&
scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon))
{
tm.tm_wday = tm_wday;
tm.tm_mon = tm_mon;
tm.tm_mday = tm_mday;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
tm.tm_year = tm_year;
}
#endif /* Day of week not yet supported by NuttX */
else
{
return (time_t) - 1;
}
if (tm.tm_year > 1900)
{
tm.tm_year -= 1900;
}
else if (tm.tm_year < 70)
{
tm.tm_year += 100;
}
return mktime(&tm);
#else
return 0; // for now
#endif
}
+41
View File
@@ -0,0 +1,41 @@
/****************************************************************************
* netutils/thttpd/fdwatch.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in THTTPD:
*
* 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.
*
****************************************************************************/
#ifndef __NETUTILS_TDATE_PARSE_H
#define __NETUTILS_TDATE_PARSE_H
extern time_t tdate_parse(char *str);
#endif /* __NETUTILS_TDATE_PARSE_H */
+861
View File
@@ -0,0 +1,861 @@
/****************************************************************************
* netutils/thttpd/thttpd.c
* Tiny HTTP Server
*
* Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,1998,1999,2000,2001 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 <nuttx/config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/compiler.h>
#include <nuttx/symtab.h>
#include <apps/netutils/thttpd.h>
#include "config.h"
#include "fdwatch.h"
#include "libhttpd.h"
#include "thttpd_alloc.h"
#include "thttpd_strings.h"
#include "timers.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef MAXPATHLEN
# define MAXPATHLEN 64
#endif
/* The connection states */
#define CNST_FREE 0
#define CNST_READING 1
#define CNST_SENDING 2
#define CNST_LINGERING 3
#define SPARE_FDS 2
#define AVAILABLE_FDS (CONFIG_NSOCKET_DESCRIPTORS - SPARE_FDS)
/****************************************************************************
* Private Types
****************************************************************************/
struct connect_s
{
struct connect_s *next;
int conn_state;
httpd_conn *hc;
time_t active_at;
Timer *wakeup_timer;
Timer *linger_timer;
off_t end_offset; /* The final offset+1 of the file to send */
off_t offset; /* The current offset into the file to send */
bool eof; /* Set true when length==0 read from file */
};
/****************************************************************************
* Private Data
****************************************************************************/
static httpd_server *hs;
static struct connect_s *free_connections;
static struct connect_s *connects;
static struct fdwatch_s *fw;
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void shut_down(void);
static int handle_newconnect(struct timeval *tv, int listen_fd);
static void handle_read(struct connect_s *conn, struct timeval *tv);
static void handle_send(struct connect_s *conn, struct timeval *tv);
static void handle_linger(struct connect_s *conn, struct timeval *tv);
static void finish_connection(struct connect_s *conn, struct timeval *tv);
static void clear_connection(struct connect_s *conn, struct timeval *tv);
static void really_clear_connection(struct connect_s *conn);
static void idle(ClientData client_data, struct timeval *nowP);
static void linger_clear_connection(ClientData client_data, struct timeval *nowP);
static void occasional(ClientData client_data, struct timeval *nowP);
/****************************************************************************
* Private Functions
****************************************************************************/
static void shut_down(void)
{
int cnum;
for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum)
{
if (connects[cnum].conn_state != CNST_FREE)
{
httpd_close_conn(connects[cnum].hc);
}
if (connects[cnum].hc != NULL)
{
httpd_destroy_conn(connects[cnum].hc);
httpd_free((void *)connects[cnum].hc);
connects[cnum].hc = NULL;
}
}
if (hs)
{
httpd_server *ths = hs;
hs = NULL;
if (ths->listen_fd != -1)
{
fdwatch_del_fd(fw, ths->listen_fd);
}
httpd_terminate(ths);
}
tmr_destroy();
httpd_free((void *)connects);
}
static int handle_newconnect(struct timeval *tv, int listen_fd)
{
struct connect_s *conn;
ClientData client_data;
/* This loops until the accept() fails, trying to start new connections as
* fast as possible so we don't overrun the listen queue.
*/
nvdbg("New connection(s) on listen_fd %d\n", listen_fd);
for (;;)
{
/* Get the next free connection from the free list */
conn = free_connections;
/* Are there any free connections? */
if (!conn)
{
/* Out of connection slots. Run the timers, then the existing
* connections, and maybe we'll free up a slot by the time we get
* back here.
*/
ndbg("No free connections\n");
tmr_run(tv);
return -1;
}
/* Make the httpd_conn if necessary */
if (!conn->hc)
{
conn->hc = NEW(httpd_conn, 1);
if (conn->hc == NULL)
{
ndbg("out of memory allocating an httpd_conn\n");
exit(1);
}
conn->hc->initialized = 0;
}
/* Get the connection */
switch (httpd_get_conn(hs, listen_fd, conn->hc))
{
/* Some error happened. Run the timers, then the existing
* connections. Maybe the error will clear.
*/
case GC_FAIL:
tmr_run(tv);
return -1;
/* No more connections to accept for now */
case GC_NO_MORE:
return 0;
default:
break;
}
nvdbg("New connection fd %d\n", conn->hc->conn_fd);
/* Remove the connection entry from the free list */
conn->conn_state = CNST_READING;
free_connections = conn->next;
conn->next = NULL;
client_data.p = conn;
conn->active_at = tv->tv_sec;
conn->wakeup_timer = NULL;
conn->linger_timer = NULL;
conn->offset = 0;
/* Set the connection file descriptor to no-delay mode */
httpd_set_ndelay(conn->hc->conn_fd);
fdwatch_add_fd(fw, conn->hc->conn_fd, conn);
}
}
static void handle_read(struct connect_s *conn, struct timeval *tv)
{
ClientData client_data;
httpd_conn *hc = conn->hc;
off_t actual;
int sz;
/* Is there room in our buffer to read more bytes? */
if (hc->read_idx >= hc->read_size)
{
if (hc->read_size > CONFIG_THTTPD_MAXREALLOC)
{
BADREQUEST("MAXREALLOC");
goto errout_with_400;
}
httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->read_size + CONFIG_THTTPD_REALLOCINCR);
}
/* Read some more bytes */
sz = read(hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx);
if (sz == 0)
{
BADREQUEST("EOF");
goto errout_with_400;
}
if (sz < 0)
{
/* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glance
* you would think that connections returned by fdwatch as readable
* should never give an EWOULDBLOCK; however, this apparently can
* happen if a packet gets garbled.
*/
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
{
return;
}
ndbg("read(fd=%d) failed: %d\n", hc->conn_fd, errno);
BADREQUEST("read");
goto errout_with_400;
}
hc->read_idx += sz;
conn->active_at = tv->tv_sec;
/* Do we have a complete request yet? */
switch (httpd_got_request(hc))
{
case GR_NO_REQUEST:
return;
case GR_BAD_REQUEST:
BADREQUEST("httpd_got_request");
goto errout_with_400;
}
/* Yes. Try parsing and resolving it */
if (httpd_parse_request(hc) < 0)
{
goto errout_with_connection;
}
/* Start the connection going */
if (httpd_start_request(hc, tv) < 0)
{
/* Something went wrong. Close down the connection */
goto errout_with_connection;
}
/* Set up the file offsets to read */
conn->eof = false;
if (hc->got_range)
{
conn->offset = hc->range_start;
conn->end_offset = hc->range_end + 1;
}
else
{
conn->offset = 0;
if (hc->bytes_to_send < 0)
{
conn->end_offset = 0;
}
else
{
conn->end_offset = hc->bytes_to_send;
}
}
/* Check if it's already handled */
if (hc->file_fd < 0)
{
/* No file descriptor means someone else is handling it */
conn->offset = hc->bytes_sent;
goto errout_with_connection;
}
if (conn->offset >= conn->end_offset)
{
/* There's nothing to send */
goto errout_with_connection;
}
/* Seek to the offset of the next byte to send */
actual = lseek(hc->file_fd, conn->offset, SEEK_SET);
if (actual != conn->offset)
{
ndbg("fseek to %d failed: offset=%d errno=%d\n", conn->offset, actual, errno);
BADREQUEST("lseek");
goto errout_with_400;
}
/* We have a valid connection and a file to send to it */
conn->conn_state = CNST_SENDING;
client_data.p = conn;
fdwatch_del_fd(fw, hc->conn_fd);
return;
errout_with_400:
BADREQUEST("errout");
httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, "");
errout_with_connection:
finish_connection(conn, tv);
return;
}
static inline int read_buffer(struct connect_s *conn)
{
httpd_conn *hc = conn->hc;
ssize_t nread = 0;
if (hc->buflen < CONFIG_THTTPD_IOBUFFERSIZE && !conn->eof)
{
nread = read(hc->file_fd, &hc->buffer[hc->buflen],
CONFIG_THTTPD_IOBUFFERSIZE - hc->buflen);
if (nread == 0)
{
/* Reading zero bytes means we are at the end of file */
conn->end_offset = conn->offset;
conn->eof = true;
}
else if (nread > 0)
{
hc->buflen += nread;
}
}
return nread;
}
static void handle_send(struct connect_s *conn, struct timeval *tv)
{
httpd_conn *hc = conn->hc;
int nwritten;
int nread;
/* Read until the entire file is sent -- this could take awhile!! */
while (conn->offset < conn->end_offset)
{
nvdbg("offset: %d end_offset: %d bytes_sent: %d\n",
conn->offset, conn->end_offset, conn->hc->bytes_sent);
/* Fill the rest of the response buffer with file data */
nread = read_buffer(conn);
if (nread < 0)
{
ndbg("File read error: %d\n", errno);
goto errout_clear_connection;
}
nvdbg("Read %d bytes, buflen %d\n", nread, hc->buflen);
/* Send the buffer */
if (hc->buflen > 0)
{
/* httpd_write does not return until all bytes have been sent
* (or an error occurs).
*/
nwritten = httpd_write(hc->conn_fd, hc->buffer, hc->buflen);
if (nwritten < 0)
{
ndbg("Error sending %s: %d\n", hc->encodedurl, errno);
goto errout_clear_connection;
}
/* We wrote one full buffer of data (httpd_write does not
* return until the full buffer is written (or an error occurs).
*/
conn->active_at = tv->tv_sec;
hc->buflen = 0;
/* And update how much of the file we wrote */
conn->offset += nwritten;
conn->hc->bytes_sent += nwritten;
nvdbg("Wrote %d bytes\n", nwritten);
}
}
/* The file transfer is complete -- finish the connection */
nvdbg("Finish connection\n");
finish_connection(conn, tv);
return;
errout_clear_connection:
ndbg("Clear connection\n");
clear_connection(conn, tv);
return;
}
static void handle_linger(struct connect_s *conn, struct timeval *tv)
{
httpd_conn *hc = conn->hc;
int ret;
/* In lingering-close mode we just read and ignore bytes. An error or EOF
* ends things, otherwise we go until a timeout
*/
ret = read(conn->hc->conn_fd, hc->buffer, CONFIG_THTTPD_IOBUFFERSIZE);
if (ret < 0 && (errno == EINTR || errno == EAGAIN))
{
return;
}
if (ret <= 0)
{
really_clear_connection(conn);
}
}
static void finish_connection(struct connect_s *conn, struct timeval *tv)
{
/* If we haven't actually sent the buffered response yet, do so now */
httpd_write_response(conn->hc);
/* And clear */
clear_connection(conn, tv);
}
static void clear_connection(struct connect_s *conn, struct timeval *tv)
{
ClientData client_data;
if (conn->wakeup_timer != NULL)
{
tmr_cancel(conn->wakeup_timer);
conn->wakeup_timer = 0;
}
/* This is our version of Apache's lingering_close() routine, which is
* their version of the often-broken SO_LINGER socket option. For why
* this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html
* What we do is delay the actual closing for a few seconds, while reading
* any bytes that come over the connection. However, we don't want to do
* this unless it's necessary, because it ties up a connection slot and
* file descriptor which means our maximum connection-handling rateis
* lower. So, elsewhere we set a flag when we detect the few
* circumstances that make a lingering close necessary. If the flag isn't
* set we do the real close now.
*/
if (conn->conn_state == CNST_LINGERING)
{
/* If we were already lingering, shut down for real */
tmr_cancel(conn->linger_timer);
conn->linger_timer = NULL;
conn->hc->should_linger = false;
}
else if (conn->hc->should_linger)
{
fdwatch_del_fd(fw, conn->hc->conn_fd);
conn->conn_state = CNST_LINGERING;
fdwatch_add_fd(fw, conn->hc->conn_fd, conn);
client_data.p = conn;
conn->linger_timer = tmr_create(tv, linger_clear_connection, client_data,
CONFIG_THTTPD_LINGER_MSEC, 0);
if (conn->linger_timer != NULL)
{
return;
}
ndbg("tmr_create(linger_clear_connection) failed\n");
}
/* Either we are done lingering, we shouldn't linger, or we failed to setup the linger */
really_clear_connection(conn);
}
static void really_clear_connection(struct connect_s *conn)
{
fdwatch_del_fd(fw, conn->hc->conn_fd);
httpd_close_conn(conn->hc);
if (conn->linger_timer != NULL)
{
tmr_cancel(conn->linger_timer);
conn->linger_timer = 0;
}
/* Put the connection structure back on the free list */
conn->conn_state = CNST_FREE;
conn->next = free_connections;
free_connections = conn;
}
static void idle(ClientData client_data, struct timeval *nowP)
{
int cnum;
struct connect_s *conn;
for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum)
{
conn = &connects[cnum];
switch (conn->conn_state)
{
case CNST_READING:
if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_READ_LIMIT_SEC)
{
ndbg("%s connection timed out reading\n", httpd_ntoa(&conn->hc->client_addr));
httpd_send_err(conn->hc, 408, httpd_err408title, "",
httpd_err408form, "");
finish_connection(conn, nowP);
}
break;
case CNST_SENDING:
if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC)
{
ndbg("%s connection timed out sending\n", httpd_ntoa(&conn->hc->client_addr));
clear_connection(conn, nowP);
}
break;
}
}
}
static void linger_clear_connection(ClientData client_data, struct timeval *nowP)
{
struct connect_s *conn;
nvdbg("Clear connection\n");
conn = (struct connect_s *) client_data.p;
conn->linger_timer = NULL;
really_clear_connection(conn);
}
static void occasional(ClientData client_data, struct timeval *nowP)
{
tmr_cleanup();
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: thttpd_main
*
* Description:
* This function is the entrypoint into the THTTPD server. It does not
* return. It may be called, the normal mechanism for starting the server
* is:
*
* 1) Set is g_thttpdsymtab and g_thttpdnsymbols. The user is required
* to provide a symbol table to use for binding CGI programs (if CGI
* is enabled. See examples/nxflat and examples/thttpd for examples of
* how such a symbol table may be created.
* 2) Call task_create() to start thttpd_main()
*
****************************************************************************/
int thttpd_main(int argc, char **argv)
{
int num_ready;
int cnum;
FAR struct connect_s *conn;
FAR httpd_conn *hc;
httpd_sockaddr sa;
struct timeval tv;
#ifdef CONFIG_THTTPD_DIR
int ret;
#endif
nvdbg("THTTPD started\n");
/* Setup host address */
#ifdef CONFIG_NET_IPv6
# error "IPv6 support not yet implemented"
#else
sa.sin_family = AF_INET;
sa.sin_port = HTONS(CONFIG_THTTPD_PORT);
sa.sin_addr.s_addr = HTONL(CONFIG_THTTPD_IPADDR);
#endif
/* Initialize the fdwatch package to handle all of the configured
* socket descriptors
*/
fw = fdwatch_initialize(CONFIG_NSOCKET_DESCRIPTORS);
if (!fw)
{
ndbg("fdwatch initialization failure\n");
exit(1);
}
/* Switch directories again if requested */
#ifdef CONFIG_THTTPD_DATADIR
if (chdir(CONFIG_THTTPD_DATADIR) < 0)
{
ndbg("chdir to %s: %d\n", CONFIG_THTTPD_DATADIR, errno);
exit(1);
}
#endif
/* Initialize the timer package */
tmr_init();
/* Initialize the HTTP layer */
nvdbg("Calling httpd_initialize()\n");
hs = httpd_initialize(&sa);
if (!hs)
{
ndbg("httpd_initialize() failed\n");
exit(1);
}
/* Set up the occasional timer */
if (tmr_create(NULL, occasional, JunkClientData, CONFIG_THTTPD_OCCASIONAL_MSEC * 1000L, 1) == NULL)
{
ndbg("tmr_create(occasional) failed\n");
exit(1);
}
/* Set up the idle timer */
if (tmr_create(NULL, idle, JunkClientData, 5 * 1000L, 1) == NULL)
{
ndbg("tmr_create(idle) failed\n");
exit(1);
}
/* Initialize our connections table */
connects = NEW(struct connect_s, AVAILABLE_FDS);
if (connects == NULL)
{
ndbg("Out of memory allocating a struct connect_s\n");
exit(1);
}
for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum)
{
connects[cnum].conn_state = CNST_FREE;
connects[cnum].next = &connects[cnum + 1];
connects[cnum].hc = NULL;
}
connects[AVAILABLE_FDS-1].next = NULL; /* End of link list */
free_connections = connects; /* Beginning of the link list */
if (hs != NULL)
{
if (hs->listen_fd != -1)
{
fdwatch_add_fd(fw, hs->listen_fd, NULL);
}
}
/* Main loop */
nvdbg("Entering the main loop\n");
(void)gettimeofday(&tv, NULL);
for(;;)
{
/* Do the fd watch */
num_ready = fdwatch(fw, tmr_mstimeout(&tv));
if (num_ready < 0)
{
if (errno == EINTR || errno == EAGAIN)
{
/* Not errors... try again */
continue;
}
ndbg("fdwatch failed: %d\n", errno);
exit(1);
}
(void)gettimeofday(&tv, NULL);
if (num_ready == 0)
{
/* No fd's are ready - run the timers */
tmr_run(&tv);
continue;
}
/* Is it a new connection? */
if (fdwatch_check_fd(fw, hs->listen_fd))
{
if (!handle_newconnect(&tv, hs->listen_fd))
{
/* Go around the loop and do another fdwatch, rather than
* dropping through and processing existing connections. New
* connections always get priority.
*/
continue;
}
}
/* Find the connections that need servicing */
while ((conn = (struct connect_s*)fdwatch_get_next_client_data(fw)) != (struct connect_s*)-1)
{
if (conn)
{
hc = conn->hc;
if (fdwatch_check_fd(fw, hc->conn_fd))
{
nvdbg("Handle conn_state %d\n", conn->conn_state);
switch (conn->conn_state)
{
case CNST_READING:
{
handle_read(conn, &tv);
/* If a GET request was received and a file is ready to
* be sent, then fall through to send the file.
*/
if (conn->conn_state != CNST_SENDING)
{
break;
}
}
case CNST_SENDING:
{
/* Send a file -- this really should be performed on a
* separate thread to keep the serve from locking up during
* the write.
*/
handle_send(conn, &tv);
}
break;
case CNST_LINGERING:
{
/* Linger close the connection */
handle_linger(conn, &tv);
}
break;
}
}
}
}
tmr_run(&tv);
}
/* The main loop terminated */
shut_down();
ndbg("Exiting\n");
exit(0);
}
#endif /* CONFIG_THTTPD */
+199
View File
@@ -0,0 +1,199 @@
/****************************************************************************
* netutils/thttpd/thttpd_alloc.c
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdlib.h>
#include <debug.h>
#include <errno.h>
#include "config.h"
#include "thttpd_alloc.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef MAX
# define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef CONFIG_THTTPD_MEMDEBUG
static int g_nallocations = 0;
static int g_nfreed = 0;
static size_t g_allocated = 0;
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/* Generate debugging statistics */
#ifdef CONFIG_THTTPD_MEMDEBUG
void httpd_memstats(void)
{
static struct mallinfo mm;
ndbg("%d allocations (%lu bytes), %d freed\n", g_nallocations, (unsigned long)g_allocated, g_nfreed);
/* Get the current memory usage */
#ifdef CONFIG_CAN_PASS_STRUCTS
mm = mallinfo();
#else
(void)mallinfo(&mm);
#endif
ndbg("arena: %08x ordblks: %08x mxordblk: %08x uordblks: %08x fordblks: %08x\n",
mm.arena, mm.ordblks, mm.mxordblk, mm.uordblks, mm.fordblks);
}
#endif
/****************************************************************************
* Global Functions
****************************************************************************/
#ifdef CONFIG_THTTPD_MEMDEBUG
FAR void *httpd_malloc(size_t nbytes)
{
void *ptr = malloc(nbytes);
if (!ptr)
{
ndbg("Allocation of %d bytes failed\n", nbytes);
}
else
{
nvdbg("Allocated %d bytes at %p\n", nbytes, ptr);
g_nallocations++;
g_allocated += nbytes;
}
httpd_memstats();
return ptr;
}
#endif
#ifdef CONFIG_THTTPD_MEMDEBUG
FAR void *httpd_realloc(FAR void *oldptr, size_t oldsize, size_t newsize)
{
void *ptr = realloc(oldptr, newsize);
if (!ptr)
{
ndbg("Re-allocation from %d to %d bytes failed\n",
oldsize, newsize);
}
else
{
nvdbg("Re-allocated form %d to %d bytes (from %p to %p)\n",
oldsize, newsize, oldptr, ptr);
g_allocated += (newsize - oldsize);
}
httpd_memstats();
return ptr;
}
#endif
#ifdef CONFIG_THTTPD_MEMDEBUG
void httpd_free(FAR void *ptr)
{
free(ptr);
g_nfreed++;
nvdbg("Freed memory at %p\n", ptr);
httpd_memstats();
}
#endif
#ifdef CONFIG_THTTPD_MEMDEBUG
FAR char *httpd_strdup(const char *str)
{
FAR char *newstr = strdup(str);
if (!newstr)
{
ndbg("strdup of %s failed\n", str);
}
else
{
nvdbg("strdup'ed %s\n", str);
g_nallocations++;
g_allocated += (strlen(str)+1);
}
httpd_memstats();
return newstr;
}
#endif
/* Helpers to implement dynamically allocated strings */
void httpd_realloc_str(char **pstr, size_t *maxsize, size_t size)
{
size_t oldsize;
if (*maxsize == 0)
{
*maxsize = MAX(CONFIG_THTTPD_MINSTRSIZE, size + CONFIG_THTTPD_REALLOCINCR);
*pstr = NEW(char, *maxsize + 1);
}
else if (size > *maxsize)
{
oldsize = *maxsize;
*maxsize = MAX(oldsize * 2, size * 5 / 4);
*pstr = httpd_realloc(*pstr, oldsize + 1, *maxsize + 1);
}
else
{
return;
}
if (!*pstr)
{
ndbg("out of memory reallocating a string to %d bytes\n", *maxsize);
exit(1);
}
}
#endif /* CONFIG_THTTPD */
+78
View File
@@ -0,0 +1,78 @@
/****************************************************************************
* netutils/thttpd/thttpd_alloc.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_HTTDP_ALLOC_H
#define __NETUTILS_THTTPD_HTTDP_ALLOC_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Global Functions
****************************************************************************/
/* Allows all memory management calls to be intercepted */
#ifdef CONFIG_THTTPD_MEMDEBUG
extern FAR void *httpd_malloc(size_t nbytes);
extern FAR void *httpd_realloc(FAR void *oldptr, size_t oldsize, size_t newsize);
extern void httpd_free(FAR void *ptr);
extern FAR char *httpd_strdup(const char *str);
#else
# define httpd_malloc(n) malloc(n)
# define httpd_realloc(p,o,n) realloc(p,n)
# define httpd_free(p) free(p)
# define httpd_strdup(s) strdup(s)
#endif
/* Helpers to support allocations in multiples of a type size */
#define NEW(t,n) ((t*)httpd_malloc(sizeof(t)*(n)))
#define RENEW(p,t,o,n) ((t*)httpd_realloc((void*)p, sizeof(t)*(o), sizeof(t)*(n)))
/* Helpers to implement dynamically allocated strings */
extern void httpd_realloc_str(char **pstr, size_t *maxsizeP, size_t size);
#endif /* CONFIG_THTTPD */
#endif /* __NETUTILS_THTTPD_HTTDP_ALLOC_H */
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
/****************************************************************************
* netutils/thttpd/thttpd_cgi.h
* CGI support
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file libhttpd.c in the original THTTPD package:
*
* Copyright © 1995,1998,1999,2000,2001 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.
*
****************************************************************************/
#ifndef __HTTPD_CGI_H
#define __HTTPD_CGI_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "config.h"
#include "libhttpd.h"
#if defined(CONFIG_THTTPD) && defined(CONFIG_THTTPD_CGI_PATTERN)
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
extern int cgi(httpd_conn *hc);
#if CONFIG_THTTPD_CGI_TIMELIMIT > 0
static void cgi_kill(ClientData client_data, struct timeval *now);
#endif
#endif /* CONFIG_THTTPD && CONFIG_THTTPD_CGI_PATTERN */
#endif /* __HTTPD_CGI_H */
+179
View File
@@ -0,0 +1,179 @@
/****************************************************************************
* netutils/thttpd/thttpd_strings.c
* HTTP strings
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,1998,1999,2000,2001 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 <nuttx/config.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "config.h"
#include "thttpd_strings.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Public Data
****************************************************************************/
/* This is the 'root' of the Filesystem as seen by the HTTP client */
const char httpd_root[] = CONFIG_THTTPD_PATH;
/* HTPP status */
const char ok200title[] = "OK";
const char ok206title[] = "Partial Content";
const char err302title[] = "Found";
const char err302form[] = "The actual URL is '%s'.\n";
const char err304title[] = "Not Modified";
const char httpd_err400title[] = "Bad Request";
const char httpd_err400form[] = "Your request has bad syntax or is inherently impossible to satisfy.\n";
#ifdef CONFIG_THTTPD_AUTH_FILE
const char err401title[] = "Unauthorized";
const char err401form[] = "Authorization required for the URL '%s'.\n";
#endif
const char err403title[] = "Forbidden";
#ifndef EXPLICIT_ERROR_PAGES
const char err403form[] = "You do not have permission to get URL '%s' from this server.\n";
#endif
const char err404title[] = "Not Found";
const char err404form[] = "The requested URL '%s' was not found on this server.\n";
const char httpd_err408title[] = "Request Timeout";
const char httpd_err408form[] = "No request appeared within a reasonable time period.\n";
const char err500title[] = "Internal Error";
const char err500form[] = "There was an unusual problem serving the requested URL '%s'.\n";
const char err501title[] = "Not Implemented";
const char err501form[] = "The requested method '%s' is not implemented by this server.\n";
const char httpd_err503title[] = "Service Temporarily Overloaded";
const char httpd_err503form[] = "The requested URL '%s' is temporarily overloaded. Please try again later.\n";
/* HTML strings */
const char html_crlf[] = "\r\n";
const char html_html[] = "<HTML>\r\n";
const char html_endhtml[] = "</HTML>\r\n";
const char html_hdtitle[] = "<HEAD><TITLE>";
const char html_titlehd[] = "</TITLE></HEAD>\r\n";
const char html_body[] = "<BODY BGCOLOR=\"#99cc99\" TEXT=\"#000000\" LINK=\"#2020ff\" VLINK=\"#4040cc\">\r\n";
const char html_endbody[] = "</BODY>\r\n";
const char html_hdr2[] = "<H2>";
const char html_endhdr2[] = "</H2>";
/****************************************************************************
* Private Functions
****************************************************************************/
static int hexit(char nibble)
{
if (nibble >= '0' && nibble <= '9')
{
return nibble - '0';
}
else if (nibble >= 'a' && nibble <= 'f')
{
return nibble - 'a' + 10;
}
else if (nibble >= 'A' && nibble <= 'F')
{
return nibble - 'A' + 10;
}
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/* Copies and decodes a string. It's ok for from and to to be the same string. */
void httpd_strdecode(char *to, char *from)
{
for (; *from != '\0'; ++to, ++from)
{
if (from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
{
*to = hexit(from[1]) * 16 + hexit(from[2]);
from += 2;
}
else
{
*to = *from;
}
}
*to = '\0';
}
/* Copies and encodes a string. */
#ifdef CONFIG_THTTPD_GENERATE_INDICES
static void httpd_strencode(char *to, int tosize, char *from)
{
int tolen;
for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from)
{
if (isalnum(*from) || strchr("/_.-~", *from) != NULL)
{
*to = *from;
++to;
++tolen;
}
else
{
(void)sprintf(to, "%%%02x", (int)*from & 0xff);
to += 3;
tolen += 3;
}
}
*to = '\0';
}
#endif /* CONFIG_THTTPD_GENERATE_INDICES */
#endif /* CONFIG_THTTPD */
+123
View File
@@ -0,0 +1,123 @@
/****************************************************************************
* netutils/thttpd/thttpd_strings.h
* HTTP strings
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,1998,1999,2000,2001 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.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_THTTPD_STRINGS_H
#define __NETUTILS_THTTPD_THTTPD_STRINGS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "config.h"
#ifdef CONFIG_THTTPD
/****************************************************************************
* Public Data
****************************************************************************/
/* This is the 'root' of the Filesystem as seen by the HTTP client */
extern const char httpd_root[];
/* HTPP status */
extern const char ok200title[];
extern const char ok206title[];
extern const char err302title[];
extern const char err302form[];
extern const char err304title[];
extern const char httpd_err400title[];
extern const char httpd_err400form[];
#ifdef CONFIG_THTTPD_AUTH_FILE
extern const char err401title[];
extern const char err401form[];
#endif
extern const char err403title[];
#ifndef EXPLICIT_ERROR_PAGES
extern const char err403form[];
#endif
extern const char err404title[];
extern const char err404form[];
extern const char httpd_err408title[];
extern const char httpd_err408form[];
extern const char err500title[];
extern const char err500form[];
extern const char err501title[];
extern const char err501form[];
extern const char httpd_err503title[];
extern const char httpd_err503form[];
/* HTML strings */
extern const char html_crlf[];
extern const char html_html[];
extern const char html_endhtml[];
extern const char html_hdtitle[];
extern const char html_titlehd[];
extern const char html_body[];
extern const char html_endbody[];
extern const char html_hdr2[];
extern const char html_endhdr2[];
/****************************************************************************
* Public Functions
****************************************************************************/
/* Copies and decodes a string. It's ok for from and to to be the same string. */
extern void httpd_strdecode(char *to, char *from);
/* Copies and encodes a string. */
#ifdef CONFIG_THTTPD_GENERATE_INDICES
extern void httpd_strencode(char *to, int tosize, char *from);
#endif
#endif /* CONFIG_THTTPD */
#endif /* __NETUTILS_THTTPD_THTTPD_STRINGS_H */
+365
View File
@@ -0,0 +1,365 @@
/****************************************************************************
* netutils/thttpd/timers.c
* Simple Timer Routines
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,1998,2000 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/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <debug.h>
#include "thttpd_alloc.h"
#include "timers.h"
/****************************************************************************
* Pre-Processor Definitons
****************************************************************************/
#define HASH_SIZE 67
/****************************************************************************
* Private Data
****************************************************************************/
static Timer *timers[HASH_SIZE];
static Timer *free_timers;
/****************************************************************************
* Public Data
****************************************************************************/
ClientData JunkClientData;
/****************************************************************************
* Private Functions
****************************************************************************/
static unsigned int hash(Timer *tmr)
{
/* We can hash on the trigger time, even though it can change over the
* life of a timer via the periodic bit.
* This is because both of those guys call l_resort(), which * recomputes
* the hash and moves the timer to the appropriate list.
*/
return ((unsigned int)tmr->time.tv_sec ^
(unsigned int)tmr->time.tv_usec) % HASH_SIZE;
}
static void l_add(Timer *tmr)
{
int h = tmr->hash;
register Timer *tmr2;
register Timer *tmr2prev;
tmr2 = timers[h];
if (tmr2 == NULL)
{
/* The list is empty. */
timers[h] = tmr;
tmr->prev = tmr->next = NULL;
}
else
{
if (tmr->time.tv_sec < tmr2->time.tv_sec ||
(tmr->time.tv_sec == tmr2->time.tv_sec &&
tmr->time.tv_usec <= tmr2->time.tv_usec))
{
/* The new timer goes at the head of the list. */
timers[h] = tmr;
tmr->prev = NULL;
tmr->next = tmr2;
tmr2->prev = tmr;
}
else
{
/* Walk the list to find the insertion point. */
for (tmr2prev = tmr2, tmr2 = tmr2->next; tmr2 != NULL;
tmr2prev = tmr2, tmr2 = tmr2->next)
{
if (tmr->time.tv_sec < tmr2->time.tv_sec ||
(tmr->time.tv_sec == tmr2->time.tv_sec &&
tmr->time.tv_usec <= tmr2->time.tv_usec))
{
/* Found it. */
tmr2prev->next = tmr;
tmr->prev = tmr2prev;
tmr->next = tmr2;
tmr2->prev = tmr;
return;
}
}
/* Oops, got to the end of the list. Add to tail. */
tmr2prev->next = tmr;
tmr->prev = tmr2prev;
tmr->next = NULL;
}
}
}
static void l_remove(Timer *tmr)
{
int h = tmr->hash;
if (tmr->prev == NULL)
{
timers[h] = tmr->next;
}
else
{
tmr->prev->next = tmr->next;
}
if (tmr->next != NULL)
{
tmr->next->prev = tmr->prev;
}
}
static void l_resort(Timer *tmr)
{
/* Remove the timer from its old list. */
l_remove(tmr);
/* Recompute the hash. */
tmr->hash = hash(tmr);
/* And add it back in to its new list, sorted correctly. */
l_add(tmr);
}
/****************************************************************************
* Public Functions
****************************************************************************/
void tmr_init(void)
{
int h;
for (h = 0; h < HASH_SIZE; ++h)
{
timers[h] = NULL;
}
free_timers = NULL;
}
Timer *tmr_create(struct timeval *now, TimerProc *timer_proc,
ClientData client_data, long msecs, int periodic)
{
Timer *tmr;
if (free_timers != NULL)
{
tmr = free_timers;
free_timers = tmr->next;
}
else
{
tmr = (Timer*)httpd_malloc(sizeof(Timer));
if (!tmr)
{
return NULL;
}
}
tmr->timer_proc = timer_proc;
tmr->client_data = client_data;
tmr->msecs = msecs;
tmr->periodic = periodic;
if (now != NULL)
{
tmr->time = *now;
}
else
{
(void)gettimeofday(&tmr->time, NULL);
}
tmr->time.tv_sec += msecs / 1000L;
tmr->time.tv_usec += (msecs % 1000L) * 1000L;
if (tmr->time.tv_usec >= 1000000L)
{
tmr->time.tv_sec += tmr->time.tv_usec / 1000000L;
tmr->time.tv_usec %= 1000000L;
}
tmr->hash = hash(tmr);
/* Add the new timer to the proper active list. */
l_add(tmr);
return tmr;
}
long tmr_mstimeout(struct timeval *now)
{
int h;
int gotone;
long msecs, m;
register Timer *tmr;
gotone = 0;
msecs = 0;
/* Since the lists are sorted, we only need to look at the * first timer on
* each one.
*/
for (h = 0; h < HASH_SIZE; ++h)
{
tmr = timers[h];
if (tmr != NULL)
{
m = (tmr->time.tv_sec - now->tv_sec) * 1000L +
(tmr->time.tv_usec - now->tv_usec) / 1000L;
if (!gotone)
{
msecs = m;
gotone = 1;
}
else if (m < msecs)
{
msecs = m;
}
}
}
if (!gotone)
{
return INFTIM;
}
if (msecs <= 0)
{
msecs = 0;
}
return msecs;
}
void tmr_run(struct timeval *now)
{
int h;
Timer *tmr;
Timer *next;
for (h = 0; h < HASH_SIZE; ++h)
{
for (tmr = timers[h]; tmr != NULL; tmr = next)
{
next = tmr->next;
/* Since the lists are sorted, as soon as we find a timer * that isn'tmr
* ready yet, we can go on to the next list
*/
if (tmr->time.tv_sec > now->tv_sec ||
(tmr->time.tv_sec == now->tv_sec && tmr->time.tv_usec > now->tv_usec))
{
break;
}
(tmr->timer_proc)(tmr->client_data, now);
if (tmr->periodic)
{
/* Reschedule. */
tmr->time.tv_sec += tmr->msecs / 1000L;
tmr->time.tv_usec += (tmr->msecs % 1000L) * 1000L;
if (tmr->time.tv_usec >= 1000000L)
{
tmr->time.tv_sec += tmr->time.tv_usec / 1000000L;
tmr->time.tv_usec %= 1000000L;
}
l_resort(tmr);
}
else
{
tmr_cancel(tmr);
}
}
}
}
void tmr_cancel(Timer *tmr)
{
/* Remove it from its active list. */
l_remove(tmr);
/* And put it on the free list. */
tmr->next = free_timers;
free_timers = tmr;
tmr->prev = NULL;
}
void tmr_cleanup(void)
{
Timer *tmr;
while (free_timers != NULL)
{
tmr = free_timers;
free_timers = tmr->next;
httpd_free((void*)tmr);
}
}
void tmr_destroy(void)
{
int h;
for (h = 0; h < HASH_SIZE; ++h)
{
while (timers[h] != NULL)
{
tmr_cancel(timers[h]);
}
}
tmr_cleanup();
}
+136
View File
@@ -0,0 +1,136 @@
/****************************************************************************
* netutils/thttpd/timers.h
* Header file for THTTPD timers package
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derived from the file of the same name in THTTPD:
*
* Copyright © 1995,1998,1999,2000 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.
*
****************************************************************************/
#ifndef __NETUTILS_THTTPD_TIMERS_H
#define __NETUTILS_THTTPD_TIMERS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <time.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef INFTIM
# define INFTIM -1
#endif
/****************************************************************************
* Public Types
****************************************************************************/
/* ClientData is a random value that tags along with a timer. The client
* can use it for whatever, and it gets passed to the callback when the
* timer triggers.
*/
typedef union
{
void *p;
int i;
long l;
} ClientData;
/* The TimerProc gets called when the timer expires. It gets passed
* the ClientData associated with the timer, and a timeval in case
* it wants to schedule another timer.
*/
typedef void TimerProc(ClientData client_data, struct timeval *nowP);
/* The Timer struct. */
typedef struct TimerStruct
{
TimerProc *timer_proc;
ClientData client_data;
long msecs;
int periodic;
struct timeval time;
struct TimerStruct *prev;
struct TimerStruct *next;
int hash;
} Timer;
/****************************************************************************
* Public Data
****************************************************************************/
extern ClientData JunkClientData; /* For use when you don't care */
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Initialize the timer package. */
extern void tmr_init(void);
/* Set up a timer, either periodic or one-shot. Returns (Timer*) 0 on errors. */
extern Timer *tmr_create(struct timeval *nowP, TimerProc * timer_proc,
ClientData client_data, long msecs, int periodic);
/* Returns a timeout in milliseconds indicating how long until the next timer
* triggers. You can just put the call to this routine right in your poll().
* Returns INFTIM (-1) if no timers are pending.
*/
extern long tmr_mstimeout(struct timeval *nowP);
/* Run the list of timers. Your main program needs to call this every so often. */
extern void tmr_run(struct timeval *nowP);
/* Deschedule a timer. Note that non-periodic timers are automatically
* descheduled when they run, so you don't have to call this on them.
*/
extern void tmr_cancel(Timer *timer);
/* Clean up the timers package, freeing any unused storage. */
extern void tmr_cleanup(void);
/* Cancel all timers and free storage, usually in preparation for exitting. */
extern void tmr_destroy(void);
#endif /* __NETUTILS_THTTPD_TIMERS_H */