├── CHANGES ├── COPYING ├── CREDITS ├── Makefile.in ├── README ├── aclocal.m4 ├── config.guess ├── config.sub ├── configure ├── configure.in ├── contrib ├── README.chroot.solaris └── rpm │ ├── boa.conf │ ├── boa.init-redhat │ ├── boa.init-suse │ ├── boa.logrotate │ └── boa.spec ├── debian ├── README.Debian ├── boa.conf ├── changelog ├── clean ├── compat ├── control ├── copyright ├── dirs ├── docs ├── examples ├── info ├── init ├── install ├── logrotate ├── manpages ├── patches │ └── series ├── postinst ├── postrm ├── preinst ├── prerm ├── rules ├── source │ └── format └── watch ├── docs ├── .cvsignore ├── Makefile.in ├── boa.8 ├── boa.texi └── boa_banner.png ├── examples ├── boa.conf ├── cgi-test.cgi ├── nph-test.cgi └── resolver.pl ├── extra_macros.m4 ├── extras ├── alphasort.c ├── scandir.c └── strutil.c ├── install-sh └── src ├── .depend ├── Makefile.in ├── access.c ├── access.h ├── alias.c ├── boa.c ├── boa.h ├── buffer.c ├── cgi.c ├── cgi_header.c ├── compat.h ├── config.c ├── config.h.in ├── defines.h ├── escape.c ├── escape.h ├── get.c ├── globals.h ├── hash.c ├── index_dir.c ├── ip.c ├── log.c ├── mmap_cache.c ├── pipe.c ├── poll.c ├── queue.c ├── range.c ├── read.c ├── request.c ├── response.c ├── select.c ├── signals.c ├── sublog.c ├── timestamp.c └── util.c /CREDITS: -------------------------------------------------------------------------------- 1 | Liam Widdowson 2 | Lots of improvement for Solaris support 3 | 4 | Wes Hardaker 5 | 6 | Michal Kara 7 | mmap_cache buglet fix 8 | 9 | Matt Callaway 10 | CGI chdir issue 11 | 12 | Jari Korva 13 | IPv6 patch 14 | 15 | William Meadows 16 | escape.c bug notification and (first) fix 17 | 18 | Thomas Neumann 19 | *BSD compilation/core bugfixes 20 | 21 | Paul Saab 22 | Remove SO_REUSEADDR setting on each client socket 23 | 24 | David N. Welton 25 | Added "Listen" directive for server bind address 26 | 27 | Craig Silverstein 28 | patches for config.h and config.c 29 | 30 | Russ Nelson 31 | Original, Experimental IP-based Virtual Host code 32 | 33 | Landon Curt Noll http://www.isthe.com/chongo 34 | Allow non-standard date format 31 September 2000 23:59:59 GMT 35 | Skip whitespace before HTTP/major.minor 36 | FNV1a hash in hash.c 37 | 38 | Brieuc Jeunhomme 39 | fix buglet in alias expansion 40 | the name-based virtualhost code patch send to us by Brieuc 41 | was *very* close to the one that had been developed in-house, 42 | so we merged them. Special thanks for *actually* writing 43 | DOCS!! 44 | 45 | Laurent Pelecq 46 | test for socket in -lnet for BeOS 47 | tests for herror and inet_addr 48 | 49 | Don Mahurin (dma) 50 | pidfile patch 51 | default mime_types patch 52 | NCSA environment environment variables wrapped in 53 | #ifdef USE_NCSA_CGI_ENV 54 | 55 | Ulf Harnhammar 56 | fixed a small escaping issue with the automatic directory 57 | index maker 58 | 59 | Fraser McCrossan 60 | dummy install target 61 | some prototype cleaning for *BSD 62 | sprintf -> snprintf for local redirection in get.c 63 | 64 | MJ Pomraning 65 | suggestions to update index_dir.c to make sure filenames are 66 | http and html safe. 67 | 68 | Peter Korsgaard 69 | basic access control 70 | disable-gunzip support 71 | capitalization changes, etc.. to configure.in 72 | 73 | Davide Pagnin 74 | notes regarding find_mmap misuse 75 | 76 | Peter Pentchev 77 | fixes to sa_family_t detection on *BSD 78 | 79 | Alan H. Teague 80 | general cleanups 81 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # $Id: Makefile.in,v 1.1.2.6 2002/12/12 21:29:04 jnelson Exp $ 2 | 3 | MAKE=@MAKE@ 4 | 5 | .PHONY: clean mrclean distclean boa docs 6 | 7 | all: boa 8 | 9 | boa: 10 | (cd src && $(MAKE) $(MFLAGS)) 11 | 12 | docs: 13 | (cd docs && $(MAKE) $(MFLAGS)) 14 | 15 | clean: 16 | -(cd src && $(MAKE) $(MFLAGS) clean) 17 | -(cd docs && $(MAKE) clean) 18 | 19 | distclean: mrclean 20 | 21 | mrclean: clean 22 | -(cd src && $(MAKE) $(MFLAGS) mrclean) 23 | -(cd docs && $(MAKE) $(MFLAGS) mrclean) 24 | rm -f config.status config.cache config.h config.log 25 | rm -f Makefile *~ 26 | 27 | # dummy target for install 28 | install: 29 | @echo Please read the documentation then install manually. 30 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is Boa, a high performance web server for Unix-alike computers, 2 | covered by the Gnu General Public License. This is version 0.94, 3 | released January 2000. It is well tested and appears to be of 4 | at least "gamma" quality. 5 | 6 | Boa was created in 1991 by Paul Phillips . It is now being 7 | maintained and enhanced by Larry Doolittle 8 | and Jon Nelson . 9 | 10 | For more information (including installation instructions) examine 11 | the file docs/boa.txt or docs/boa.dvi, point your web browser to docs/boa.html, 12 | or visit the Boa homepage at 13 | 14 | http://www.boa.org/ 15 | 16 | -------------------------------------------------------------------------------- /aclocal.m4: -------------------------------------------------------------------------------- 1 | # aclocal.m4 generated automatically by aclocal 1.6.2 -*- Autoconf -*- 2 | 3 | # Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 4 | # Free Software Foundation, Inc. 5 | # This file is free software; the Free Software Foundation 6 | # gives unlimited permission to copy and/or distribute it, 7 | # with or without modifications, as long as this notice is preserved. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 11 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 | # PARTICULAR PURPOSE. 13 | 14 | dnl Many of the following macros courtesy of: 15 | dnl http://www.gnu.org/software/ac-archive/ 16 | dnl 17 | dnl The Following macros courtesy of: 18 | dnl Installed_Packages/check_gnu_make.html 19 | dnl 20 | dnl Copyrights are by the individual authors, as listed. 21 | dnl License: GPL 22 | dnl 23 | 24 | 25 | dnl CHECK_GNU_MAKE() 26 | dnl 27 | dnl This macro searches for a GNU version of make. If a match is found, the 28 | dnl makefile variable `ifGNUmake' is set to the empty string, otherwise it is 29 | dnl set to "#". This is useful for including a special features in a Makefile, 30 | dnl which cannot be handled by other versions of make. The variable 31 | dnl _cv_gnu_make_command is set to the command to invoke GNU make if it exists, 32 | dnl the empty string otherwise. 33 | dnl 34 | dnl Here is an example of its use: 35 | dnl 36 | dnl Makefile.in might contain: 37 | dnl 38 | dnl # A failsafe way of putting a dependency rule into a makefile 39 | dnl $(DEPEND): 40 | dnl $(CC) -MM $(srcdir)/*.c > $(DEPEND) 41 | dnl 42 | dnl @ifGNUmake@ ifeq ($(DEPEND),$(wildcard $(DEPEND))) 43 | dnl @ifGNUmake@ include $(DEPEND) 44 | dnl @ifGNUmake@ endif 45 | dnl 46 | dnl Then configure.in would normally contain: 47 | dnl 48 | dnl CHECK_GNU_MAKE() 49 | dnl AC_OUTPUT(Makefile) 50 | dnl 51 | dnl Then perhaps to cause gnu make to override any other make, we could do 52 | dnl something like this (note that GNU make always looks for GNUmakefile first): 53 | dnl 54 | dnl if ! test x$_cv_gnu_make_command = x ; then 55 | dnl mv Makefile GNUmakefile 56 | dnl echo .DEFAULT: > Makefile ; 57 | dnl echo \ $_cv_gnu_make_command \$@ >> Makefile; 58 | dnl fi 59 | dnl 60 | dnl Then, if any (well almost any) other make is called, and GNU make also exists, 61 | dnl then the other make wraps the GNU make. 62 | dnl 63 | dnl John Darrington 64 | dnl 1.3 (2002/01/04) 65 | dnl 66 | dnl Modified 18 Sep 2002 by Jon Nelson 67 | 68 | AC_DEFUN([CHECK_GNU_MAKE], 69 | [ AC_CACHE_CHECK( for GNU make, _cv_gnu_make_command, 70 | [_cv_gnu_make_command='' 71 | dnl Search all the common names for GNU make 72 | for a in "$MAKE" make gmake gnumake ; do 73 | if test -z "$a" ; then continue ; fi 74 | if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ); then 75 | _cv_gnu_make_command=$a 76 | break; 77 | fi 78 | done 79 | if test "x$_cv_gnu_make_command" = "x"; then 80 | _cv_gnu_make_command="Not found" 81 | fi 82 | ]) 83 | dnl If there was a GNU version, then set @ifGNUmake@ to the empty string, '#' otherwise 84 | if test "$_cv_gnu_make_command" != "Not found"; then 85 | ifGNUmake=''; 86 | else 87 | ifGNUmake='#'; 88 | _cv_gnu_make_command=''; 89 | fi 90 | AC_SUBST(ifGNUmake) 91 | ]) 92 | 93 | dnl AC_CHECK_STRUCT_FOR(INCLUDES,STRUCT,MEMBER,DEFINE,[no]) 94 | dnl 1.1 (2000/09/19) 95 | dnl Wes Hardaker 96 | 97 | dnl ---------------------------------------------------------- 98 | 99 | AC_DEFUN([AC_CHECK_STRUCT_FOR],[ 100 | ac_safe_struct=`echo "$2" | sed 'y%./+-%__p_%'` 101 | ac_safe_member=`echo "$3" | sed 'y%./+-%__p_%'` 102 | ac_safe_all="ac_cv_struct_${ac_safe_struct}_has_${ac_safe_member}" 103 | changequote(, )dnl 104 | ac_uc_define=STRUCT_`echo "${ac_safe_struct}_HAS_${ac_safe_member}" | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` 105 | changequote([, ])dnl 106 | 107 | AC_MSG_CHECKING([for $2.$3]) 108 | AC_CACHE_VAL($ac_safe_all, 109 | [ 110 | if test "x$4" = "x"; then 111 | defineit="= 0" 112 | elif test "x$4" = "xno"; then 113 | defineit="" 114 | else 115 | defineit="$4" 116 | fi 117 | AC_TRY_COMPILE([ 118 | $1 119 | ],[ 120 | struct $2 testit; 121 | testit.$3 $defineit; 122 | ], eval "${ac_safe_all}=yes", eval "${ac_safe_all}=no" ) 123 | ]) 124 | 125 | if eval "test \"x$`echo ${ac_safe_all}`\" = \"xyes\""; then 126 | AC_MSG_RESULT(yes) 127 | AC_DEFINE_UNQUOTED($ac_uc_define) 128 | else 129 | AC_MSG_RESULT(no) 130 | fi 131 | ]) 132 | 133 | dnl @synopsis AC_C_VAR_FUNC 134 | dnl 135 | dnl This macro tests if the C complier supports the C9X standard 136 | dnl __func__ indentifier. 137 | dnl 138 | dnl The new C9X standard for the C language stipulates that the 139 | dnl identifier __func__ shall be implictly declared by the compiler 140 | dnl as if, immediately following the opening brace of each function 141 | dnl definition, the declaration 142 | dnl 143 | dnl static const char __func__[] = "function-name"; 144 | dnl 145 | dnl appeared, where function-name is the name of the function where 146 | dnl the __func__ identifier is used. 147 | dnl 148 | dnl @version $Id: aclocal.m4,v 1.1.2.5 2003/01/20 20:53:52 jnelson Exp $ 149 | dnl @author Christopher Currie 150 | 151 | AC_DEFUN([AC_C_VAR_FUNC], 152 | [AC_REQUIRE([AC_PROG_CC]) 153 | AC_CACHE_CHECK(whether $CC recognizes __func__, ac_cv_c_var_func, 154 | AC_TRY_COMPILE(, 155 | [int main() { 156 | char *s = __func__; 157 | }], 158 | AC_DEFINE(HAVE_FUNC,, 159 | [Define if the C complier supports __func__]) ac_cv_c_var_func=yes, 160 | ac_cv_c_var_func=no) ) 161 | ])dnl 162 | 163 | dnl Exports one of ac_cv_func_poll or ac_cv_func_select 164 | dnl Author - Jon Nelson 165 | dnl Copyright 2002 166 | AC_DEFUN([POLL_OR_SELECT], 167 | [ 168 | AC_MSG_CHECKING(whether to use poll or select) 169 | AC_ARG_WITH(poll, 170 | [ --with-poll Use poll], 171 | [ 172 | if test "$withval" = "yes" ; then 173 | AC_MSG_RESULT(trying poll) 174 | ac_x=1 175 | else 176 | AC_MSG_RESULT(trying select) 177 | ac_x=0 178 | fi 179 | ], 180 | [ 181 | AC_MSG_RESULT(trying select) 182 | ac_x=0 183 | ]) 184 | 185 | if test $ac_x = 1; then 186 | AC_CHECK_HEADERS(sys/poll.h) 187 | AC_CHECK_FUNCS(poll) 188 | if test "x$ac_cv_func_poll" = "x"; then 189 | AC_MSG_ERROR(We attempted to find poll but could not. Please try again with --without-poll) 190 | fi 191 | BOA_ASYNC_IO="poll" 192 | else 193 | AC_CHECK_HEADERS(sys/select.h) 194 | AC_CHECK_FUNCS(select) 195 | if test "x$ac_cv_func_select" = "x"; then 196 | AC_MSG_ERROR(We attempted to find select but could not. Please try again with --with-poll) 197 | fi 198 | BOA_ASYNC_IO="select" 199 | fi 200 | ] 201 | ) 202 | 203 | 204 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | dnl $Id: configure.in,v 1.1.2.16 2003/10/05 04:00:05 jnelson Exp $ 2 | dnl Process this file with autoconf to produce a configure script. 3 | AC_INIT 4 | AC_CONFIG_SRCDIR([src/boa.c]) 5 | 6 | dnl Make config.h 7 | AC_CONFIG_HEADER(src/config.h) 8 | 9 | AC_CANONICAL_HOST 10 | 11 | dnl Checks for programs. 12 | AC_PROG_CC 13 | AC_PROG_CPP 14 | AC_C_VAR_FUNC 15 | 16 | CHECK_GNU_MAKE 17 | if test "x$_cv_gnu_make_command" != "x"; then 18 | MAKE="$_cv_gnu_make_command" 19 | ALLSOURCES="\$^" 20 | else 21 | MAKE="make" 22 | ALLSOURCES="\$(.ALLSRC)" 23 | fi 24 | AC_SUBST(ALLSOURCES) 25 | AC_SUBST(MAKE) 26 | 27 | dnl AC_MSG_RESULT($host) dnl i686-pc-linux-gnu 28 | dnl AC_MSG_RESULT($host_cpu) dnl i686 29 | dnl AC_MSG_RESULT($host_vendor) dnl pc 30 | dnl AC_MSG_RESULT($host_os) dnl linux-gnu 31 | dnl i386-unknown-freebsd4.2 32 | 33 | dnl Checks for libraries. 34 | # AC_SEARCH_LIBS (function, search-libs, [action-if-found], [action-if-not-found], [other-libraries]) 35 | AC_SEARCH_LIBS(socket, socket net) 36 | AC_SEARCH_LIBS(inet_aton, resolv) 37 | AC_SEARCH_LIBS(gethostname, nsl) 38 | AC_SEARCH_LIBS(gethostbyname, nsl) 39 | 40 | dnl Checks for header files. 41 | AC_HEADER_DIRENT 42 | AC_HEADER_STDC 43 | AC_HEADER_SYS_WAIT 44 | AC_CHECK_HEADERS(fcntl.h sys/fcntl.h limits.h sys/time.h) 45 | AC_CHECK_HEADERS(getopt.h unistd.h) 46 | 47 | dnl Checks for typedefs, structures, and compiler characteristics. 48 | AC_C_CONST 49 | AC_TYPE_UID_T 50 | AC_TYPE_OFF_T 51 | AC_TYPE_PID_T 52 | AC_TYPE_SIZE_T 53 | AC_HEADER_TIME 54 | AC_STRUCT_TM 55 | dnl AC_CHECK_TYPE(sa_family_t,unsigned short int) 56 | dnl AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[],[]) (includes, function-body, [action-if-found], [action-if-not-found]) 57 | AC_MSG_CHECKING(whether sa_family_t is defined) 58 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ 59 | #include 60 | #include 61 | ]], [[sa_family_t foo2;]])],[AC_MSG_RESULT(yes)],[ 62 | AC_MSG_RESULT(no) 63 | AC_DEFINE(DONT_HAVE_SA_FAMILY_T,1,[Define if sa_family_t is not defined]) 64 | 65 | ]) 66 | 67 | dnl Checks for library functions. 68 | AC_FUNC_FNMATCH 69 | AC_FUNC_MEMCMP 70 | AC_FUNC_MMAP 71 | AC_FUNC_SETVBUF_REVERSED 72 | AC_CHECK_FUNCS(getcwd strdup strstr strcspn strtol) 73 | AC_CHECK_FUNCS(gethostname gethostbyname socket inet_aton herror inet_addr) 74 | AC_CHECK_FUNCS(scandir alphasort) 75 | AC_CHECK_FUNCS(madvise) 76 | 77 | AC_CHECK_STRUCT_FOR([ 78 | #if TIME_WITH_SYS_TIME 79 | # include 80 | # include 81 | #else 82 | # if HAVE_SYS_TIME_H 83 | # include 84 | # else 85 | # include 86 | # endif 87 | #endif 88 | ],tm,tm_gmtoff) 89 | 90 | if test "$ac_cv_struct_tm_has_tm_gmtoff" = "yes"; then 91 | AC_DEFINE(HAVE_TM_GMTOFF,1,[Define if struct tm has a tm_gmtoff member]) 92 | fi 93 | 94 | AC_CHECK_STRUCT_FOR([ 95 | 96 | #if TIME_WITH_SYS_TIME 97 | # include 98 | # include 99 | #else 100 | # if HAVE_SYS_TIME_H 101 | # include 102 | # else 103 | # include 104 | # endif 105 | #endif 106 | ],tm,tm_zone) 107 | 108 | if test "$ac_cv_struct_tm_has_tm_zone" = "yes"; then 109 | AC_DEFINE(HAVE_TM_ZONE,1,[Define if struct tm has tm_zone member]) 110 | fi 111 | 112 | AC_CHECK_STRUCT_FOR([ 113 | #include 114 | #include 115 | ],sockaddr_in,sin_len) 116 | 117 | if test "$ac_cv_struct_sockaddr_in_has_sin_len" = "yes"; then 118 | AC_DEFINE(HAVE_SIN_LEN,1,[Define if struct sockaddr_in has sin_len member]) 119 | fi 120 | 121 | if test $ac_cv_func_scandir = no; then 122 | # scandir not defined, add it 123 | SCANDIR="scandir.o" 124 | AC_SUBST(SCANDIR) 125 | fi 126 | 127 | if test $ac_cv_func_alphasort = no; then 128 | # alphasort not defined, add it 129 | ALPHASORT="alphasort.o" 130 | AC_SUBST(ALPHASORT) 131 | fi 132 | 133 | if test $ac_cv_func_strdup = no -o $ac_cv_func_strstr = no; then 134 | # strdup or strstr not defined 135 | STRUTIL="strutil.o" 136 | AC_SUBST(STRUTIL) 137 | fi 138 | 139 | if test -n "$GCC"; then 140 | dnl if we are running gcc, use -pipe 141 | test -n "$GCC" && CFLAGS="$CFLAGS -pipe" 142 | 143 | AC_MSG_CHECKING(compile and link profiling code) 144 | AC_ARG_ENABLE(profiling, 145 | [ --enable-profiling Compile and link profiling code], 146 | [ 147 | if test "$enableval" = "yes" ; then 148 | AC_MSG_RESULT(yes) 149 | CFLAGS="$CFLAGS -pg" 150 | LDFLAGS="$LDFLAGS -g -pg" 151 | else 152 | AC_MSG_RESULT(no) 153 | fi 154 | ], 155 | [ 156 | AC_MSG_RESULT(no) 157 | ]) 158 | fi 159 | 160 | AC_MSG_CHECKING(whether to enable gunzip support) 161 | AC_ARG_ENABLE(gunzip, 162 | [ --disable-gunzip Disable use of gunzip], 163 | [ 164 | if test "$enableval" = "yes" ; then 165 | AC_MSG_RESULT(yes) 166 | AC_PATH_PROG(GUNZIP, gunzip) 167 | AC_DEFINE_UNQUOTED(GUNZIP, "$ac_cv_path_GUNZIP", [Define if gunzip can be found]) 168 | else 169 | AC_MSG_RESULT(no) 170 | fi 171 | ], 172 | [ 173 | AC_MSG_RESULT(yes) 174 | AC_PATH_PROG(GUNZIP, gunzip) 175 | AC_DEFINE_UNQUOTED(GUNZIP, "$ac_cv_path_GUNZIP", [Define if gunzip can be found]) 176 | ]) 177 | 178 | AC_MSG_CHECKING(whether to enable access control support) 179 | AC_ARG_ENABLE(access-control, 180 | [ --enable-access-control Enable support for allow/deny rules], 181 | [ 182 | if test "$enableval" = "yes" ; then 183 | AC_MSG_RESULT(yes) 184 | CFLAGS="$CFLAGS -DACCESS_CONTROL" 185 | ACCESSCONTROL_SOURCE="access.c" 186 | else 187 | AC_MSG_RESULT(no) 188 | fi 189 | ], 190 | [ 191 | AC_MSG_RESULT(no) 192 | ]) 193 | AC_SUBST(ACCESSCONTROL_SOURCE) 194 | 195 | AC_MSG_CHECKING(whether to compile and link debugging code) 196 | AC_ARG_ENABLE(debug, 197 | [ --disable-debug Do not compile and link debugging code], 198 | [ 199 | if test "$enableval" = "yes" ; then 200 | AC_MSG_RESULT(yes) 201 | LDFLAGS="$LDFLAGS -g" 202 | test -n "$GCC" && CFLAGS="$CFLAGS -Wall" 203 | else 204 | AC_MSG_RESULT(no) 205 | fi 206 | ], 207 | [ 208 | AC_MSG_RESULT(yes) 209 | LDFLAGS="$LDFLAGS -g" 210 | test -n "$GCC" && CFLAGS="$CFLAGS -Wall" 211 | ]) 212 | 213 | AC_MSG_CHECKING(whether to disable verbose/debug logging) 214 | AC_ARG_ENABLE(verbose, 215 | [ --disable-verbose Do not enable verbose/debug logging], 216 | [ 217 | if test "$enableval" = "yes" ; then 218 | AC_MSG_RESULT(yes) 219 | else 220 | CFLAGS="$CFLAGS -DDISABLE_DEBUG" 221 | AC_MSG_RESULT(no) 222 | fi 223 | ], 224 | [ 225 | AC_MSG_RESULT(yes) 226 | ]) 227 | 228 | AC_MSG_CHECKING(whether to link with the Dmalloc memory debugger/profiler) 229 | AC_ARG_WITH(dmalloc, 230 | [ --with-dmalloc Link with the Dmalloc memory debugger/profiler], 231 | [ 232 | if test "$withval" = "yes"; then 233 | AC_MSG_RESULT(trying) 234 | AC_CHECK_LIB(dmalloc, dmalloc_shutdown) 235 | else 236 | AC_MSG_RESULT(no) 237 | fi 238 | ], 239 | [ 240 | AC_MSG_RESULT(no) 241 | ]) 242 | 243 | AC_MSG_CHECKING(whether to link with the Electric Fence memory debugger) 244 | AC_ARG_WITH(efence, 245 | [ --with-efence Link with the Electric Fence memory debugger], 246 | [ 247 | if test "$withval" = "yes"; then 248 | AC_MSG_RESULT(trying) 249 | AC_CHECK_LIB(efence, main) 250 | else 251 | AC_MSG_RESULT(no) 252 | fi 253 | ], 254 | [ 255 | AC_MSG_RESULT(no) 256 | ]) 257 | 258 | case $host_os in 259 | *linux*) 260 | AC_MSG_CHECKING(whether to enable the use of the sendfile(2) system call) 261 | AC_ARG_ENABLE(sendfile, 262 | [ --disable-sendfile Disable the use of the sendfile(2) system call], 263 | [ 264 | if test "$enableval" = "no" ; then 265 | AC_MSG_RESULT(no) 266 | else 267 | AC_MSG_RESULT(yes) 268 | AC_CHECK_HEADERS(sys/sendfile.h) 269 | AC_CHECK_FUNCS(sendfile) 270 | fi 271 | ], 272 | [ 273 | AC_MSG_RESULT(yes) 274 | AC_CHECK_HEADERS(sys/sendfile.h) 275 | AC_CHECK_FUNCS(sendfile) 276 | ]) 277 | ;; 278 | *) ;; 279 | esac 280 | 281 | POLL_OR_SELECT 282 | 283 | if test "$BOA_ASYNC_IO" = "poll"; then 284 | ASYNCIO_SOURCE="poll.c" 285 | else 286 | ASYNCIO_SOURCE="select.c" 287 | fi 288 | AC_SUBST(ASYNCIO_SOURCE) 289 | 290 | # there are three scenarios 291 | # GNU make is installed as "make" 292 | # GNU make is installed as something else we detected 293 | # GNU make is not installed 294 | # Unfortunately, we can't deal with it one way or the other 295 | # Trying multiple AC_OUTPUT confuses autoconf, and using variables 296 | # *in* AC_OUTPUT is even worse. 297 | # *so*, make a default makefile that just forces make to call gmake 298 | # or whatever. 299 | 300 | AC_CONFIG_FILES([Makefile src/Makefile docs/Makefile]) 301 | AC_OUTPUT 302 | -------------------------------------------------------------------------------- /contrib/README.chroot.solaris: -------------------------------------------------------------------------------- 1 | Boa chroot mini-HOWTO 2 | =================================================== 3 | by Liam Widdowson 4 | modified slightly by Jon Nelson 5 | 6 | The following is required to get Boa working in a chroot jail. Whilst this 7 | README is about Solaris specifically, the principals here will apply to 8 | other operating systems. 9 | 10 | The following assumptions are made: 11 | 12 | - Boa has been compiled and installed in /opt/boa 13 | - The chroot jail will be created in /var/www 14 | - A user and group 'www' have been created. 15 | 16 | Make sure you change the above directories to suit your system. 17 | 18 | Your boa.conf should look something like the following: 19 | 20 | ## begin config file 21 | 22 | Port 80 23 | User www 24 | Group www 25 | 26 | # Note, these paths are used releative to the chroot jail. i.e /var/log is 27 | # really /var/www/var/log 28 | ErrorLog /var/log/error_log 29 | AccessLog /var/log/access_log 30 | DocumentRoot /var/www 31 | 32 | # You won't be able to access user home directories outside of the chroot 33 | # but you may replicate them into the chroot jail. You'll need a working 34 | # and valid /etc/passwd as well 35 | UserDir public_html 36 | 37 | DirectoryIndex index.html 38 | 39 | # this binary must exist in the chroot jail. Again, the path is relative. 40 | DirectoryMaker /usr/bin/boa_indexer 41 | 42 | KeepAliveMax 1000 43 | KeepAliveTimeout 10 44 | 45 | # this file must exist inside AND outside the chroot jail. 46 | MimeTypes /opt/boa/mime.types 47 | 48 | DefaultType text/plain 49 | 50 | ## end config file 51 | 52 | Once the configuration file is created, you must begin creating your 53 | chroot jail. A variety of libraries, timezone files, device files and other 54 | bits and pieces must be copied in order for this to work. Below is a ls -lR 55 | of what your jail should be at a minimum: 56 | 57 | .: 58 | total 10 59 | drwxr-xr-x 2 root other 512 Jan 21 18:58 dev 60 | drwxr-xr-x 2 root other 512 Jan 21 19:20 etc 61 | drwxr-xr-x 3 root other 512 Jan 21 19:20 opt 62 | drwxr-xr-x 5 root other 512 Jan 21 19:08 usr 63 | drwxr-xr-x 4 root other 512 Jan 21 18:57 var 64 | 65 | ./dev: 66 | total 0 67 | crw-rw-rw- 1 root other 13, 2 Jan 21 18:58 null 68 | crw-rw-rw- 1 root other 41, 0 Jan 21 18:58 udp 69 | 70 | ./etc: 71 | total 16 72 | -r-xr-xr-x 1 root other 482 Jan 21 19:20 TIMEZONE 73 | -r--r--r-- 1 root other 74 Jan 21 19:20 hosts 74 | -rw-r--r-- 1 root other 1239 Jan 21 19:20 netconfig 75 | -rw-r--r-- 1 root other 1298 Jan 21 19:20 nsswitch.conf 76 | -r--r--r-- 1 root other 514 Jan 21 19:44 passwd 77 | -rw-r--r-- 1 root other 94 Jan 21 19:20 resolv.conf 78 | drwx------ 2 root other 512 Jan 21 19:20 boa 79 | 80 | ./boa: 81 | total 4 82 | -rw-r--r-- 1 root other 1234 Jan 21 19:26 boa.conf 83 | 84 | ./opt: 85 | total 2 86 | drwxr-xr-x 2 root other 512 Jan 21 19:26 boa 87 | 88 | ./opt/boa: 89 | total 20 90 | -rw-r--r-- 1 root other 9964 Jan 21 19:26 mime.types 91 | 92 | ./usr: 93 | total 6 94 | drwxr-xr-x 2 root other 512 Jan 21 19:21 bin 95 | drwxr-xr-x 2 root other 512 Jan 21 19:03 lib 96 | drwxr-xr-x 3 root other 512 Jan 21 19:08 share 97 | 98 | ./usr/bin: 99 | total 18 100 | -rwxr-xr-x 1 root other 8944 Jan 21 19:23 boa_indexer 101 | 102 | ./usr/lib: 103 | total 5094 104 | -rwxr-xr-x 1 root other 185020 Jan 21 19:03 ld.so.1 105 | -rwxr-xr-x 1 root other 1126652 Jan 21 18:56 libc.so.1 106 | -rwxr-xr-x 1 root other 4308 Jan 21 18:56 libdl.so.1 107 | -rwxr-xr-x 1 root other 24968 Jan 21 18:56 libmp.so.2 108 | -rwxr-xr-x 1 root other 883500 Jan 21 18:56 libnsl.so.1 109 | -rwxr-xr-x 1 root other 265860 Jan 21 18:56 libresolv.so.2 110 | -rwxr-xr-x 1 root other 70260 Jan 21 18:56 libsocket.so.1 111 | 112 | ./usr/share: 113 | total 2 114 | drwxr-xr-x 3 root other 512 Jan 21 19:08 lib 115 | 116 | ./usr/share/lib: 117 | total 2 118 | drwxr-xr-x 3 root other 512 Jan 21 19:08 zoneinfo 119 | 120 | ./usr/share/lib/zoneinfo: 121 | total 2 122 | drwxr-xr-x 2 root other 512 Jan 21 19:09 Australia 123 | 124 | ./usr/share/lib/zoneinfo/Australia: 125 | total 22 126 | -rw-r--r-- 1 root other 785 Jan 21 19:09 ACT 127 | -rw-r--r-- 1 root other 785 Jan 21 19:09 Broken_Hill 128 | -rw-r--r-- 1 root other 663 Jan 21 19:09 LHI 129 | -rw-r--r-- 1 root other 785 Jan 21 19:09 NSW 130 | -rw-r--r-- 1 root other 104 Jan 21 19:09 North 131 | -rw-r--r-- 1 root other 160 Jan 21 19:09 Queensland 132 | -rw-r--r-- 1 root other 785 Jan 21 19:09 South 133 | -rw-r--r-- 1 root other 825 Jan 21 19:09 Tasmania 134 | -rw-r--r-- 1 root other 785 Jan 21 19:09 Victoria 135 | -rw-r--r-- 1 root other 150 Jan 21 19:09 West 136 | -rw-r--r-- 1 root other 785 Jan 21 19:09 Yancowinna 137 | 138 | ./var: 139 | total 4 140 | drwxr-xr-x 2 www www 512 Jan 21 19:44 log 141 | drwxr-xr-x 2 root other 512 Jan 21 18:57 www 142 | 143 | ./var/log: 144 | total 4 145 | -rw-r--r-- 1 root other 202 Jan 21 19:47 access_log 146 | -rw-r--r-- 1 root other 590 Jan 21 19:49 error_log 147 | 148 | ./var/www: 149 | total 0 150 | 151 | Note, your boa binary should be kept outside of the chroot jail as 152 | they are not required. 153 | 154 | The commandline issued to boa requires "-r /var/www" which tells 155 | boa to chroot to /var/www before it does anything else, including 156 | reading its configuration file. 157 | 158 | That's all that's required. Start your new chrooting boa up and enjoy! 159 | -------------------------------------------------------------------------------- /contrib/rpm/boa.conf: -------------------------------------------------------------------------------- 1 | # Boa v0.94 configuration file 2 | # File format has not changed from 0.93 3 | # File format has changed little from 0.92 4 | # version changes are noted in the comments 5 | # 6 | # The Boa configuration file is parsed with a lex/yacc or flex/bison 7 | # generated parser. If it reports an error, the line number will be 8 | # provided; it should be easy to spot. The syntax of each of these 9 | # rules is very simple, and they can occur in any order. Where possible 10 | # these directives mimic those of NCSA httpd 1.3; I saw no reason to 11 | # introduce gratuitous differences. 12 | 13 | # $Id: boa.conf,v 1.2 2001/09/25 03:28:31 jnelson Exp $ 14 | 15 | # The "ServerRoot" is not in this configuration file. It can be compiled 16 | # into the server (see defines.h) or specified on the command line with 17 | # the -c option, for example: 18 | # 19 | # boa -c /usr/local/boa 20 | 21 | 22 | # Port: The port Boa runs on. The default port for http servers is 80. 23 | # If it is less than 1024, the server must be started as root. 24 | 25 | Port 80 26 | 27 | # Listen: the Internet address to bind(2) to. If you leave it out, 28 | # it takes the behavior before 0.93.17.2, which is to bind to all 29 | # addresses (INADDR_ANY). You only get one "Listen" directive, 30 | # if you want service on multiple IP addresses, you have three choices: 31 | # 1. Run boa without a "Listen" directive 32 | # a. All addresses are treated the same; makes sense if the addresses 33 | # are localhost, ppp, and eth0. 34 | # b. Use the VirtualHost directive below to point requests to different 35 | # files. Should be good for a very large number of addresses (web 36 | # hosting clients). 37 | # 2. Run one copy of boa per IP address, each has its own configuration 38 | # with a "Listen" directive. No big deal up to a few tens of addresses. 39 | # Nice separation between clients. 40 | # The name you provide gets run through inet_aton(3), so you have to use dotted 41 | # quad notation. This configuration is too important to trust some DNS. 42 | 43 | #Listen 192.68.0.5 44 | 45 | # User: The name or UID the server should run as. 46 | # Group: The group name or GID the server should run as. 47 | 48 | User nobody 49 | Group nobody 50 | 51 | # ServerAdmin: The email address where server problems should be sent. 52 | # Note: this is not currently used, except as an environment variable 53 | # for CGIs. 54 | 55 | #ServerAdmin root@localhost 56 | 57 | # ErrorLog: The location of the error log file. If this does not start 58 | # with /, it is considered relative to the server root. 59 | # Set to /dev/null if you don't want errors logged. 60 | # If unset, defaults to /dev/stderr 61 | 62 | ErrorLog /var/log/boa/error_log 63 | # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 64 | # is somewhat experimental and might fail under heavy load. 65 | # "Usual libc implementations of printf will stall the whole 66 | # process if the receiving end of a pipe stops reading." 67 | #ErrorLog "|/usr/sbin/cronolog --symlink=/var/log/boa/error_log /var/log/boa/error-%Y%m%d.log" 68 | 69 | # AccessLog: The location of the access log file. If this does not 70 | # start with /, it is considered relative to the server root. 71 | # Comment out or set to /dev/null (less effective) to disable 72 | # Access logging. 73 | 74 | AccessLog /var/log/boa/access_log 75 | # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 76 | # is somewhat experimental and might fail under heavy load. 77 | # "Usual libc implementations of printf will stall the whole 78 | # process if the receiving end of a pipe stops reading." 79 | #AccessLog "|/usr/sbin/cronolog --symlink=/var/log/boa/access_log /var/log/boa/access-%Y%m%d.log" 80 | 81 | # VerboseCGILogs: this is just a logical switch. 82 | # It simply notes the start and stop times of cgis in the error log 83 | # Comment out to disable. 84 | 85 | #VerboseCGILogs 86 | 87 | # ServerName: the name of this server that should be sent back to 88 | # clients if different than that returned by gethostname + gethostbyname 89 | 90 | #ServerName www.your.org.here 91 | 92 | # VirtualHost: a logical switch. 93 | # Comment out to disable. 94 | # Given DocumentRoot /var/www, requests on interface 'A' or IP 'IP-A' 95 | # become /var/www/IP-A. 96 | # Example: http://localhost/ becomes /var/www/127.0.0.1 97 | # 98 | # Not used until version 0.93.17.2. This "feature" also breaks commonlog 99 | # output rules, it prepends the interface number to each access_log line. 100 | # You are expected to fix that problem with a postprocessing script. 101 | 102 | #VirtualHost 103 | 104 | # DocumentRoot: The root directory of the HTML documents. 105 | # Comment out to disable server non user files. 106 | 107 | DocumentRoot /home/httpd/html 108 | 109 | # UserDir: The name of the directory which is appended onto a user's home 110 | # directory if a ~user request is recieved. 111 | 112 | UserDir public_html 113 | 114 | # DirectoryIndex: Name of the file to use as a pre-written HTML 115 | # directory index. Please MAKE AND USE THESE FILES. On the 116 | # fly creation of directory indexes can be _slow_. 117 | # Comment out to always use DirectoryMaker 118 | 119 | DirectoryIndex index.html 120 | 121 | # DirectoryMaker: Name of program used to create a directory listing. 122 | # Comment out to disable directory listings. If both this and 123 | # DirectoryIndex are commented out, accessing a directory will give 124 | # an error (though accessing files in the directory are still ok). 125 | 126 | DirectoryMaker /usr/lib/boa/boa_indexer 127 | 128 | # DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker 129 | # has been commented out, the the on-the-fly indexing of Boa can be used 130 | # to generate indexes of directories. Be warned that the output is 131 | # extremely minimal and can cause delays when slow disks are used. 132 | # Note: The DirectoryCache must be writable by the same user/group that 133 | # Boa runs as. 134 | 135 | # DirectoryCache /var/spool/boa/dircache 136 | 137 | # KeepAliveMax: Number of KeepAlive requests to allow per connection 138 | # Comment out, or set to 0 to disable keepalive processing 139 | 140 | KeepAliveMax 1000 141 | 142 | # KeepAliveTimeout: seconds to wait before keepalive connection times out 143 | 144 | KeepAliveTimeout 10 145 | 146 | # MimeTypes: This is the file that is used to generate mime type pairs 147 | # and Content-Type fields for boa. 148 | # Set to /dev/null if you do not want to load a mime types file. 149 | # Do *not* comment out (better use AddType!) 150 | 151 | MimeTypes /etc/mime.types 152 | 153 | # DefaultType: MIME type used if the file extension is unknown, or there 154 | # is no file extension. 155 | 156 | DefaultType text/plain 157 | 158 | # AddType: adds types without editing mime.types 159 | # Example: AddType type extension [extension ...] 160 | 161 | # Uncomment the next line if you want .cgi files to execute from anywhere 162 | #AddType application/x-httpd-cgi cgi 163 | 164 | # Redirect, Alias, and ScriptAlias all have the same semantics -- they 165 | # match the beginning of a request and take appropriate action. Use 166 | # Redirect for other servers, Alias for the same server, and ScriptAlias 167 | # to enable directories for script execution. 168 | 169 | # Redirect allows you to tell clients about documents which used to exist in 170 | # your server's namespace, but do not anymore. This allows you to tell the 171 | # clients where to look for the relocated document. 172 | # Example: Redirect /bar http://elsewhere/feh/bar 173 | 174 | # Aliases: Aliases one path to another. 175 | # Example: Alias /path1/bar /path2/foo 176 | 177 | Alias /doc /usr/doc 178 | 179 | # ScriptAlias: Maps a virtual path to a directory for serving scripts 180 | # Example: ScriptAlias /htbin/ /www/htbin/ 181 | 182 | ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/ 183 | 184 | -------------------------------------------------------------------------------- /contrib/rpm/boa.init-redhat: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # The following two lines enable chkconfig(1) to manipulate this script 3 | # chkconfig: 345 87 13 4 | # description: Boa is a World Wide Web server. It is used to serve \ 5 | # HTML files and CGI. 6 | # processname: boa 7 | # config: /etc/boa/boa.conf 8 | # There is no pid file 9 | 10 | # Source function library. 11 | . /etc/rc.d/init.d/functions 12 | 13 | # See how we were called. 14 | case "$1" in 15 | start) 16 | echo -n "Starting boa: " 17 | daemon boa 18 | touch /var/lock/subsys/boa 19 | echo 20 | ;; 21 | stop) 22 | echo -n "Shutting down boa: " 23 | killproc boa 24 | echo 25 | rm -f /var/lock/subsys/boa 26 | rm -f /var/run/boa.pid 27 | ;; 28 | status) 29 | status boa 30 | ;; 31 | restart) 32 | $0 stop 33 | $0 start 34 | ;; 35 | reload) 36 | echo -n "Reloading boa: " 37 | killproc boa -HUP 38 | echo 39 | ;; 40 | *) 41 | echo "Usage: $0 {start|stop|restart|reload|status}" 42 | exit 1 43 | esac 44 | 45 | exit 0 46 | -------------------------------------------------------------------------------- /contrib/rpm/boa.init-suse: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # Portions Copyright (c) 2003 SuSE Linux AG 4 | # Original Author: Peter Poeml 5 | # 6 | # Based on the init script for OpenVPN 7 | # 8 | ### BEGIN INIT INFO 9 | # Provides: boa 10 | # Required-Start: $local_fs $remote_fs $network 11 | # Required-Stop: $local_fs $remote_fs $network 12 | # Default-Start: 3 5 13 | # Default-Stop: 0 1 2 6 14 | # Short-Description: Boa httpd 15 | # Description: Start Boa httpd 16 | ### END INIT INFO 17 | 18 | 19 | DAEMON="Boa" 20 | boa=/usr/sbin/boa 21 | #piddir=/var/run 22 | 23 | test -x $boa || exit 5 24 | 25 | # Shell functions sourced from /etc/rc.status: 26 | # rc_check check and set local and overall rc status 27 | # rc_status check and set local and overall rc status 28 | # rc_status -v ditto but be verbose in local rc status 29 | # rc_status -v -r ditto and clear the local rc status 30 | # rc_failed set local and overall rc status to failed 31 | # rc_failed set local and overall rc status to 32 | # rc_reset clear local rc status (overall remains) 33 | # rc_exit exit appropriate to overall rc status 34 | . /etc/rc.status 35 | 36 | # First reset status of this service 37 | rc_reset 38 | 39 | # Return values acc. to LSB for all commands but status: 40 | # 0 - success 41 | # 1 - generic or unspecified error 42 | # 2 - invalid or excess argument(s) 43 | # 3 - unimplemented feature (e.g. "reload") 44 | # 4 - insufficient privilege 45 | # 5 - program is not installed 46 | # 6 - program is not configured 47 | # 7 - program is not running 48 | # 49 | # Note that starting an already running service, stopping 50 | # or restarting a not-running service as well as the restart 51 | # with force-reload (in case signalling is not supported) are 52 | # considered a success. 53 | 54 | shopt -s nullglob 55 | ret=true 56 | 57 | case "$1" in 58 | start) 59 | echo -n "Starting $DAEMON " 60 | 61 | $boa || ret=false 62 | 63 | # Remember status and be verbose 64 | $ret 65 | rc_status -v 66 | ;; 67 | stop) 68 | echo -n "Shutting down $DAEMON " 69 | 70 | ## Stop daemon with killproc(8) and if this fails 71 | ## set echo the echo return value. 72 | killproc -TERM $boa || ret=false 73 | 74 | # Remember status and be verbose 75 | $ret 76 | rc_status -v 77 | ;; 78 | try-restart) 79 | ## Do a restart only if the service was active before. 80 | ## Note: try-restart is now part of LSB (as of 1.9). 81 | ## RH has a similar command named condrestart. 82 | $0 status 83 | if test $? = 0; then 84 | $0 restart 85 | else 86 | rc_reset # Not running is not a failure. 87 | fi 88 | # Remember status and be quiet 89 | rc_status 90 | ;; 91 | restart) 92 | ## Stop the service and regardless of whether it was 93 | ## running or not, start it again. 94 | $0 stop 95 | sleep 3 96 | $0 start 97 | 98 | # Remember status and be quiet 99 | rc_status 100 | ;; 101 | reload) 102 | killproc -HUP $boa || ret=false 103 | rc_status -v 104 | ;; 105 | reopen) 106 | killproc -USR1 $boa || ret=false 107 | rc_status -v 108 | ;; 109 | # status) 110 | # echo -n "Checking for $DAEMON: " 111 | # running=false 112 | # running=true 113 | # killproc -p $i -USR2 $boa || { rv=$?; ret=false; } 114 | # if $running; then 115 | # $ret 116 | # rc_status -v 117 | # echo Status written to /var/log/messages 118 | # else 119 | # rc_failed 3 120 | # rc_status -v 121 | # fi 122 | # ;; 123 | *) 124 | echo "Usage: $0 {start|stop|status|try-restart|restart|reload|reopen}" 125 | exit 1 126 | esac 127 | rc_exit 128 | -------------------------------------------------------------------------------- /contrib/rpm/boa.logrotate: -------------------------------------------------------------------------------- 1 | /var/log/boa/*_log { 2 | weekly 3 | compress 4 | copytruncate 5 | missingok 6 | } 7 | -------------------------------------------------------------------------------- /contrib/rpm/boa.spec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/boa/7b13e12faf3ca5543b371987a89fe80cf31ff43c/contrib/rpm/boa.spec -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | boa for DEBIAN 2 | -------------- 3 | 4 | To read the docs try 5 | 6 | file:///usr/share/doc/boa/boa.html 7 | or 8 | http://localhost/doc/boa/boa.html 9 | 10 | Specific thanks go out to Joy (Josip Rodin) 11 | for help with some various Debianisms. 12 | 13 | To use the cronolog logging facilities, the following changes must be made: 14 | 15 | 1) install cronolog 16 | 2) edit /etc/boa/boa.conf to use the cronolog logging 17 | 3) comment out everything in /etc/logrotate.d/boa pre-pending a 18 | '#' character to each line. This is very important! 19 | 4) move the old log files out of the way before restarting Boa 20 | 21 | NOTE: Cronolog does *not* rotate files in the traditional way. 22 | -------------------------------------------------------------------------------- /debian/boa.conf: -------------------------------------------------------------------------------- 1 | # Boa v0.94 configuration file 2 | # File format has not changed from 0.93 3 | # File format has changed little from 0.92 4 | # version changes are noted in the comments 5 | # 6 | # The Boa configuration file is parsed with a custom parser. If it 7 | # reports an error, the line number will be provided; it should be easy 8 | # to spot. The syntax of each of these rules is very simple, and they 9 | # can occur in any order. Where possible these directives mimic those 10 | # of NCSA httpd 1.3; I saw no reason to introduce gratuitous 11 | # differences. 12 | 13 | # $Id: boa.conf,v 1.3.2.6 2003/02/02 05:02:22 jnelson Exp $ 14 | 15 | # The "ServerRoot" is not in this configuration file. It can be 16 | # compiled into the server (see defines.h) or specified on the command 17 | # line with the -c option, for example: 18 | # 19 | # boa -c /usr/local/boa 20 | 21 | 22 | # Port: The port Boa runs on. The default port for http servers is 80. 23 | # If it is less than 1024, the server must be started as root. 24 | 25 | Port 80 26 | 27 | # Listen: the Internet address to bind(2) to. If you leave it out, 28 | # it takes the behavior before 0.93.17.2, which is to bind to all 29 | # addresses (INADDR_ANY). You only get one "Listen" directive, 30 | # if you want service on multiple IP addresses, you have three choices: 31 | # 1. Run boa without a "Listen" directive 32 | # a. All addresses are treated the same; makes sense if the addresses 33 | # are localhost, ppp, and eth0. 34 | # b. Use the VirtualHost directive below to point requests to different 35 | # files. Should be good for a very large number of addresses (web 36 | # hosting clients). 37 | # 2. Run one copy of boa per IP address, each has its own configuration 38 | # with a "Listen" directive. No big deal up to a few tens of addresses. 39 | # Nice separation between clients. 40 | # The name you provide gets run through inet_aton(3), so you have to use dotted 41 | # quad notation. This configuration is too important to trust some DNS. 42 | 43 | #Listen 192.68.0.5 44 | 45 | # User: The name or UID the server should run as. 46 | # Group: The group name or GID the server should run as. 47 | 48 | User www-data 49 | Group www-data 50 | 51 | # ServerAdmin: The email address where server problems should be sent. 52 | # Note: this is not currently used, except as an environment variable 53 | # for CGIs. 54 | 55 | #ServerAdmin root@localhost 56 | 57 | # PidFile: where to put the pid of the process. 58 | # Comment out to write no pid file. 59 | # Note: Because Boa drops privileges at startup, and the 60 | # pid file is written by the UID/GID before doing so, Boa 61 | # does not attempt removal of the pid file. 62 | # PidFile /var/run/boa.pid 63 | 64 | # ErrorLog: The location of the error log file. If this does not start 65 | # with /, it is considered relative to the server root. 66 | # Set to /dev/null if you don't want errors logged. 67 | # If unset, defaults to /dev/stderr 68 | # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 69 | # is somewhat experimental and might fail under heavy load. 70 | # "Usual libc implementations of printf will stall the whole 71 | # process if the receiving end of a pipe stops reading." 72 | #ErrorLog "|/usr/sbin/cronolog --symlink=/var/log/boa/error_log /var/log/boa/error-%Y%m%d.log" 73 | 74 | ErrorLog /var/log/boa/error_log 75 | 76 | # AccessLog: The location of the access log file. If this does not 77 | # start with /, it is considered relative to the server root. 78 | # Comment out or set to /dev/null (less effective) to disable. 79 | # Useful to set to /dev/stdout for use with daemontools. 80 | # Access logging. 81 | # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 82 | # is somewhat experimental and might fail under heavy load. 83 | # "Usual libc implementations of printf will stall the whole 84 | # process if the receiving end of a pipe stops reading." 85 | #AccessLog "|/usr/sbin/cronolog --symlink=/var/log/boa/access_log /var/log/boa/access-%Y%m%d.log" 86 | 87 | AccessLog /var/log/boa/access_log 88 | 89 | # CGILog /var/log/boa/cgi_log 90 | # CGILog: The location of the CGI stderr log file. If this does not 91 | # start with /, it is considered relative to the server root. 92 | # The log file would contain any contents send to /dev/stderr 93 | # by the CGI. If this is commented out, it defaults to whatever 94 | # ErrorLog points. Set to /dev/null to disable CGI stderr logging. 95 | # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 96 | # is somewhat experimental and might fail under heavy load. 97 | # "Usual libc implementations of printf will stall the whole 98 | # process if the receiving end of a pipe stops reading." 99 | #CGILog "|/usr/sbin/cronolog --symlink=/var/log/boa/cgi_log /var/log/boa/cgi-%Y%m%d.log" 100 | 101 | # CGIumask 027 (no mask for user, read-only for group, and nothing for user) 102 | # CGIumask 027 103 | # The CGIumask is set immediately before execution of the CGI. 104 | 105 | # UseLocaltime: Logical switch. Uncomment to use localtime 106 | # instead of UTC time 107 | #UseLocaltime 108 | 109 | # VerboseCGILogs: this is just a logical switch. 110 | # It simply notes the start and stop times of cgis in the error log 111 | # Comment out to disable. 112 | 113 | #VerboseCGILogs 114 | 115 | # ServerName: the name of this server that should be sent back to 116 | # clients if different than that returned by gethostname + gethostbyname 117 | 118 | #ServerName www.your.org.here 119 | 120 | # VirtualHost: a logical switch. 121 | # Comment out to disable. 122 | # Given DocumentRoot /var/www, requests on interface 'A' or IP 'IP-A' 123 | # become /var/www/IP-A. 124 | # Example: http://localhost/ becomes /var/www/127.0.0.1 125 | # 126 | # Not used until version 0.93.17.2. This "feature" also breaks commonlog 127 | # output rules, it prepends the interface number to each access_log line. 128 | # You are expected to fix that problem with a postprocessing script. 129 | 130 | #VirtualHost 131 | 132 | 133 | # VHostRoot: the root location for all virtually hosted data 134 | # Comment out to disable. 135 | # Incompatible with 'Virtualhost' and 'DocumentRoot'!! 136 | # Given VHostRoot /var/www, requests to host foo.bar.com, 137 | # where foo.bar.com is ip a.b.c.d, 138 | # become /var/www/a.b.c.d/foo.bar.com 139 | # Hostnames are "cleaned", and must conform to the rules 140 | # specified in rfc1034, which are be summarized here: 141 | # 142 | # Hostnames must start with a letter, end with a letter or digit, 143 | # and have as interior characters only letters, digits, and hyphen. 144 | # Hostnames must not exceed 63 characters in length. 145 | 146 | #VHostRoot /var/www 147 | 148 | # DefaultVHost 149 | # Define this in order to have a default hostname when the client does not 150 | # specify one, if using VirtualHostName. If not specified, the word 151 | # "default" will be used for compatibility with older clients. 152 | 153 | #DefaultVHost foo.bar.com 154 | 155 | # DocumentRoot: The root directory of the HTML documents. 156 | # Comment out to disable server non user files. 157 | 158 | DocumentRoot /var/www 159 | 160 | # UserDir: The name of the directory which is appended onto a user's home 161 | # directory if a ~user request is received. 162 | 163 | UserDir public_html 164 | 165 | # DirectoryIndex: Name of the file to use as a pre-written HTML 166 | # directory index. Please MAKE AND USE THESE FILES. On the 167 | # fly creation of directory indexes can be _slow_. 168 | # Comment out to always use DirectoryMaker 169 | 170 | DirectoryIndex index.html 171 | 172 | # DirectoryMaker: Name of program used to create a directory listing. 173 | # Comment out to disable directory listings. If both this and 174 | # DirectoryIndex are commented out, accessing a directory will give 175 | # an error (though accessing files in the directory are still ok). 176 | 177 | DirectoryMaker /usr/lib/boa/boa_indexer 178 | 179 | # DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker 180 | # has been commented out, the the on-the-fly indexing of Boa can be used 181 | # to generate indexes of directories. Be warned that the output is 182 | # extremely minimal and can cause delays when slow disks are used. 183 | # Note: The DirectoryCache must be writable by the same user/group that 184 | # Boa runs as. 185 | 186 | # DirectoryCache /var/spool/boa/dircache 187 | 188 | # KeepAliveMax: Number of KeepAlive requests to allow per connection 189 | # Comment out, or set to 0 to disable keepalive processing 190 | 191 | KeepAliveMax 1000 192 | 193 | # KeepAliveTimeout: seconds to wait before keepalive connection times out 194 | 195 | KeepAliveTimeout 10 196 | 197 | # MimeTypes: This is the file that is used to generate mime type pairs 198 | # and Content-Type fields for boa. 199 | # Set to /dev/null if you do not want to load a mime types file. 200 | # Do *not* comment out (better use AddType!) 201 | 202 | MimeTypes /etc/mime.types 203 | 204 | # DefaultType: MIME type used if the file extension is unknown, or there 205 | # is no file extension. 206 | 207 | DefaultType text/plain 208 | 209 | # CGIPath: The value of the $PATH environment variable given to CGI progs. 210 | 211 | CGIPath /bin:/usr/bin:/usr/local/bin 212 | 213 | # SinglePostLimit: The maximum allowable number of bytes in 214 | # a single POST. Default is normally 1MB. 215 | 216 | # AddType: adds types without editing mime.types 217 | # Example: AddType type extension [extension ...] 218 | 219 | # Uncomment the next line if you want .cgi files to execute from anywhere 220 | #AddType application/x-httpd-cgi cgi 221 | 222 | # Redirect, Alias, and ScriptAlias all have the same semantics -- they 223 | # match the beginning of a request and take appropriate action. Use 224 | # Redirect for other servers, Alias for the same server, and ScriptAlias 225 | # to enable directories for script execution. 226 | 227 | # Redirect allows you to tell clients about documents which used to exist in 228 | # your server's namespace, but do not anymore. This allows you to tell the 229 | # clients where to look for the relocated document. 230 | # Example: Redirect /bar http://elsewhere/feh/bar 231 | 232 | # Aliases: Aliases one path to another. 233 | # Example: Alias /path1/bar /path2/foo 234 | 235 | Alias /doc /usr/share/doc 236 | 237 | # ScriptAlias: Maps a virtual path to a directory for serving scripts 238 | # Example: ScriptAlias /htbin/ /www/htbin/ 239 | 240 | ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ 241 | -------------------------------------------------------------------------------- /debian/clean: -------------------------------------------------------------------------------- 1 | docs/boa.info 2 | docs/boa.html 3 | docs/index.html 4 | config.log 5 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: boa 2 | Section: httpd 3 | Priority: optional 4 | Maintainer: Debian QA Group 5 | Standards-Version: 3.9.4 6 | Build-Depends: autotools-dev, 7 | bison, 8 | debhelper (>= 9~), 9 | flex, 10 | po-debconf, 11 | texinfo 12 | Homepage: http://www.boa.org/ 13 | Vcs-Git: git://anonscm.debian.org/collab-maint/boa.git 14 | Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/boa.git 15 | 16 | Package: boa 17 | Architecture: any 18 | Provides: httpd, 19 | httpd-cgi 20 | Depends: logrotate, 21 | mime-support, 22 | ${misc:Depends}, 23 | ${shlibs:Depends} 24 | Description: Lightweight and high performance web server 25 | Boa is a single-tasking HTTP server. That means that unlike 26 | traditional web servers, it does not fork for each incoming 27 | connection, nor does it fork many copies of itself to handle multiple 28 | connections. It internally multiplexes all of the ongoing HTTP 29 | connections, and forks only for CGI programs (which must be separate 30 | processes). Preliminary tests show boa is capable of handling several 31 | hundred hits per second on a 100 MHz Pentium. 32 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was initially debianized by Christoph Lameter 2 | clameter@debian.org on Mon, 23 Dec 1996 20:27:43 -0800. 3 | 4 | It has since been taken over by Jonathon Nelson 5 | 6 | It was originally downloaded from sunsite.unc.edu:/pub/Linux/Incoming 7 | 8 | Boa can now be found at http://www.boa.org/ 9 | 10 | Copyright 1991- Paul Phillips 11 | Copyright 2000- Larry Doolittle 12 | Copyright 2000- Jon Nelson . 13 | 14 | Boa is distributed under the terms of GNU General Public License, 15 | version 2 or higher, as found in /usr/share/common-licenses/GPL-2 16 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/sbin 2 | etc/boa 3 | var/www 4 | var/log/boa 5 | usr/lib/boa 6 | etc/logrotate.d 7 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README 2 | docs/boa.html 3 | docs/boa_banner.png 4 | docs/boa.texi 5 | -------------------------------------------------------------------------------- /debian/examples: -------------------------------------------------------------------------------- 1 | examples/cgi-test.cgi 2 | examples/nph-test.cgi 3 | examples/resolver.pl 4 | -------------------------------------------------------------------------------- /debian/info: -------------------------------------------------------------------------------- 1 | docs/boa.info 2 | -------------------------------------------------------------------------------- /debian/init: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # Written by Miquel van Smoorenburg . 4 | # Modified for Debian GNU/Linux 5 | # by Ian Murdock . 6 | # Modified for boa by Bill Allombert . 7 | 8 | ### BEGIN INIT INFO 9 | # Provides: boa 10 | # Description: Boa HTTPd 11 | # Required-Start: $local_fs $remote_fs $network 12 | # Required-Stop: $local_fs $remote_fs $network 13 | # Default-Start: 2 3 4 5 14 | # Default-Stop: 0 1 6 15 | # Short-Description: Boa: lightweight and high performance web server 16 | ### END INIT INFO 17 | 18 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 19 | DAEMON=/usr/sbin/boa 20 | NAME=boa 21 | DESC="HTTP server" 22 | 23 | test -x $DAEMON || exit 0 24 | 25 | set -e 26 | 27 | case "$1" in 28 | start) 29 | echo -n "Starting $DESC: $NAME" 30 | start-stop-daemon --start --quiet --exec $DAEMON 31 | echo "." 32 | ;; 33 | stop) 34 | echo -n "Stopping $DESC: $NAME" 35 | start-stop-daemon --stop --quiet --oknodo --exec $DAEMON 36 | echo "." 37 | ;; 38 | status) 39 | start-stop-daemon --status --exec $DAEMON 40 | exit $? 41 | ;; 42 | restart|force-reload) 43 | $0 stop 44 | $0 start 45 | ;; 46 | reload) 47 | echo -n "Reloading $DESC configuration... " 48 | start-stop-daemon --stop --signal HUP --quiet --oknodo --exec $DAEMON 49 | echo "done." 50 | ;; 51 | *) 52 | N=/etc/init.d/$NAME 53 | echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 54 | exit 1 55 | ;; 56 | esac 57 | 58 | exit 0 59 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | src/boa usr/sbin 2 | src/boa_indexer usr/lib/boa 3 | debian/boa.conf etc/boa 4 | -------------------------------------------------------------------------------- /debian/logrotate: -------------------------------------------------------------------------------- 1 | /var/log/boa/*_log { 2 | rotate 7 3 | daily 4 | compress 5 | copytruncate 6 | missingok 7 | notifempty 8 | } 9 | -------------------------------------------------------------------------------- /debian/manpages: -------------------------------------------------------------------------------- 1 | docs/boa.8 2 | -------------------------------------------------------------------------------- /debian/patches/series: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | PATH=/bin:/sbin:/usr/bin:/usr/sbin 3 | 4 | set -e 5 | 6 | if [ -e /etc/cron.daily/boa ]; then 7 | echo 'conffile /etc/cron.daily/boa exists. New functionality is in /etc/logrotate.d/boa.' 8 | if test `md5sum /etc/cron.daily/boa | awk '{print $1}'` = '5e05937798a45a32ed7bf03e596d1427'; then 9 | echo '/etc/cron.daily/boa not modified -- Removing /etc/cron.daily/boa' 10 | rm -f /etc/cron.daily/boa 11 | else 12 | echo '/etc/cron.daily/boa modified -- Moving to /etc/cron.daily/boa.obsolete' 13 | mv -f /etc/cron.daily/boa /etc/cron.daily/boa.obsolete 14 | fi 15 | fi 16 | 17 | #DEBHELPER# 18 | 19 | exit 0 -------------------------------------------------------------------------------- /debian/postrm: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # postrm script for #PACKAGE# 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | # summary of how this script can be called: 8 | # * `remove' 9 | # * `purge' 10 | # * `upgrade' 11 | # * `failed-upgrade' 12 | # * `abort-install' 13 | # * `abort-install' 14 | # * `abort-upgrade' 15 | # * `disappear' overwrit>r> 16 | # for details, see /usr/share/doc/packaging-manual/ 17 | 18 | case "$1" in 19 | purge) 20 | rm -rf /var/log/boa 21 | rm -rf /etc/boa 22 | ;; 23 | 24 | remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 25 | 26 | ;; 27 | 28 | *) 29 | echo "postrm called with unknown argument \`$1'" >&2 30 | exit 0 31 | 32 | esac 33 | 34 | # dh_installdeb will replace this with shell code automatically 35 | # generated by other debhelper scripts. 36 | 37 | #DEBHELPER# 38 | 39 | -------------------------------------------------------------------------------- /debian/preinst: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | if [ -x "/etc/init.d/boa" ]; then 6 | if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then 7 | invoke-rc.d boa stop || exit $? 8 | else 9 | /etc/init.d/boa stop || exit $? 10 | fi 11 | fi 12 | 13 | #DEBHELPER# 14 | -------------------------------------------------------------------------------- /debian/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | if [ -x "/etc/init.d/boa" ]; then 6 | if [ -x /usr/sbin/invoke-rc.d ] ; then 7 | invoke-rc.d boa stop 8 | else 9 | /etc/init.d/boa stop 10 | fi 11 | fi 12 | 13 | #DEBHELPER# 14 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | %: 4 | dh $@ --with autotools-dev 5 | 6 | override_dh_auto_configure: 7 | dh_auto_configure -- --enable-access-control 8 | 9 | override_dh_auto_build: 10 | dh_auto_build 11 | cd docs;make boa.html boa.info 12 | 13 | override_dh_installinit: 14 | dh_installinit --error-handler=true 15 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | 3 | http://www.boa.org/ boa-(.*).tar.gz 4 | -------------------------------------------------------------------------------- /docs/.cvsignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | *.xml 3 | *.html 4 | *.txt 5 | *.dvi 6 | *.info 7 | -------------------------------------------------------------------------------- /docs/Makefile.in: -------------------------------------------------------------------------------- 1 | # $Id: Makefile.in,v 1.1.2.3 2002/09/19 03:03:54 jnelson Exp $ 2 | 3 | srcdir = @srcdir@ 4 | VPATH = @srcdir@ 5 | 6 | all: boa.html boa.dvi boa.info boa.txt 7 | 8 | boa.info: boa.texi 9 | makeinfo --number-sections @ALLSOURCES@ 10 | 11 | boa.dvi: boa.texi 12 | texi2dvi --clean @ALLSOURCES@ 13 | 14 | boa.pdf: boa.texi 15 | texi2dvi --pdf --clean @ALLSOURCES@ 16 | 17 | boa.ps: boa.dvi 18 | dvips -o $@ @ALLSOURCES@ 19 | 20 | boa_toc.html: boa.texi 21 | texi2html -split_chapter -menu @ALLSOURCES@ 22 | 23 | boa.html: boa.texi 24 | makeinfo --html --number-sections --no-split -o - @ALLSOURCES@ | \ 25 | sed -e 's/Node:.*//' | sed -e 's/Next:.*//' | \ 26 | sed -e 's/Previous:.*//' | sed -e 's/Up:.*//' > $@ 27 | 28 | boa.txt: boa.texi 29 | makeinfo --no-headers --no-split -o $@ @ALLSOURCES@ 30 | 31 | 32 | clean: 33 | rm -f boa.{html,txt,dvi,ps,pdf,info} boa_*.html 34 | rm -f boa.{cp,fn,fns,ky,log,pg,toc,tp,vr,vrs,aux} *~ 35 | 36 | distclean: mrclean 37 | 38 | mrclean: clean 39 | rm -f Makefile 40 | -------------------------------------------------------------------------------- /docs/boa_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gpg/boa/7b13e12faf3ca5543b371987a89fe80cf31ff43c/docs/boa_banner.png -------------------------------------------------------------------------------- /examples/cgi-test.cgi: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl -wT 2 | 3 | # Remember that CGI programs have to close out the HTTP header 4 | # (with a pair of newlines), after giving the Content-type: 5 | # and any other relevant or available header information. 6 | 7 | # Unlike CGI programs running under Apache, CGI programs under Boa 8 | # should understand some simple HTTP options. The header (and the 9 | # double-newline) should not be printed if the incoming request was 10 | # in HTTP/0.9. Also, we should stop after the header if 11 | # REQUEST_METHOD == "HEAD". Under Apache, nph- programs also have 12 | # to worry about such stuff. 13 | 14 | # Feb 3, 2000 -- updated to support POST, and avoid passing 15 | # Malicious HTML Tags as described in CERT's CA-2000-02 advisory. 16 | # 17 | # 20 Aug 2002 -- Big internal changes, to support much more 18 | # than just a printout of the environment. Now the CGI can 19 | # do various, GET, isindex, and POST requests, and respond 20 | # to them as well. 21 | 22 | # 26 Sep 2002 -- Additional security paranoia by Landon Curt Noll 23 | # http://www.isthe.com/chongo/index.html 24 | 25 | # paranoia 26 | # 27 | delete $ENV{IFS}; 28 | delete $ENV{CDPATH}; 29 | delete $ENV{ENV}; 30 | delete $ENV{BASH_ENV}; 31 | #$ENV{PATH} = "/bin:/usr/bin"; 32 | $SIG{ALRM} = sub { die "\n

timeout on stdin

\n"; }; 33 | alarm(3); 34 | 35 | # initial setup 36 | # 37 | use strict; 38 | use POSIX qw(strftime getegid); 39 | 40 | # Print Content-type, if allowed 41 | # 42 | if (defined $ENV{"SERVER_PROTOCOL"} && 43 | $ENV{"SERVER_PROTOCOL"} !~ m{HTTP/0.9}i) { 44 | print "Content-type: text/html; charset=ISO-8859-1\r\n\r\n"; 45 | } 46 | 47 | # Nothing to do if just a HEAD request 48 | # 49 | if (defined $ENV{"REQUEST_METHOD"} && $ENV{"REQUEST_METHOD"} =~ /^HEAD$/i) { 50 | exit 0; 51 | } 52 | 53 | # Initial HTML lines 54 | # 55 | print "Boa CGI test\n"; 56 | print "

Boa CGI test

\n\n"; 57 | print "Date: ", strftime("%a %b %e %H:%M:%S %Y\n", localtime); 58 | print "

\n"; 59 | 60 | # Main form code 61 | # 62 | if (defined $ENV{"REQUEST_METHOD"}) { 63 | print "Method: $ENV{\"REQUEST_METHOD\"}\n"; 64 | } else { 65 | print "Method: <>\n"; 66 | } 67 | print "

\n"; 68 | 69 | print "\n"; 70 | print ""; 80 | print ""; 90 | print "\n"; 91 | print ""; 98 | print "
Basic GET Form:
"; 71 | print "
\n\ 72 | \ 73 | \ 77 | \ 78 |
"; 79 | print "
Basic POST Form:
"; 81 | print "
\n\ 82 | \ 83 | \ 87 | \ 88 |
"; 89 | print "
Sample ISINDEX form:
\n"; 92 | if (defined $ENV{"SCRIPT_NAME"}) { 93 | print "$ENV{\"SCRIPT_NAME\"}?param1+param2+param3\n"; 94 | } else { 95 | print "undefined SCRIPT_NAME\n"; 96 | } 97 | print "
\n"; 99 | 100 | if (defined $ENV{"QUERY_STRING"}) { 101 | print "

Query String: $ENV{\"QUERY_STRING\"}\n"; 102 | } else { 103 | print "

Query String: undefined QUERY_STRING\n"; 104 | } 105 | 106 | # Print the arguments 107 | # 108 | print "

\nArguments:\n

    \n"; 109 | if ($#ARGV >= 0) { 110 | while ($a=shift(@ARGV)) { 111 | $a=~s/&/&/g; 112 | $a=~s//>/g; 114 | print "
  1. $a\n"; 115 | } 116 | } 117 | print "
\n"; 118 | 119 | # Print environment list 120 | # 121 | print "

\nEnvironment:\n

    \n"; 122 | foreach my $i (keys %ENV) { 123 | $a=$ENV{$i}; 124 | $a=~s/&/&/g; 125 | $a=~s//>/g; 127 | $i=~s/&/&/g; 128 | $i=~s//>/g; 130 | print "
  • $i = $a\n"; 131 | } 132 | print "
\n"; 133 | 134 | # Print posted data, if any 135 | # 136 | my $line_cnt = 0; 137 | my $line; 138 | if (defined $ENV{REQUEST_METHOD} && 139 | $ENV{REQUEST_METHOD} =~ /POST/i) { 140 | print "Input stream:

\n"; 141 | while (defined($line = )) { 142 | if (++$line_cnt > 100) { 143 | print "

... ignoring the rest of the input data

"; 144 | last; 145 | } 146 | $line =~ s/&/&/g; 147 | $line =~ s//>/g; 149 | print "

" if $line_cnt == 1;
150 |         print "$line";
151 |     }
152 |     print "
" if $line_cnt > 0; 153 | print "
\n"; 154 | } else { 155 | print "No input stream: (not POST)

\n"; 156 | } 157 | 158 | # Print a little additional server information 159 | # 160 | print "uid: $> gid: ", getegid(), "\n

\n"; 161 | 162 | # Disabled use of this call due to DoS attack potential 163 | # 164 | #if (defined $ENV{"QUERY_STRING"} && defined $ENV{"REMOTE_PORT"} && 165 | # $ENV{"QUERY_STRING"} =~ /ident/i && $ENV{"REMOTE_PORT"} =~ /^\s*$/) { 166 | # 167 | ## Uses idlookup-1.2 from Peter Eriksson 168 | ## ftp://coast.cs.purdue.edu/pub/tools/unix/ident/tools/idlookup-1.2.tar.gz 169 | ## Could use modification to timeout and trap stderr messages 170 | # my $a="idlookup ". 171 | # $ENV{"REMOTE_ADDR"}." ".$ENV{"REMOTE_PORT"}." ".$ENV{"SERVER_PORT"}; 172 | # my $b=qx/$a/; 173 | # print "ident output:

\n$b
\n"; 174 | #} 175 | 176 | # End of HTML 177 | # 178 | print "\nBoa http server\n"; 179 | print "\n"; 180 | 181 | # All done! :-) 182 | # 183 | exit 0; 184 | 185 | -------------------------------------------------------------------------------- /examples/nph-test.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Remember that CGI programs have to close out the HTTP header 4 | # (with a pair of newlines), after giving the Content-type: 5 | # and any other relevant or available header information. 6 | 7 | # This test program always reports success (200 OK), and 8 | # correctly uses SERVER_PROTOCOL and REQUEST_METHOD to decide 9 | # whether or not to send the headers and content. 10 | 11 | # Feb 3, 2000 -- updated to support POST, and avoid passing 12 | # Malicious HTML Tags as described in CERT's CA-2000-02 advisory. 13 | 14 | $now=`date`; 15 | chomp($now); 16 | if ($ENV{"SERVER_PROTOCOL"} ne "HTTP/0.9") { 17 | print "HTTP/1.0 200 OK\r\nDate: $now\r\n"; 18 | print "Connection: close\r\n"; 19 | print "Content-type: text/html; charset=ISO-8859-1\r\n\r\n"; 20 | } 21 | 22 | exit 0 if ($ENV{"REQUEST_METHOD"} eq "HEAD"); 23 | 24 | print "Boa nph-CGI test\n"; 25 | print "

Boa nph-CGI test

\n\n"; 26 | 27 | print "Date: $now\n"; 28 | 29 | print "

\n\n

    \n"; 30 | 31 | foreach (keys %ENV) { 32 | $a= $ENV{$_}; 33 | $a=~s/&/&/g; 34 | $a=~s//>/g; 36 | print "
  • $_ == $a\n"; 37 | } 38 | 39 | print "
\n"; 40 | 41 | if ($ENV{REQUEST_METHOD} eq "POST") { 42 | print "Input stream:

\n";
43 |     while () {
44 | 	s/&/&/g;
45 | 	s//>/g;
47 |         print "$_";
48 |     }
49 |     print "

\n"; 50 | } 51 | 52 | print "id: ", `id`, "\n

\n"; 53 | 54 | if ($ENV{"QUERY_STRING"}=~/ident/ && $ENV{"REMOTE_PORT"} ne "") { 55 | 56 | # Uses idlookup-1.2 from Peter Eriksson 57 | # ftp://coast.cs.purdue.edu/pub/tools/unix/ident/tools/idlookup-1.2.tar.gz 58 | # Could use modification to timeout and trap stderr messages 59 | $a="idlookup ". 60 | $ENV{"REMOTE_ADDR"}." ".$ENV{"REMOTE_PORT"}." ".$ENV{"SERVER_PORT"}; 61 | $b=qx/$a/; 62 | print "ident output:

\n$b
\n"; 63 | } 64 | 65 | print "\nBoa http server\n"; 66 | print "\n"; 67 | 68 | exit 0; 69 | 70 | -------------------------------------------------------------------------------- /examples/resolver.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # IP address resolver for Boa 4 | 5 | # If you want an "in place" change to the log file, 6 | # change the first line to 7 | #!/usr/local/bin/perl -i.bak 8 | # Otherwise, send the output of this program wherever you want: 9 | # resolver.pl access_log >access_log_resolved 10 | 11 | $AF_INET = 2; 12 | 13 | while(<>) { 14 | next unless (($ip, $rest) = /([\d\.]+) (.*)/o); 15 | 16 | if(!$hosts{$ip}) { 17 | $packed_ip = pack('C4', split(/\./, $ip)); 18 | $host = (gethostbyaddr($packed_ip, $AF_INET))[0]; 19 | $hosts{$ip} = ($host ? $host : $ip); 20 | } 21 | 22 | print "$hosts{$ip} $rest\n"; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /extra_macros.m4: -------------------------------------------------------------------------------- 1 | dnl Many of the following macros courtesy of: 2 | dnl http://www.gnu.org/software/ac-archive/ 3 | dnl 4 | dnl The Following macros courtesy of: 5 | dnl Installed_Packages/check_gnu_make.html 6 | dnl 7 | dnl Copyrights are by the individual authors, as listed. 8 | dnl License: GPL 9 | dnl 10 | 11 | 12 | dnl CHECK_GNU_MAKE() 13 | dnl 14 | dnl This macro searches for a GNU version of make. If a match is found, the 15 | dnl makefile variable `ifGNUmake' is set to the empty string, otherwise it is 16 | dnl set to "#". This is useful for including a special features in a Makefile, 17 | dnl which cannot be handled by other versions of make. The variable 18 | dnl _cv_gnu_make_command is set to the command to invoke GNU make if it exists, 19 | dnl the empty string otherwise. 20 | dnl 21 | dnl Here is an example of its use: 22 | dnl 23 | dnl Makefile.in might contain: 24 | dnl 25 | dnl # A failsafe way of putting a dependency rule into a makefile 26 | dnl $(DEPEND): 27 | dnl $(CC) -MM $(srcdir)/*.c > $(DEPEND) 28 | dnl 29 | dnl @ifGNUmake@ ifeq ($(DEPEND),$(wildcard $(DEPEND))) 30 | dnl @ifGNUmake@ include $(DEPEND) 31 | dnl @ifGNUmake@ endif 32 | dnl 33 | dnl Then configure.in would normally contain: 34 | dnl 35 | dnl CHECK_GNU_MAKE() 36 | dnl AC_OUTPUT(Makefile) 37 | dnl 38 | dnl Then perhaps to cause gnu make to override any other make, we could do 39 | dnl something like this (note that GNU make always looks for GNUmakefile first): 40 | dnl 41 | dnl if ! test x$_cv_gnu_make_command = x ; then 42 | dnl mv Makefile GNUmakefile 43 | dnl echo .DEFAULT: > Makefile ; 44 | dnl echo \ $_cv_gnu_make_command \$@ >> Makefile; 45 | dnl fi 46 | dnl 47 | dnl Then, if any (well almost any) other make is called, and GNU make also exists, 48 | dnl then the other make wraps the GNU make. 49 | dnl 50 | dnl John Darrington 51 | dnl 1.3 (2002/01/04) 52 | dnl 53 | dnl Modified 18 Sep 2002 by Jon Nelson 54 | 55 | AC_DEFUN([CHECK_GNU_MAKE], 56 | [ AC_CACHE_CHECK( for GNU make, _cv_gnu_make_command, 57 | [_cv_gnu_make_command='' 58 | dnl Search all the common names for GNU make 59 | for a in "$MAKE" make gmake gnumake ; do 60 | if test -z "$a" ; then continue ; fi 61 | if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ); then 62 | _cv_gnu_make_command=$a 63 | break; 64 | fi 65 | done 66 | if test "x$_cv_gnu_make_command" = "x"; then 67 | _cv_gnu_make_command="Not found" 68 | fi 69 | ]) 70 | dnl If there was a GNU version, then set @ifGNUmake@ to the empty string, '#' otherwise 71 | if test "$_cv_gnu_make_command" != "Not found"; then 72 | ifGNUmake=''; 73 | else 74 | ifGNUmake='#'; 75 | _cv_gnu_make_command=''; 76 | fi 77 | AC_SUBST(ifGNUmake) 78 | ]) 79 | 80 | dnl AC_CHECK_STRUCT_FOR(INCLUDES,STRUCT,MEMBER,DEFINE,[no]) 81 | dnl 1.1 (2000/09/19) 82 | dnl Wes Hardaker 83 | 84 | dnl ---------------------------------------------------------- 85 | 86 | AC_DEFUN([AC_CHECK_STRUCT_FOR],[ 87 | ac_safe_struct=`echo "$2" | sed 'y%./+-%__p_%'` 88 | ac_safe_member=`echo "$3" | sed 'y%./+-%__p_%'` 89 | ac_safe_all="ac_cv_struct_${ac_safe_struct}_has_${ac_safe_member}" 90 | changequote(, )dnl 91 | ac_uc_define=STRUCT_`echo "${ac_safe_struct}_HAS_${ac_safe_member}" | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` 92 | changequote([, ])dnl 93 | 94 | AC_MSG_CHECKING([for $2.$3]) 95 | AC_CACHE_VAL($ac_safe_all, 96 | [ 97 | if test "x$4" = "x"; then 98 | defineit="= 0" 99 | elif test "x$4" = "xno"; then 100 | defineit="" 101 | else 102 | defineit="$4" 103 | fi 104 | AC_TRY_COMPILE([ 105 | $1 106 | ],[ 107 | struct $2 testit; 108 | testit.$3 $defineit; 109 | ], eval "${ac_safe_all}=yes", eval "${ac_safe_all}=no" ) 110 | ]) 111 | 112 | if eval "test \"x$`echo ${ac_safe_all}`\" = \"xyes\""; then 113 | AC_MSG_RESULT(yes) 114 | AC_DEFINE_UNQUOTED($ac_uc_define) 115 | else 116 | AC_MSG_RESULT(no) 117 | fi 118 | ]) 119 | 120 | dnl @synopsis AC_C_VAR_FUNC 121 | dnl 122 | dnl This macro tests if the C complier supports the C9X standard 123 | dnl __func__ indentifier. 124 | dnl 125 | dnl The new C9X standard for the C language stipulates that the 126 | dnl identifier __func__ shall be implictly declared by the compiler 127 | dnl as if, immediately following the opening brace of each function 128 | dnl definition, the declaration 129 | dnl 130 | dnl static const char __func__[] = "function-name"; 131 | dnl 132 | dnl appeared, where function-name is the name of the function where 133 | dnl the __func__ identifier is used. 134 | dnl 135 | dnl @author Christopher Currie 136 | 137 | AC_DEFUN([AC_C_VAR_FUNC], 138 | [AC_REQUIRE([AC_PROG_CC]) 139 | AC_CACHE_CHECK(whether $CC recognizes __func__, ac_cv_c_var_func, 140 | AC_TRY_COMPILE(, 141 | [int main() { 142 | char *s = __func__; 143 | }], 144 | AC_DEFINE(HAVE_FUNC,, 145 | [Define if the C complier supports __func__]) ac_cv_c_var_func=yes, 146 | ac_cv_c_var_func=no) ) 147 | ])dnl 148 | 149 | dnl Exports one of ac_cv_func_poll or ac_cv_func_select 150 | dnl Author - Jon Nelson 151 | dnl Copyright 2002 152 | AC_DEFUN([POLL_OR_SELECT], 153 | [ 154 | AC_MSG_CHECKING(whether to use poll or select) 155 | AC_ARG_WITH(poll, 156 | [ --with-poll Use poll], 157 | [ 158 | if test "$withval" = "yes" ; then 159 | AC_MSG_RESULT(trying poll) 160 | ac_x=1 161 | else 162 | AC_MSG_RESULT(trying select) 163 | ac_x=0 164 | fi 165 | ], 166 | [ 167 | AC_MSG_RESULT(trying select) 168 | ac_x=0 169 | ]) 170 | 171 | if test $ac_x = 1; then 172 | AC_CHECK_HEADERS(sys/poll.h) 173 | AC_CHECK_FUNCS(poll) 174 | if test "x$ac_cv_func_poll" = "x"; then 175 | AC_MSG_ERROR(We attempted to find poll but could not. Please try again with --without-poll) 176 | fi 177 | BOA_ASYNC_IO="poll" 178 | else 179 | AC_CHECK_HEADERS(sys/select.h) 180 | AC_CHECK_FUNCS(select) 181 | if test "x$ac_cv_func_select" = "x"; then 182 | AC_MSG_ERROR(We attempted to find select but could not. Please try again with --with-poll) 183 | fi 184 | BOA_ASYNC_IO="select" 185 | fi 186 | ] 187 | ) 188 | 189 | -------------------------------------------------------------------------------- /extras/alphasort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "compat.h" 3 | 4 | int alphasort(const struct dirent **a, const struct dirent **b) 5 | { 6 | return (strcmp((*a)->d_name, (*b)->d_name)); 7 | } 8 | -------------------------------------------------------------------------------- /extras/scandir.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; c-file-style: "gnu" -*- */ 2 | /* 3 | Copyright (c) 2000 Petter Reinholdtsen 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, copy, 9 | modify, merge, publish, distribute, sublicense, and/or sell copies 10 | of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | */ 25 | 26 | /* 27 | * scandir.c -- if scandir() is missing, make a replacement 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "compat.h" 36 | 37 | /* 38 | * XXX This is a simple hack version which doesn't sort the data, and 39 | * just passes all unsorted. 40 | */ 41 | 42 | int 43 | scandir(const char *dir, struct dirent ***namelist, 44 | int (*select) (const struct dirent *), 45 | int (*compar) (const struct dirent **, const struct dirent **)) 46 | { 47 | DIR *d = opendir(dir); 48 | struct dirent *current; 49 | struct dirent **names; 50 | int count = 0; 51 | int pos = 0; 52 | int result = -1; 53 | 54 | if (NULL == d) 55 | return -1; 56 | 57 | while (NULL != readdir(d)) 58 | count++; 59 | 60 | names = malloc(sizeof (struct dirent *) * count); 61 | 62 | closedir(d); 63 | d = opendir(dir); 64 | if (NULL == d) 65 | return -1; 66 | 67 | while (NULL != (current = readdir(d))) { 68 | if (NULL == select || select(current)) { 69 | struct dirent *copyentry = malloc(current->d_reclen); 70 | 71 | memcpy(copyentry, current, current->d_reclen); 72 | 73 | names[pos] = copyentry; 74 | pos++; 75 | } 76 | } 77 | result = closedir(d); 78 | 79 | if (pos != count) 80 | names = realloc(names, sizeof (struct dirent *) * pos); 81 | 82 | *namelist = names; 83 | 84 | return pos; 85 | } 86 | -------------------------------------------------------------------------------- /extras/strutil.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Name: strstr and strdup 3 | * 4 | * These are the standard library utilities. We define them here for 5 | * systems that don't have them. 6 | */ 7 | 8 | #ifndef HAVE_STRSTR 9 | char *strstr(char *s1, char *s2) 10 | { /* from libiberty */ 11 | char *p; 12 | int len = strlen(s2); 13 | 14 | if (*s2 == '\0') /* everything matches empty string */ 15 | return s1; 16 | for (p = s1; (p = strchr(p, *s2)) != NULL; p = strchr(p + 1, *s2)) { 17 | if (strncmp(p, s2, len) == 0) 18 | return (p); 19 | } 20 | return NULL; 21 | } 22 | #endif 23 | 24 | #ifndef HAVE_STRDUP 25 | char *strdup(char *s) 26 | { 27 | char *retval; 28 | 29 | retval = (char *) malloc(strlen(s) + 1); 30 | if (retval == NULL) { 31 | perror("boa: out of memory in strdup"); 32 | exit(1); 33 | } 34 | return strcpy(retval, s); 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # 5 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 6 | # later released in X11R6 (xc/config/util/install.sh) with the 7 | # following copyright and license. 8 | # 9 | # Copyright (C) 1994 X Consortium 10 | # 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documentation files (the "Software"), to 13 | # deal in the Software without restriction, including without limitation the 14 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 15 | # sell copies of the Software, and to permit persons to whom the Software is 16 | # furnished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 25 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 26 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | # 28 | # Except as contained in this notice, the name of the X Consortium shall not 29 | # be used in advertising or otherwise to promote the sale, use or other deal- 30 | # ings in this Software without prior written authorization from the X Consor- 31 | # tium. 32 | # 33 | # 34 | # FSF changes to this file are in the public domain. 35 | # 36 | # Calling this script install-sh is preferred over install.sh, to prevent 37 | # `make' implicit rules from creating a file called install from it 38 | # when there is no Makefile. 39 | # 40 | # This script is compatible with the BSD install script, but was written 41 | # from scratch. It can only install one file at a time, a restriction 42 | # shared with many OS's install programs. 43 | 44 | 45 | # set DOITPROG to echo to test this script 46 | 47 | # Don't use :- since 4.3BSD and earlier shells don't like it. 48 | doit="${DOITPROG-}" 49 | 50 | 51 | # put in absolute paths if you don't have them in your path; or use env. vars. 52 | 53 | mvprog="${MVPROG-mv}" 54 | cpprog="${CPPROG-cp}" 55 | chmodprog="${CHMODPROG-chmod}" 56 | chownprog="${CHOWNPROG-chown}" 57 | chgrpprog="${CHGRPPROG-chgrp}" 58 | stripprog="${STRIPPROG-strip}" 59 | rmprog="${RMPROG-rm}" 60 | mkdirprog="${MKDIRPROG-mkdir}" 61 | 62 | transformbasename="" 63 | transform_arg="" 64 | instcmd="$mvprog" 65 | chmodcmd="$chmodprog 0755" 66 | chowncmd="" 67 | chgrpcmd="" 68 | stripcmd="" 69 | rmcmd="$rmprog -f" 70 | mvcmd="$mvprog" 71 | src="" 72 | dst="" 73 | dir_arg="" 74 | 75 | while [ x"$1" != x ]; do 76 | case $1 in 77 | -c) instcmd=$cpprog 78 | shift 79 | continue;; 80 | 81 | -d) dir_arg=true 82 | shift 83 | continue;; 84 | 85 | -m) chmodcmd="$chmodprog $2" 86 | shift 87 | shift 88 | continue;; 89 | 90 | -o) chowncmd="$chownprog $2" 91 | shift 92 | shift 93 | continue;; 94 | 95 | -g) chgrpcmd="$chgrpprog $2" 96 | shift 97 | shift 98 | continue;; 99 | 100 | -s) stripcmd=$stripprog 101 | shift 102 | continue;; 103 | 104 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 105 | shift 106 | continue;; 107 | 108 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 109 | shift 110 | continue;; 111 | 112 | *) if [ x"$src" = x ] 113 | then 114 | src=$1 115 | else 116 | # this colon is to work around a 386BSD /bin/sh bug 117 | : 118 | dst=$1 119 | fi 120 | shift 121 | continue;; 122 | esac 123 | done 124 | 125 | if [ x"$src" = x ] 126 | then 127 | echo "$0: no input file specified" >&2 128 | exit 1 129 | else 130 | : 131 | fi 132 | 133 | if [ x"$dir_arg" != x ]; then 134 | dst=$src 135 | src="" 136 | 137 | if [ -d "$dst" ]; then 138 | instcmd=: 139 | chmodcmd="" 140 | else 141 | instcmd=$mkdirprog 142 | fi 143 | else 144 | 145 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 146 | # might cause directories to be created, which would be especially bad 147 | # if $src (and thus $dsttmp) contains '*'. 148 | 149 | if [ -f "$src" ] || [ -d "$src" ] 150 | then 151 | : 152 | else 153 | echo "$0: $src does not exist" >&2 154 | exit 1 155 | fi 156 | 157 | if [ x"$dst" = x ] 158 | then 159 | echo "$0: no destination specified" >&2 160 | exit 1 161 | else 162 | : 163 | fi 164 | 165 | # If destination is a directory, append the input filename; if your system 166 | # does not like double slashes in filenames, you may need to add some logic 167 | 168 | if [ -d "$dst" ] 169 | then 170 | dst=$dst/`basename "$src"` 171 | else 172 | : 173 | fi 174 | fi 175 | 176 | ## this sed command emulates the dirname command 177 | dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 178 | 179 | # Make sure that the destination directory exists. 180 | # this part is taken from Noah Friedman's mkinstalldirs script 181 | 182 | # Skip lots of stat calls in the usual case. 183 | if [ ! -d "$dstdir" ]; then 184 | defaultIFS=' 185 | ' 186 | IFS="${IFS-$defaultIFS}" 187 | 188 | oIFS=$IFS 189 | # Some sh's can't handle IFS=/ for some reason. 190 | IFS='%' 191 | set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` 192 | IFS=$oIFS 193 | 194 | pathcomp='' 195 | 196 | while [ $# -ne 0 ] ; do 197 | pathcomp=$pathcomp$1 198 | shift 199 | 200 | if [ ! -d "$pathcomp" ] ; 201 | then 202 | $mkdirprog "$pathcomp" 203 | else 204 | : 205 | fi 206 | 207 | pathcomp=$pathcomp/ 208 | done 209 | fi 210 | 211 | if [ x"$dir_arg" != x ] 212 | then 213 | $doit $instcmd "$dst" && 214 | 215 | if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && 216 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && 217 | if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && 218 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi 219 | else 220 | 221 | # If we're going to rename the final executable, determine the name now. 222 | 223 | if [ x"$transformarg" = x ] 224 | then 225 | dstfile=`basename "$dst"` 226 | else 227 | dstfile=`basename "$dst" $transformbasename | 228 | sed $transformarg`$transformbasename 229 | fi 230 | 231 | # don't allow the sed command to completely eliminate the filename 232 | 233 | if [ x"$dstfile" = x ] 234 | then 235 | dstfile=`basename "$dst"` 236 | else 237 | : 238 | fi 239 | 240 | # Make a couple of temp file names in the proper directory. 241 | 242 | dsttmp=$dstdir/_inst.$$_ 243 | rmtmp=$dstdir/_rm.$$_ 244 | 245 | # Trap to clean up temp files at exit. 246 | 247 | trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 248 | trap '(exit $?); exit' 1 2 13 15 249 | 250 | # Move or copy the file name to the temp name 251 | 252 | $doit $instcmd "$src" "$dsttmp" && 253 | 254 | # and set any options; do chmod last to preserve setuid bits 255 | 256 | # If any of these fail, we abort the whole thing. If we want to 257 | # ignore errors from any of these, just make sure not to ignore 258 | # errors from the above "$doit $instcmd $src $dsttmp" command. 259 | 260 | if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && 261 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && 262 | if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && 263 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && 264 | 265 | # Now remove or move aside any old file at destination location. We try this 266 | # two ways since rm can't unlink itself on some systems and the destination 267 | # file might be busy for other reasons. In this case, the final cleanup 268 | # might fail but the new file should still install successfully. 269 | 270 | { 271 | if [ -f "$dstdir/$dstfile" ] 272 | then 273 | $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || 274 | $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || 275 | { 276 | echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 277 | (exit 1); exit 278 | } 279 | else 280 | : 281 | fi 282 | } && 283 | 284 | # Now rename the file to the real destination. 285 | 286 | $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" 287 | 288 | fi && 289 | 290 | # The final little trick to "correctly" pass the exit status to the exit trap. 291 | 292 | { 293 | (exit 0); exit 294 | } 295 | -------------------------------------------------------------------------------- /src/.depend: -------------------------------------------------------------------------------- 1 | alias.o: alias.c boa.h compat.h config.h defines.h globals.h escape.h 2 | boa.o: boa.c boa.h compat.h config.h defines.h globals.h escape.h 3 | buffer.o: buffer.c boa.h compat.h config.h defines.h globals.h escape.h 4 | cgi.o: cgi.c boa.h compat.h config.h defines.h globals.h escape.h 5 | cgi_header.o: cgi_header.c boa.h compat.h config.h defines.h globals.h \ 6 | escape.h 7 | config.o: config.c boa.h compat.h config.h defines.h globals.h escape.h \ 8 | access.h 9 | escape.o: escape.c boa.h compat.h config.h defines.h globals.h escape.h 10 | get.o: get.c boa.h compat.h config.h defines.h globals.h escape.h \ 11 | access.h 12 | hash.o: hash.c boa.h compat.h config.h defines.h globals.h escape.h 13 | ip.o: ip.c boa.h compat.h config.h defines.h globals.h escape.h 14 | log.o: log.c boa.h compat.h config.h defines.h globals.h escape.h 15 | mmap_cache.o: mmap_cache.c boa.h compat.h config.h defines.h globals.h \ 16 | escape.h 17 | pipe.o: pipe.c boa.h compat.h config.h defines.h globals.h escape.h 18 | queue.o: queue.c boa.h compat.h config.h defines.h globals.h escape.h 19 | range.o: range.c boa.h compat.h config.h defines.h globals.h escape.h 20 | read.o: read.c boa.h compat.h config.h defines.h globals.h escape.h 21 | request.o: request.c boa.h compat.h config.h defines.h globals.h escape.h 22 | response.o: response.c boa.h compat.h config.h defines.h globals.h \ 23 | escape.h 24 | signals.o: signals.c boa.h compat.h config.h defines.h globals.h escape.h 25 | util.o: util.c boa.h compat.h config.h defines.h globals.h escape.h 26 | sublog.o: sublog.c compat.h config.h 27 | select.o: select.c boa.h compat.h config.h defines.h globals.h escape.h 28 | select.o: select.c boa.h compat.h config.h defines.h globals.h escape.h 29 | poll.o: poll.c boa.h compat.h config.h defines.h globals.h escape.h 30 | access.o: access.c boa.h compat.h config.h defines.h globals.h escape.h \ 31 | access.h 32 | -------------------------------------------------------------------------------- /src/Makefile.in: -------------------------------------------------------------------------------- 1 | # $Id: Makefile.in,v 1.59.2.15 2005/02/22 03:02:40 jnelson Exp $ 2 | 3 | .SUFFIXES: 4 | .SUFFIXES: .o .c 5 | .PHONY: clean mrclean distclean all dist@ifGNUmake@ depend 6 | 7 | # The following gcc warning switches are too noisy to be useful checking 8 | # Boa for lint: 9 | # -Wtraditional -Wconversion -Wredundant-decls -Wunreachable-code 10 | # The following gcc warning switches should generate no warnings: 11 | GCC_FLAGS = -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wcast-qual \ 12 | -Wshadow -Waggregate-return -Wmissing-prototypes -Wnested-externs \ 13 | -Wall -W -Wno-unused -Winline -Wwrite-strings -Wundef -pedantic 14 | 15 | srcdir = @srcdir@ 16 | VPATH = @srcdir@:@srcdir@/../extras 17 | LDFLAGS = @LDFLAGS@ 18 | LIBS = @LIBS@ 19 | CFLAGS = @CFLAGS@ 20 | CPPFLAGS = @CPPFLAGS@ -I@srcdir@ -I. 21 | @ifGNUmake@DEPEND = .depend 22 | 23 | CC = @CC@ 24 | CPP = @CPP@ 25 | 26 | SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \ 27 | get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c range.c \ 28 | read.c request.c response.c signals.c util.c sublog.c \ 29 | @ASYNCIO_SOURCE@ @ACCESSCONTROL_SOURCE@ 30 | 31 | OBJS = $(SOURCES:.c=.o) timestamp.o @STRUTIL@ 32 | 33 | all: boa boa_indexer 34 | 35 | boa: $(OBJS) 36 | $(CC) -o $@ @ALLSOURCES@ $(LDFLAGS) $(LIBS) 37 | 38 | boa_indexer: index_dir.o escape.o @SCANDIR@ @ALPHASORT@ @STRUTIL@ 39 | $(CC) -o $@ @ALLSOURCES@ $(LDFLAGS) $(LIBS) 40 | 41 | clean: 42 | rm -f $(OBJS) boa core *~ boa_indexer index_dir.o 43 | rm -f @SCANDIR@ @ALPHASORT@ @STRUTIL@ poll.o select.o access.o 44 | 45 | distclean: mrclean 46 | 47 | mrclean: clean 48 | rm -f config.status config.cache config.h Makefile config.log 49 | 50 | # timestamp 51 | 52 | timestamp.o: $(SOURCES) 53 | 54 | # depend stuff 55 | @ifGNUmake@depend: $(SOURCES) 56 | @ifGNUmake@ $(CPP) $(CPPFLAGS) -MM @ALLSOURCES@ select.c poll.c access.c > $(DEPEND) 57 | 58 | @ifGNUmake@-include $(DEPEND) 59 | 60 | 61 | # tags 62 | tags: $(SOURCES) 63 | ctags -o tags @ALLSOURCES@ *.h 64 | 65 | # object dump 66 | boa.objdump: boa 67 | objdump --disassemble-all --source boa > $@ 68 | 69 | -------------------------------------------------------------------------------- /src/access.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * This file Copyright (C) 2002 Peter Korsgaard 4 | * Some changes Copyright (C) 2003-2004 Jon Nelson 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 1, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | /* $Id: access.c,v 1.1.2.6 2005/02/22 14:11:29 jnelson Exp $ */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "boa.h" 27 | #include "access.h" 28 | 29 | struct access_node { 30 | char *pattern; 31 | enum access_type type; 32 | }; 33 | 34 | static int n_access; 35 | 36 | static struct access_node *nodes = NULL; 37 | 38 | static void access_shutdown(void); 39 | 40 | static void access_shutdown(void) 41 | { 42 | int i; 43 | 44 | if (nodes) { 45 | for (i = 0; i < n_access; i++) { 46 | if (nodes[i].pattern) { 47 | free(nodes[i].pattern); 48 | } else { 49 | WARN("Not freeing NULL access pattern!"); 50 | } 51 | } 52 | free(nodes); 53 | } 54 | 55 | nodes = NULL; 56 | n_access = 0; 57 | } 58 | 59 | void access_init(void) 60 | { 61 | if (n_access || nodes) { 62 | access_shutdown(); 63 | } 64 | } 65 | 66 | void access_add(const char *pattern, enum access_type type) 67 | { 68 | nodes = realloc(nodes, (n_access + 1) * sizeof (struct access_node)); 69 | if (!nodes) { 70 | DIE("realloc of nodes failed!"); 71 | } 72 | 73 | nodes[n_access].type = type; 74 | nodes[n_access].pattern = strdup(pattern); 75 | if (!nodes[n_access].pattern) { 76 | DIE("strdup of pattern failed!"); 77 | } 78 | ++n_access; 79 | } /* access_add */ 80 | 81 | 82 | enum access_type access_allow(const char *file) 83 | { 84 | int i; 85 | 86 | /* find first match in allow / deny rules */ 87 | for (i = 0; i < n_access; i++) { 88 | if (fnmatch(nodes[i].pattern, file, 0) == 0) { 89 | return nodes[i].type; 90 | } 91 | } 92 | 93 | /* default to allow */ 94 | return ACCESS_ALLOW; 95 | } /* access_allow */ 96 | -------------------------------------------------------------------------------- /src/access.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * This file Copyright (C) 2002 Peter Korsgaard 4 | * Some changes (C) 2004 Jon Nelson 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 1, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | 22 | /* $Id: access.h,v 1.1.2.4 2005/02/22 14:11:29 jnelson Exp $ */ 23 | 24 | #ifndef _ACCESS_H 25 | #define _ACCESS_H 26 | 27 | enum access_type { ACCESS_DENY, ACCESS_ALLOW }; 28 | 29 | void access_init(void); 30 | void access_add(const char *pattern, enum access_type); 31 | enum access_type access_allow(const char *file); 32 | 33 | #endif /* _ACCESS_H */ 34 | -------------------------------------------------------------------------------- /src/boa.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Some changes Copyright (C) 1996 Charles F. Randall 5 | * Copyright (C) 1996-1999 Larry Doolittle 6 | * Copyright (C) 1996-2005 Jon Nelson 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 1, or (at your option) 11 | * any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /* $Id: boa.c,v 1.99.2.26 2005/02/22 14:11:29 jnelson Exp $*/ 25 | 26 | #include "boa.h" 27 | 28 | /* globals */ 29 | int backlog = SO_MAXCONN; 30 | time_t start_time; 31 | 32 | int debug_level = 0; 33 | int sighup_flag = 0; /* 1 => signal has happened, needs attention */ 34 | int sigchld_flag = 0; /* 1 => signal has happened, needs attention */ 35 | int sigalrm_flag = 0; /* 1 => signal has happened, needs attention */ 36 | int sigterm_flag = 0; /* lame duck mode */ 37 | time_t current_time; 38 | int pending_requests = 0; 39 | int override_server_port; 40 | const char *override_server_ip; 41 | 42 | extern const char *config_file_name; 43 | 44 | /* static to boa.c */ 45 | static void usage(const char *programname); 46 | static void parse_commandline(int argc, char *argv[]); 47 | static void fixup_server_root(void); 48 | static int create_server_socket(void); 49 | static void drop_privs(void); 50 | 51 | static int sock_opt = 1; 52 | static int do_fork = 1; 53 | 54 | int main(int argc, char *argv[]) 55 | { 56 | int server_s; /* boa socket */ 57 | pid_t pid; 58 | 59 | /* set umask to u+rw, u-x, go-rwx */ 60 | /* according to the man page, umask always succeeds */ 61 | umask(077); 62 | 63 | /* but first, update timestamp, because log_error_time uses it */ 64 | (void) time(¤t_time); 65 | 66 | /* set timezone right away */ 67 | tzset(); 68 | 69 | { 70 | int devnullfd = -1; 71 | devnullfd = open("/dev/null", 0); 72 | 73 | /* make STDIN point to /dev/null */ 74 | if (devnullfd == -1) { 75 | DIE("can't open /dev/null"); 76 | } 77 | 78 | if (dup2(devnullfd, STDIN_FILENO) == -1) { 79 | DIE("can't dup2 /dev/null to STDIN_FILENO"); 80 | } 81 | 82 | (void) close(devnullfd); 83 | } 84 | 85 | parse_commandline(argc, argv); 86 | fixup_server_root(); 87 | read_config_files(); 88 | create_common_env(); 89 | open_logs(); 90 | server_s = create_server_socket(); 91 | init_signals(); 92 | build_needs_escape(); 93 | 94 | /* background ourself */ 95 | if (do_fork) { 96 | pid = fork(); 97 | } else { 98 | pid = getpid(); 99 | } 100 | 101 | switch (pid) { 102 | case -1: 103 | /* error */ 104 | perror("fork/getpid"); 105 | exit(EXIT_FAILURE); 106 | case 0: 107 | /* child, success */ 108 | break; 109 | default: 110 | /* parent, success */ 111 | if (pid_file != NULL) { 112 | FILE *PID_FILE = fopen(pid_file, "w"); 113 | if (PID_FILE != NULL) { 114 | fprintf(PID_FILE, "%d", pid); 115 | fclose(PID_FILE); 116 | } else { 117 | perror("fopen pid file"); 118 | } 119 | } 120 | 121 | if (do_fork) 122 | exit(EXIT_SUCCESS); 123 | break; 124 | } 125 | 126 | drop_privs(); 127 | /* main loop */ 128 | timestamp(); 129 | 130 | status.requests = 0; 131 | status.errors = 0; 132 | 133 | start_time = current_time; 134 | loop(server_s); 135 | return 0; 136 | } 137 | 138 | static void usage(const char *programname) 139 | { 140 | fprintf(stderr, 141 | "Usage: %s [-c serverroot] [-d] [-f configfile] [-r chroot]%s\n", 142 | programname, 143 | #ifndef DISABLE_DEBUG 144 | " [-l debug_level]" 145 | #else 146 | "" 147 | #endif 148 | ); 149 | #ifndef DISABLE_DEBUG 150 | print_debug_usage(); 151 | #endif 152 | exit(EXIT_FAILURE); 153 | 154 | } 155 | 156 | static void parse_commandline(int argc, char *argv[]) 157 | { 158 | int c; /* command line arg */ 159 | 160 | while ((c = getopt(argc, argv, "c:dl:f:r:p:L:")) != -1) { 161 | switch (c) { 162 | case 'c': 163 | if (server_root) 164 | free(server_root); 165 | server_root = strdup(optarg); 166 | if (!server_root) { 167 | perror("strdup in command line option parsing"); 168 | exit(EXIT_FAILURE); 169 | } 170 | break; 171 | case 'd': 172 | do_fork = 0; 173 | break; 174 | case 'f': 175 | config_file_name = optarg; 176 | break; 177 | case 'r': 178 | if (chdir(optarg) == -1) { 179 | log_error_time(); 180 | perror("chdir (to chroot)"); 181 | exit(EXIT_FAILURE); 182 | } 183 | if (chroot(optarg) == -1) { 184 | log_error_time(); 185 | perror("chroot"); 186 | exit(EXIT_FAILURE); 187 | } 188 | if (chdir("/") == -1) { 189 | log_error_time(); 190 | perror("chdir (after chroot)"); 191 | exit(EXIT_FAILURE); 192 | } 193 | break; 194 | #ifndef DISABLE_DEBUG 195 | case 'l': 196 | parse_debug(optarg); 197 | break; 198 | #endif 199 | case 'p': 200 | override_server_port = strtol (optarg, NULL, 0); 201 | break; 202 | case 'L': 203 | override_server_ip = optarg; 204 | break; 205 | default: 206 | usage(argv[0]); 207 | exit(EXIT_FAILURE); 208 | } 209 | } 210 | } 211 | 212 | static int create_server_socket(void) 213 | { 214 | int server_s; 215 | 216 | server_s = socket(SERVER_PF, SOCK_STREAM, IPPROTO_TCP); 217 | if (server_s == -1) { 218 | DIE("unable to create socket"); 219 | } 220 | 221 | /* server socket is nonblocking */ 222 | if (set_nonblock_fd(server_s) == -1) { 223 | DIE("fcntl: unable to set server socket to nonblocking"); 224 | } 225 | 226 | /* close server socket on exec so CGIs can't write to it */ 227 | if (fcntl(server_s, F_SETFD, 1) == -1) { 228 | DIE("can't set close-on-exec on server socket!"); 229 | } 230 | 231 | /* reuse socket addr */ 232 | if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt, 233 | sizeof (sock_opt))) == -1) { 234 | DIE("setsockopt"); 235 | } 236 | 237 | /* Internet family-specific code encapsulated in bind_server() */ 238 | if (bind_server(server_s, server_ip, server_port) == -1) { 239 | DIE("unable to bind"); 240 | } 241 | 242 | /* listen: large number just in case your kernel is nicely tweaked */ 243 | if (listen(server_s, backlog) == -1) { 244 | DIE("unable to listen"); 245 | } 246 | return server_s; 247 | } 248 | 249 | static void drop_privs(void) 250 | { 251 | /* give away our privs if we can */ 252 | if (getuid() == 0) { 253 | struct passwd *passwdbuf; 254 | passwdbuf = getpwuid(server_uid); 255 | if (passwdbuf == NULL) { 256 | DIE("getpwuid"); 257 | } 258 | if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) { 259 | DIE("initgroups"); 260 | } 261 | if (setgid(server_gid) == -1) { 262 | DIE("setgid"); 263 | } 264 | if (setuid(server_uid) == -1) { 265 | DIE("setuid"); 266 | } 267 | /* test for failed-but-return-was-successful setuid 268 | * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html 269 | */ 270 | if (server_uid != 0 && setuid(0) != -1) { 271 | DIE("icky Linux kernel bug!"); 272 | } 273 | } else { 274 | if (server_gid || server_uid) { 275 | log_error_time(); 276 | fprintf(stderr, "Warning: " 277 | "Not running as root: no attempt to change" 278 | " to uid %u gid %u\n", server_uid, server_gid); 279 | } 280 | server_gid = getgid(); 281 | server_uid = getuid(); 282 | } 283 | } 284 | 285 | /* 286 | * Name: fixup_server_root 287 | * 288 | * Description: Makes sure the server root is valid. 289 | * 290 | */ 291 | 292 | static void fixup_server_root() 293 | { 294 | if (!server_root) { 295 | #ifdef SERVER_ROOT 296 | server_root = strdup(SERVER_ROOT); 297 | if (!server_root) { 298 | perror("strdup (SERVER_ROOT)"); 299 | exit(EXIT_FAILURE); 300 | } 301 | #else 302 | fputs("boa: don't know where server root is. Please #define " 303 | "SERVER_ROOT in boa.h\n" 304 | "and recompile, or use the -c command line option to " 305 | "specify it.\n", stderr); 306 | exit(EXIT_FAILURE); 307 | #endif 308 | } 309 | 310 | if (chdir(server_root) == -1) { 311 | fprintf(stderr, "Could not chdir to \"%s\": aborting\n", 312 | server_root); 313 | exit(EXIT_FAILURE); 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /src/boa.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1996-1999 Larry Doolittle 5 | * Copyright (C) 1997-2004 Jon Nelson 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 1, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | /* $Id: boa.h,v 1.63.2.27 2005/02/22 14:11:29 jnelson Exp $*/ 24 | 25 | #ifndef _BOA_H 26 | #define _BOA_H 27 | 28 | /* Important, include before anything else */ 29 | #include "config.h" 30 | 31 | #include 32 | #include /* malloc, free, etc. */ 33 | #include /* stdin, stdout, stderr */ 34 | #include /* strdup */ 35 | #include 36 | #include /* localtime, time */ 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include /* OPEN_MAX */ 42 | #include 43 | 44 | #include 45 | 46 | #include 47 | #include /* socket, bind, accept */ 48 | #include /* socket, bind, accept, setsockopt, */ 49 | #include /* open */ 50 | 51 | #include "compat.h" /* oh what fun is porting */ 52 | #include "defines.h" 53 | #include "globals.h" 54 | 55 | /* alias */ 56 | void add_alias(const char *fakename, const char *realname, enum ALIAS type); 57 | int translate_uri(request * req); 58 | void dump_alias(void); 59 | 60 | /* config */ 61 | void read_config_files(void); 62 | 63 | /* escape */ 64 | #include "escape.h" 65 | 66 | /* get */ 67 | int init_get(request * req); 68 | int process_get(request * req); 69 | int get_dir(request * req, struct stat *statbuf); 70 | 71 | /* hash */ 72 | unsigned get_mime_hash_value(const char *extension); 73 | char *get_mime_type(const char *filename); 74 | char *get_home_dir(const char *name); 75 | void dump_mime(void); 76 | void dump_passwd(void); 77 | void hash_show_stats(void); 78 | void add_mime_type(const char *extension, const char *type); 79 | 80 | /* log */ 81 | void open_logs(void); 82 | void log_access(request * req); 83 | void log_error_doc(request * req); 84 | void boa_perror(request * req, const char *message); 85 | void log_error_time(void); 86 | void log_error(const char *mesg); 87 | #ifdef HAVE_FUNC 88 | void log_error_mesg(const char *file, int line, const char *func, const char *mesg); 89 | void log_error_mesg_fatal(const char *file, int line, const char *func, const char *mesg); 90 | #else 91 | void log_error_mesg(const char *file, int line, const char *mesg); 92 | void log_error_mesg_fatal(const char *file, int line, const char *mesg); 93 | #endif 94 | 95 | /* queue */ 96 | void block_request(request * req); 97 | void ready_request(request * req); 98 | void dequeue(request ** head, request * req); 99 | void enqueue(request ** head, request * req); 100 | 101 | /* read */ 102 | int read_header(request * req); 103 | int read_body(request * req); 104 | int write_body(request * req); 105 | 106 | /* request */ 107 | request *new_request(void); 108 | void get_request(int); 109 | void process_requests(int server_s); 110 | int process_header_end(request * req); 111 | int process_header_line(request * req); 112 | int process_logline(request * req); 113 | int process_option_line(request * req); 114 | void add_accept_header(request * req, const char *mime_type); 115 | void free_requests(void); 116 | 117 | /* response */ 118 | const char *http_ver_string(enum HTTP_VERSION ver); 119 | void print_ka_phrase(request * req); 120 | void print_content_type(request * req); 121 | void print_content_length(request * req); 122 | void print_last_modified(request * req); 123 | void print_http_headers(request * req); 124 | void print_content_range(request * req); 125 | void print_partial_content_continue(request * req); 126 | void print_partial_content_done(request * req); 127 | int complete_response(request *req); 128 | 129 | void send_r_continue(request * req); /* 100 */ 130 | void send_r_request_ok(request * req); /* 200 */ 131 | void send_r_no_content(request * req); /* 204 */ 132 | void send_r_partial_content(request * req); /* 206 */ 133 | void send_r_moved_perm(request * req, const char *url); /* 301 */ 134 | void send_r_moved_temp(request * req, const char *url, const char *more_hdr); /* 302 */ 135 | void send_r_not_modified(request * req); /* 304 */ 136 | void send_r_bad_request(request * req); /* 400 */ 137 | void send_r_unauthorized(request * req, const char *name); /* 401 */ 138 | void send_r_forbidden(request * req); /* 403 */ 139 | void send_r_not_found(request * req); /* 404 */ 140 | void send_r_length_required(request * req); /* 411 */ 141 | void send_r_precondition_failed(request * req); /* 412 */ 142 | void send_r_request_uri_too_long(request * req); /* 414 */ 143 | void send_r_invalid_range(request * req); /* 416 */ 144 | void send_r_error(request * req); /* 500 */ 145 | void send_r_not_implemented(request * req); /* 501 */ 146 | void send_r_bad_gateway(request * req); /* 502 */ 147 | void send_r_service_unavailable(request * req); /* 503 */ 148 | void send_r_bad_version(request * req, const char * version); /* 505 */ 149 | 150 | /* cgi */ 151 | void create_common_env(void); 152 | void add_to_common_env(char *key, char *value); 153 | void clear_common_env(void); 154 | int add_cgi_env(request * req, const char *key, const char *value, int http_prefix); 155 | int init_cgi(request * req); 156 | 157 | /* signals */ 158 | void init_signals(void); 159 | void reset_signals(void); 160 | void sighup_run(void); 161 | void sigchld_run(void); 162 | void sigalrm_run(void); 163 | void sigterm_stage1_run(void); 164 | void sigterm_stage2_run(void); 165 | 166 | /* util.c */ 167 | void clean_pathname(char *pathname); 168 | char *get_commonlog_time(void); 169 | void rfc822_time_buf(char *buf, time_t s); 170 | char *simple_itoa(uint64_t i); 171 | int boa_atoi(const char *s); 172 | int month2int(const char *month); 173 | int modified_since(time_t * mtime, const char *if_modified_since); 174 | int unescape_uri(char *uri, char **query_string); 175 | int create_temporary_file(short want_unlink, char *storage, unsigned int size); 176 | int real_set_block_fd(int fd); 177 | int real_set_nonblock_fd(int fd); 178 | char *to_upper(char *str); 179 | void strlower(char *s); 180 | char *strconcat (const char *s1, ...) BOA_ATTR_SENTINEL(0); 181 | int check_host(const char *r); 182 | #ifndef DISABLE_DEBUG 183 | void parse_debug(char *foo); 184 | void print_debug_usage(void); 185 | #endif 186 | 187 | /* buffer */ 188 | int req_write(request * req, const char *msg); 189 | void reset_output_buffer(request * req); 190 | int req_write_escape_http(request * req, const char *msg); 191 | int req_write_escape_html(request * req, const char *msg); 192 | int req_flush(request * req); 193 | char *escape_uri(const char *uri); 194 | char *escape_string(const char *inp, char *buf); 195 | 196 | /* timestamp */ 197 | void timestamp(void); 198 | 199 | /* mmap_cache */ 200 | struct mmap_entry *find_mmap(int data_fd, struct stat *s); 201 | void release_mmap(struct mmap_entry *e); 202 | 203 | /* sublog */ 204 | int open_gen_fd(char *spec); 205 | int process_cgi_header(request * req); 206 | 207 | /* pipe */ 208 | int read_from_pipe(request * req); 209 | int write_from_pipe(request * req); 210 | int io_shuffle(request * req); 211 | #ifdef HAVE_SENDFILE 212 | #include 213 | int io_shuffle_sendfile(request * req); 214 | #endif 215 | 216 | /* ip */ 217 | int bind_server(int sock, char *ip, unsigned int port); 218 | char *ascii_sockaddr(struct SOCKADDR *s, char *dest, unsigned int len); 219 | int net_port(struct SOCKADDR *s); 220 | 221 | /* select or poll */ 222 | void loop(int server_s); 223 | 224 | /* range.c */ 225 | void ranges_reset(request * req); 226 | Range *range_pool_pop(void); 227 | void range_pool_empty(void); 228 | void range_pool_push(Range * r); 229 | int ranges_fixup(request * req); 230 | int range_parse(request * req, const char *str); 231 | 232 | #endif 233 | -------------------------------------------------------------------------------- /src/buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1999-2004 Jon Nelson 5 | * Copyright (C) 1999-2000 Larry Doolittle 6 | 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 1, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | /* $Id: buffer.c,v 1.10.2.14 2005/02/22 14:11:29 jnelson Exp $ */ 24 | 25 | #include "boa.h" 26 | #include "escape.h" 27 | 28 | 29 | /* 30 | * Name: req_write 31 | * 32 | * Description: Buffers data before sending to client. 33 | * Returns: -1 for error, otherwise how much is stored 34 | */ 35 | 36 | int req_write(request * req, const char *msg) 37 | { 38 | unsigned int msg_len; 39 | 40 | msg_len = strlen(msg); 41 | 42 | if (!msg_len || req->status > DONE) 43 | return req->buffer_end; 44 | 45 | if (req->buffer_end + msg_len > BUFFER_SIZE) { 46 | log_error_doc(req); 47 | fprintf(stderr, "There is not enough room in the buffer to" 48 | " copy %u bytes (%d available). Shutting down connection.\n", 49 | msg_len, 50 | BUFFER_SIZE - req->buffer_end); 51 | #ifdef FASCIST_LOGGING 52 | *(req->buffer + req->buffer_end) = '\0'; 53 | fprintf(stderr, "The request looks like this:\n%s\n", 54 | req->buffer); 55 | #endif 56 | req->status = DEAD; 57 | return -1; 58 | } 59 | memcpy(req->buffer + req->buffer_end, msg, msg_len); 60 | req->buffer_end += msg_len; 61 | return req->buffer_end; 62 | } 63 | 64 | void reset_output_buffer(request * req) 65 | { 66 | req->buffer_end = 0; 67 | } 68 | 69 | /* 70 | * Name: req_write_escape_http 71 | * Description: Buffers and "escapes" data before sending to client. 72 | * as above, but translates as it copies, into a form suitably 73 | * encoded for URLs in HTTP headers. 74 | * Returns: -1 for error, otherwise how much is stored 75 | */ 76 | int req_write_escape_http(request * req, const char *msg) 77 | { 78 | char c, *dest; 79 | const char *inp; 80 | int left; 81 | int skip = 0; 82 | 83 | inp = msg; 84 | dest = req->buffer + req->buffer_end; 85 | /* 3 is a guard band, since we don't check the destination pointer 86 | * in the middle of a transfer of up to 3 bytes */ 87 | left = BUFFER_SIZE - req->buffer_end; 88 | while ((c = *inp++) && left >= 3) { 89 | /* Lower the skip character count. */ 90 | if (skip) skip--; 91 | /* If we have a '%', we skip the two follow characters. */ 92 | if (c == '%') skip = 2; 93 | 94 | if (!skip && needs_escape((unsigned int) c)) { 95 | *dest++ = '%'; 96 | *dest++ = INT_TO_HEX((c >> 4) & 0xf); 97 | *dest++ = INT_TO_HEX(c & 0xf); 98 | left -= 3; 99 | } else { 100 | *dest++ = c; 101 | left--; 102 | } 103 | } 104 | --inp; 105 | req->buffer_end = dest - req->buffer; 106 | 107 | #ifdef TESTING 108 | if (left < 0) { 109 | log_error_time(); /* don't use log_error_doc here */ 110 | fprintf(stderr, "Overflowed buffer space!\n"); 111 | chdir("/tmp"); 112 | abort(); 113 | } 114 | #endif 115 | 116 | if (*inp != '\0') { 117 | log_error_doc(req); 118 | fprintf(stderr, "Ran out of Buffer space! [req_write_escape_http]\n"); 119 | req->status = DEAD; 120 | return -1; 121 | } 122 | return req->buffer_end; 123 | } 124 | 125 | /* 126 | * Name: req_write_escape_html 127 | * Description: Buffers and "escapes" data before sending to client. 128 | * as above, but translates as it copies, into a form suitably 129 | * encoded for HTML bodies. 130 | * Returns: -1 for error, otherwise how much is stored 131 | */ 132 | int req_write_escape_html(request * req, const char *msg) 133 | { 134 | char c, *dest; 135 | const char *inp; 136 | int left; 137 | 138 | inp = msg; 139 | dest = req->buffer + req->buffer_end; 140 | /* 6 is a guard band, since we don't check the destination pointer 141 | * in the middle of a transfer of up to 6 bytes 142 | */ 143 | left = BUFFER_SIZE - req->buffer_end; 144 | while ((c = *inp++) && left >= 6) { 145 | switch (c) { 146 | case '>': 147 | *dest++ = '&'; 148 | *dest++ = 'g'; 149 | *dest++ = 't'; 150 | *dest++ = ';'; 151 | left -= 4; 152 | break; 153 | case '<': 154 | *dest++ = '&'; 155 | *dest++ = 'l'; 156 | *dest++ = 't'; 157 | *dest++ = ';'; 158 | left -= 4; 159 | break; 160 | case '&': 161 | *dest++ = '&'; 162 | *dest++ = 'a'; 163 | *dest++ = 'm'; 164 | *dest++ = 'p'; 165 | *dest++ = ';'; 166 | left -= 5; 167 | break; 168 | case '\"': 169 | *dest++ = '&'; 170 | *dest++ = 'q'; 171 | *dest++ = 'u'; 172 | *dest++ = 'o'; 173 | *dest++ = 't'; 174 | *dest++ = ';'; 175 | left -= 6; 176 | break; 177 | default: 178 | *dest++ = c; 179 | left--; 180 | } 181 | } 182 | --inp; 183 | req->buffer_end = dest - req->buffer; 184 | 185 | #ifdef TESTING 186 | if (left < 0) { 187 | log_error_time(); /* don't use log_error_doc here */ 188 | fprintf(stderr, "Overflowed buffer space! [req_write_escape_html]\n"); 189 | chdir("/tmp"); 190 | abort(); 191 | } 192 | #endif 193 | 194 | if (*inp != '\0') { 195 | log_error_doc(req); 196 | fprintf(stderr, "Ran out of Buffer space (%d chars left)! " 197 | "[req_write_escape_html]\n", left); 198 | req->status = DEAD; 199 | return -1; 200 | } 201 | return req->buffer_end; 202 | } 203 | 204 | 205 | /* 206 | * Name: flush_req 207 | * 208 | * Description: Sends any backlogged buffer to client. 209 | * 210 | * Returns: -2 for error, -1 for blocked, otherwise how much is stored 211 | */ 212 | 213 | int req_flush(request * req) 214 | { 215 | unsigned bytes_to_write; 216 | 217 | bytes_to_write = req->buffer_end - req->buffer_start; 218 | if (req->status > DONE) 219 | return -2; 220 | 221 | if (bytes_to_write) { 222 | off_t bytes_written; 223 | 224 | bytes_written = write(req->fd, req->buffer + req->buffer_start, 225 | bytes_to_write); 226 | 227 | if (bytes_written < 0) { 228 | if (errno == EWOULDBLOCK || errno == EAGAIN) 229 | return -1; /* request blocked at the pipe level, but keep going */ 230 | else { 231 | req->buffer_start = req->buffer_end = 0; 232 | /* OK to disable if your logs get too big */ 233 | #ifdef QUIET_DISCONNECT 234 | if (errno != ECONNRESET && errno != EPIPE) 235 | #endif 236 | { 237 | log_error_doc(req); 238 | perror("buffer flush"); 239 | } 240 | req->status = DEAD; 241 | req->buffer_end = 0; 242 | return -2; 243 | } 244 | } 245 | #ifdef FASCIST_LOGGING 246 | log_error_time(); 247 | fprintf(stderr, "%s:%d - Wrote \"", __FILE__, __LINE__); 248 | fwrite(req->buffer + req->buffer_start, sizeof (char), 249 | bytes_written, stderr); 250 | fprintf(stderr, "\" (%d bytes)\n", bytes_written); 251 | #endif 252 | req->buffer_start += bytes_written; 253 | } 254 | if (req->buffer_start == req->buffer_end) 255 | req->buffer_start = req->buffer_end = 0; 256 | return req->buffer_end; /* successful */ 257 | } 258 | 259 | /* 260 | * Name: escape_string 261 | * 262 | * Description: escapes the string inp. Uses variable buf. If buf is 263 | * NULL when the program starts, it will attempt to dynamically allocate 264 | * the space that it needs, otherwise it will assume that the user 265 | * has already allocated enough space for the variable buf, which 266 | * could be up to 3 times the size of inp. If the routine dynamically 267 | * allocates the space, the user is responsible for freeing it afterwords 268 | * Returns: NULL on error, pointer to string otherwise. 269 | * Note: this function doesn't really belong here, I plopped it here to 270 | * work around a "bug" in escape.h (it defines a global, so can't be 271 | * used in multiple source files). Actually, this routine shouldn't 272 | * exist anywhere, it's only usage is in get.c's handling of on-the-fly 273 | * directory generation, which would be better configured to use a combination 274 | * of req_write_escape_http and req_write_escape_html. That would involve 275 | * more work than I'm willing to put in right now, though, so here we are. 276 | */ 277 | 278 | char *escape_string(const char *inp, char *buf) 279 | { 280 | int max; 281 | char *ix; 282 | unsigned char c; 283 | 284 | max = strlen(inp) * 3; 285 | 286 | if (buf == NULL && max) 287 | buf = malloc(sizeof (char) * (max + 1)); 288 | 289 | if (buf == NULL) { 290 | log_error_time(); 291 | perror("malloc"); 292 | return NULL; 293 | } 294 | 295 | ix = buf; 296 | while ((c = *inp++) && max > 0) { 297 | if (needs_escape((unsigned int) c)) { 298 | *ix++ = '%'; 299 | *ix++ = INT_TO_HEX((c >> 4) & 0xf); 300 | *ix++ = INT_TO_HEX(c & 0xf); 301 | } else 302 | *ix++ = c; 303 | } 304 | *ix = '\0'; 305 | return buf; 306 | } 307 | -------------------------------------------------------------------------------- /src/cgi_header.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * cgi_header.c - cgi header parsing and control 4 | * Copyright (C) 1997-2003 Jon Nelson 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 1, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | 22 | #include "boa.h" 23 | 24 | /* process_cgi_header 25 | 26 | * returns 0 -=> error or HEAD, close down. 27 | * returns 1 -=> done processing 28 | * leaves req->cgi_status as WRITE 29 | */ 30 | 31 | /* 32 | The server MUST also resolve any conflicts between header fields returned by 33 | the script and header fields that it would otherwise send itself. 34 | 35 | ... 36 | 37 | At least one CGI-Field MUST be supplied, but no CGI field name may be used 38 | more than once in a response. If a body is supplied, then a 39 | "Content-type" header field MUST be supplied by the script, 40 | otherwise the script MUST send a "Location" or "Status" header 41 | field. If a Location CGI-Field is returned, then the script 42 | MUST NOT supply any HTTP-Fields. 43 | */ 44 | 45 | /* TODO: 46 | We still need to cycle through the data before the end of the headers, 47 | line-by-line, and check for any problems with the CGI 48 | outputting overriding http responses, etc... 49 | */ 50 | 51 | int process_cgi_header(request * req) 52 | { 53 | char *buf; 54 | char *c; 55 | 56 | if (req->cgi_status != CGI_DONE) 57 | req->cgi_status = CGI_BUFFER; 58 | 59 | buf = req->header_line; 60 | 61 | c = strstr(buf, "\n\r\n"); 62 | if (c == NULL) { 63 | c = strstr(buf, "\n\n"); 64 | if (c == NULL) { 65 | log_error_doc(req); 66 | fputs("cgi_header: unable to find LFLF\n", stderr); 67 | #ifdef FASCIST_LOGGING 68 | log_error_time(); 69 | fprintf(stderr, "\"%s\"\n", buf); 70 | #endif 71 | send_r_bad_gateway(req); 72 | return 0; 73 | } 74 | } 75 | if (req->http_version == HTTP09) { 76 | if (*(c + 1) == '\r') 77 | req->header_line = c + 2; 78 | else 79 | req->header_line = c + 1; 80 | return 1; 81 | } 82 | if (!strncasecmp(buf, "Status: ", 8)) { 83 | req->header_line--; 84 | memcpy(req->header_line, "HTTP/1.0 ", 9); 85 | } else if (!strncasecmp(buf, "Location: ", 10)) { /* got a location header */ 86 | #ifdef FASCIST_LOGGING 87 | 88 | log_error_time(); 89 | fprintf(stderr, "%s:%d - found Location header \"%s\"\n", 90 | __FILE__, __LINE__, buf + 10); 91 | #endif 92 | 93 | 94 | if (buf[10] == '/') { /* virtual path */ 95 | log_error_doc(req); 96 | fprintf(stderr, 97 | "server does not support internal redirection: " 98 | "\"%s\"\n", buf + 10); 99 | send_r_bad_request(req); 100 | 101 | /* 102 | * We (I, Jon) have declined to support absolute-path parsing 103 | * because I see it as a major security hole. 104 | * Location: /etc/passwd or Location: /etc/shadow is not funny. 105 | * 106 | * Also, the below code is borked. 107 | * request_uri could contain /cgi-bin/bob/extra_path 108 | */ 109 | 110 | /* 111 | strcpy(req->request_uri, buf + 10); 112 | return internal_redirect(req); 113 | */ 114 | } else { /* URL */ 115 | char *c2; 116 | c2 = strchr(buf + 10, '\n'); 117 | /* c2 cannot ever equal NULL here because we already have found one */ 118 | 119 | --c2; 120 | while (*c2 == '\r') 121 | --c2; 122 | ++c2; 123 | /* c2 now points to a '\r' or the '\n' */ 124 | *c2++ = '\0'; /* end header */ 125 | 126 | /* first next header, or is at req->header_end */ 127 | while ((*c2 == '\n' || *c2 == '\r') && c2 < req->header_end) 128 | ++c2; 129 | if (c2 == req->header_end) 130 | send_r_moved_temp(req, buf + 10, ""); 131 | else 132 | send_r_moved_temp(req, buf + 10, c2); 133 | } 134 | req->status = DONE; 135 | return 1; 136 | } else { /* not location and not status */ 137 | char *dest; 138 | unsigned int howmuch; 139 | send_r_request_ok(req); /* does not terminate */ 140 | /* got to do special things because 141 | a) we have a single buffer divided into 2 pieces 142 | b) we need to merge those pieces 143 | Easiest way is to memmove the cgi data backward until 144 | it touches the buffered data, then reset the cgi data pointers 145 | */ 146 | dest = req->buffer + req->buffer_end; 147 | if (req->method == M_HEAD) { 148 | if (*(c + 1) == '\r') 149 | req->header_end = c + 2; 150 | else 151 | req->header_end = c + 1; 152 | req->cgi_status = CGI_DONE; 153 | } 154 | howmuch = req->header_end - req->header_line; 155 | 156 | if (dest + howmuch > req->buffer + BUFFER_SIZE) { 157 | /* big problem */ 158 | log_error_doc(req); 159 | fprintf(stderr, "Too much data to move! Aborting! %s %d\n", 160 | __FILE__, __LINE__); 161 | /* reset buffer pointers because we already called 162 | send_r_request_ok... */ 163 | req->buffer_start = req->buffer_end = 0; 164 | send_r_error(req); 165 | return 0; 166 | } 167 | memmove(dest, req->header_line, howmuch); 168 | req->buffer_end += howmuch; 169 | req->header_line = req->buffer + req->buffer_end; 170 | req->header_end = req->header_line; 171 | req_flush(req); 172 | if (req->method == M_HEAD) 173 | return 0; 174 | } 175 | return 1; 176 | } 177 | -------------------------------------------------------------------------------- /src/compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1999 Larry Doolittle 5 | * Copyright (C) 1999-2005 Jon Nelson 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 1, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | /* $Id: compat.h,v 1.18.2.12 2005/02/22 14:11:29 jnelson Exp $*/ 24 | 25 | #ifndef _COMPAT_H 26 | #define _COMPAT_H 27 | 28 | #include "config.h" 29 | 30 | #ifdef HAVE_POLL 31 | #include 32 | #else 33 | #include 34 | #endif /* HAVE_POLL */ 35 | 36 | #ifdef TIME_WITH_SYS_TIME 37 | #include 38 | #endif 39 | 40 | #ifdef HAVE_SYS_FCNTL_H 41 | #include 42 | #endif 43 | 44 | #ifndef OPEN_MAX 45 | #define OPEN_MAX 256 46 | #endif 47 | 48 | #ifdef FD_SETSIZE 49 | #define MAX_FD FD_SETSIZE 50 | #else 51 | #define MAX_FD OPEN_MAX 52 | #endif /* FD_SETSIZE */ 53 | 54 | #include 55 | #ifndef SO_MAXCONN 56 | #define SO_MAXCONN 250 57 | #endif 58 | 59 | #ifndef PATH_MAX 60 | #define PATH_MAX 2048 61 | #endif 62 | 63 | /* Wild guess time, probably better done with configure */ 64 | #ifdef O_NONBLOCK 65 | #define NOBLOCK O_NONBLOCK /* Linux */ 66 | #else /* O_NONBLOCK */ 67 | #ifdef O_NDELAY 68 | #define NOBLOCK O_NDELAY /* Sun */ 69 | #else /* O_NDELAY */ 70 | #error "Can't find a way to #define NOBLOCK" 71 | #endif /* O_NDELAY */ 72 | #endif /* O_NONBLOCK */ 73 | 74 | #ifndef MAP_FILE 75 | #define MAP_OPTIONS MAP_PRIVATE /* Sun */ 76 | #else 77 | #define MAP_OPTIONS MAP_FILE|MAP_PRIVATE /* Linux */ 78 | #endif 79 | 80 | #include 81 | #ifdef INET6 82 | /* #define S_FAMILY __s_family */ 83 | #define SOCKADDR sockaddr_storage 84 | #define SERVER_PF PF_INET6 85 | #define S_FAMILY sin6_family 86 | #ifndef NI_MAXHOST 87 | #error NI_MAXHOST undefined!! 88 | #endif /* ifndef NI_MAXHOST */ 89 | #define BOA_NI_MAXHOST NI_MAXHOST 90 | #else /* ifdef INET6 */ 91 | #define SOCKADDR sockaddr_in 92 | #define SERVER_PF PF_INET 93 | #define S_FAMILY sin_family 94 | #define BOA_NI_MAXHOST 20 95 | #endif /* ifdef INET6 */ 96 | 97 | #if HAVE_DIRENT_H 98 | # include 99 | # define NAMLEN(dirent) strlen((dirent)->d_name) 100 | #else 101 | # define dirent direct 102 | # define NAMLEN(dirent) (dirent)->d_namlen 103 | # if HAVE_SYS_NDIR_H 104 | # include 105 | # endif 106 | # if HAVE_SYS_DIR_H 107 | # include 108 | # endif 109 | # if HAVE_NDIR_H 110 | # include 111 | # endif 112 | #endif 113 | 114 | /* below here, functions are provided in extras */ 115 | #ifndef HAVE_SCANDIR 116 | int 117 | scandir(const char *dir, struct dirent ***namelist, 118 | int (*select) (const struct dirent *), 119 | int (*compar) (const struct dirent **, const struct dirent **)); 120 | #endif 121 | 122 | #ifndef HAVE_ALPHASORT 123 | int alphasort(const struct dirent **a, const struct dirent **b); 124 | #endif 125 | 126 | #ifndef HAVE_STRSTR 127 | char *strstr(char *s1, char *s2); 128 | #endif 129 | 130 | #ifndef HAVE_STRDUP 131 | char *strdup(char *s); 132 | #endif 133 | 134 | #ifdef HAVE_TM_GMTOFF 135 | #define TIMEZONE_OFFSET(foo) foo->tm_gmtoff 136 | #else 137 | #define TIMEZONE_OFFSET(foo) timezone 138 | #endif 139 | 140 | #ifdef HAVE_TM_ZONE 141 | #define TIMEZONE(foo) foo->tm_zone 142 | #else 143 | #define TIMEZONE(foo) *tzname 144 | #endif 145 | 146 | #ifdef HAVE_LIBDMALLOC 147 | #define DMALLOC_FUNC_CHECK 148 | #include 149 | #endif 150 | 151 | #ifdef HAVE_GETOPT_H 152 | #include 153 | #endif 154 | 155 | #ifdef DONT_HAVE_SA_FAMILY_T 156 | /* POSIX.1g specifies this type name for the `sa_family' member. */ 157 | typedef unsigned short int sa_family_t; 158 | #endif 159 | 160 | /* GCC feature tests. */ 161 | #if __GNUC__ 162 | # define BOA_GCC_VERSION (__GNUC__ * 10000 \ 163 | + __GNUC_MINOR__ * 100 \ 164 | + __GNUC_PATCHLEVEL__) 165 | #else 166 | # define BOA_GCC_VERSION 0 167 | #endif 168 | 169 | #if BOA_GCC_VERSION >= 40000 170 | # define BOA_ATTR_SENTINEL(a) __attribute__ ((sentinel(a))) 171 | #else 172 | # define BOA_ATTR_SENTINEL(a) 173 | #endif 174 | 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /src/config.h.in: -------------------------------------------------------------------------------- 1 | /* src/config.h.in. Generated from configure.in by autoheader. */ 2 | 3 | /* Define if sa_family_t is not defined */ 4 | #undef DONT_HAVE_SA_FAMILY_T 5 | 6 | /* Define if gunzip can be found */ 7 | #undef GUNZIP 8 | 9 | /* Define to 1 if you have the `alphasort' function. */ 10 | #undef HAVE_ALPHASORT 11 | 12 | /* Define to 1 if you have the header file, and it defines `DIR'. 13 | */ 14 | #undef HAVE_DIRENT_H 15 | 16 | /* Define to 1 if you have the header file. */ 17 | #undef HAVE_FCNTL_H 18 | 19 | /* Define to 1 if your system has a working POSIX `fnmatch' function. */ 20 | #undef HAVE_FNMATCH 21 | 22 | /* Define if the C complier supports __func__ */ 23 | #undef HAVE_FUNC 24 | 25 | /* Define to 1 if you have the `getcwd' function. */ 26 | #undef HAVE_GETCWD 27 | 28 | /* Define to 1 if you have the `gethostbyname' function. */ 29 | #undef HAVE_GETHOSTBYNAME 30 | 31 | /* Define to 1 if you have the `gethostname' function. */ 32 | #undef HAVE_GETHOSTNAME 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #undef HAVE_GETOPT_H 36 | 37 | /* Define to 1 if you have the `getpagesize' function. */ 38 | #undef HAVE_GETPAGESIZE 39 | 40 | /* Define to 1 if you have the `herror' function. */ 41 | #undef HAVE_HERROR 42 | 43 | /* Define to 1 if you have the `inet_addr' function. */ 44 | #undef HAVE_INET_ADDR 45 | 46 | /* Define to 1 if you have the `inet_aton' function. */ 47 | #undef HAVE_INET_ATON 48 | 49 | /* Define to 1 if you have the header file. */ 50 | #undef HAVE_INTTYPES_H 51 | 52 | /* Define to 1 if you have the `dmalloc' library (-ldmalloc). */ 53 | #undef HAVE_LIBDMALLOC 54 | 55 | /* Define to 1 if you have the `efence' library (-lefence). */ 56 | #undef HAVE_LIBEFENCE 57 | 58 | /* Define to 1 if you have the header file. */ 59 | #undef HAVE_LIMITS_H 60 | 61 | /* Define to 1 if you have the `madvise' function. */ 62 | #undef HAVE_MADVISE 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #undef HAVE_MEMORY_H 66 | 67 | /* Define to 1 if you have a working `mmap' system call. */ 68 | #undef HAVE_MMAP 69 | 70 | /* Define to 1 if you have the header file, and it defines `DIR'. */ 71 | #undef HAVE_NDIR_H 72 | 73 | /* Define to 1 if you have the `poll' function. */ 74 | #undef HAVE_POLL 75 | 76 | /* Define to 1 if you have the `scandir' function. */ 77 | #undef HAVE_SCANDIR 78 | 79 | /* Define to 1 if you have the `select' function. */ 80 | #undef HAVE_SELECT 81 | 82 | /* Define to 1 if you have the `sendfile' function. */ 83 | #undef HAVE_SENDFILE 84 | 85 | /* Define if struct sockaddr_in has sin_len member */ 86 | #undef HAVE_SIN_LEN 87 | 88 | /* Define to 1 if you have the `socket' function. */ 89 | #undef HAVE_SOCKET 90 | 91 | /* Define to 1 if you have the header file. */ 92 | #undef HAVE_STDINT_H 93 | 94 | /* Define to 1 if you have the header file. */ 95 | #undef HAVE_STDLIB_H 96 | 97 | /* Define to 1 if you have the `strcspn' function. */ 98 | #undef HAVE_STRCSPN 99 | 100 | /* Define to 1 if you have the `strdup' function. */ 101 | #undef HAVE_STRDUP 102 | 103 | /* Define to 1 if you have the header file. */ 104 | #undef HAVE_STRINGS_H 105 | 106 | /* Define to 1 if you have the header file. */ 107 | #undef HAVE_STRING_H 108 | 109 | /* Define to 1 if you have the `strstr' function. */ 110 | #undef HAVE_STRSTR 111 | 112 | /* Define to 1 if you have the `strtol' function. */ 113 | #undef HAVE_STRTOL 114 | 115 | /* Define to 1 if you have the header file, and it defines `DIR'. 116 | */ 117 | #undef HAVE_SYS_DIR_H 118 | 119 | /* Define to 1 if you have the header file. */ 120 | #undef HAVE_SYS_FCNTL_H 121 | 122 | /* Define to 1 if you have the header file, and it defines `DIR'. 123 | */ 124 | #undef HAVE_SYS_NDIR_H 125 | 126 | /* Define to 1 if you have the header file. */ 127 | #undef HAVE_SYS_POLL_H 128 | 129 | /* Define to 1 if you have the header file. */ 130 | #undef HAVE_SYS_SELECT_H 131 | 132 | /* Define to 1 if you have the header file. */ 133 | #undef HAVE_SYS_SENDFILE_H 134 | 135 | /* Define to 1 if you have the header file. */ 136 | #undef HAVE_SYS_STAT_H 137 | 138 | /* Define to 1 if you have the header file. */ 139 | #undef HAVE_SYS_TIME_H 140 | 141 | /* Define to 1 if you have the header file. */ 142 | #undef HAVE_SYS_TYPES_H 143 | 144 | /* Define to 1 if you have that is POSIX.1 compatible. */ 145 | #undef HAVE_SYS_WAIT_H 146 | 147 | /* Define if struct tm has a tm_gmtoff member */ 148 | #undef HAVE_TM_GMTOFF 149 | 150 | /* Define if struct tm has tm_zone member */ 151 | #undef HAVE_TM_ZONE 152 | 153 | /* Define to 1 if you have the header file. */ 154 | #undef HAVE_UNISTD_H 155 | 156 | /* Define to the address where bug reports for this package should be sent. */ 157 | #undef PACKAGE_BUGREPORT 158 | 159 | /* Define to the full name of this package. */ 160 | #undef PACKAGE_NAME 161 | 162 | /* Define to the full name and version of this package. */ 163 | #undef PACKAGE_STRING 164 | 165 | /* Define to the one symbol short name of this package. */ 166 | #undef PACKAGE_TARNAME 167 | 168 | /* Define to the version of this package. */ 169 | #undef PACKAGE_VERSION 170 | 171 | /* Define to 1 if the C compiler supports function prototypes. */ 172 | #undef PROTOTYPES 173 | 174 | /* Define to 1 if the `setvbuf' function takes the buffering type as its 175 | second argument and the buffer pointer as the third, as on System V before 176 | release 3. */ 177 | #undef SETVBUF_REVERSED 178 | 179 | /* Define to 1 if you have the ANSI C header files. */ 180 | #undef STDC_HEADERS 181 | 182 | /* Define to 1 if you can safely include both and . */ 183 | #undef TIME_WITH_SYS_TIME 184 | 185 | /* Define to 1 if your declares `struct tm'. */ 186 | #undef TM_IN_SYS_TIME 187 | 188 | /* Define like PROTOTYPES; this can be used by system headers. */ 189 | #undef __PROTOTYPES 190 | 191 | /* Define to empty if `const' does not conform to ANSI C. */ 192 | #undef const 193 | 194 | /* Define to `int' if doesn't define. */ 195 | #undef gid_t 196 | 197 | /* Define to `long' if does not define. */ 198 | #undef off_t 199 | 200 | /* Define to `int' if does not define. */ 201 | #undef pid_t 202 | 203 | /* Define to `unsigned' if does not define. */ 204 | #undef size_t 205 | 206 | /* Define to `int' if doesn't define. */ 207 | #undef uid_t 208 | 209 | /* Those enable the LFS ready structures in the system headers */ 210 | #define _FILE_OFFSET_BITS 64 /* glibc style */ 211 | #define _LARGEFILE_SOURCE 1 /* To make ftello() visible (HP-UX 10.20). */ 212 | #define _LARGE_FILES 1 /* Large file defined on AIX-style hosts. */ 213 | 214 | #define _LARGEFILE64_SOURCE /* tell kernel headers to provide the O_LARGEFILE value */ 215 | 216 | #if __WORDSIZE == 64 217 | #define PRINTF_OFF_T_ARG "%ld" 218 | #elif __WORDSIZE == 32 219 | #define PRINTF_OFF_T_ARG "%lld" 220 | #endif 221 | -------------------------------------------------------------------------------- /src/defines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1996-1999 Larry Doolittle 5 | * Copyright (C) 1997-2004 Jon Nelson 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 1, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | /* $Id: defines.h,v 1.107.2.42 2005/02/22 14:11:29 jnelson Exp $*/ 24 | 25 | #ifndef _DEFINES_H 26 | #define _DEFINES_H 27 | 28 | /***** Change this, or use -c on the command line to specify it *****/ 29 | 30 | #ifndef SERVER_ROOT 31 | #define SERVER_ROOT "/etc/boa" 32 | #endif 33 | 34 | /* Uncomment the following #define if you don't want your logs 35 | * filled with messages about client disconnects, etc... 36 | */ 37 | 38 | /* #define QUIET_DISCONNECT 1 */ 39 | 40 | /***** Change this via the CGIPath configuration value in boa.conf *****/ 41 | #define DEFAULT_PATH "/bin:/usr/bin:/usr/local/bin" 42 | 43 | /***** Change this via the DefaultVHost configuration directive in boa.conf *****/ 44 | #define DEFAULT_VHOST "default" 45 | #define DEFAULT_CONFIG_FILE "boa.conf" /* locate me in the server root */ 46 | 47 | /***** Change this via the SinglePostLimit configuration value in boa.conf *****/ 48 | #define SINGLE_POST_LIMIT_DEFAULT 1024 * 1024 /* 1 MB */ 49 | 50 | /***** Various stuff that you may want to tweak, but probably shouldn't *****/ 51 | 52 | #define SOCKETBUF_SIZE 32768 53 | #define CLIENT_STREAM_SIZE 8192 54 | #define BUFFER_SIZE 4096 55 | /* Changed from 1024 to cope with mailman problem. */ 56 | #define MAX_HEADER_LENGTH 1536 57 | 58 | #define MIME_HASHTABLE_SIZE 47 59 | #define ALIAS_HASHTABLE_SIZE 17 60 | #define PASSWD_HASHTABLE_SIZE 47 61 | 62 | #define REQUEST_TIMEOUT 60 63 | 64 | #define MIME_TYPES_DEFAULT "/etc/mime.types" 65 | #define CGI_MIME_TYPE "application/x-httpd-cgi" 66 | 67 | /***** CHANGE ANYTHING BELOW THIS LINE AT YOUR OWN PERIL *****/ 68 | /***** You will probably introduce buffer overruns unless you know 69 | what you are doing *****/ 70 | 71 | #define MAX_FILE_LENGTH NAME_MAX 72 | #define MAX_PATH_LENGTH PATH_MAX 73 | 74 | #ifdef ACCEPT_ON 75 | #define MAX_ACCEPT_LENGTH MAX_HEADER_LENGTH 76 | #else 77 | #define MAX_ACCEPT_LENGTH 0 78 | #endif 79 | 80 | #ifndef SERVER_VERSION 81 | #define SERVER_VERSION "Boa/0.94.101wk" 82 | #endif 83 | 84 | #define CGI_VERSION "CGI/1.1" 85 | 86 | #ifdef USE_NCSA_CGI_ENV 87 | #define COMMON_CGI_COUNT 8 88 | #else 89 | #define COMMON_CGI_COUNT 6 90 | #endif 91 | 92 | #define CGI_ENV_MAX 100 93 | #define CGI_ARGC_MAX 128 94 | 95 | #define SERVER_METHOD "http" 96 | 97 | /*********** MMAP_LIST CONSTANTS ************************/ 98 | #define MMAP_LIST_SIZE 256 99 | #define MMAP_LIST_MASK 255 100 | #define MMAP_LIST_USE_MAX 128 101 | 102 | #define MAX_FILE_MMAP 100 * 1024 /* 100K */ 103 | 104 | /*************** POLL / SELECT MACROS *******************/ 105 | #ifdef HAVE_POLL 106 | #define BOA_READ (POLLIN|POLLPRI|POLLHUP) 107 | #define BOA_WRITE (POLLOUT|POLLHUP) 108 | #define BOA_FD_SET(req, thefd,where) { struct pollfd *my_pfd = &pfds[pfd_len]; req->pollfd_id = pfd_len++; my_pfd->fd = thefd; my_pfd->events = where; } 109 | #define BOA_FD_CLR(req, fd, where) /* this doesn't do anything? */ 110 | #else /* SELECT */ 111 | #define BOA_READ (&block_read_fdset) 112 | #define BOA_WRITE (&block_write_fdset) 113 | #define BOA_FD_SET(req, fd, where) { FD_SET(fd, where); if (fd > max_fd) max_fd = fd; } 114 | #define BOA_FD_CLR(req, fd, where) { FD_CLR(fd, where); } 115 | #endif 116 | 117 | /******** MACROS TO CHANGE BLOCK/NON-BLOCK **************/ 118 | /* If and when everyone has a modern gcc or other near-C99 compiler, 119 | * change these to static inline functions. Also note that since 120 | * we never fuss with O_APPEND append or O_ASYNC, we shouldn't have 121 | * to perform an extra system call to F_GETFL first. 122 | */ 123 | #ifdef BOA_USE_GETFL 124 | #define set_block_fd(fd) real_set_block_fd(fd) 125 | #define set_nonblock_fd(fd) real_set_nonblock_fd(fd) 126 | #else 127 | #define set_block_fd(fd) fcntl(fd, F_SETFL, 0) 128 | #define set_nonblock_fd(fd) fcntl(fd, F_SETFL, NOBLOCK) 129 | #endif 130 | 131 | /********************* DEBUG STUFF ***********************/ 132 | extern int debug_level; 133 | 134 | #ifdef DISABLE_DEBUG 135 | #define real_debug_level 0 136 | #else 137 | #define real_debug_level debug_level 138 | #endif 139 | 140 | #define DEBUG(foo) if (real_debug_level & foo) 141 | 142 | #define DEBUG_ALIAS (1<<0) 143 | #define DEBUG_CGI_OUTPUT (1<<1) 144 | #define DEBUG_CGI_INPUT (1<<2) 145 | #define DEBUG_CGI_ENV (1<<3) 146 | #define DEBUG_HEADER_READ (1<<4) 147 | #define DEBUG_PIPELINE (1<<5) 148 | #define DEBUG_PLUGIN_ERRORS (1<<6) 149 | #define DEBUG_RANGE (1<<7) 150 | #define DEBUG_CONFIG (1<<8) 151 | #define DEBUG_BUFFER_IO (1<<9) 152 | #define DEBUG_BODY_READ (1<<10) 153 | #define DEBUG_MMAP_CACHE (1<<11) 154 | #define DEBUG_REQUEST (1<<12) 155 | #define DEBUG_HASH (1<<13) 156 | 157 | /***************** USEFUL MACROS ************************/ 158 | 159 | #define CRLF "\r\n" 160 | #define SQUASH_KA(req) (req->keepalive=KA_STOPPED) 161 | 162 | #ifdef HAVE_FUNC 163 | #define WARN(mesg) log_error_mesg(__FILE__, __LINE__, __func__, mesg) 164 | #define DIE(mesg) log_error_mesg_fatal(__FILE__, __LINE__, __func__, mesg) 165 | #else 166 | #define WARN(mesg) log_error_mesg(__FILE__, __LINE__, mesg) 167 | #define DIE(mesg) log_error_mesg_fatal(__FILE__, __LINE__, mesg) 168 | #endif 169 | 170 | #define INT_TO_HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x))) 171 | #define HEX_TO_DECIMAL(char1, char2) \ 172 | (((char1 >= 'A') ? (((char1 & 0xdf) - 'A') + 10) : (char1 - '0')) * 16) + \ 173 | (((char2 >= 'A') ? (((char2 & 0xdf) - 'A') + 10) : (char2 - '0'))) 174 | 175 | #ifndef EXIT_SUCCESS 176 | #define EXIT_SUCCESS 0 177 | #endif 178 | 179 | #ifndef EXIT_FAILURE 180 | #define EXIT_FAILURE 1 181 | #endif 182 | 183 | #ifndef DIM 184 | # define DIM(array) (sizeof (array) / sizeof (*array)) 185 | #endif 186 | 187 | #endif 188 | -------------------------------------------------------------------------------- /src/escape.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * escape.c 4 | * Copyright (C) 2001 Jon Nelson 5 | * Based on escape.pl, Copyright (C) 1996 Larry Doolittle 6 | * Copyright (C) 2001 Larry Doolittle 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 1, or (at your option) 11 | * any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /* $Id: escape.c,v 1.7.2.2 2004/06/04 02:45:26 jnelson Exp $ */ 25 | 26 | /* 27 | unreserved = alnum | mark 28 | alnum = "0".."9" | "A".."Z" | "a".."z" 29 | mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" 30 | noescape = unreserved | ":" | "@" | "&" | "=" | "+" | "$" | "," | "/" 31 | */ 32 | 33 | #ifdef TEST 34 | #include 35 | #include 36 | #else 37 | #include "boa.h" 38 | #endif 39 | 40 | #include "escape.h" 41 | 42 | unsigned long 43 | _needs_escape[(NEEDS_ESCAPE_BITS + NEEDS_ESCAPE_WORD_LENGTH - 44 | 1) / NEEDS_ESCAPE_WORD_LENGTH]; 45 | 46 | void build_needs_escape(void) 47 | { 48 | unsigned int a, b; 49 | const unsigned char special[] = 50 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 51 | "abcdefghijklmnopqrstuvwxyz" "0123456789" "-_.!~*'():@&=+$,/?"; 52 | /* 21 Mar 2002 - jnelson - confirm with Apache 1.3.23 that '?' 53 | * is safe to leave unescaped. 54 | */ 55 | unsigned short i, j; 56 | 57 | b = 1; 58 | for (a = 0; b != 0; a++) 59 | b = b << 1; 60 | /* I found $a bit positions available in an unsigned long. */ 61 | if (a < NEEDS_ESCAPE_WORD_LENGTH) { 62 | fprintf(stderr, 63 | "NEEDS_ESCAPE_SHIFT configuration error -- " 64 | "%d should be <= log2(%d)\n", NEEDS_ESCAPE_SHIFT, a); 65 | exit(EXIT_FAILURE); 66 | } else if (a >= 2 * NEEDS_ESCAPE_WORD_LENGTH) { 67 | /* needs_escape_shift configuration suboptimal */ 68 | } else { 69 | /* Ahh, just right! */ ; 70 | } 71 | memset(_needs_escape, ~0, sizeof (_needs_escape)); 72 | for (i = 0; i < sizeof (special) - 1; ++i) { 73 | j = special[i]; 74 | if (j >= NEEDS_ESCAPE_BITS) { 75 | /* warning: character $j will be needlessly escaped. */ 76 | } else { 77 | _needs_escape[NEEDS_ESCAPE_INDEX(j)] &= ~NEEDS_ESCAPE_MASK(j); 78 | } 79 | } 80 | } 81 | 82 | #ifdef TEST 83 | int main(void) 84 | { 85 | int i; 86 | build_needs_escape(); 87 | for (i = 0; i <= NEEDS_ESCAPE_BITS; ++i) { 88 | if (needs_escape(i)) { 89 | fprintf(stdout, "%3d needs escape.\n", i); 90 | } 91 | } 92 | return (0); 93 | } 94 | #endif 95 | -------------------------------------------------------------------------------- /src/escape.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 2001 Jon Nelson 5 | * Copyright (C) 2001 Larry Doolittle 6 | 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 1, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | /* $Id: escape.h,v 1.18.2.1 2002/10/26 14:42:31 jnelson Exp $ */ 24 | 25 | #include "config.h" 26 | 27 | /* Highest character number that can possibly be passed through un-escaped */ 28 | #define NEEDS_ESCAPE_BITS 128 29 | 30 | #ifndef NEEDS_ESCAPE_SHIFT 31 | #define NEEDS_ESCAPE_SHIFT 5 /* 1 << 5 is 32 bits */ 32 | #endif 33 | 34 | #define NEEDS_ESCAPE_WORD_LENGTH (1<>NEEDS_ESCAPE_SHIFT) 37 | 38 | /* Assume variable shift is fast, otherwise this could be a table lookup */ 39 | #define NEEDS_ESCAPE_MASK(c) (1<<((c)&(NEEDS_ESCAPE_WORD_LENGTH - 1))) 40 | 41 | /* Newer compilers could use an inline function. 42 | * This macro works great, as long as you pass unsigned int or unsigned char. 43 | */ 44 | #define needs_escape(c) ((c)>=NEEDS_ESCAPE_BITS || _needs_escape[NEEDS_ESCAPE_INDEX(c)]&NEEDS_ESCAPE_MASK(c)) 45 | 46 | extern unsigned long 47 | _needs_escape[(NEEDS_ESCAPE_BITS + NEEDS_ESCAPE_WORD_LENGTH - 48 | 1) / NEEDS_ESCAPE_WORD_LENGTH]; 49 | void build_needs_escape(void); 50 | -------------------------------------------------------------------------------- /src/globals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1996-2005 Larry Doolittle 5 | * Copyright (C) 1997-2004 Jon Nelson 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 1, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | /* $Id: globals.h,v 1.65.2.29 2005/02/22 14:11:29 jnelson Exp $*/ 24 | 25 | #ifndef _GLOBALS_H 26 | #define _GLOBALS_H 27 | 28 | /********************** METHODS **********************/ 29 | enum HTTP_METHOD { M_GET = 1, M_HEAD, M_PUT, M_POST, 30 | M_DELETE, M_LINK, M_UNLINK, M_MOVE, M_TRACE 31 | }; 32 | 33 | /******************* HTTP VERSIONS *******************/ 34 | enum HTTP_VERSION { HTTP09=1, HTTP10, HTTP11 }; 35 | 36 | /************** REQUEST STATUS (req->status) ***************/ 37 | enum REQ_STATUS { READ_HEADER, ONE_CR, ONE_LF, TWO_CR, 38 | BODY_READ, BODY_WRITE, 39 | WRITE, 40 | PIPE_READ, PIPE_WRITE, 41 | IOSHUFFLE, 42 | DONE, 43 | TIMED_OUT, 44 | DEAD 45 | }; 46 | 47 | /******************* RESPONSE CODES ******************/ 48 | enum RESPONSE_CODE { R_CONTINUE = 100, 49 | R_REQUEST_OK = 200, 50 | R_CREATED, 51 | R_ACCEPTED, 52 | R_PROVISIONAL, 53 | R_NO_CONTENT, 54 | R_205, 55 | R_PARTIAL_CONTENT, 56 | R_MULTIPLE = 300, 57 | R_MOVED_PERM, 58 | R_MOVED_TEMP, 59 | R_303, 60 | R_NOT_MODIFIED, 61 | R_BAD_REQUEST = 400, 62 | R_UNAUTHORIZED, 63 | R_PAYMENT, 64 | R_FORBIDDEN, 65 | R_NOT_FOUND, 66 | R_METHOD_NA, /* method not allowed */ 67 | R_NON_ACC, /* non acceptable */ 68 | R_PROXY, /* proxy auth required */ 69 | R_REQUEST_TO, /* request timeout */ 70 | R_CONFLICT, 71 | R_GONE, 72 | R_LENGTH_REQUIRED, 73 | R_PRECONDITION_FAILED, 74 | R_REQUEST_URI_TOO_LONG = 414, 75 | R_INVALID_RANGE = 416, 76 | R_ERROR = 500, 77 | R_NOT_IMP, 78 | R_BAD_GATEWAY, 79 | R_SERVICE_UNAV, 80 | R_GATEWAY_TO, /* gateway timeout */ 81 | R_BAD_VERSION }; 82 | 83 | /************* ALIAS TYPES (aliasp->type) ***************/ 84 | enum ALIAS { ALIAS, SCRIPTALIAS, REDIRECT }; 85 | 86 | /*********** KEEPALIVE CONSTANTS (req->keepalive) *******/ 87 | enum KA_STATUS { KA_INACTIVE, KA_ACTIVE, KA_STOPPED }; 88 | 89 | /********* CGI STATUS CONSTANTS (req->cgi_status) *******/ 90 | enum CGI_STATUS { CGI_PARSE, CGI_BUFFER, CGI_DONE }; 91 | 92 | /************** CGI TYPE (req->is_cgi) ******************/ 93 | enum CGI_TYPE { NPH = 1, CGI }; 94 | 95 | /**************** STRUCTURES ****************************/ 96 | struct range { 97 | unsigned long start; 98 | unsigned long stop; 99 | struct range *next; 100 | }; 101 | 102 | typedef struct range Range; 103 | 104 | struct mmap_entry { 105 | dev_t dev; 106 | ino_t ino; 107 | char *mmap; 108 | int use_count; 109 | off_t len; 110 | }; 111 | 112 | struct request { /* pending requests */ 113 | enum REQ_STATUS status; 114 | enum KA_STATUS keepalive; /* keepalive status */ 115 | enum HTTP_VERSION http_version; 116 | enum HTTP_METHOD method; /* M_GET, M_POST, etc. */ 117 | enum RESPONSE_CODE response_status; /* R_NOT_FOUND, etc.. */ 118 | 119 | enum CGI_TYPE cgi_type; 120 | enum CGI_STATUS cgi_status; 121 | 122 | /* should pollfd_id be zeroable or no ? */ 123 | #ifdef HAVE_POLL 124 | int pollfd_id; 125 | #endif 126 | 127 | char *pathname; /* pathname of requested file */ 128 | 129 | Range *ranges; /* our Ranges */ 130 | int numranges; 131 | 132 | int data_fd; /* fd of data */ 133 | off_t filesize; /* filesize */ 134 | off_t filepos; /* position in file */ 135 | size_t bytes_written; /* total bytes written (sans header) */ 136 | char *data_mem; /* mmapped/malloced char array */ 137 | 138 | char *logline; /* line to log file */ 139 | 140 | char *header_line; /* beginning of un or incompletely processed header line */ 141 | char *header_end; /* last known end of header, or end of processed data */ 142 | int parse_pos; /* how much have we parsed */ 143 | 144 | int buffer_start; /* where the buffer starts */ 145 | int buffer_end; /* where the buffer ends */ 146 | 147 | char *if_modified_since; /* If-Modified-Since */ 148 | time_t last_modified; /* Last-modified: */ 149 | 150 | /* CGI vars */ 151 | int cgi_env_index; /* index into array */ 152 | 153 | /* Agent and referer for logfiles */ 154 | char *header_host; 155 | char *header_user_agent; 156 | char *header_referer; 157 | char *header_ifrange; 158 | char *header_forwarded_for; /* X-Forwarded-For or NULL. */ 159 | char *host; /* what we end up using for 'host', no matter the contents of header_host */ 160 | 161 | int post_data_fd; /* fd for post data tmpfile */ 162 | 163 | char *path_info; /* env variable */ 164 | char *path_translated; /* env variable */ 165 | char *script_name; /* env variable */ 166 | char *query_string; /* env variable */ 167 | char *content_type; /* env variable */ 168 | char *content_length; /* env variable */ 169 | 170 | struct mmap_entry *mmap_entry_var; 171 | 172 | /* everything **above** this line is zeroed in sanitize_request */ 173 | /* this may include 'fd' */ 174 | /* in sanitize_request with the 'new' parameter set to 1, 175 | * kacount is set to ka_max and client_stream_pos is also zeroed. 176 | * Also, time_last is set to 'NOW' 177 | */ 178 | int fd; /* client's socket fd */ 179 | time_t time_last; /* time of last succ. op. */ 180 | char local_ip_addr[BOA_NI_MAXHOST]; /* for virtualhost */ 181 | char remote_ip_addr[BOA_NI_MAXHOST]; /* after inet_ntoa */ 182 | unsigned int remote_port; /* could be used for ident */ 183 | 184 | unsigned int kacount; /* keepalive count */ 185 | int client_stream_pos; /* how much have we read... */ 186 | 187 | /* everything below this line is kept regardless */ 188 | char buffer[BUFFER_SIZE + 1]; /* generic I/O buffer */ 189 | char request_uri[MAX_HEADER_LENGTH + 1]; /* uri */ 190 | char client_stream[CLIENT_STREAM_SIZE]; /* data from client - fit or be hosed */ 191 | char *cgi_env[CGI_ENV_MAX + 4]; /* CGI environment */ 192 | 193 | #ifdef ACCEPT_ON 194 | char accept[MAX_ACCEPT_LENGTH]; /* Accept: fields */ 195 | #endif 196 | 197 | struct request *next; /* next */ 198 | struct request *prev; /* previous */ 199 | }; 200 | 201 | typedef struct request request; 202 | 203 | struct status { 204 | long requests; 205 | long errors; 206 | }; 207 | 208 | extern struct status status; 209 | 210 | extern char *optarg; /* For getopt */ 211 | 212 | extern request *request_ready; /* first in ready list */ 213 | extern request *request_block; /* first in blocked list */ 214 | extern request *request_free; /* first in free list */ 215 | 216 | #ifdef HAVE_POLL 217 | extern struct pollfd *pfds; 218 | extern unsigned int pfd_len; 219 | #else 220 | extern fd_set block_read_fdset; /* fds blocked on read */ 221 | extern fd_set block_write_fdset; /* fds blocked on write */ 222 | extern int max_fd; 223 | #endif 224 | 225 | /* global server variables */ 226 | 227 | extern char *access_log_name; 228 | extern char *error_log_name; 229 | extern char *cgi_log_name; 230 | extern int cgi_log_fd; 231 | extern int use_localtime; 232 | extern int log_forwarded_for; 233 | 234 | extern unsigned int server_port; 235 | extern uid_t server_uid; 236 | extern gid_t server_gid; 237 | extern char *server_admin; 238 | extern char *server_root; 239 | extern char *server_name; 240 | extern char *server_ip; 241 | 242 | extern char *document_root; 243 | extern char *user_dir; 244 | extern char *directory_index; 245 | extern char *default_type; 246 | extern char *default_charset; 247 | extern char *dirmaker; 248 | extern char *mime_types; 249 | extern char *pid_file; 250 | extern char *cachedir; 251 | 252 | extern const char *tempdir; 253 | 254 | extern char *cgi_path; 255 | extern short common_cgi_env_count; 256 | extern int single_post_limit; 257 | extern int conceal_server_identity; 258 | 259 | extern int ka_timeout; 260 | extern int unsigned default_timeout; 261 | extern int unsigned ka_max; 262 | 263 | extern int sighup_flag; 264 | extern int sigchld_flag; 265 | extern int sigalrm_flag; 266 | extern int sigterm_flag; 267 | extern time_t start_time; 268 | 269 | extern int pending_requests; 270 | extern unsigned max_connections; 271 | 272 | extern int verbose_cgi_logs; 273 | 274 | extern int backlog; 275 | extern time_t current_time; 276 | 277 | extern int virtualhost; 278 | extern char *vhost_root; 279 | extern const char *default_vhost; 280 | extern int use_lang_rewrite; 281 | extern int use_caudium_hack; 282 | extern char *hsts_header; 283 | extern int no_redirect_port; 284 | 285 | extern unsigned total_connections; 286 | extern unsigned int system_bufsize; /* Default size of SNDBUF given by system */ 287 | 288 | extern sigjmp_buf env; 289 | extern int handle_sigbus; 290 | extern unsigned int cgi_umask; 291 | 292 | #endif 293 | -------------------------------------------------------------------------------- /src/ip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1999 Larry Doolittle 4 | * Copyright (C) 2000-2003 Jon Nelson 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 1, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | * 21 | 22 | Encapsulation of ipv4 and ipv6 stuff, try to get rid of the ifdef's 23 | elsewhere in the code. 24 | 25 | The IPv6 code here is based on contributions from Martin Hinner 26 | and Arkadiusz Miskiewicz . This incarnation of that 27 | code is untested. The original IPv4 code is based on original Boa code 28 | from Paul Phillips . 29 | 30 | A goal is to compile in as many families as are supported, and 31 | make the final choice at runtime. 32 | 33 | globals.h: 34 | #ifdef INET6 35 | char remote_ip_addr[BOA_NI_MAXHOST]; 36 | #else 37 | char remote_ip_addr[20]; after inet_ntoa 38 | #endif 39 | 40 | None of this code interacts with the rest of Boa except through 41 | the parameter lists and return values. 42 | 43 | Consider making these functions __inline__ and using this as a .h file 44 | */ 45 | 46 | #include "boa.h" 47 | #include /* inet_ntoa */ 48 | 49 | /* Binds to the existing server_s, based on the configuration string 50 | in server_ip. IPv6 version doesn't pay attention to server_ip yet. */ 51 | int bind_server(int sock, char *ip, unsigned int port) 52 | { 53 | #ifdef INET6 54 | struct sockaddr_in6 server_sockaddr; 55 | server_sockaddr.sin6_family = PF_INET6; 56 | memcpy(&server_sockaddr.sin6_addr, &in6addr_any, sizeof (in6addr_any)); 57 | server_sockaddr.sin6_port = htons(server_port); 58 | #else 59 | struct sockaddr_in server_sockaddr; 60 | memset(&server_sockaddr, 0, sizeof server_sockaddr); 61 | #ifdef HAVE_SIN_LEN /* uncomment for BSDs */ 62 | server_sockaddr.sin_len = sizeof server_sockaddr; 63 | #endif 64 | server_sockaddr.sin_family = PF_INET; 65 | if (ip != NULL) { 66 | #ifdef HAVE_INET_ATON 67 | inet_aton(ip, &server_sockaddr.sin_addr); 68 | #elif defined HAVE_INET_ADDR 69 | server_sockaddr.sin_addr.s_addr = inet_addr(ip); 70 | #else 71 | #error "Neither inet_aton nor inet_addr exist!" 72 | #endif 73 | } else { 74 | server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); 75 | } 76 | server_sockaddr.sin_port = htons(port); 77 | #endif 78 | 79 | return bind(sock, (struct sockaddr *) &server_sockaddr, 80 | sizeof (server_sockaddr)); 81 | } 82 | 83 | char *ascii_sockaddr(struct SOCKADDR *s, char *dest, unsigned int len) 84 | { 85 | #ifdef INET6 86 | if (getnameinfo((struct sockaddr *) s, 87 | sizeof (struct SOCKADDR), 88 | dest, len, NULL, 0, NI_NUMERICHOST)) { 89 | fprintf(stderr, "[IPv6] getnameinfo failed\n"); 90 | *dest = '\0'; 91 | } 92 | #ifdef WHEN_DOES_THIS_APPLY 93 | #error Dont use memmove 94 | if ((s->__ss_family == PF_INET6) && 95 | IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *) s)->sin6_addr))) { 96 | #error The following two lines are broken 97 | memmove(dest, dest + 7, BOA_NI_MAXHOST); 98 | dest[BOA_NI_MAXHOST] = '\0'; 99 | } 100 | #endif /* ifdef WHEN_DOES_THIS_APPLY */ 101 | #else /* ifdef INET6 */ 102 | unsigned int newlen; 103 | char *buf; 104 | 105 | /* memmove(dest, inet_ntoa(s->sin_addr), len); */ 106 | buf = inet_ntoa(s->sin_addr); 107 | newlen = strlen(buf); 108 | /* we need newlen + 1 byte to be <= len, thus 109 | * newlen <= len - 1 is good 110 | * and newlen > len -1 is bad thus 111 | * newlen + 1 > len ==== newlen >= len 112 | */ 113 | if (newlen + 1 > len) { /* too many bytes incl. the NUL */ 114 | return NULL; 115 | } 116 | memcpy(dest, buf, newlen); 117 | dest[newlen] = '\0'; 118 | #endif /* ifdef INET6 */ 119 | return dest; 120 | } 121 | 122 | int net_port(struct SOCKADDR *s) 123 | { 124 | int p = -1; 125 | #ifdef INET6 126 | char serv[NI_MAXSERV]; 127 | 128 | if (getnameinfo((struct sockaddr *) s, 129 | sizeof (struct SOCKADDR), 130 | NULL, 0, serv, sizeof (serv), NI_NUMERICSERV)) { 131 | fprintf(stderr, "[IPv6] getnameinfo failed\n"); 132 | } else { 133 | p = atoi(serv); 134 | } 135 | #else 136 | p = ntohs(s->sin_port); 137 | #endif 138 | return p; 139 | } 140 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1996-1999 Larry Doolittle 5 | * Copyright (C) 1999-2004 Jon Nelson 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 1, or (at your option) 10 | * any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | * 21 | */ 22 | 23 | /* $Id: log.c,v 1.36.2.27 2005/02/22 14:11:29 jnelson Exp $*/ 24 | 25 | #include "boa.h" 26 | 27 | int cgi_log_fd; 28 | 29 | /* 30 | * Name: open_logs 31 | * 32 | * Description: Opens access log, error log, and if specified, CGI log 33 | * Ties stderr to error log, except during CGI execution, at which 34 | * time CGI log is the stderr for CGIs. 35 | * 36 | * Access log is line buffered, error log is not buffered. 37 | * 38 | */ 39 | 40 | void open_logs(void) 41 | { 42 | int access_log; 43 | 44 | /* if error_log_name is set, dup2 stderr to it */ 45 | /* otherwise, leave stderr alone */ 46 | /* we don't want to tie stderr to /dev/null */ 47 | if (error_log_name) { 48 | int error_log; 49 | 50 | /* open the log file */ 51 | error_log = open_gen_fd(error_log_name); 52 | if (error_log < 0) { 53 | DIE("unable to open error log"); 54 | } 55 | 56 | /* redirect stderr to error_log */ 57 | if (dup2(error_log, STDERR_FILENO) == -1) { 58 | DIE("unable to dup2 the error log"); 59 | } 60 | close(error_log); 61 | } 62 | 63 | if (access_log_name) { 64 | access_log = open_gen_fd(access_log_name); 65 | } else { 66 | access_log = open("/dev/null", 0); 67 | } 68 | if (access_log < 0) { 69 | DIE("unable to open access log"); 70 | } 71 | 72 | if (dup2(access_log, STDOUT_FILENO) == -1) { 73 | DIE("can't dup2 /dev/null to STDOUT_FILENO"); 74 | } 75 | if (fcntl(access_log, F_SETFD, 1) == -1) { 76 | DIE("unable to set close-on-exec flag for access_log"); 77 | } 78 | 79 | close(access_log); 80 | 81 | if (cgi_log_name) { 82 | cgi_log_fd = open_gen_fd(cgi_log_name); 83 | if (cgi_log_fd == -1) { 84 | WARN("open cgi_log"); 85 | free(cgi_log_name); 86 | cgi_log_name = NULL; 87 | cgi_log_fd = 0; 88 | } else { 89 | if (fcntl(cgi_log_fd, F_SETFD, 1) == -1) { 90 | WARN("unable to set close-on-exec flag for cgi_log"); 91 | free(cgi_log_name); 92 | cgi_log_name = NULL; 93 | close(cgi_log_fd); 94 | cgi_log_fd = 0; 95 | } 96 | } 97 | } 98 | #ifdef SETVBUF_REVERSED 99 | setvbuf(stderr, _IONBF, (char *) NULL, 0); 100 | setvbuf(stdout, _IOLBF, (char *) NULL, 0); 101 | #else 102 | setvbuf(stderr, (char *) NULL, _IONBF, 0); 103 | setvbuf(stdout, (char *) NULL, _IOLBF, 0); 104 | #endif 105 | } 106 | 107 | 108 | /* Print the remote IP to the stream FP. */ 109 | static void 110 | print_remote_ip (request * req, FILE *fp) 111 | { 112 | if (log_forwarded_for) { 113 | const char *s = req->header_forwarded_for; 114 | if (s && *s) { 115 | for (; *s; s++) { 116 | /* Take extra care not to write bogus characters. In 117 | particular no spaces. We know that only IP addresses 118 | and a comma are allowed in the XFF header. */ 119 | if (strchr ("0123456789.abcdef:ABCDEF,", *s)) 120 | putc (*s, fp); 121 | else 122 | putc ('_', fp); 123 | } 124 | } 125 | else /* Missing - print remote IP in parenthesis. */ 126 | fprintf (fp, "(%s)", req->remote_ip_addr); 127 | } 128 | else 129 | fputs (req->remote_ip_addr, fp); 130 | } 131 | 132 | 133 | /* 134 | * Name: log_access 135 | * 136 | * Description: Writes log data to access_log. 137 | */ 138 | 139 | /* NOTES on the commonlog format: 140 | * Taken from notes on the NetBuddy program 141 | * http://www.computer-dynamics.com/commonlog.html 142 | 143 | remotehost 144 | 145 | remotehost rfc931 authuser [date] "request" status bytes 146 | 147 | remotehost - IP of the client 148 | rfc931 - remote name of the user (always '-') 149 | authuser - username entered for authentication - almost always '-' 150 | [date] - the date in [08/Nov/1997:01:05:03 -0600] (with brackets) format 151 | "request" - literal request from the client (boa may clean this up, 152 | replacing control-characters with '_' perhaps - NOTE: not done) 153 | status - http status code 154 | bytes - number of bytes transferred 155 | 156 | boa appends: 157 | referer 158 | user-agent 159 | 160 | and may prepend (depending on configuration): 161 | virtualhost - the name or IP (depending on whether name-based 162 | virtualhosting is enabled) of the host the client accessed 163 | */ 164 | 165 | void log_access(request * req) 166 | { 167 | if (!access_log_name) 168 | return; 169 | 170 | if (virtualhost) { 171 | printf("%s ", req->local_ip_addr); 172 | } else if (vhost_root) { 173 | printf("%s ", (req->host ? req->host : "(null)")); 174 | } 175 | print_remote_ip (req, stdout); 176 | printf(" - - %s\"%s\" %d %zu \"%s\" \"%s\"\n", 177 | get_commonlog_time(), 178 | req->logline ? req->logline : "-", 179 | req->response_status, 180 | req->bytes_written, 181 | (req->header_referer ? req->header_referer : "-"), 182 | (req->header_user_agent ? req->header_user_agent : "-")); 183 | } 184 | 185 | static char *escape_pathname(const char *inp) 186 | { 187 | const unsigned char *s; 188 | char *escaped, *d; 189 | 190 | if (!inp) { 191 | return NULL; 192 | } 193 | escaped = malloc (4 * strlen(inp) + 1); 194 | if (!escaped) { 195 | perror("malloc"); 196 | return NULL; 197 | } 198 | for (d = escaped, s = (const unsigned char *)inp; *s; s++) { 199 | if (needs_escape (*s)) { 200 | snprintf (d, 5, "\\x%02x", *s); 201 | d += strlen (d); 202 | } else { 203 | *d++ = *s; 204 | } 205 | } 206 | *d++ = '\0'; 207 | return escaped; 208 | } 209 | 210 | /* 211 | * Name: log_error_doc 212 | * 213 | * Description: Logs the current time and transaction identification 214 | * to the stderr (the error log): 215 | * should always be followed by an fprintf to stderr 216 | * 217 | * Example output: 218 | [08/Nov/1997:01:05:03 -0600] request from 192.228.331.232 "GET /~joeblow/dir/ HTTP/1.0" ("/usr/user1/joeblow/public_html/dir/"): write: Broken pipe 219 | 220 | Apache uses: 221 | [Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1] client denied by server configuration: /export/home/live/ap/htdocs/test 222 | */ 223 | 224 | void log_error_doc(request * req) 225 | { 226 | int errno_save = errno; 227 | char *escaped_pathname; 228 | 229 | if (virtualhost) { 230 | fprintf(stderr, "%s ", req->local_ip_addr); 231 | } else if (vhost_root) { 232 | fprintf(stderr, "%s ", (req->host ? req->host : "(null)")); 233 | } 234 | escaped_pathname = escape_pathname(req->pathname); 235 | print_remote_ip (req, stderr); 236 | if (vhost_root) { 237 | fprintf(stderr, " - - %srequest [%s] \"%s\" (\"%s\"): ", 238 | get_commonlog_time(), 239 | (req->header_host ? req->header_host : "(null)"), 240 | (req->logline ? req->logline : "(null)"), 241 | (escaped_pathname ? escaped_pathname : "(null)")); 242 | } else { 243 | fprintf(stderr, " - - %srequest \"%s\" (\"%s\"): ", 244 | get_commonlog_time(), 245 | (req->logline ? req->logline : "(null)"), 246 | (escaped_pathname ? escaped_pathname : "(null)")); 247 | } 248 | free(escaped_pathname); 249 | 250 | errno = errno_save; 251 | } 252 | 253 | /* 254 | * Name: boa_perror 255 | * 256 | * Description: logs an error to user and error file both 257 | * 258 | */ 259 | void boa_perror(request * req, const char *message) 260 | { 261 | log_error_doc(req); 262 | perror(message); /* don't need to save errno because log_error_doc does */ 263 | send_r_error(req); 264 | } 265 | 266 | /* 267 | * Name: log_error_time 268 | * 269 | * Description: Logs the current time to the stderr (the error log): 270 | * should always be followed by an fprintf to stderr 271 | */ 272 | 273 | void log_error_time(void) 274 | { 275 | int errno_save = errno; 276 | fputs(get_commonlog_time(), stderr); 277 | errno = errno_save; 278 | } 279 | 280 | /* 281 | * Name: log_error 282 | * 283 | * Description: performs a log_error_time and writes a message to stderr 284 | * 285 | */ 286 | 287 | void log_error(const char *mesg) 288 | { 289 | fprintf(stderr, "%s%s", get_commonlog_time(), mesg); 290 | } 291 | 292 | /* 293 | * Name: log_error_mesg 294 | * 295 | * Description: performs a log_error_time, writes the file and lineno 296 | * to stderr (saving errno), and then a perror with message 297 | * 298 | */ 299 | 300 | #ifdef HAVE_FUNC 301 | void log_error_mesg(const char *file, int line, const char *func, const char *mesg) 302 | { 303 | int errno_save = errno; 304 | fprintf(stderr, "%s%s:%d (%s) - ", get_commonlog_time(), file, line, func); 305 | errno = errno_save; 306 | perror(mesg); 307 | errno = errno_save; 308 | } 309 | 310 | void log_error_mesg_fatal(const char *file, int line, const char *func, const char *mesg) 311 | { 312 | int errno_save = errno; 313 | fprintf(stderr, "%s%s:%d (%s) - ", get_commonlog_time(), file, line, func); 314 | errno = errno_save; 315 | perror(mesg); 316 | exit(EXIT_FAILURE); 317 | } 318 | 319 | 320 | #else 321 | void log_error_mesg(const char *file, int line, const char *mesg) 322 | { 323 | int errno_save = errno; 324 | fprintf(stderr, "%s%s:%d - ", get_commonlog_time(), file, line); 325 | errno = errno_save; 326 | perror(mesg); 327 | errno = errno_save; 328 | } 329 | 330 | void log_error_mesg_fatal(const char *file, int line, const char *mesg) 331 | { 332 | int errno_save = errno; 333 | fprintf(stderr, "%s%s:%d - ", get_commonlog_time(), file, line); 334 | errno = errno_save; 335 | perror(mesg); 336 | exit(EXIT_FAILURE); 337 | } 338 | #endif 339 | -------------------------------------------------------------------------------- /src/mmap_cache.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1999-2005 Larry Doolittle 4 | * Copyright (C) 2000-2004 Jon Nelson 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 1, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | 22 | /* $Id: mmap_cache.c,v 1.9.2.9 2005/02/22 14:11:29 jnelson Exp $*/ 23 | 24 | #include "boa.h" 25 | 26 | static int mmap_list_entries_used = 0; 27 | static int mmap_list_total_requests = 0; 28 | static int mmap_list_hash_bounces = 0; 29 | 30 | #define MMAP_LIST_NEXT(i) (((i)+1)&MMAP_LIST_MASK) 31 | #define MMAP_LIST_HASH(dev,ino,size) ((ino)&MMAP_LIST_MASK) 32 | 33 | /* define local table variable */ 34 | static struct mmap_entry mmap_list[MMAP_LIST_SIZE]; 35 | 36 | struct mmap_entry *find_mmap(int data_fd, struct stat *s) 37 | { 38 | void *m; 39 | int i, start; 40 | mmap_list_total_requests++; 41 | i = start = MMAP_LIST_HASH(s->st_dev, s->st_ino, s->st_size); 42 | for (; mmap_list[i].use_count;) { 43 | if (mmap_list[i].dev == s->st_dev && 44 | mmap_list[i].ino == s->st_ino && 45 | mmap_list[i].len == s->st_size) { 46 | mmap_list[i].use_count++; 47 | DEBUG(DEBUG_MMAP_CACHE) { 48 | fprintf(stderr, 49 | "Old mmap_list entry %d use_count now %d (hash was %d)\n", 50 | i, mmap_list[i].use_count, start); 51 | } 52 | return mmap_list + i; 53 | } 54 | mmap_list_hash_bounces++; 55 | i = MMAP_LIST_NEXT(i); 56 | if (i == start) { 57 | /* didn't find an entry that matches our dev/inode/size. 58 | There might be an entry that matches later in the table, 59 | but that _should_ be rare. The worst case is that we 60 | needlessly mmap() a file that is already mmap'd, but we 61 | did that all the time before this code was written, 62 | so it shouldn't be _too_ bad. 63 | */ 64 | /* we've looped, and found neither a free one nor a 65 | * match. Thus, there is no room for a new entry. 66 | */ 67 | /* WARN("mmap hash table is full. Consider enlarging."); */ 68 | return NULL; 69 | } 70 | } 71 | 72 | /* Enforce a size limit here */ 73 | /* Disallow more entries than MMAP_LIST_USE_MAX, despite 74 | * having found an available slot. 75 | */ 76 | if (mmap_list_entries_used > MMAP_LIST_USE_MAX) { 77 | /* WARN("Too many entries in mmap hash table."); */ 78 | return NULL; 79 | } 80 | 81 | m = mmap(0, s->st_size, PROT_READ, MAP_OPTIONS, data_fd, 0); 82 | 83 | if ((long) m == -1) { 84 | int saved_errno = errno; 85 | log_error_time(); 86 | fprintf(stderr, "Unable to mmap file: "); 87 | errno = saved_errno; 88 | perror("mmap"); 89 | return NULL; 90 | } 91 | 92 | #ifdef HAVE_MADVISE 93 | { 94 | int mret; 95 | 96 | mret = madvise(m, s->st_size, MADV_SEQUENTIAL); 97 | if (mret == -1) { 98 | int saved_errno = errno; 99 | log_error_time(); 100 | fprintf(stderr, "Unable to madvise file: "); 101 | errno = saved_errno; 102 | perror("madvise"); 103 | munmap(m, s->st_size); 104 | return NULL; 105 | } 106 | } 107 | #endif 108 | 109 | DEBUG(DEBUG_MMAP_CACHE) { 110 | fprintf(stderr, "New mmap_list entry %d (hash was %d)\n", i, start); 111 | } 112 | mmap_list_entries_used++; 113 | mmap_list[i].dev = s->st_dev; 114 | mmap_list[i].ino = s->st_ino; 115 | mmap_list[i].len = s->st_size; 116 | mmap_list[i].mmap = m; 117 | mmap_list[i].use_count = 1; 118 | return mmap_list + i; 119 | } 120 | 121 | void release_mmap(struct mmap_entry *e) 122 | { 123 | if (!e) 124 | return; 125 | if (!e->use_count) { 126 | DEBUG(DEBUG_MMAP_CACHE) { 127 | fprintf(stderr, "mmap_list(%p)->use_count already zero!\n", (void *) e); 128 | } 129 | return; 130 | } 131 | if (!--(e->use_count)) { 132 | munmap(e->mmap, e->len); 133 | mmap_list_entries_used--; 134 | } 135 | } 136 | 137 | #if 0 138 | static struct mmap_entry *find_named_mmap(char *fname) 139 | { 140 | int data_fd; 141 | struct stat statbuf; 142 | struct mmap_entry *e; 143 | data_fd = open(fname, O_RDONLY|O_LARGEFILE); 144 | if (data_fd == -1) { 145 | perror(fname); 146 | return NULL; 147 | } 148 | fstat(data_fd, &statbuf); 149 | if (S_ISDIR(statbuf.st_mode)) { 150 | #ifdef DEBUG 151 | fprintf(stderr, "%s is a directory\n", fname); 152 | #endif 153 | return NULL; 154 | } 155 | 156 | e = find_mmap(data_fd, &statbuf); 157 | close(data_fd); 158 | return e; 159 | } 160 | #endif 161 | 162 | /* 163 | int main(int argc, char *argv[]) 164 | { 165 | #define MAXTEST 2048 166 | struct mmap_entry *mlist[MAXTEST]; 167 | char name[1024], *s; 168 | int i, tests=0; 169 | while (fgets(name,sizeof(name),stdin) && tests < MAXTEST) { 170 | if (name[0]=='-') { 171 | i=atoi(name+1); 172 | release_mmap(mlist[i]); 173 | mlist[i]=NULL; 174 | } else { 175 | if ((s=strchr(name,'\n'))) *s='\0'; 176 | mlist[tests] = find_named_mmap(name); 177 | if (mlist[tests]) tests++; 178 | else fprintf(stderr, "find_named_mmap(%s) failed\n",name); 179 | } 180 | } 181 | fprintf(stderr, "mmap_list entries_used=%d ",mmap_list_entries_used); 182 | fprintf(stderr, "total_requests=%d ",mmap_list_total_requests); 183 | fprintf(stderr, "hash_bounces=%d\n",mmap_list_hash_bounces); 184 | for (i=0; i 4 | * Some changes Copyright (C) 1996 Charles F. Randall 5 | * Copyright (C) 1996-1999 Larry Doolittle 6 | * Copyright (C) 1996-2004 Jon Nelson 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 1, or (at your option) 11 | * any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /* $Id: poll.c,v 1.2.2.18 2005/02/22 14:11:29 jnelson Exp $*/ 25 | 26 | #include "boa.h" 27 | 28 | void update_blocked(struct pollfd pfd1[]); 29 | 30 | struct pollfd *pfds; 31 | unsigned int pfd_len; 32 | 33 | void loop(int server_s) 34 | { 35 | struct pollfd pfd1[2][MAX_FD]; 36 | short which = 0, other = 1, temp; 37 | int server_pfd, watch_server; 38 | 39 | pfds = pfd1[which]; 40 | pfd_len = server_pfd = 0; 41 | watch_server = 1; 42 | 43 | while (1) { 44 | int timeout; 45 | 46 | time(¤t_time); 47 | 48 | if (sighup_flag) 49 | sighup_run(); 50 | if (sigchld_flag) 51 | sigchld_run(); 52 | if (sigalrm_flag) 53 | sigalrm_run(); 54 | 55 | if (sigterm_flag) { 56 | if (sigterm_flag == 1) { 57 | sigterm_stage1_run(); 58 | close(server_s); 59 | server_s = -1; 60 | /* remove server_pfd */ 61 | { 62 | unsigned int i, j; 63 | 64 | for(i = 0, j = 0;i < pfd_len;++i) { 65 | if (i == (unsigned) server_pfd) 66 | continue; 67 | pfd1[other][j].fd = pfd1[which][j].fd; 68 | pfd1[other][j].events = pfd1[which][j].events; 69 | ++j; 70 | } 71 | pfd_len = j; 72 | pfds = pfd1[other]; 73 | temp = other; 74 | other = which; 75 | which = temp; 76 | } 77 | watch_server = 0; 78 | } 79 | if (sigterm_flag == 2 && !request_ready && !request_block) { 80 | sigterm_stage2_run(); 81 | } 82 | } else { 83 | if (total_connections < max_connections) { 84 | server_pfd = pfd_len++; 85 | pfds[server_pfd].fd = server_s; 86 | pfds[server_pfd].events = BOA_READ; 87 | watch_server = 1; 88 | } else { 89 | watch_server = 0; 90 | } 91 | } 92 | 93 | /* If there are any requests ready, the timeout is 0. 94 | * If not, and there are any requests blocking, the 95 | * timeout is ka_timeout ? ka_timeout * 1000, otherwise 96 | * REQUEST_TIMEOUT * 1000. 97 | * -1 means forever 98 | */ 99 | pending_requests = 0; 100 | if (pfd_len) { 101 | timeout = (request_ready ? 0 : 102 | (request_block ? default_timeout : -1)); 103 | 104 | if (poll(pfds, pfd_len, timeout) == -1) { 105 | if (errno == EINTR) 106 | continue; /* while(1) */ 107 | } 108 | if (!sigterm_flag && watch_server) { 109 | /* */ 110 | if (pfds[server_pfd].revents & 111 | (POLLNVAL|POLLERR)) { 112 | /* problem with the server socket, unexpected */ 113 | log_error("server pfd revent contains " 114 | "POLLNVAL or POLLERR! Exiting."); 115 | exit(EXIT_FAILURE); 116 | } else if (pfds[server_pfd].revents & BOA_READ) { 117 | pending_requests = 1; 118 | } 119 | } 120 | time(¤t_time); 121 | /* if pfd_len is 0, we didn't poll, so the current time 122 | * should be up-to-date, and we *won't* be accepting anyway 123 | */ 124 | } 125 | 126 | /* go through blocked and unblock them if possible */ 127 | /* also resets pfd_len and pfd to known blocked */ 128 | pfd_len = 0; 129 | if (request_block) { 130 | update_blocked(pfd1[other]); 131 | } 132 | 133 | /* swap pfd */ 134 | pfds = pfd1[other]; 135 | temp = other; 136 | other = which; 137 | which = temp; 138 | 139 | /* process any active requests */ 140 | process_requests(server_s); 141 | } 142 | } 143 | 144 | /* 145 | * Name: update_blocked 146 | * 147 | * Description: iterate through the blocked requests, checking whether 148 | * that file descriptor has been set by select. Update the fd_set to 149 | * reflect current status. 150 | * 151 | * Here, we need to do some things: 152 | * - keepalive timeouts simply close 153 | * (this is special:: a keepalive timeout is a timeout where 154 | * keepalive is active but nothing has been read yet) 155 | * - regular timeouts close + error 156 | * - stuff in buffer and fd ready? write it out 157 | * - fd ready for other actions? do them 158 | */ 159 | 160 | void update_blocked(struct pollfd pfd1[]) 161 | { 162 | request *current, *next = NULL; 163 | time_t time_since; 164 | int revents; 165 | 166 | time(¤t_time); 167 | for (current = request_block; current; current = next) { 168 | time_since = current_time - current->time_last; 169 | next = current->next; 170 | 171 | // FIXME:: the first below has the chance of leaking memory! 172 | // (setting status to DEAD not DONE....) 173 | /* hmm, what if we are in "the middle" of a request and not 174 | * just waiting for a new one... perhaps check to see if anything 175 | * has been read via header position, etc... */ 176 | revents = pfds[current->pollfd_id].revents; 177 | if (revents & (POLLNVAL|POLLERR)) { 178 | /* socket returned error */ 179 | log_error_time(); 180 | fprintf(stderr, "Socket %d returned " 181 | "POLLNVAL|POLLERR (%s%s) ", 182 | current->fd, 183 | revents & POLLNVAL ? "POLLNVAL ":"", 184 | revents & POLLERR ? "POLLERR ":""); 185 | current->status = DEAD; 186 | } else if (time_since > REQUEST_TIMEOUT) { 187 | log_error_doc(current); 188 | fputs("connection timed out\n", stderr); 189 | current->status = TIMED_OUT; /* connection timed out */ 190 | } else if (current->kacount < ka_max && /* we *are* in a keepalive */ 191 | (time_since >= ka_timeout) && /* ka timeout has passed */ 192 | !current->logline) { /* haven't read anything yet */ 193 | log_error_doc(current); 194 | fputs("connection timed out\n", stderr); 195 | current->status = TIMED_OUT; /* connection timed out */ 196 | } else if (revents == 0) { /* still blocked */ 197 | pfd1[pfd_len].fd = pfds[current->pollfd_id].fd; 198 | pfd1[pfd_len].events = pfds[current->pollfd_id].events; 199 | current->pollfd_id = pfd_len++; 200 | continue; 201 | } 202 | ready_request(current); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1997-2002 Jon Nelson 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 1, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | 22 | /* $Id: queue.c,v 1.21.2.4 2005/02/22 14:11:29 jnelson Exp $*/ 23 | 24 | #include "boa.h" 25 | 26 | request *request_ready = NULL; /* ready list head */ 27 | request *request_block = NULL; /* blocked list head */ 28 | request *request_free = NULL; /* free list head */ 29 | 30 | /* 31 | * Name: block_request 32 | * 33 | * Description: Moves a request from the ready queue to the blocked queue 34 | */ 35 | 36 | void block_request(request * req) 37 | { 38 | dequeue(&request_ready, req); 39 | enqueue(&request_block, req); 40 | 41 | if (req->buffer_end) { 42 | BOA_FD_SET(req, req->fd, BOA_WRITE); 43 | } else { 44 | switch (req->status) { 45 | case IOSHUFFLE: 46 | #ifndef HAVE_SENDFILE 47 | if (req->buffer_end - req->buffer_start == 0) { 48 | BOA_FD_SET(req, req->data_fd, BOA_READ); 49 | break; 50 | } 51 | #endif 52 | case WRITE: 53 | case PIPE_WRITE: 54 | case DONE: 55 | BOA_FD_SET(req, req->fd, BOA_WRITE); 56 | break; 57 | case PIPE_READ: 58 | BOA_FD_SET(req, req->data_fd, BOA_READ); 59 | break; 60 | case BODY_WRITE: 61 | BOA_FD_SET(req, req->post_data_fd, BOA_WRITE); 62 | break; 63 | default: 64 | BOA_FD_SET(req, req->fd, BOA_READ); 65 | break; 66 | } 67 | } 68 | } 69 | 70 | /* 71 | * Name: ready_request 72 | * 73 | * Description: Moves a request from the blocked queue to the ready queue 74 | */ 75 | 76 | void ready_request(request * req) 77 | { 78 | dequeue(&request_block, req); 79 | enqueue(&request_ready, req); 80 | 81 | if (req->buffer_end) { 82 | BOA_FD_CLR(req, req->fd, BOA_WRITE); 83 | } else { 84 | switch (req->status) { 85 | case IOSHUFFLE: 86 | #ifndef HAVE_SENDFILE 87 | if (req->buffer_end - req->buffer_start == 0) { 88 | BOA_FD_CLR(req, req->data_fd, BOA_READ); 89 | break; 90 | } 91 | #endif 92 | case WRITE: 93 | case PIPE_WRITE: 94 | case DONE: 95 | BOA_FD_CLR(req, req->fd, BOA_WRITE); 96 | break; 97 | case PIPE_READ: 98 | BOA_FD_CLR(req, req->data_fd, BOA_READ); 99 | break; 100 | case BODY_WRITE: 101 | BOA_FD_CLR(req, req->post_data_fd, BOA_WRITE); 102 | break; 103 | default: 104 | BOA_FD_CLR(req, req->fd, BOA_READ); 105 | } 106 | } 107 | } 108 | 109 | 110 | /* 111 | * Name: dequeue 112 | * 113 | * Description: Removes a request from its current queue 114 | */ 115 | 116 | void dequeue(request ** head, request * req) 117 | { 118 | if (*head == req) 119 | *head = req->next; 120 | 121 | if (req->prev) 122 | req->prev->next = req->next; 123 | if (req->next) 124 | req->next->prev = req->prev; 125 | 126 | req->next = NULL; 127 | req->prev = NULL; 128 | } 129 | 130 | /* 131 | * Name: enqueue 132 | * 133 | * Description: Adds a request to the head of a queue 134 | */ 135 | 136 | void enqueue(request ** head, request * req) 137 | { 138 | if (*head) 139 | (*head)->prev = req; /* previous head's prev is us */ 140 | 141 | req->next = *head; /* our next is previous head */ 142 | req->prev = NULL; /* first in list */ 143 | 144 | *head = req; /* now we are head */ 145 | } 146 | -------------------------------------------------------------------------------- /src/select.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Some changes Copyright (C) 1996 Charles F. Randall 5 | * Copyright (C) 1996-1999 Larry Doolittle 6 | * Copyright (C) 1996-2003 Jon Nelson 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 1, or (at your option) 11 | * any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /* $Id: select.c,v 1.1.2.17 2005/02/22 14:11:29 jnelson Exp $*/ 25 | 26 | /* algorithm: 27 | * handle any signals 28 | * if we still want to accept new connections, add the server to the 29 | * list. 30 | * if there are any blocked requests or the we are still accepting new 31 | * connections, determine appropriate timeout and select, then move 32 | * blocked requests back into the active list. 33 | * handle active connections 34 | * repeat 35 | */ 36 | 37 | 38 | 39 | #include "boa.h" 40 | 41 | static void fdset_update(void); 42 | fd_set block_read_fdset; 43 | fd_set block_write_fdset; 44 | int max_fd = 0; 45 | 46 | void loop(int server_s) 47 | { 48 | FD_ZERO(BOA_READ); 49 | FD_ZERO(BOA_WRITE); 50 | 51 | max_fd = -1; 52 | 53 | while (1) { 54 | /* handle signals here */ 55 | if (sighup_flag) 56 | sighup_run(); 57 | if (sigchld_flag) 58 | sigchld_run(); 59 | if (sigalrm_flag) 60 | sigalrm_run(); 61 | 62 | if (sigterm_flag) { 63 | /* sigterm_flag: 64 | * 1. caught, unprocessed. 65 | * 2. caught, stage 1 processed 66 | */ 67 | if (sigterm_flag == 1) { 68 | sigterm_stage1_run(); 69 | BOA_FD_CLR(req, server_s, BOA_READ); 70 | close(server_s); 71 | /* make sure the server isn't in the block list */ 72 | server_s = -1; 73 | } 74 | if (sigterm_flag == 2 && !request_ready && !request_block) { 75 | sigterm_stage2_run(); /* terminal */ 76 | } 77 | } else { 78 | if (total_connections > max_connections) { 79 | /* FIXME: for poll we don't subtract 20. why? */ 80 | BOA_FD_CLR(req, server_s, BOA_READ); 81 | } else { 82 | BOA_FD_SET(req, server_s, BOA_READ); /* server always set */ 83 | } 84 | } 85 | 86 | pending_requests = 0; 87 | /* max_fd is > 0 when something is blocked */ 88 | 89 | if (max_fd) { 90 | struct timeval req_timeout; /* timeval for select */ 91 | 92 | req_timeout.tv_sec = (request_ready ? 0 : default_timeout); 93 | req_timeout.tv_usec = 0l; /* reset timeout */ 94 | 95 | if (select(max_fd + 1, BOA_READ, 96 | BOA_WRITE, NULL, 97 | (request_ready || request_block ? 98 | &req_timeout : NULL)) == -1) { 99 | /* what is the appropriate thing to do here on EBADF */ 100 | if (errno == EINTR) 101 | continue; /* while(1) */ 102 | else if (errno != EBADF) { 103 | DIE("select"); 104 | } 105 | } 106 | /* FIXME: optimize for when select returns 0 (timeout). 107 | * Thus avoiding many operations in fdset_update 108 | * and others. 109 | */ 110 | if (!sigterm_flag && FD_ISSET(server_s, BOA_READ)) { 111 | pending_requests = 1; 112 | } 113 | time(¤t_time); /* for "new" requests if we've been in 114 | * select too long */ 115 | /* if we skip this section (for example, if max_fd == 0), 116 | * then we aren't listening anyway, so we can't accept 117 | * new conns. Don't worry about it. 118 | */ 119 | } 120 | 121 | /* reset max_fd */ 122 | max_fd = -1; 123 | 124 | if (request_block) { 125 | /* move selected req's from request_block to request_ready */ 126 | fdset_update(); 127 | } 128 | 129 | /* any blocked req's move from request_ready to request_block */ 130 | if (pending_requests || request_ready) { 131 | process_requests(server_s); 132 | } 133 | } 134 | } 135 | 136 | /* 137 | * Name: fdset_update 138 | * 139 | * Description: iterate through the blocked requests, checking whether 140 | * that file descriptor has been set by select. Update the fd_set to 141 | * reflect current status. 142 | * 143 | * Here, we need to do some things: 144 | * - keepalive timeouts simply close 145 | * (this is special:: a keepalive timeout is a timeout where 146 | keepalive is active but nothing has been read yet) 147 | * - regular timeouts close + error 148 | * - stuff in buffer and fd ready? write it out 149 | * - fd ready for other actions? do them 150 | */ 151 | 152 | static void fdset_update(void) 153 | { 154 | request *current, *next; 155 | 156 | time(¤t_time); 157 | for (current = request_block; current; current = next) { 158 | time_t time_since = current_time - current->time_last; 159 | next = current->next; 160 | 161 | /* hmm, what if we are in "the middle" of a request and not 162 | * just waiting for a new one... perhaps check to see if anything 163 | * has been read via header position, etc... */ 164 | if (current->kacount < ka_max && /* we *are* in a keepalive */ 165 | (time_since >= ka_timeout) && /* ka timeout */ 166 | !current->logline) { /* haven't read anything yet */ 167 | log_error_doc(current); 168 | fputs("connection timed out\n", stderr); 169 | current->status = TIMED_OUT; /* connection timed out */ 170 | } else if (time_since > REQUEST_TIMEOUT) { 171 | log_error_doc(current); 172 | fputs("connection timed out\n", stderr); 173 | current->status = TIMED_OUT; /* connection timed out */ 174 | } 175 | if (current->buffer_end && /* there is data to write */ 176 | current->status < DONE) { 177 | if (FD_ISSET(current->fd, BOA_WRITE)) 178 | ready_request(current); 179 | else { 180 | BOA_FD_SET(current, current->fd, BOA_WRITE); 181 | } 182 | } else { 183 | switch (current->status) { 184 | case IOSHUFFLE: 185 | #ifndef HAVE_SENDFILE 186 | if (current->buffer_end - current->buffer_start == 0) { 187 | if (FD_ISSET(current->data_fd, BOA_READ)) 188 | ready_request(current); 189 | break; 190 | } 191 | #endif 192 | case WRITE: 193 | case PIPE_WRITE: 194 | if (FD_ISSET(current->fd, BOA_WRITE)) 195 | ready_request(current); 196 | else { 197 | BOA_FD_SET(current, current->fd, BOA_WRITE); 198 | } 199 | break; 200 | case BODY_WRITE: 201 | if (FD_ISSET(current->post_data_fd, BOA_WRITE)) 202 | ready_request(current); 203 | else { 204 | BOA_FD_SET(current, current->post_data_fd, 205 | BOA_WRITE); 206 | } 207 | break; 208 | case PIPE_READ: 209 | if (FD_ISSET(current->data_fd, BOA_READ)) 210 | ready_request(current); 211 | else { 212 | BOA_FD_SET(current, current->data_fd, 213 | BOA_READ); 214 | } 215 | break; 216 | case DONE: 217 | if (FD_ISSET(current->fd, BOA_WRITE)) 218 | ready_request(current); 219 | else { 220 | BOA_FD_SET(current, current->fd, BOA_WRITE); 221 | } 222 | break; 223 | case TIMED_OUT: 224 | case DEAD: 225 | ready_request(current); 226 | break; 227 | default: 228 | if (FD_ISSET(current->fd, BOA_READ)) 229 | ready_request(current); 230 | else { 231 | BOA_FD_SET(current, current->fd, BOA_READ); 232 | } 233 | break; 234 | } 235 | } 236 | current = next; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/signals.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1995 Paul Phillips 4 | * Copyright (C) 1996-1999 Larry Doolittle 5 | * Copyright (C) 1996-2005 Jon Nelson 6 | * Some changes Copyright (C) 1997 Alain Magloire 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 1, or (at your option) 11 | * any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | */ 23 | 24 | /* $Id: signals.c,v 1.37.2.14 2005/02/22 14:11:29 jnelson Exp $*/ 25 | 26 | #include "boa.h" 27 | #ifdef HAVE_SYS_WAIT_H 28 | #include /* wait */ 29 | #endif 30 | #include /* signal */ 31 | 32 | sigjmp_buf env; 33 | int handle_sigbus; 34 | 35 | void sigsegv(int); 36 | void sigbus(int); 37 | void sigterm(int); 38 | void sighup(int); 39 | void sigint(int); 40 | void sigchld(int); 41 | void sigalrm(int); 42 | 43 | /* 44 | * Name: init_signals 45 | * Description: Sets up signal handlers for all our friends. 46 | */ 47 | 48 | void init_signals(void) 49 | { 50 | struct sigaction sa; 51 | 52 | sa.sa_flags = 0; 53 | 54 | sigemptyset(&sa.sa_mask); 55 | sigaddset(&sa.sa_mask, SIGSEGV); 56 | sigaddset(&sa.sa_mask, SIGBUS); 57 | sigaddset(&sa.sa_mask, SIGTERM); 58 | sigaddset(&sa.sa_mask, SIGHUP); 59 | sigaddset(&sa.sa_mask, SIGINT); 60 | sigaddset(&sa.sa_mask, SIGPIPE); 61 | sigaddset(&sa.sa_mask, SIGCHLD); 62 | sigaddset(&sa.sa_mask, SIGALRM); 63 | sigaddset(&sa.sa_mask, SIGUSR1); 64 | sigaddset(&sa.sa_mask, SIGUSR2); 65 | 66 | sa.sa_handler = sigsegv; 67 | sigaction(SIGSEGV, &sa, NULL); 68 | 69 | sa.sa_handler = sigbus; 70 | sigaction(SIGBUS, &sa, NULL); 71 | 72 | sa.sa_handler = sigterm; 73 | sigaction(SIGTERM, &sa, NULL); 74 | 75 | sa.sa_handler = sighup; 76 | sigaction(SIGHUP, &sa, NULL); 77 | 78 | sa.sa_handler = sigint; 79 | sigaction(SIGINT, &sa, NULL); 80 | 81 | sa.sa_handler = SIG_IGN; 82 | sigaction(SIGPIPE, &sa, NULL); 83 | 84 | sa.sa_handler = sigchld; 85 | sigaction(SIGCHLD, &sa, NULL); 86 | 87 | sa.sa_handler = sigalrm; 88 | sigaction(SIGALRM, &sa, NULL); 89 | 90 | sa.sa_handler = SIG_IGN; 91 | sigaction(SIGUSR1, &sa, NULL); 92 | 93 | sa.sa_handler = SIG_IGN; 94 | sigaction(SIGUSR2, &sa, NULL); 95 | } 96 | 97 | void reset_signals(void) 98 | { 99 | struct sigaction sa; 100 | 101 | sa.sa_flags = 0; 102 | sa.sa_handler = SIG_DFL; 103 | 104 | sigemptyset(&sa.sa_mask); 105 | sigaddset(&sa.sa_mask, SIGSEGV); 106 | sigaddset(&sa.sa_mask, SIGBUS); 107 | sigaddset(&sa.sa_mask, SIGTERM); 108 | sigaddset(&sa.sa_mask, SIGHUP); 109 | sigaddset(&sa.sa_mask, SIGINT); 110 | sigaddset(&sa.sa_mask, SIGPIPE); 111 | sigaddset(&sa.sa_mask, SIGCHLD); 112 | sigaddset(&sa.sa_mask, SIGALRM); 113 | sigaddset(&sa.sa_mask, SIGUSR1); 114 | sigaddset(&sa.sa_mask, SIGUSR2); 115 | 116 | sigaction(SIGSEGV, &sa, NULL); 117 | sigaction(SIGBUS, &sa, NULL); 118 | sigaction(SIGTERM, &sa, NULL); 119 | sigaction(SIGHUP, &sa, NULL); 120 | sigaction(SIGINT, &sa, NULL); 121 | sigaction(SIGPIPE, &sa, NULL); 122 | sigaction(SIGCHLD, &sa, NULL); 123 | sigaction(SIGALRM, &sa, NULL); 124 | sigaction(SIGUSR1, &sa, NULL); 125 | sigaction(SIGUSR2, &sa, NULL); 126 | } 127 | 128 | void sigsegv(int dummy) 129 | { 130 | time(¤t_time); 131 | log_error_time(); 132 | fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir); 133 | if (chdir(tempdir) == -1) 134 | perror ("chdir (tempdir) failed"); 135 | abort(); 136 | } 137 | 138 | extern sigjmp_buf env; 139 | extern int handle_sigbus; 140 | 141 | void sigbus(int dummy) 142 | { 143 | if (handle_sigbus) { 144 | longjmp(env, dummy); 145 | } 146 | time(¤t_time); 147 | log_error_time(); 148 | fprintf(stderr, "caught SIGBUS, dumping core in %s\n", tempdir); 149 | if (chdir (tempdir) == -1) 150 | perror ("chdir (tempdir) failed"); 151 | abort(); 152 | } 153 | 154 | void sigterm(int dummy) 155 | { 156 | if (!sigterm_flag) 157 | sigterm_flag = 1; 158 | } 159 | 160 | void sigterm_stage1_run(void) 161 | { /* lame duck mode */ 162 | time(¤t_time); 163 | log_error_time(); 164 | fputs("caught SIGTERM, starting shutdown\n", stderr); 165 | sigterm_flag = 2; 166 | } 167 | 168 | void sigterm_stage2_run(void) 169 | { /* lame duck mode */ 170 | log_error_time(); 171 | fprintf(stderr, 172 | "exiting Boa normally (uptime %d seconds)\n", 173 | (int) (current_time - start_time)); 174 | if (chdir(tempdir) == -1) 175 | perror ("chdir (tempdir) failed"); 176 | clear_common_env(); 177 | dump_mime(); 178 | dump_passwd(); 179 | dump_alias(); 180 | free_requests(); 181 | range_pool_empty(); 182 | free(server_root); 183 | free(server_name); 184 | server_root = NULL; 185 | exit(EXIT_SUCCESS); 186 | } 187 | 188 | 189 | void sighup(int dummy) 190 | { 191 | sighup_flag = 1; 192 | } 193 | 194 | void sighup_run(void) 195 | { 196 | sighup_flag = 0; 197 | time(¤t_time); 198 | log_error_time(); 199 | fputs("caught SIGHUP, restarting\n", stderr); 200 | 201 | /* Philosophy change for 0.92: don't close and attempt reopen of logfiles, 202 | * since usual permission structure prevents such reopening. 203 | */ 204 | 205 | /* why ? */ 206 | /* 207 | FD_ZERO(&block_read_fdset); 208 | FD_ZERO(&block_write_fdset); 209 | */ 210 | /* clear_common_env(); NEVER DO THIS */ 211 | dump_mime(); 212 | dump_passwd(); 213 | dump_alias(); 214 | free_requests(); 215 | range_pool_empty(); 216 | 217 | log_error_time(); 218 | fputs("re-reading configuration files\n", stderr); 219 | read_config_files(); 220 | 221 | log_error_time(); 222 | fputs("successful restart\n", stderr); 223 | } 224 | 225 | void sigint(int dummy) 226 | { 227 | time(¤t_time); 228 | log_error_time(); 229 | fputs("caught SIGINT: shutting down\n", stderr); 230 | if (chdir(tempdir) == -1) 231 | perror ("chdir (tempdir) failed"); 232 | exit(EXIT_FAILURE); 233 | } 234 | 235 | void sigchld(int dummy) 236 | { 237 | sigchld_flag = 1; 238 | } 239 | 240 | void sigchld_run(void) 241 | { 242 | int child_status; 243 | pid_t pid; 244 | 245 | sigchld_flag = 0; 246 | 247 | while ((pid = waitpid(-1, &child_status, WNOHANG)) > 0) 248 | if (verbose_cgi_logs) { 249 | time(¤t_time); 250 | log_error_time(); 251 | fprintf(stderr, "reaping child %d: status %d\n", (int) pid, 252 | child_status); 253 | } 254 | return; 255 | } 256 | 257 | void sigalrm(int dummy) 258 | { 259 | sigalrm_flag = 1; 260 | } 261 | 262 | void sigalrm_run(void) 263 | { 264 | time(¤t_time); 265 | log_error_time(); 266 | fprintf(stderr, "%ld requests, %ld errors\n", 267 | status.requests, status.errors); 268 | hash_show_stats(); 269 | sigalrm_flag = 0; 270 | } 271 | -------------------------------------------------------------------------------- /src/sublog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1999 Larry Doolittle 4 | * Copyright (C) 2000-2005 Jon Nelson 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 1, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | */ 21 | 22 | /* $Id: sublog.c,v 1.6.2.6 2005/02/22 14:11:29 jnelson Exp $*/ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "compat.h" 37 | 38 | int open_pipe_fd(const char *command); 39 | int open_net_fd(const char *spec); 40 | int open_gen_fd(const char *spec); 41 | 42 | /* Like popen, but gives fd instead of FILE * */ 43 | int open_pipe_fd(const char *command) 44 | { 45 | int pipe_fds[2]; 46 | int pid; 47 | /* "man pipe" says "filedes[0] is for reading, 48 | * filedes[1] is for writing. */ 49 | if (pipe(pipe_fds) == -1) 50 | return -1; 51 | pid = fork(); 52 | if (pid == 0) { /* child */ 53 | close(pipe_fds[1]); 54 | if (pipe_fds[0] != 0) { 55 | dup2(pipe_fds[0], 0); 56 | close(pipe_fds[0]); 57 | } 58 | execl("/bin/sh", "sh", "-c", command, (char *) 0); 59 | exit(EXIT_FAILURE); 60 | } 61 | close(pipe_fds[0]); 62 | if (pid < 0) { 63 | close(pipe_fds[1]); 64 | return -1; 65 | } 66 | return pipe_fds[1]; 67 | } 68 | 69 | int open_net_fd(const char *spec) 70 | { 71 | char *p; 72 | int fd, port; 73 | struct sockaddr_in sa; 74 | struct hostent *he; 75 | p = strchr(spec, ':'); 76 | if (!p) 77 | return -1; 78 | *p++ = '\0'; 79 | port = strtol(p, NULL, 10); 80 | /* printf("Host %s, port %d\n",spec,port); */ 81 | sa.sin_family = PF_INET; 82 | sa.sin_port = htons(port); 83 | he = gethostbyname(spec); 84 | if (!he) { 85 | #ifdef HAVE_HERROR 86 | herror("open_net_fd"); 87 | #endif 88 | return -1; 89 | } 90 | memcpy(&sa.sin_addr, he->h_addr, he->h_length); 91 | /* printf("using ip %s\n",inet_ntoa(sa.sin_addr)); */ 92 | fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 93 | if (fd < 0) 94 | return fd; 95 | if (connect(fd, (struct sockaddr *) &sa, sizeof (sa)) < 0) 96 | return -1; 97 | return fd; 98 | } 99 | 100 | int open_gen_fd(const char *spec) 101 | { 102 | int fd; 103 | if (*spec == '|') { 104 | fd = open_pipe_fd(spec + 1); 105 | } else if (*spec == ':') { 106 | fd = open_net_fd(spec + 1); 107 | } else { 108 | fd = open(spec, 109 | O_WRONLY | O_CREAT | O_APPEND, 110 | S_IRUSR | S_IWUSR | S_IROTH | S_IRGRP); 111 | } 112 | return fd; 113 | } 114 | 115 | #ifdef STANDALONE_TEST 116 | int main(int argc, char *argv[]) 117 | { 118 | char buff[1024]; 119 | int fd, nr, nw; 120 | if (argc < 2) { 121 | fprintf(stderr, 122 | "usage: %s output-filename\n" 123 | " %s |output-command\n" 124 | " %s :host:port\n", argv[0], argv[0], argv[0]); 125 | return 1; 126 | } 127 | fd = open_gen_fd(argv[1]); 128 | if (fd < 0) { 129 | perror("open_gen_fd"); 130 | exit(EXIT_FAILURE); 131 | } 132 | while ((nr = read(0, buff, sizeof (buff))) != 0) { 133 | if (nr < 0) { 134 | if (errno == EINTR) 135 | continue; 136 | perror("read"); 137 | exit(EXIT_FAILURE); 138 | } 139 | nw = write(fd, buff, nr); 140 | if (nw < 0) { 141 | perror("write"); 142 | exit(EXIT_FAILURE); 143 | } 144 | } 145 | return 0; 146 | } 147 | #endif 148 | -------------------------------------------------------------------------------- /src/timestamp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Boa, an http server 3 | * Copyright (C) 1998-2002 Jon Nelson 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 1, or (at your option) 8 | * any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | * 19 | */ 20 | 21 | /* $Id: timestamp.c,v 1.9.2.1 2005/02/22 14:11:29 jnelson Exp $*/ 22 | 23 | #include "boa.h" 24 | 25 | void timestamp(void) 26 | { 27 | log_error_time(); 28 | fprintf(stderr, "boa: server version %s\n", SERVER_VERSION); 29 | log_error_time(); 30 | fprintf(stderr, "boa: server built " __DATE__ " at " __TIME__ ".\n"); 31 | log_error_time(); 32 | fprintf(stderr, "boa: starting server pid=%d, port %d\n", 33 | (int) getpid(), server_port); 34 | } 35 | --------------------------------------------------------------------------------