Move nuttx/netutils to apps/netutils

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3401 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2011-03-19 21:04:13 +00:00
parent a399c7bddf
commit 5b96d86bfb
73 changed files with 19286 additions and 15 deletions

121
netutils/thttpd/Makefile Normal file
View file

@ -0,0 +1,121 @@
#############################################################################
# apps/netutils/thttpd/Makefile
#
# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#############################################################################
-include $(TOPDIR)/.config
-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)
BIN = ../../libapps$(LIBEXT)
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) $(BIN)
.PHONY: depend clean distclean
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
$(BIN): $(OBJS)
@( for obj in $(OBJS) ; do \
$(call ARCHIVE, $@, $${obj}); \
done ; )
@touch .built
.built: $(BIN)
.depend: Makefile $(SRCS)
@$(MKDEP) $(ROOTDEPPATH) \
$(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
@touch $@
# Register application
depend: .depend
clean:
@rm -f $(BIN) *.o *~ .*.swp .built
$(call CLEAN)
distclean: clean
@rm -f Make.dep .depend
-include Make.dep

View file

@ -0,0 +1,136 @@
############################################################################
# apps/netutils/cgi-src/Makefile
#
# Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
-include $(TOPDIR)/.config
-include $(TOPDIR)/Make.defs
CFLAGS += -I$(APPDIR)/netutils/thttpd -I$(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

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 <spudmonkey@racsa.co.cr>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1996 by Jef Poskanzer <jef@mail.acme.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
****************************************************************************/
/* Old distributions of the NCSA and Apache web servers included a
* version of the phf program that had a bug. The program could
* easily be made to run arbitrary shell commands. There is no real
* legitimate use for phf, so any attempts to run it must be considered
* to be attacks. Accordingly, this version of phf logs the attack
* on stderr and then returns a page on CONFIG_THTTPD_CGI_OUTFD indicating
* that phf doesn't exist.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, char *argv[])
{
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;
}

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 <spudmonkey@racsa.co.cr>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
****************************************************************************/
/* Three steps to set up a redirection:
*
* 1. Make sure your web server is set up to allow CGI programs.
* 2. Make a symbolic link from the file you want to redirect,
* pointing at this program in the CGI bin directory.
* 3. Add an entry to the file ".redirects" in the directory where your
* http server runs CGI programs. For most servers, this is the
* directory where the given CGI program lives. The format of the
* file is a bunch of lines with a filename, whitespace, and the new
* URL. For example:
*
* /test/oldfile.html http://www.acme.com/test/newfile.html
*
* The easiest way to figure out precisely what filename to put into
* .redirects is to set up the symlink and then click on it. You'll get
* back a "404 Not Found" page which includes the filename as received by
* the redirect program, and that's what you want to use.
*
* Note: this is designed for thttpd (http://www.acme.com/software/thttpd/)
* and using it with other web servers may require some hacking. A possible
* gotcha is with the symbolic link from the old file pointing at this
* script - servers other than thttpd may not allow that link to be run
* as a CGI program, because they don't check the link to see that it
* points into the allowed CGI directory.
*
* Note two: It would be really cool to have this program look for
* the .redirects file in the same directory as the file being redirected,
* instead of in the binaries directory. Unfortunately, this appears
* to be impossible with the information CGI gives, plus the non-standardized
* but widespread practice of running CGI programs in the directory where
* the binary lives. Perhaps CGI 1.2 will address this.
*/
/****************************************************************************
* Public Functions
****************************************************************************/
#include <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;
}

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 <spudmonkey@racsa.co.cr>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <nuttx/regex.h>
#include "config.h"
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
#define ST_GROUND 0
#define ST_LESSTHAN 1
#define ST_BANG 2
#define ST_MINUS1 3
#define ST_MINUS2 4
#define SF_BYTES 0
#define SF_ABBREV 1
#define DI_CONFIG 0
#define DI_INCLUDE 1
#define DI_ECHO 2
#define DI_FSIZE 3
#define DI_FLASTMOD 4
#define BUFFER_SIZE 512
#define TIMEFMT_SIZE 80
#define MAX_TAGS 32
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void read_file(FILE *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
netutils/thttpd/config.h Normal file
View file

@ -0,0 +1,253 @@
/****************************************************************************
* netutils/thttpd/config.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __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
netutils/thttpd/fdwatch.c Normal file
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 <spudmonkey@racsa.co.cr>
*
* 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
netutils/thttpd/fdwatch.h Normal file
View file

@ -0,0 +1,111 @@
/****************************************************************************
* netutils/thttpd/fdwatch.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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 */

3525
netutils/thttpd/libhttpd.c Normal file

File diff suppressed because it is too large Load diff

342
netutils/thttpd/libhttpd.h Normal file
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 <spudmonkey@racsa.co.cr>
*
* 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 */

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 <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __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 */

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 <spudmonkey@racsa.co.cr>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <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
}

View file

@ -0,0 +1,41 @@
/****************************************************************************
* netutils/thttpd/fdwatch.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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
netutils/thttpd/thttpd.c Normal file
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 <spudmonkey@racsa.co.cr>
*
* 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
netutils/thttpd/thttpd_alloc.c Executable file
View file

@ -0,0 +1,199 @@
/****************************************************************************
* netutils/thttpd/thttpd_alloc.c
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* 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
netutils/thttpd/thttpd_alloc.h Executable file
View file

@ -0,0 +1,78 @@
/****************************************************************************
* netutils/thttpd/thttpd_alloc.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __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 */

1080
netutils/thttpd/thttpd_cgi.c Executable file

File diff suppressed because it is too large Load diff

61
netutils/thttpd/thttpd_cgi.h Executable file
View file

@ -0,0 +1,61 @@
/****************************************************************************
* netutils/thttpd/thttpd_cgi.h
* CGI support
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* 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
netutils/thttpd/thttpd_strings.c Executable file
View file

@ -0,0 +1,179 @@
/****************************************************************************
* netutils/thttpd/thttpd_strings.c
* HTTP strings
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,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
netutils/thttpd/thttpd_strings.h Executable file
View file

@ -0,0 +1,123 @@
/****************************************************************************
* netutils/thttpd/thttpd_strings.h
* HTTP strings
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,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
netutils/thttpd/timers.c Normal file
View file

@ -0,0 +1,365 @@
/****************************************************************************
* netutils/thttpd/timers.c
* Simple Timer Routines
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Derived from the file of the same name in the original THTTPD package:
*
* Copyright © 1995,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
netutils/thttpd/timers.h Normal file
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 <spudmonkey@racsa.co.cr>
*
* 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 */