init
parent
591cf4b4c8
commit
a386d0c62b
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,38 @@
|
|||
Liam Widdowson <lbw@telstra.com>
|
||||
Lots of improvement for Solaris support
|
||||
|
||||
Wes Hardaker <wjhardaker@ucdavis.edu>
|
||||
|
||||
Michal Kara <lemming@netcentrum.cz>
|
||||
mmap_cache buglet fix
|
||||
|
||||
Matt Callaway <matt@securepipe.com>
|
||||
CGI chdir issue
|
||||
|
||||
Jari Korva <jpkorva@iki.fi>
|
||||
IPv6 patch
|
||||
|
||||
William Meadows <wmeadows@linux-support.net>
|
||||
escape.c bug notification and (first) fix
|
||||
|
||||
Thomas Neumann <tn@tmr-online.de>
|
||||
*BSD compilation/core bugfixes
|
||||
|
||||
Paul Saab <paul@mu.org>
|
||||
Remove SO_REUSEADDR setting on each client socket
|
||||
|
||||
David N. Welton <davidw@linuxcare.com>
|
||||
Added "Listen" directive for server bind address
|
||||
|
||||
Craig Silverstein <csilvers@google.com>
|
||||
patches for config.h and config.c
|
||||
|
||||
Russ Nelson <nelson@crynwr.com>
|
||||
Original, Experimental IP-based Virtual Host code
|
||||
|
||||
Landon Curt Noll http://www.isthe.com/chongo
|
||||
Allow non-standard date format 31 September 2000 23:59:59 GMT
|
||||
Skip whitespace before HTTP/major.minor
|
||||
|
||||
Brieuc Jeunhomme <bbp@via.ecp.fr>
|
||||
fix buglet in alias expansion
|
|
@ -0,0 +1,433 @@
|
|||
** Changes from 0.94.12 to 0.94.13
|
||||
* Change many instances of log_error_mesg + exit to DIE macro
|
||||
* Change all instance of log_error_mesg (without exit) to WARN macro
|
||||
* do a much better job of checking return values from malloc and
|
||||
especially strdup.
|
||||
* check results of calling umask and getrlimit
|
||||
* server_s is no longer a global int
|
||||
* check results of fork via switch instead of if (fork())
|
||||
* check for getopt.h and include it if found
|
||||
* remove unused #defines, and add WARN macro, and replace
|
||||
many calls to log_error_mesg(..) with WARN macro
|
||||
* fix bug in get_commonlog_time where time_offset calculation was
|
||||
the opposite of what it should be ('-' and '+' were swapped)
|
||||
* fix compatability bug with old and newer versions of flex/yacc
|
||||
* add check for AC_FUNC_MMAP to configure.in
|
||||
* fix really lame thinko in normalize_path, which would prepend the
|
||||
results of earlier calls to results from later calls
|
||||
* Add MaxConnections, a configuration directive which allows the
|
||||
user to specify the maximum number of connections that Boa will
|
||||
accept concurrently.
|
||||
* add SERVER_ADDR and REQUEST_URI to environment of CGI
|
||||
* handle SIGBUS during writes of data that has been memory mapped
|
||||
* minor optimization in select.c that prevents DEAD requests from
|
||||
being added to the block set
|
||||
* fix bug in CGI environment script_name - closes sf.net bug #576725
|
||||
* make 'status' variable local to requests.c, not local to every file
|
||||
by forgetting to declare 'extern' in globals.h :-|
|
||||
* make getsockname non-fatal, and do it every time because we may
|
||||
need it for the CGI
|
||||
* some minor refactoring optimizations in hash.c
|
||||
|
||||
** Changes from 0.94.11 to 0.94.12
|
||||
* Renamed Changelog ChangeLog, and moved up to top-level directory
|
||||
* Next 3 items due in part or whole thanks to
|
||||
Liam Widdowson
|
||||
* when printf'ing a pid type, force to int, because it could be
|
||||
something else on other platforms. Should probably change it to
|
||||
a long, and use that.
|
||||
* backported chroot commandline support from 0.95
|
||||
* backported support for strdup, strstr, alphasort, and scandir
|
||||
from 0.95
|
||||
* Fixed src/Makefile.in -- it didn't remove index_dir.o
|
||||
* backport create_temporary_file from 0.95
|
||||
(instead of using tmpnam)
|
||||
* Allow non-standard date format 31 September 2000 23:59:59 GMT
|
||||
Patch by Landon Curt Noll
|
||||
* Skip whitespace before HTTP/major.minor
|
||||
Adapted patch from Landon Curt Noll
|
||||
* open /dev/null first thing (affects chrooting)
|
||||
* properly handle sigalrm -- use sigalrm_flag and sigalrm_run
|
||||
instead of handling the signal in the signal handler
|
||||
* update manpage slightly
|
||||
* send 400 BAD Request when resource does not start with '/'
|
||||
* add grp.h to boa.h's includes -- remove from boa.c and config.c
|
||||
* removed duplicate header includes from boa.c, config.c, get.c,
|
||||
ip.c, request.c, response.c
|
||||
* factor out creating the server socket and dropping privs
|
||||
into create_server_socket and drop_privs
|
||||
* type all functions in boa.c (except main) as static
|
||||
* set umask after opening /dev/null
|
||||
* tie stdin/stdout to /dev/null before commandline parse
|
||||
* removed old, unused chroot code
|
||||
* move builds_needs_escape earlier in the startup
|
||||
* move fork later in the startup
|
||||
* type all c_set_* as static in config.c
|
||||
* don't bother trying to change uid/gid (or error if the
|
||||
requested uid/gid doesn't exist) if not UID 0
|
||||
* return more appropriate error code when foo.html gives
|
||||
access denied, but foo.html.gz gives some other error
|
||||
(essentially report error associated with foo.html, not foo.html.gz)
|
||||
* send NOT Implemented when an unknown method is attempted
|
||||
* always attempt a 32k read right before close
|
||||
(stopgap until blackhole can be merged)
|
||||
* allow more than 1 space in logline between method, resource,
|
||||
and http version
|
||||
* don't use inline functions
|
||||
* update configure.in so that autoconf 2.50 doesn't complain (as much)
|
||||
* properly use VPATH and srcdir according to autoconf docs
|
||||
* change curly-braces to parentheses in Makefilein
|
||||
* use $^ instead of manually listing the dependencies in Makefile.in
|
||||
* remove tests section in Makefile.in
|
||||
* write tags not TAGS in Makefile.in
|
||||
* Add gethostbyname and inet_aton to function checks
|
||||
* Add code from 0.95 which checks for socket in -lsocket,
|
||||
inet_aton in -lresolv, and gethost{by}name in -lnsl
|
||||
* Also remove broken bc-based "how big is an unsigned int" checks:
|
||||
assume minimum of 32 bits and check in escape.c at runtime.
|
||||
* Added new file: README.chroot.solaris, based on a
|
||||
modified version by Liam Widdowson
|
||||
* Add check_struct_for.m4, which allows us to check a structure
|
||||
for a member (found at http://www.gnu.org/software/ac-archive/
|
||||
authored by Wes Hardaker
|
||||
* Call "aclocal -I ." to rebuild aclocal.m4
|
||||
* Using new check-struct-for-member autoconf macro, check
|
||||
for tm_gmtoff and tm_zone in struct tm -- useful in
|
||||
portability tests for localtime.
|
||||
* Also check sockaddr_in for structure sin_len so we can set
|
||||
it properly.
|
||||
* index_dir.c (which ends up in boa_indexer) can now be compiled
|
||||
with USE_LOCALTIME, and if so, it will report the local time
|
||||
using the timezone name. Otherwise it uses UTC time and UTC
|
||||
timezone designation.
|
||||
* fix buglet in mmap_cache.c which shows up when under
|
||||
heavy load by many different files.
|
||||
Found and squashed by Michal Kara
|
||||
* normalize paths on Aliases, log files, server root, dirmaker
|
||||
This makes sure that paths are 'absolute'
|
||||
* don't generate DOCUMENT_ROOT or SERVER_ROOT,
|
||||
CGIs have no business knowing that information
|
||||
* if CGI, chdir to the cgi's root path
|
||||
Bug found by Matt Callaway
|
||||
* remove ChrootPath and PidFile directives from the parser
|
||||
(they aren't used anyway)
|
||||
* keep track of maximum file descriptor in use to optimize call
|
||||
to select()
|
||||
* apply IPv6 patch from Jari Korva
|
||||
* optimize keep-alive copy data routine
|
||||
* try to use memcpy instead of strcpy/strcat in more places (alias.c)
|
||||
* update .depend file
|
||||
* use fcntl + GET_FL to get a file descriptor's flags, then
|
||||
add or remove only the bits we want to set. This prevents
|
||||
accidentally setting or unsettings bits we don't have anything
|
||||
to do with inadvertantly. (removed, at least temporarily.
|
||||
Show me a system where it is needed -- LRD)
|
||||
* make sure to call FD_ZERO when we handle a restart
|
||||
* in read.c, don't call boa_perror on read failure -- socket is
|
||||
dead or messed up anyway, no reason to try to write to it.
|
||||
* explicit .SUFFIXES in Makefile.in
|
||||
* boa.objdump target added
|
||||
* use @MAKE_SET@ (for when $(MAKE) != "make")
|
||||
* add -Wundef -Wwrite-strings -Wredundant-decls -Winline to GCC_FLAGS
|
||||
* change Paul Phillips' and Larry Doolittle's emails in source
|
||||
* add --disable-debug, --enable-profile, --with-dmalloc, and --with-efence
|
||||
* test for failed-but-return-was-successful setuid:
|
||||
http://www.securityfocus.com/bid/1322
|
||||
* use _exit not exit in CGI child
|
||||
* always place new keepalive request on blocked list, we can't be
|
||||
sure of the state of the active list, and since enqueue places
|
||||
things at the *front* of the list, it doesn't do us much good
|
||||
to place the new request on the active list anyway.
|
||||
* update some Copyright statements for 2002
|
||||
* When comparing the uri to an alias, only compare if
|
||||
the uri length is greater than or equal to the length of the alias
|
||||
* in init_script_alias, make sure to check for document_root before
|
||||
trying to use it
|
||||
* script_name is now just a copy of the request, rather
|
||||
than some complicated variation on the pathname
|
||||
* change the way the CGI environment is handled.
|
||||
Now, it is allocated at request allocation time, and exists
|
||||
throughout the life of the structure.
|
||||
* check memory allocations, etc.. when creating the static
|
||||
CGI environment and when making new CGI environment variables
|
||||
* wait until process_option_end to call unescape_uri, clean_pathname,
|
||||
and translate_uri
|
||||
* remove debian package information
|
||||
* move RedHat packaging information to contrib
|
||||
* remove tests -- they weren't usable anyway
|
||||
* add some new hash routines, and use djb2 (a variant on a
|
||||
hash algorithm popularized by Dan J. Bernstein)
|
||||
* a side-effect of the new hash routines is a bugfix,
|
||||
involving negative return values from hash routines.
|
||||
This has been fixed.
|
||||
* add a routine, show_hash_stats, which is called with other
|
||||
statistical output via sigalarm
|
||||
* remove some duplicate prototypes from config.c
|
||||
* make simple_itoa take an unsigned int
|
||||
* try to make NOBLOCK handling in compat.h compatible with Solaris
|
||||
* make sure to update current_time before calling signal handlers
|
||||
* alter primary loop to make sure that select gets called even
|
||||
when there are requests that are not blocking, and call fdset_update
|
||||
and process_requests (when appropriate) after signal handlers but
|
||||
before select to make sure that blocked requests are still handled
|
||||
by select after a sighup. (Thanks to Karl Olsen)
|
||||
* pull select loop into select.c
|
||||
* poll server socket once per active connection
|
||||
* add send_r_service_unavailable and use it when appropriate
|
||||
* state uptime in seconds at normal program termination
|
||||
* include sys/fcntl.h if it is found by configure
|
||||
* fix POST bug where a content-length < 0 would cause Boa to
|
||||
consume its full share of CPU until killed
|
||||
Bug report by Landon Curt Noll
|
||||
* add CGIPath configuration variable
|
||||
based upon a patch by Landon Curt Noll
|
||||
* add function boa_atoi, which wraps atoi, but does not
|
||||
accept negative values. Additionally, it checks to make sure
|
||||
the converted value and the original value are the same, avoiding
|
||||
issues like "124.3" -> "123" and "123abc" -=> "123".
|
||||
Either a value is an int or it isn't - no middle ground.
|
||||
* use boa_atoi to convert content-length from client.
|
||||
* add new #define - SINGLE_POST_LIMIT_DEFAULT, which defines
|
||||
(in bytes) the *default* single_post_limit.
|
||||
* single_post_limit is now in bytes.
|
||||
* when adding aliases, only "normalize" paths that start
|
||||
with "./" - this is a departure from previous behavior
|
||||
* add "?" to the list of characters that it is safe to leave unescaped
|
||||
* clean up Makefile.in of no-longer-pertinent comments
|
||||
* add send_r_bad_gateway and use it
|
||||
* tie stderr to either cgi_log_fd or devnullfd - either way
|
||||
make sure stderr is a valid filehandle before cgi execution
|
||||
* cgi_env is no longer allocated, it's part of the struct now
|
||||
* fix bug in CgiPath logic
|
||||
* when unable to allocate memory for an environment variable, log it
|
||||
* add clear_common_env, which de-allocates the cgi_common_env stuff
|
||||
[NEVER USE THIS outside of a terminal signal handler!]
|
||||
* don't be so wasteful of memory in normalize_path
|
||||
* adapted fix for alias expansion from Brieuc Jeunhomme
|
||||
|
||||
** Changes from 0.94.10.1 to 0.94.11
|
||||
* use LIBS in Makefile.in (which propagates from autoconf)
|
||||
* properly free memory allocated by scandir in index_dir.c
|
||||
* rearrange some header files and includes
|
||||
* on reads and writes, don't check for -1, check for < 0
|
||||
* include fix by William Meadows
|
||||
for escape.c which fixes segfaults due to improper allocation
|
||||
* above fix by William Meadows no longer needed;
|
||||
escape.c and escape.h rewritten by Larry Doolittle -- requires
|
||||
at least 32 bit words, but is correct (jdn's 1st attempt was faulty)
|
||||
|
||||
** Changes from 0.94.10 to 0.94.10.1
|
||||
* Actually update the SERVER_VERSION in src/defines.h
|
||||
|
||||
** Changes from 0.94.9 to 0.94.10
|
||||
* Fixes escaping rules
|
||||
* Fixes segfault when directory_index is undefined and
|
||||
directory needs to be generated
|
||||
* adds dummy signal handlers for SIGUSR1 and SIGUSR2 (Closes SF #425921)
|
||||
* Update documentation regarding mime.types (Closes Debian #69991)
|
||||
* Make sure documentation builds (Closes Debian #110818)
|
||||
|
||||
** Changes from 0.94.8.3 to 0.94.9
|
||||
* src/Makefile.in updated to take CFLAGS, LIBS, and LDFLAGS
|
||||
from autoconf
|
||||
* Update escaping rules with latest RFC
|
||||
* unescape_uri skips fragments and also stop parsing at '?'
|
||||
* Don't accept fd over FD_SETSIZE in request.c:get_request
|
||||
* use backported documentation from 0.95
|
||||
* make sure POST fd gets closed even on client cancel
|
||||
* use backported index_dir.c from 0.95
|
||||
* support subdirectories in ScriptAlias directories
|
||||
* add SinglePostLimit (int, in Kilobytes) to config system
|
||||
* check for ENOSPC on body write
|
||||
* use environment variable TMP (or "/tmp" if not available),
|
||||
and chdir there when boa exits.
|
||||
* add 1-time-only hack to make a 32kB read at the end of a request
|
||||
on POST or PUT
|
||||
* close unused file descriptors (/dev/null in boa.c, and the
|
||||
unused part of the pipes call in cgi.c)
|
||||
* made Makefile.in VPATH happy
|
||||
|
||||
** Changes from 0.94.8.2 to 0.94.8.3
|
||||
* Move unescape_uri *before* clean_pathname to prevent
|
||||
encoding of / and .. in pathname
|
||||
* wrap execution of GUNZIP in cgi.c with #ifdef GUNZIP
|
||||
* stop parsing when fragment found in URL ('#')
|
||||
|
||||
** Changes from 0.94.8.1 to 0.94.8.2
|
||||
* close pipes[1] in child and generate HTTP_REFERER environment
|
||||
variable in cgi.c
|
||||
* Minor changes to the Debian package
|
||||
|
||||
** Changes from 0.94.8 to 0.94.8.1
|
||||
* Change umask call from (umask(0600)) to (umask(~0600))
|
||||
|
||||
** Changes from 0.94.7 to 0.94.8
|
||||
* Fix major thinko in temp file permissions
|
||||
* unlink temporary file immediately following creation
|
||||
* implement maximum # of active connections at 10 less than RLIMIT_NOFILE
|
||||
to avoid or eliminate crashes resulting from running out of
|
||||
file descriptors
|
||||
* Fix thinko in POST
|
||||
|
||||
** Changes from 0.94.6 to 0.94.7
|
||||
* STDIN and STDOUT are now tied to /dev/null
|
||||
* sets PATH_MAX to 2048 if not defined (for Hurd)
|
||||
* core dumps (should never happen) would be located in /tmp
|
||||
* alter behavior when select gets a EBADF
|
||||
* add translation for the \" char -> "
|
||||
* remove use of sys_errlist. Use perror.
|
||||
* better makedist.sh (still a stupid program though)
|
||||
|
||||
** Changes from 0.94.5 to 0.94.6
|
||||
* Removed doc++ commenting
|
||||
* Removed erroneous debugging statments
|
||||
* Move some stuff out of config.c (read_config_file) to boa.c
|
||||
* Altered some of fixup_server_root()
|
||||
* Bug fix in get.c re: automatic gunzip
|
||||
* Added some stubs for chroot code (*not* ready yet)
|
||||
|
||||
** Changes from 0.94.4 to 0.94.5
|
||||
* Alteration of most of the comments and such for doc++ use
|
||||
* Fixed buffer overflow in alias.c
|
||||
* Fixed buffer underflow in util.c
|
||||
|
||||
** Changes from 0.94.3 to 0.94.4
|
||||
* Better escaping of data to user, both for HTTP headers and HTML body
|
||||
* Proper escaping of output in CGI example perl scripts
|
||||
|
||||
** Changes from 0.94.0 to 0.94.2
|
||||
* Fixed obnoxious pipeline bug
|
||||
* Fixed (sorta) a compilation/core bug for *BSD systems
|
||||
Original code by Thomas Neumann
|
||||
* Moved to GPLv2
|
||||
* Changed manpage to section 8
|
||||
* boa.sgml now references a .png file instead of evil .gif
|
||||
|
||||
** Changes from 0.93.19.2 to 0.94.0
|
||||
* Added UseGMT to the configuration parser
|
||||
* util.c commonlog now logs in Apache-style commonlog time format
|
||||
* Remove SO_SNDBUF on-start message
|
||||
|
||||
** Changes from 0.93.19 to 0.93.19.2
|
||||
* Changed to combined log (from NCSA access_log format) ala Drew Streib
|
||||
* Altered POST cgi code to handle bug in Netscape
|
||||
* SO_SNDBUF changes by Larry
|
||||
|
||||
** Changes from 0.93.17.2 to 0.93.19 (all 0.93.18.x changes inclusive)
|
||||
* Update of some copyright statements for 99
|
||||
* Replacement of sprintf with strlen/memcpy or strcpy/strcat
|
||||
wherever possible
|
||||
* Significant rearrangement in alias.c, minor functional differences
|
||||
(some CGI environment variables handled differently)
|
||||
* Removal of die function. Replace with log_err_mesg and exit.
|
||||
* initial IPv6 stubs and support
|
||||
* Move #include "config.h" to top of boa.h where it will do some good
|
||||
* Stubs and functions for strstr and strdup
|
||||
* Seperation of buffer code into it's own file
|
||||
* Significant changes to cgi.c et al (cgi_header.c, etc...)
|
||||
* Speed patches by removal of "extra" calls to time(): Use global variable!
|
||||
* pipelining changes... it works now.
|
||||
* require content-length from clients (ala rfc1945)
|
||||
* alter body_read and body_write to work more efficiently with known content-length
|
||||
* move read(2) part to *after* parsing...
|
||||
* added support for additional header message in send_redirect_temp
|
||||
* change use of NO_ZERO_FILL_LENGTH to offsetof() use
|
||||
* Remove SO_REUSEADDR setting on each client socket, Paul Saab
|
||||
* Avoid SO_SNDBUF setting if possible
|
||||
* Large quantities of otherwise not-insignificant changes
|
||||
|
||||
** Changes from 0.93.17.2 to 0.93.17.3
|
||||
* Put on-the-fly directories back in, stripped down from the 0.92 version
|
||||
* Fixed DocumentRoot, ServerAdmin and ServerName null-value handling in
|
||||
CGI environment generation
|
||||
* Fixed argument order in Script* directives (bug introduced in 0.93.17.2)
|
||||
* Got rid of MAX_CGI_VARS because it was not being used consistently, or
|
||||
for that matter, at all, really.
|
||||
* Added some more FASCIST_LOGGING to cgi.c
|
||||
* Minor mmap patch by LRD for request.c
|
||||
|
||||
** Changes from 0.93.17.1 to 0.93.17.2
|
||||
* Added "Listen" directive for server bind address, as most recently
|
||||
suggested by David N. Welton
|
||||
* Put virtualhost feature in, was experimental in 0.92q
|
||||
|
||||
** Changes from 0.93.16.2 to 0.93.17.1
|
||||
* New config file parser (supposed to be more maintainable) (LRD)
|
||||
* Support for "|command" and ":host:port" syntax for logfiles (untested) (LRD)
|
||||
|
||||
** Changes for the 0.93 version **
|
||||
* Huge quantities of changes
|
||||
* keepalive Bugfix in 0.93.16.2 by Jon Nelson
|
||||
report by Craig Silverstein of Google fame.
|
||||
* patch for config.h by Craig Silverstein
|
||||
* fixed "Parent Directory" problem in boa_indexer for title "/"
|
||||
(Debian bug #36165)
|
||||
* More Craig Silverstein
|
||||
modifications, namely:
|
||||
ErrorLog (if omitted, print to stderr)
|
||||
DocumentRoot (if omitted, can only server user-dir files)
|
||||
DirectoryIndex (if omitted, always use DirectoryMaker)
|
||||
MimeTypes (if omitted, don't load -- users can use AddType instead)
|
||||
|
||||
|
||||
** Changes from v0.92o to v0.92p **
|
||||
|
||||
* Documented misbehavior of CGI, SIGHUP, short aliases, stale dircache.
|
||||
* Documented how to patch signals.c for use on SunOS.
|
||||
* Closed file descriptor leak when redirecting a bare directory URL to
|
||||
one with an appended "/".
|
||||
* Closed potential file descriptor leak if errors encountered generating
|
||||
on-the-fly index.
|
||||
* Cleaned up include file handling to be simultaneously compatible with
|
||||
Linux, SunOS, HP-UX, and AIX.
|
||||
* Supress message body for codes 302, 400, 403, 404, 500, and 501 if
|
||||
incoming request is "HEAD".
|
||||
|
||||
** Changes from v0.91 to v0.92o **
|
||||
(0.92o released 27 December, 1996)
|
||||
|
||||
* Maintenance handover from Paul Phillips to Larry Doolittle
|
||||
* Changed (char)NULL to '\0'
|
||||
* Cleaned up signal handler prototypes in signals.c
|
||||
* Modified handling of CGI environment variable PATH_TRANSLATED,
|
||||
should now work the same as NCSA.
|
||||
* More conservative buffer size in add_cgi_env()
|
||||
* Build argv list for a CGI script according to spec
|
||||
* Speedup process_header_line, eliminate potential memory leak
|
||||
* Occasional spelling fixes and lint removal
|
||||
* Added REMOTE_PORT env var for CGI scripts, to allow easy ident lookups
|
||||
* Changed rfc822 time format
|
||||
* Log timeouts and broken connections
|
||||
* Fix mime suffix handling for filenames with multiple "."s
|
||||
* Initialize conn->time_last, fixes bug with rapid-fire connections
|
||||
* Performance tweak to req_write()
|
||||
* Changed http_version from float to char[8]
|
||||
* Rewrote on-the-fly directory generation; it works now
|
||||
* Added user configurable dircache directory in boa.conf
|
||||
* Fixed "simple" response bugs, including incorrect CGI handling
|
||||
* Keepalive (HTTP/1.1 draft) support, mostly by Jon Nelson
|
||||
* Close data_fd in 304 Not Modified flow of control
|
||||
* Switch socket flags to non-blocking before cgi handoff
|
||||
* Try to handle errno properly in the face of multiple errors
|
||||
* Close fd's of all other transactions before cgi handoff
|
||||
* Move real work for sighup and sigchld out of signal handler
|
||||
* Fix free(req->cgi_env) in request.c
|
||||
* Response message cleanup - better match to HTML-2.0 DTD
|
||||
* Experimental Virtual Host code from Russ Nelson
|
||||
* Expand buffer for escaped URI in init_get()
|
||||
* SIGTERM triggers lame duck mode until all pending transactions complete
|
||||
* Close and unlink temp file for POST in parent process
|
||||
|
||||
** Changes from v0.90 to v0.91 **
|
||||
|
||||
* Cleaned up main while loop
|
||||
* Optimized request line parsing
|
||||
* Added state machine for header reads -- necessary to deal wtih
|
||||
possibility of obtaining header data in multiple reads. This
|
||||
also allows interactive use of server.
|
||||
* Added 500/501 return codes for various conditions
|
||||
|
||||
** v0.90 **
|
||||
|
||||
* Initial release
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,15 @@
|
|||
This is Boa, a high performance web server for Unix-alike computers,
|
||||
covered by the Gnu General Public License. This is version 0.94,
|
||||
released January 2000. It is well tested and appears to be of
|
||||
at least "gamma" quality.
|
||||
|
||||
Boa was created in 1991 by Paul Phillips <paulp@go2net.com>. It is now being
|
||||
maintained and enhanced by Larry Doolittle <ldoolitt@boa.org>
|
||||
and Jon Nelson <jnelson@boa.org>.
|
||||
|
||||
For more information (including installation instructions) examine
|
||||
the file docs/boa.txt or docs/boa.dvi, point your web browser to docs/boa.html,
|
||||
or visit the Boa homepage at
|
||||
|
||||
http://www.boa.org/
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
# Boa v0.94 configuration file
|
||||
# File format has not changed from 0.93
|
||||
# File format has changed little from 0.92
|
||||
# version changes are noted in the comments
|
||||
#
|
||||
# The Boa configuration file is parsed with a lex/yacc or flex/bison
|
||||
# generated parser. If it reports an error, the line number will be
|
||||
# provided; it should be easy to spot. The syntax of each of these
|
||||
# rules is very simple, and they can occur in any order. Where possible
|
||||
# these directives mimic those of NCSA httpd 1.3; I saw no reason to
|
||||
# introduce gratuitous differences.
|
||||
|
||||
# $Id: boa.conf,v 1.25 2002/03/22 04:33:09 jnelson Exp $
|
||||
|
||||
# The "ServerRoot" is not in this configuration file. It can be compiled
|
||||
# into the server (see defines.h) or specified on the command line with
|
||||
# the -c option, for example:
|
||||
#
|
||||
# boa -c /usr/local/boa
|
||||
|
||||
|
||||
# Port: The port Boa runs on. The default port for http servers is 80.
|
||||
# If it is less than 1024, the server must be started as root.
|
||||
|
||||
Port 80
|
||||
|
||||
# Listen: the Internet address to bind(2) to. If you leave it out,
|
||||
# it takes the behavior before 0.93.17.2, which is to bind to all
|
||||
# addresses (INADDR_ANY). You only get one "Listen" directive,
|
||||
# if you want service on multiple IP addresses, you have three choices:
|
||||
# 1. Run boa without a "Listen" directive
|
||||
# a. All addresses are treated the same; makes sense if the addresses
|
||||
# are localhost, ppp, and eth0.
|
||||
# b. Use the VirtualHost directive below to point requests to different
|
||||
# files. Should be good for a very large number of addresses (web
|
||||
# hosting clients).
|
||||
# 2. Run one copy of boa per IP address, each has its own configuration
|
||||
# with a "Listen" directive. No big deal up to a few tens of addresses.
|
||||
# Nice separation between clients.
|
||||
# The name you provide gets run through inet_aton(3), so you have to use dotted
|
||||
# quad notation. This configuration is too important to trust some DNS.
|
||||
|
||||
#Listen 192.68.0.5
|
||||
|
||||
# User: The name or UID the server should run as.
|
||||
# Group: The group name or GID the server should run as.
|
||||
|
||||
User nobody
|
||||
Group nogroup
|
||||
|
||||
# ServerAdmin: The email address where server problems should be sent.
|
||||
# Note: this is not currently used, except as an environment variable
|
||||
# for CGIs.
|
||||
|
||||
#ServerAdmin root@localhost
|
||||
|
||||
# ErrorLog: The location of the error log file. If this does not start
|
||||
# with /, it is considered relative to the server root.
|
||||
# Set to /dev/null if you don't want errors logged.
|
||||
# If unset, defaults to /dev/stderr
|
||||
|
||||
ErrorLog /var/log/boa/error_log
|
||||
# Please NOTE: Sending the logs to a pipe ('|'), as shown below,
|
||||
# is somewhat experimental and might fail under heavy load.
|
||||
# "Usual libc implementations of printf will stall the whole
|
||||
# process if the receiving end of a pipe stops reading."
|
||||
#ErrorLog "|/usr/sbin/cronolog --symlink=/var/log/boa/error_log /var/log/boa/error-%Y%m%d.log"
|
||||
|
||||
# AccessLog: The location of the access log file. If this does not
|
||||
# start with /, it is considered relative to the server root.
|
||||
# Comment out or set to /dev/null (less effective) to disable
|
||||
# Access logging.
|
||||
|
||||
AccessLog /var/log/boa/access_log
|
||||
# Please NOTE: Sending the logs to a pipe ('|'), as shown below,
|
||||
# is somewhat experimental and might fail under heavy load.
|
||||
# "Usual libc implementations of printf will stall the whole
|
||||
# process if the receiving end of a pipe stops reading."
|
||||
#AccessLog "|/usr/sbin/cronolog --symlink=/var/log/boa/access_log /var/log/boa/access-%Y%m%d.log"
|
||||
|
||||
# UseLocaltime: Logical switch. Uncomment to use localtime
|
||||
# instead of UTC time
|
||||
#UseLocaltime
|
||||
|
||||
# VerboseCGILogs: this is just a logical switch.
|
||||
# It simply notes the start and stop times of cgis in the error log
|
||||
# Comment out to disable.
|
||||
|
||||
#VerboseCGILogs
|
||||
|
||||
# ServerName: the name of this server that should be sent back to
|
||||
# clients if different than that returned by gethostname + gethostbyname
|
||||
|
||||
#ServerName www.your.org.here
|
||||
|
||||
# VirtualHost: a logical switch.
|
||||
# Comment out to disable.
|
||||
# Given DocumentRoot /var/www, requests on interface 'A' or IP 'IP-A'
|
||||
# become /var/www/IP-A.
|
||||
# Example: http://localhost/ becomes /var/www/127.0.0.1
|
||||
#
|
||||
# Not used until version 0.93.17.2. This "feature" also breaks commonlog
|
||||
# output rules, it prepends the interface number to each access_log line.
|
||||
# You are expected to fix that problem with a postprocessing script.
|
||||
|
||||
#VirtualHost
|
||||
|
||||
# DocumentRoot: The root directory of the HTML documents.
|
||||
# Comment out to disable server non user files.
|
||||
|
||||
DocumentRoot /var/www
|
||||
|
||||
# UserDir: The name of the directory which is appended onto a user's home
|
||||
# directory if a ~user request is recieved.
|
||||
|
||||
UserDir public_html
|
||||
|
||||
# DirectoryIndex: Name of the file to use as a pre-written HTML
|
||||
# directory index. Please MAKE AND USE THESE FILES. On the
|
||||
# fly creation of directory indexes can be _slow_.
|
||||
# Comment out to always use DirectoryMaker
|
||||
|
||||
DirectoryIndex index.html
|
||||
|
||||
# DirectoryMaker: Name of program used to create a directory listing.
|
||||
# Comment out to disable directory listings. If both this and
|
||||
# DirectoryIndex are commented out, accessing a directory will give
|
||||
# an error (though accessing files in the directory are still ok).
|
||||
|
||||
DirectoryMaker /usr/lib/boa/boa_indexer
|
||||
|
||||
# DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker
|
||||
# has been commented out, the the on-the-fly indexing of Boa can be used
|
||||
# to generate indexes of directories. Be warned that the output is
|
||||
# extremely minimal and can cause delays when slow disks are used.
|
||||
# Note: The DirectoryCache must be writable by the same user/group that
|
||||
# Boa runs as.
|
||||
|
||||
# DirectoryCache /var/spool/boa/dircache
|
||||
|
||||
# KeepAliveMax: Number of KeepAlive requests to allow per connection
|
||||
# Comment out, or set to 0 to disable keepalive processing
|
||||
|
||||
KeepAliveMax 1000
|
||||
|
||||
# KeepAliveTimeout: seconds to wait before keepalive connection times out
|
||||
|
||||
KeepAliveTimeout 10
|
||||
|
||||
# MimeTypes: This is the file that is used to generate mime type pairs
|
||||
# and Content-Type fields for boa.
|
||||
# Set to /dev/null if you do not want to load a mime types file.
|
||||
# Do *not* comment out (better use AddType!)
|
||||
|
||||
MimeTypes /etc/mime.types
|
||||
|
||||
# DefaultType: MIME type used if the file extension is unknown, or there
|
||||
# is no file extension.
|
||||
|
||||
DefaultType text/plain
|
||||
|
||||
# CGIPath: The value of the $PATH environment variable given to CGI progs.
|
||||
|
||||
CGIPath /bin:/usr/bin:/usr/local/bin
|
||||
|
||||
# SinglePostLimit: The maximum allowable number of bytes in
|
||||
# a single POST. Default is normally 1MB.
|
||||
|
||||
# AddType: adds types without editing mime.types
|
||||
# Example: AddType type extension [extension ...]
|
||||
|
||||
# Uncomment the next line if you want .cgi files to execute from anywhere
|
||||
#AddType application/x-httpd-cgi cgi
|
||||
|
||||
# Redirect, Alias, and ScriptAlias all have the same semantics -- they
|
||||
# match the beginning of a request and take appropriate action. Use
|
||||
# Redirect for other servers, Alias for the same server, and ScriptAlias
|
||||
# to enable directories for script execution.
|
||||
|
||||
# Redirect allows you to tell clients about documents which used to exist in
|
||||
# your server's namespace, but do not anymore. This allows you to tell the
|
||||
# clients where to look for the relocated document.
|
||||
# Example: Redirect /bar http://elsewhere/feh/bar
|
||||
|
||||
# Aliases: Aliases one path to another.
|
||||
# Example: Alias /path1/bar /path2/foo
|
||||
|
||||
Alias /doc /usr/doc
|
||||
|
||||
# ScriptAlias: Maps a virtual path to a directory for serving scripts
|
||||
# Example: ScriptAlias /htbin/ /www/htbin/
|
||||
|
||||
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
Boa chroot mini-HOWTO
|
||||
===================================================
|
||||
by Liam Widdowson <lbw@telstra.com>
|
||||
modified slightly by Jon Nelson <jnelson@boa.org>
|
||||
|
||||
The following is required to get Boa working in a chroot jail. Whilst this
|
||||
README is about Solaris specifically, the principals here will apply to
|
||||
other operating systems.
|
||||
|
||||
The following assumptions are made:
|
||||
|
||||
- Boa has been compiled and installed in /opt/boa
|
||||
- The chroot jail will be created in /var/www
|
||||
- A user and group 'www' have been created.
|
||||
|
||||
Make sure you change the above directories to suit your system.
|
||||
|
||||
Your boa.conf should look something like the following:
|
||||
|
||||
## begin config file
|
||||
|
||||
Port 80
|
||||
User www
|
||||
Group www
|
||||
|
||||
# Note, these paths are used releative to the chroot jail. i.e /var/log is
|
||||
# really /var/www/var/log
|
||||
ErrorLog /var/log/error_log
|
||||
AccessLog /var/log/access_log
|
||||
DocumentRoot /var/www
|
||||
|
||||
# You won't be able to access user home directories outside of the chroot
|
||||
# but you may replicate them into the chroot jail. You'll need a working
|
||||
# and valid /etc/passwd as well
|
||||
UserDir public_html
|
||||
|
||||
DirectoryIndex index.html
|
||||
|
||||
# this binary must exist in the chroot jail. Again, the path is relative.
|
||||
DirectoryMaker /usr/bin/boa_indexer
|
||||
|
||||
KeepAliveMax 1000
|
||||
KeepAliveTimeout 10
|
||||
|
||||
# this file must exist inside AND outside the chroot jail.
|
||||
MimeTypes /opt/boa/mime.types
|
||||
|
||||
DefaultType text/plain
|
||||
|
||||
## end config file
|
||||
|
||||
Once the configuration file is created, you must begin creating your
|
||||
chroot jail. A variety of libraries, timezone files, device files and other
|
||||
bits and pieces must be copied in order for this to work. Below is a ls -lR
|
||||
of what your jail should be at a minimum:
|
||||
|
||||
.:
|
||||
total 10
|
||||
drwxr-xr-x 2 root other 512 Jan 21 18:58 dev
|
||||
drwxr-xr-x 2 root other 512 Jan 21 19:20 etc
|
||||
drwxr-xr-x 3 root other 512 Jan 21 19:20 opt
|
||||
drwxr-xr-x 5 root other 512 Jan 21 19:08 usr
|
||||
drwxr-xr-x 4 root other 512 Jan 21 18:57 var
|
||||
|
||||
./dev:
|
||||
total 0
|
||||
crw-rw-rw- 1 root other 13, 2 Jan 21 18:58 null
|
||||
crw-rw-rw- 1 root other 41, 0 Jan 21 18:58 udp
|
||||
|
||||
./etc:
|
||||
total 16
|
||||
-r-xr-xr-x 1 root other 482 Jan 21 19:20 TIMEZONE
|
||||
-r--r--r-- 1 root other 74 Jan 21 19:20 hosts
|
||||
-rw-r--r-- 1 root other 1239 Jan 21 19:20 netconfig
|
||||
-rw-r--r-- 1 root other 1298 Jan 21 19:20 nsswitch.conf
|
||||
-r--r--r-- 1 root other 514 Jan 21 19:44 passwd
|
||||
-rw-r--r-- 1 root other 94 Jan 21 19:20 resolv.conf
|
||||
drwx------ 2 root other 512 Jan 21 19:20 boa
|
||||
|
||||
./boa:
|
||||
total 4
|
||||
-rw-r--r-- 1 root other 1234 Jan 21 19:26 boa.conf
|
||||
|
||||
./opt:
|
||||
total 2
|
||||
drwxr-xr-x 2 root other 512 Jan 21 19:26 boa
|
||||
|
||||
./opt/boa:
|
||||
total 20
|
||||
-rw-r--r-- 1 root other 9964 Jan 21 19:26 mime.types
|
||||
|
||||
./usr:
|
||||
total 6
|
||||
drwxr-xr-x 2 root other 512 Jan 21 19:21 bin
|
||||
drwxr-xr-x 2 root other 512 Jan 21 19:03 lib
|
||||
drwxr-xr-x 3 root other 512 Jan 21 19:08 share
|
||||
|
||||
./usr/bin:
|
||||
total 18
|
||||
-rwxr-xr-x 1 root other 8944 Jan 21 19:23 boa_indexer
|
||||
|
||||
./usr/lib:
|
||||
total 5094
|
||||
-rwxr-xr-x 1 root other 185020 Jan 21 19:03 ld.so.1
|
||||
-rwxr-xr-x 1 root other 1126652 Jan 21 18:56 libc.so.1
|
||||
-rwxr-xr-x 1 root other 4308 Jan 21 18:56 libdl.so.1
|
||||
-rwxr-xr-x 1 root other 24968 Jan 21 18:56 libmp.so.2
|
||||
-rwxr-xr-x 1 root other 883500 Jan 21 18:56 libnsl.so.1
|
||||
-rwxr-xr-x 1 root other 265860 Jan 21 18:56 libresolv.so.2
|
||||
-rwxr-xr-x 1 root other 70260 Jan 21 18:56 libsocket.so.1
|
||||
|
||||
./usr/share:
|
||||
total 2
|
||||
drwxr-xr-x 3 root other 512 Jan 21 19:08 lib
|
||||
|
||||
./usr/share/lib:
|
||||
total 2
|
||||
drwxr-xr-x 3 root other 512 Jan 21 19:08 zoneinfo
|
||||
|
||||
./usr/share/lib/zoneinfo:
|
||||
total 2
|
||||
drwxr-xr-x 2 root other 512 Jan 21 19:09 Australia
|
||||
|
||||
./usr/share/lib/zoneinfo/Australia:
|
||||
total 22
|
||||
-rw-r--r-- 1 root other 785 Jan 21 19:09 ACT
|
||||
-rw-r--r-- 1 root other 785 Jan 21 19:09 Broken_Hill
|
||||
-rw-r--r-- 1 root other 663 Jan 21 19:09 LHI
|
||||
-rw-r--r-- 1 root other 785 Jan 21 19:09 NSW
|
||||
-rw-r--r-- 1 root other 104 Jan 21 19:09 North
|
||||
-rw-r--r-- 1 root other 160 Jan 21 19:09 Queensland
|
||||
-rw-r--r-- 1 root other 785 Jan 21 19:09 South
|
||||
-rw-r--r-- 1 root other 825 Jan 21 19:09 Tasmania
|
||||
-rw-r--r-- 1 root other 785 Jan 21 19:09 Victoria
|
||||
-rw-r--r-- 1 root other 150 Jan 21 19:09 West
|
||||
-rw-r--r-- 1 root other 785 Jan 21 19:09 Yancowinna
|
||||
|
||||
./var:
|
||||
total 4
|
||||
drwxr-xr-x 2 www www 512 Jan 21 19:44 log
|
||||
drwxr-xr-x 2 root other 512 Jan 21 18:57 www
|
||||
|
||||
./var/log:
|
||||
total 4
|
||||
-rw-r--r-- 1 root other 202 Jan 21 19:47 access_log
|
||||
-rw-r--r-- 1 root other 590 Jan 21 19:49 error_log
|
||||
|
||||
./var/www:
|
||||
total 0
|
||||
|
||||
Note, your boa binary should be kept outside of the chroot jail as
|
||||
they are not required.
|
||||
|
||||
The commandline issued to boa requires "-r /var/www" which tells
|
||||
boa to chroot to /var/www before it does anything else, including
|
||||
reading its configuration file.
|
||||
|
||||
That's all that's required. Start your new chrooting boa up and enjoy!
|
|
@ -0,0 +1,183 @@
|
|||
# Boa v0.94 configuration file
|
||||
# File format has not changed from 0.93
|
||||
# File format has changed little from 0.92
|
||||
# version changes are noted in the comments
|
||||
#
|
||||
# The Boa configuration file is parsed with a lex/yacc or flex/bison
|
||||
# generated parser. If it reports an error, the line number will be
|
||||
# provided; it should be easy to spot. The syntax of each of these
|
||||
# rules is very simple, and they can occur in any order. Where possible
|
||||
# these directives mimic those of NCSA httpd 1.3; I saw no reason to
|
||||
# introduce gratuitous differences.
|
||||
|
||||
# $Id: boa.conf,v 1.2 2001/09/25 03:28:31 jnelson Exp $
|
||||
|
||||
# The "ServerRoot" is not in this configuration file. It can be compiled
|
||||
# into the server (see defines.h) or specified on the command line with
|
||||
# the -c option, for example:
|
||||
#
|
||||
# boa -c /usr/local/boa
|
||||
|
||||
|
||||
# Port: The port Boa runs on. The default port for http servers is 80.
|
||||
# If it is less than 1024, the server must be started as root.
|
||||
|
||||
Port 80
|
||||
|
||||
# Listen: the Internet address to bind(2) to. If you leave it out,
|
||||
# it takes the behavior before 0.93.17.2, which is to bind to all
|
||||
# addresses (INADDR_ANY). You only get one "Listen" directive,
|
||||
# if you want service on multiple IP addresses, you have three choices:
|
||||
# 1. Run boa without a "Listen" directive
|
||||
# a. All addresses are treated the same; makes sense if the addresses
|
||||
# are localhost, ppp, and eth0.
|
||||
# b. Use the VirtualHost directive below to point requests to different
|
||||
# files. Should be good for a very large number of addresses (web
|
||||
# hosting clients).
|
||||
# 2. Run one copy of boa per IP address, each has its own configuration
|
||||
# with a "Listen" directive. No big deal up to a few tens of addresses.
|
||||
# Nice separation between clients.
|
||||
# The name you provide gets run through inet_aton(3), so you have to use dotted
|
||||
# quad notation. This configuration is too important to trust some DNS.
|
||||
|
||||
#Listen 192.68.0.5
|
||||
|
||||
# User: The name or UID the server should run as.
|
||||
# Group: The group name or GID the server should run as.
|
||||
|
||||
User nobody
|
||||
Group nobody
|
||||
|
||||
# ServerAdmin: The email address where server problems should be sent.
|
||||
# Note: this is not currently used, except as an environment variable
|
||||
# for CGIs.
|
||||
|
||||
#ServerAdmin root@localhost
|
||||
|
||||
# ErrorLog: The location of the error log file. If this does not start
|
||||
# with /, it is considered relative to the server root.
|
||||
# Set to /dev/null if you don't want errors logged.
|
||||
# If unset, defaults to /dev/stderr
|
||||
|
||||
ErrorLog /var/log/boa/error_log
|
||||
# Please NOTE: Sending the logs to a pipe ('|'), as shown below,
|
||||
# is somewhat experimental and might fail under heavy load.
|
||||
# "Usual libc implementations of printf will stall the whole
|
||||
# process if the receiving end of a pipe stops reading."
|
||||
#ErrorLog "|/usr/sbin/cronolog --symlink=/var/log/boa/error_log /var/log/boa/error-%Y%m%d.log"
|
||||
|
||||
# AccessLog: The location of the access log file. If this does not
|
||||
# start with /, it is considered relative to the server root.
|
||||
# Comment out or set to /dev/null (less effective) to disable
|
||||
# Access logging.
|
||||
|
||||
AccessLog /var/log/boa/access_log
|
||||
# Please NOTE: Sending the logs to a pipe ('|'), as shown below,
|
||||
# is somewhat experimental and might fail under heavy load.
|
||||
# "Usual libc implementations of printf will stall the whole
|
||||
# process if the receiving end of a pipe stops reading."
|
||||
#AccessLog "|/usr/sbin/cronolog --symlink=/var/log/boa/access_log /var/log/boa/access-%Y%m%d.log"
|
||||
|
||||
# VerboseCGILogs: this is just a logical switch.
|
||||
# It simply notes the start and stop times of cgis in the error log
|
||||
# Comment out to disable.
|
||||
|
||||
#VerboseCGILogs
|
||||
|
||||
# ServerName: the name of this server that should be sent back to
|
||||
# clients if different than that returned by gethostname + gethostbyname
|
||||
|
||||
#ServerName www.your.org.here
|
||||
|
||||
# VirtualHost: a logical switch.
|
||||
# Comment out to disable.
|
||||
# Given DocumentRoot /var/www, requests on interface 'A' or IP 'IP-A'
|
||||
# become /var/www/IP-A.
|
||||
# Example: http://localhost/ becomes /var/www/127.0.0.1
|
||||
#
|
||||
# Not used until version 0.93.17.2. This "feature" also breaks commonlog
|
||||
# output rules, it prepends the interface number to each access_log line.
|
||||
# You are expected to fix that problem with a postprocessing script.
|
||||
|
||||
#VirtualHost
|
||||
|
||||
# DocumentRoot: The root directory of the HTML documents.
|
||||
# Comment out to disable server non user files.
|
||||
|
||||
DocumentRoot /home/httpd/html
|
||||
|
||||
# UserDir: The name of the directory which is appended onto a user's home
|
||||
# directory if a ~user request is recieved.
|
||||
|
||||
UserDir public_html
|
||||
|
||||
# DirectoryIndex: Name of the file to use as a pre-written HTML
|
||||
# directory index. Please MAKE AND USE THESE FILES. On the
|
||||
# fly creation of directory indexes can be _slow_.
|
||||
# Comment out to always use DirectoryMaker
|
||||
|
||||
DirectoryIndex index.html
|
||||
|
||||
# DirectoryMaker: Name of program used to create a directory listing.
|
||||
# Comment out to disable directory listings. If both this and
|
||||
# DirectoryIndex are commented out, accessing a directory will give
|
||||
# an error (though accessing files in the directory are still ok).
|
||||
|
||||
DirectoryMaker /usr/lib/boa/boa_indexer
|
||||
|
||||
# DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker
|
||||
# has been commented out, the the on-the-fly indexing of Boa can be used
|
||||
# to generate indexes of directories. Be warned that the output is
|
||||
# extremely minimal and can cause delays when slow disks are used.
|
||||
# Note: The DirectoryCache must be writable by the same user/group that
|
||||
# Boa runs as.
|
||||
|
||||
# DirectoryCache /var/spool/boa/dircache
|
||||
|
||||
# KeepAliveMax: Number of KeepAlive requests to allow per connection
|
||||
# Comment out, or set to 0 to disable keepalive processing
|
||||
|
||||
KeepAliveMax 1000
|
||||
|
||||
# KeepAliveTimeout: seconds to wait before keepalive connection times out
|
||||
|
||||
KeepAliveTimeout 10
|
||||
|
||||
# MimeTypes: This is the file that is used to generate mime type pairs
|
||||
# and Content-Type fields for boa.
|
||||
# Set to /dev/null if you do not want to load a mime types file.
|
||||
# Do *not* comment out (better use AddType!)
|
||||
|
||||
MimeTypes /etc/mime.types
|
||||
|
||||
# DefaultType: MIME type used if the file extension is unknown, or there
|
||||
# is no file extension.
|
||||
|
||||
DefaultType text/plain
|
||||
|
||||
# AddType: adds types without editing mime.types
|
||||
# Example: AddType type extension [extension ...]
|
||||
|
||||
# Uncomment the next line if you want .cgi files to execute from anywhere
|
||||
#AddType application/x-httpd-cgi cgi
|
||||
|
||||
# Redirect, Alias, and ScriptAlias all have the same semantics -- they
|
||||
# match the beginning of a request and take appropriate action. Use
|
||||
# Redirect for other servers, Alias for the same server, and ScriptAlias
|
||||
# to enable directories for script execution.
|
||||
|
||||
# Redirect allows you to tell clients about documents which used to exist in
|
||||
# your server's namespace, but do not anymore. This allows you to tell the
|
||||
# clients where to look for the relocated document.
|
||||
# Example: Redirect /bar http://elsewhere/feh/bar
|
||||
|
||||
# Aliases: Aliases one path to another.
|
||||
# Example: Alias /path1/bar /path2/foo
|
||||
|
||||
Alias /doc /usr/doc
|
||||
|
||||
# ScriptAlias: Maps a virtual path to a directory for serving scripts
|
||||
# Example: ScriptAlias /htbin/ /www/htbin/
|
||||
|
||||
ScriptAlias /cgi-bin/ /home/httpd/cgi-bin/
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/sh
|
||||
# The following two lines enable chkconfig(1) to manipulate this script
|
||||
# chkconfig: 345 87 13
|
||||
# description: Boa is a World Wide Web server. It is used to serve \
|
||||
# HTML files and CGI.
|
||||
# processname: boa
|
||||
# config: /etc/boa/boa.conf
|
||||
# There is no pid file
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting boa: "
|
||||
daemon boa
|
||||
touch /var/lock/subsys/boa
|
||||
echo
|
||||
;;
|
||||
stop)
|
||||
echo -n "Shutting down boa: "
|
||||
killproc boa
|
||||
echo
|
||||
rm -f /var/lock/subsys/boa
|
||||
rm -f /var/run/boa.pid
|
||||
;;
|
||||
status)
|
||||
status boa
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
reload)
|
||||
echo -n "Reloading boa: "
|
||||
killproc boa -HUP
|
||||
echo
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|reload|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,6 @@
|
|||
/var/log/boa/*_log {
|
||||
weekly
|
||||
compress
|
||||
copytruncate
|
||||
missingok
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
Summary: a single-tasking high performance http server
|
||||
Name: boa
|
||||
Version: 0.94.9
|
||||
Release: 1
|
||||
Group: System Environment/Daemons
|
||||
Source: http://www.boa.org/boa-%{version}.tar.gz
|
||||
Copyright: GNU general public license
|
||||
Requires: /etc/mime.types
|
||||
Prereq: /sbin/chkconfig, man, gzip
|
||||
Provides: setup webserver
|
||||
Buildroot: /usr/tmp/boa
|
||||
|
||||
%description
|
||||
Boa is a single-tasking HTTP server. That means that
|
||||
unlike traditional web servers, it does not fork for each
|
||||
incoming connection, nor does it fork many copies of
|
||||
itself to handle multiple connections. It internally mul
|
||||
tiplexes all of the ongoing HTTP connections, and forks
|
||||
only for CGI programs (which must be separate processes.)
|
||||
Preliminary tests show Boa is more than twice as fast as
|
||||
Apache.
|
||||
|
||||
Boa was created in 1991 by Paul Phillips <psp@well.com>. It is now being
|
||||
maintained and enhanced by Larry Doolittle <ldoolitt@boa.org>
|
||||
and Jon Nelson <jnelson@boa.org>.
|
||||
|
||||
For more information (including installation instructions) examine
|
||||
the file docs/boa.txt or docs/boa.dvi, point your web browser to docs/boa.html,
|
||||
or visit the Boa homepage at
|
||||
|
||||
http://www.boa.org/
|
||||
|
||||
%changelog
|
||||
* Thu Aug 6 2000 Jonathon D Nelson <jnelson@boa.org>
|
||||
- revamp packaging based upon examples provided by
|
||||
Jules Stuifbergen <jules@zjuul.net> and others
|
||||
|
||||
%prep
|
||||
%setup -T -b 0
|
||||
%build
|
||||
(cd src && CFLAGS=$RPM_OPT_FLAGS ./configure --prefix=$RPM_BUILD_ROOT)
|
||||
(cd src && make)
|
||||
(cd docs && gzip -c boa.8 > boa.8.gz)
|
||||
(cd docs && make boa.html)
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/{boa,logrotate.d}
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/sbin
|
||||
mkdir -p $RPM_BUILD_ROOT/home/httpd/{html,cgi-bin}
|
||||
mkdir -p $RPM_BUILD_ROOT/var/log/boa
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/lib/boa
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/man/man8
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
|
||||
|
||||
install -m755 src/boa $RPM_BUILD_ROOT/usr/sbin/
|
||||
install -m755 src/boa_indexer $RPM_BUILD_ROOT/usr/lib/boa/
|
||||
install -m644 redhat/boa.conf $RPM_BUILD_ROOT/etc/boa/
|
||||
install -m755 redhat/boa.init $RPM_BUILD_ROOT/etc/rc.d/init.d/boa
|
||||
mv docs/boa.8.gz $RPM_BUILD_ROOT/usr/man/man8/
|
||||
install -m644 redhat/boa.logrotate $RPM_BUILD_ROOT/etc/logrotate.d/boa
|
||||
|
||||
touch $RPM_BUILD_ROOT/var/log/boa/{error,access}_log
|
||||
|
||||
%post
|
||||
/sbin/chkconfig boa reset
|
||||
|
||||
%preun
|
||||
/etc/rc.d/init.d/boa stop
|
||||
/sbin/chkconfig --del boa
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%dir /home/httpd/html
|
||||
%dir /home/httpd/cgi-bin
|
||||
%dir /var/log/boa
|
||||
%doc Gnu_License README docs/*
|
||||
%doc /usr/man/man8/*
|
||||
%config /etc/boa/boa.conf
|
||||
%config /etc/rc.d/init.d/boa
|
||||
%config /etc/logrotate.d/boa
|
||||
%attr(600,nobody,nobody)/var/log/boa/error_log
|
||||
%attr(600,nobody,nobody)/var/log/boa/access_log
|
||||
/usr/sbin/boa
|
||||
/usr/lib/boa/boa_indexer
|
|
@ -0,0 +1,31 @@
|
|||
all: boa.html boa_toc.html boa.dvi boa.info boa.txt
|
||||
|
||||
boa.info: boa.texi
|
||||
makeinfo --number-sections boa.texi
|
||||
|
||||
boa.dvi: boa.texi
|
||||
texi2dvi --clean boa.texi
|
||||
|
||||
boa.pdf: boa.texi
|
||||
texi2dvi --pdf --clean boa.texi
|
||||
|
||||
boa.ps: boa.dvi
|
||||
dvips -o boa.ps boa.dvi
|
||||
|
||||
boa_toc.html: boa.texi
|
||||
texi2html -split_chapter -menu boa.texi
|
||||
|
||||
boa.html: boa.texi
|
||||
makeinfo --html --number-sections --no-split -o - boa.texi | \
|
||||
sed -e 's/Node:.*//' | sed -e 's/Next:.*//' | \
|
||||
sed -e 's/Previous:.*//' | sed -e 's/Up:.*//' > boa.html
|
||||
|
||||
boa.txt: boa.texi
|
||||
makeinfo --no-headers --no-split -o boa.txt boa.texi
|
||||
|
||||
|
||||
cleanup:
|
||||
rm -f boa.{cp,fn,fns,ky,log,pg,toc,tp,vr,vrs,aux} *~
|
||||
|
||||
clean: cleanup
|
||||
rm -f boa.{html,txt,dvi,ps,pdf,info} boa_*.html
|
|
@ -0,0 +1,196 @@
|
|||
.TH BOA 8 "Jan 22 2000" "Version 0.94"
|
||||
.SH NAME
|
||||
.B boa \- a single\-tasking high performance http server
|
||||
.SH SYNOPSIS
|
||||
.B boa
|
||||
.RB [ -c
|
||||
.IR server_root ]
|
||||
.RB [ -r
|
||||
.IR chroot ]
|
||||
.RB [ -d ]
|
||||
.SH DESCRIPTION
|
||||
Boa is a single-tasking HTTP server. That means that unlike traditional web
|
||||
servers, it does not fork for each incoming connection, nor does it fork many
|
||||
copies of itself to handle multiple connections. It internally multiplexes all
|
||||
of the ongoing HTTP connections, and forks only for CGI programs (which must be
|
||||
separate processes.) Preliminary tests show Boa is more than twice as fast as
|
||||
Apache.
|
||||
.PP
|
||||
The primary design goals of Boa are speed and security. Security, in the sense
|
||||
of "can't be subverted by a malicious user", not "fine grained access control
|
||||
and encrypted communications". Boa is not intended as a feature-packed server;
|
||||
if you want one of those, check out WN from John Franks. Modifications to Boa
|
||||
that improve its speed, security, robustness, and portability, are eagerly
|
||||
sought. Other features may be added if they can be achieved without hurting the
|
||||
primary goals.
|
||||
.SH OPTIONS
|
||||
.IP \fB-d\fR
|
||||
instruct Boa not to fork itself (non-daemonize).
|
||||
|
||||
.IP "\fB-c \fIserver_root\fR"
|
||||
choose a server root overriding the default SERVER_ROOT #define in
|
||||
.I defines.h
|
||||
|
||||
The server root must hold your local copy of the configuration file
|
||||
|
||||
.IP "\fB-r \fIchroot\fR"
|
||||
instruct Boa where to chdir and chroot to. The chdir/chroot
|
||||
is done before the configuration file is read, or any log
|
||||
files are opened.
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
\fBboa.conf\fR \- the sole configuration file for Boa.
|
||||
The directives in this file are defined in the
|
||||
.B DIRECTIVES
|
||||
section.
|
||||
|
||||
.TP
|
||||
\fBmime.types\fR \- the
|
||||
MimeTypes <filename>
|
||||
defines what Content-Type Boa will send in an HTTP/1.0
|
||||
or better transaction.
|
||||
.SH DIRECTIVES
|
||||
|
||||
The Boa configuration file is parsed with a lex/yacc or flex/bison generated
|
||||
parser. If it reports an error, the line number will be provided; it should
|
||||
be easy to spot. The syntax of each of these rules is very simple, and they
|
||||
can occur in any order. Where possible, these directives mimic those of NCSA
|
||||
httpd 1.3; We saw no reason to introduce gratuitous differences.
|
||||
.PP
|
||||
Note: the "ServerRoot" is not in this configuration file. It can be compiled
|
||||
into the server (see
|
||||
.I defines.h
|
||||
) or specified on the command line with the
|
||||
.B -c
|
||||
option.
|
||||
|
||||
The following directives are contained in the
|
||||
.I boa.conf
|
||||
file, and most, but not all, are required.
|
||||
.TP
|
||||
Port <integer>
|
||||
This is the port that Boa runs on. The default port for http servers is 80.
|
||||
If it is less than 1024, the server must be started as root.
|
||||
.TP
|
||||
User <user name or UID>
|
||||
The name or UID the server should run as. For Boa to attempt this, the
|
||||
server must be started as root.
|
||||
.TP
|
||||
Group <group name or GID>
|
||||
The group name or GID the server should run as. For Boa to attempt this,
|
||||
the server must be started as root.
|
||||
.TP
|
||||
ServerAdmin <email address>
|
||||
The email address where server problems should be sent.
|
||||
Note: this is not currently used.
|
||||
.TP
|
||||
ErrorLog <filename>
|
||||
The location of the error log file. If this does not start with
|
||||
/, it is considered relative to the server root.
|
||||
Set to /dev/null if you don't want errors logged.
|
||||
.TP
|
||||
AccessLog <filename>
|
||||
The location of the access log file. If this does not start with /, it is
|
||||
considered relative to the server root.
|
||||
Comment out or set to /dev/null (less effective) to disable access logging.
|
||||
.TP
|
||||
VerboseCGILogs
|
||||
This is a logical switch and does not take any parameters.
|
||||
Comment out to disable.
|
||||
.TP
|
||||
ServerName <server_name>
|
||||
The name of this server that should be sent back to
|
||||
clients if different than that returned by gethostname.
|
||||
.Tp
|
||||
VirtualHost
|
||||
This is a logical switch and does not take any parameters.
|
||||
Comment out to disable.
|
||||
Given DocumentRoot /var/www, requests on interface 'A' or IP 'IP-A'
|
||||
become /var/www/IP-A.
|
||||
Example: http://localhost/ becomes /var/www/127.0.0.1
|
||||
.TP
|
||||
DocumentRoot <directory>
|
||||
The root directory of the HTML documents. If this does not start with
|
||||
/, it is considered relative to the server root.
|
||||
.TP
|
||||
UserDir <directory>
|
||||
The name of the directory which is appended onto a user's home directory if a
|
||||
~user request is received.
|
||||
.TP
|
||||
DirectoryIndex <filename>
|
||||
Name of the file to use as a pre-written HTML directory index. Please make
|
||||
and use these files. On the fly creation of directory indexes can be slow.
|
||||
.TP
|
||||
DirectoryMaker <directory>
|
||||
Name of the program used to generate on-the-fly directory listings.
|
||||
The program must take one or two command-line arguments, the first
|
||||
being the directory to index (absolute), and the second, which is optional,
|
||||
contains what Boa would have the "title" of the document be.
|
||||
Comment out if you don't want on the fly directory listings.
|
||||
If this does not start with
|
||||
/, it is considered relative to the server root.
|
||||
.TP
|
||||
KeepAliveMax <integer>
|
||||
Number of KeepAlive requests to allow per connection. Comment out, or set
|
||||
to 0 to disable keepalive processing.
|
||||
.TP
|
||||
KeepAliveTimeout <integer>
|
||||
Number of seconds to wait before keepalive connections time out.
|
||||
.TP
|
||||
MimeTypes <file>
|
||||
The location of the
|
||||
.I mime.types
|
||||
file. If this does not start with /, it is considered relative to
|
||||
the server root. Set to /dev/null if you do not want to load a mime types
|
||||
file. Do *not* comment out (better use AddType!)
|
||||
.TP
|
||||
DefaultType <mime type>
|
||||
MIME type used if the file extension is unknown, or there is no file extension.
|
||||
.TP
|
||||
AddType <mime type> <extension> [extension...]
|
||||
Associates a MIME type with an extension or extensions.
|
||||
.TP
|
||||
Redirect, Alias, and ScriptAlias <path1> <path2>
|
||||
Redirect, Alias, and ScriptAlias all have the same semantics \-\- they
|
||||
match the beginning of a request and take appropriate action. Use
|
||||
Redirect for other servers, Alias for the same server, and ScriptAlias to
|
||||
enable directories for script execution.
|
||||
|
||||
Redirect allows you to tell clients about documents which used to exist
|
||||
in your server's namespace, but do not anymore. This allows you tell
|
||||
the clients where to look for the relocated document.
|
||||
|
||||
Alias aliases one path to another. Of course, symbolic links in the
|
||||
file system work fine too.
|
||||
|
||||
ScriptAlias maps a virtual path to a directory for serving scripts.
|
||||
.PP
|
||||
Please see the included
|
||||
.I boa.conf
|
||||
for defaults and examples.
|
||||
.SH HISTORY
|
||||
Like the Linux kernel, even numbered versions are "stable", and odd numbered
|
||||
versions are "unstable", or rather, "development".
|
||||
Versions 0.91 and 0.91beta of Boa were released by Paul Phillips <paulp@go2net.com>
|
||||
.PP
|
||||
Version 0.92 was released by Larry Doolittle on
|
||||
December 12, 1996.
|
||||
.PP
|
||||
Version 0.93 was the development version of 0.94.
|
||||
.PP
|
||||
Version 0.94 was released 22 Jan 2000.
|
||||
.SH BUGS
|
||||
There are probably bugs, but we are not aware of any at this time.
|
||||
.SH AUTHOR
|
||||
Boa was created by Paul Phillips <paulp@go2net.com>. It is now being maintained and
|
||||
enhanced by Larry Doolittle
|
||||
<ldoolitt@boa.org> and
|
||||
Jon Nelson <jnelson@boa.org>.
|
||||
.PP
|
||||
Linux is the development platform at the moment, other
|
||||
OS's are known to work. If you'd like to
|
||||
contribute to this effort, contact Larry or Jon via e-mail.
|
||||
.SH LICENSE
|
||||
This program is distributed under the GNU General Public License, as noted in
|
||||
each source file.
|
|
@ -0,0 +1,772 @@
|
|||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename boa.info
|
||||
@settitle The Boa HTTP Daemon
|
||||
@set UPDATED Last Updated: 2 Jan 2001
|
||||
@set COPYPHRASE Copyright @copyright{} 1996-2001 Jon Nelson and Larry Doolittle
|
||||
@set VERSION $Revision: 1.5 $
|
||||
|
||||
@paragraphindent asis
|
||||
@iftex
|
||||
@parindent 0pt
|
||||
@end iftex
|
||||
@c @setchapternewpage odd
|
||||
@c %**end of header
|
||||
|
||||
@iftex
|
||||
@titlepage
|
||||
@title The Boa HTTP Daemon
|
||||
@c @sp 2
|
||||
@end iftex
|
||||
|
||||
@ifinfo
|
||||
This file documents Boa, an HTTP daemon for UN*X like machines.
|
||||
@end ifinfo
|
||||
|
||||
@html
|
||||
<h1 align="center">The Boa HTTP Daemon</h1>
|
||||
<center><img src="boa_banner.png"></center>
|
||||
@end html
|
||||
|
||||
@ifinfo
|
||||
@dircategory Networking
|
||||
@direntry
|
||||
* Boa: (boa). The Boa Webserver
|
||||
@end direntry
|
||||
@end ifinfo
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Top, Introduction, , (dir)
|
||||
|
||||
Welcome to the documentation for Boa, a high performance
|
||||
HTTP Server for UN*X-alike computers, covered by the
|
||||
@uref{Gnu_License,GNU General Public License}.
|
||||
The on-line, updated copy of this documentation lives at
|
||||
@uref{http://www.boa.org/,http://www.boa.org/}
|
||||
@sp 1
|
||||
@center @value{COPYPHRASE}
|
||||
@center @value{UPDATED}, @value{VERSION}
|
||||
|
||||
@iftex
|
||||
@end titlepage
|
||||
@contents
|
||||
@end iftex
|
||||
|
||||
@menu
|
||||
* Introduction::
|
||||
* Installation and Usage::
|
||||
* Limits and Design Philosophy::
|
||||
* Appendix::
|
||||
|
||||
-- Detailed Node Listing --
|
||||
|
||||
Installation
|
||||
|
||||
* Files Used by Boa::
|
||||
* Compile-Time and Command-Line Options::
|
||||
* boa.conf Directives::
|
||||
* Security::
|
||||
|
||||
Limits and Design Philosophy
|
||||
|
||||
* Limits::
|
||||
* Differences between Boa and other web servers::
|
||||
* Unexpected Behavior::
|
||||
|
||||
Appendix
|
||||
|
||||
* License::
|
||||
* Acknowledgments::
|
||||
* Reference Documents::
|
||||
* Other HTTP Servers::
|
||||
* Benchmarks::
|
||||
* Tools::
|
||||
* Authors::
|
||||
|
||||
@end menu
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Introduction, Installation and Usage,top,top
|
||||
@chapter Introduction
|
||||
|
||||
Boa is a single-tasking HTTP server. That means that unlike
|
||||
traditional web servers, it does not fork for each incoming
|
||||
connection, nor does it fork many copies of itself to handle multiple
|
||||
connections. It internally multiplexes all of the ongoing HTTP
|
||||
connections, and forks only for CGI programs (which must be separate
|
||||
processes), automatic directory generation, and automatic file
|
||||
gunzipping. Preliminary tests show Boa is capable of
|
||||
handling several thousand hits per second on a 300 MHz Pentium and
|
||||
dozens of hits per second on a lowly 20 MHz 386/SX.
|
||||
|
||||
The primary design goals of Boa are speed and security. Security,
|
||||
in the sense of @emph{can't be subverted by a malicious user,} not
|
||||
@emph{fine grained access control and encrypted communications}.
|
||||
Boa is not intended as a feature-packed server; if you want one of those,
|
||||
check out
|
||||
WN (@uref{http://hopf.math.nwu.edu/}) from John Franks.
|
||||
Modifications to Boa that improve its speed, security, robustness, and
|
||||
portability, are eagerly sought. Other features may be added if they
|
||||
can be achieved without hurting the primary goals.
|
||||
|
||||
Boa was created in 1991 by Paul Phillips (@email{psp@@well.com}).
|
||||
It is now being maintained and enhanced by Larry Doolittle
|
||||
(@email{ldoolitt@@boa.org}) and Jon Nelson
|
||||
(@email{jnelson@@boa.org}).
|
||||
Please see the acknowledgement section for further
|
||||
details.
|
||||
|
||||
GNU/Linux is the development platform at the moment, other OS's are known to work.
|
||||
If you'd like to contribute to this effort, contact Larry or Jon via e-mail.
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Installation and Usage, Limits and Design Philosophy, Introduction,top
|
||||
@chapter Installation and Usage
|
||||
|
||||
Boa is currently being developed and tested on GNU/Linux/i386.
|
||||
The code is straightforward (more so than most other servers),
|
||||
so it should run easily on most modern Unix-alike platforms. Recent
|
||||
versions of Boa worked fine on FreeBSD, SunOS 4.1.4, GNU/Linux-SPARC,
|
||||
and HP-UX 9.0. Pre-1.2.0 GNU/Linux kernels may not work because of
|
||||
deficient mmap() implementations.
|
||||
|
||||
@menu
|
||||
* Installation::
|
||||
* Files Used by Boa::
|
||||
* Compile-Time and Command-Line Options::
|
||||
* Security::
|
||||
@end menu
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Installation,Files Used by Boa,,Installation and Usage
|
||||
@section Installation
|
||||
|
||||
@enumerate
|
||||
@item Unpack
|
||||
@enumerate
|
||||
@item Choose, and cd into, a convenient directory for the package.
|
||||
@item @kbd{tar -xvzf boa-0.94.tar.gz}, or for those of you with an archaic
|
||||
(non-GNU) tar; @kbd{gzip -cd < boa-0.94.tar.gz | tar -xvf -}
|
||||
@item Read the documentation. Really.
|
||||
@end enumerate
|
||||
@item Build
|
||||
@enumerate
|
||||
@item cd into the @t{src} directory.
|
||||
@item (optional) Change the default SERVER_ROOT by setting the #define
|
||||
at the top of src/defines.h
|
||||
@item Type @kbd{./configure; make}
|
||||
@item Report any errors to the maintainers for resolution, or strike
|
||||
out on your own.
|
||||
@end enumerate
|
||||
@item Configure
|
||||
@enumerate
|
||||
@item Choose a user and server port under which Boa can run. The
|
||||
traditional port is 80, and user @t{nobody} (create if
|
||||
you need to) is often a good selection for security purposes.
|
||||
If you don't have (or choose not to use) root privileges, you
|
||||
can not use port numbers less than 1024, nor can you switch user id.
|
||||
@item Choose a server root. The @t{conf} directory within the
|
||||
server root must hold your copy of the configuration file
|
||||
@emph{boa.conf}
|
||||
@item Choose locations for log files, CGI programs (if any), and
|
||||
the base of your URL tree.
|
||||
@item Set the location of the @t{mime.types} file.
|
||||
@item Edit @emph{conf/boa.conf} according to your
|
||||
choices above (this file documents itself). Read through this file
|
||||
to see what other features you can configure.
|
||||
@end enumerate
|
||||
@item Start
|
||||
@itemize
|
||||
@item Start Boa. If you didn't build the right SERVER_ROOT into the
|
||||
binary, you can specify it on the command line with the -c option
|
||||
(command line takes precedence).
|
||||
@example
|
||||
Example: ./boa -c /usr/local/boa
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
@item Test
|
||||
@itemize
|
||||
@item At this point the server should run and serve documents.
|
||||
If not, check the error_log file for clues.
|
||||
@end itemize
|
||||
|
||||
@item Install
|
||||
@itemize
|
||||
@item Copy the binary to a safe place, and put the invocation into
|
||||
your system startup scripts. Use the same -c option you used
|
||||
in your initial tests.
|
||||
@end itemize
|
||||
@end enumerate
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Files Used by Boa, Compile-Time and Command-Line Options, Installation,Installation and Usage
|
||||
@section Files Used by Boa
|
||||
|
||||
@ftable @file
|
||||
@item boa.conf
|
||||
This file is the sole configuration file for Boa. The directives in this
|
||||
file are defined in the DIRECTIVES section.
|
||||
@item mime.types
|
||||
The MimeTypes <filename> defines what Content-Type Boa will
|
||||
send in an HTTP/1.0 or better transaction.
|
||||
Set to /dev/null if you do not want to load a mime types file.
|
||||
Do *not* comment out (better use AddType!)
|
||||
@end ftable
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Compile-Time and Command-Line Options, boa.conf Directives, Files Used by Boa,Installation and Usage
|
||||
@section Compile-Time and Command-Line Options
|
||||
|
||||
@table @var
|
||||
@item SERVER_ROOT
|
||||
@itemx -c
|
||||
The default server root as #defined by @var{SERVER_ROOT} in
|
||||
@file{defines.h} can be overridden on the commandline using the
|
||||
@option{-c} option. The server root must hold your local copy of the
|
||||
configuration file @file{boa.conf}.
|
||||
@example
|
||||
Example: /usr/sbin/boa -c /etc/boa
|
||||
@end example
|
||||
|
||||
@end table
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node boa.conf Directives, Security, Compile-Time and Command-Line Options, (top)
|
||||
@section boa.conf Directives
|
||||
|
||||
The Boa configuration file is parsed with a lex/yacc or flex/bison
|
||||
generated parser. If it reports an error, the line number will be
|
||||
provided; it should be easy to spot. The syntax of each of these rules
|
||||
is very simple, and they can occur in any order. Where possible, these
|
||||
directives mimic those of NCSA httpd 1.3; I (Paul Phillips) saw no reason
|
||||
to introduce gratuitous differences.
|
||||
|
||||
Note: the "ServerRoot" is not in this configuration file. It can be
|
||||
compiled into the server (see @file{defines.h}) or specified on the command
|
||||
line with the @command{-c} option.
|
||||
|
||||
The following directives are contained in the @file{boa.conf} file, and most,
|
||||
but not all, are required.
|
||||
|
||||
@table @option
|
||||
@item Port <Integer>
|
||||
This is the port that Boa runs on. The default port for http servers is 80.
|
||||
If it is less than 1024, the server must be started as root.
|
||||
|
||||
@item Listen <IP>
|
||||
The Internet address to bind(2) to, in quadded-octet form (numbers).
|
||||
If you leave it out, it binds to all addresses (INADDR_ANY).
|
||||
|
||||
The name you provide gets run through inet_aton(3), so you have to
|
||||
use dotted quad notation. This configuration is too important to trust some DNS.
|
||||
|
||||
You only get one "Listen" directive, if you want service on multiple
|
||||
IP addresses, you have three choices:
|
||||
|
||||
@enumerate
|
||||
@item Run boa without a "Listen" directive:
|
||||
@itemize @bullet
|
||||
@item All addresses are treated the same; makes sense if the addresses
|
||||
are localhost, ppp, and eth0.
|
||||
@item Use the VirtualHost directive below to point requests to different files.
|
||||
Should be good for a very large number of addresses (web hosting clients).
|
||||
@end itemize
|
||||
@item Run one copy of boa per IP address:
|
||||
@itemize @bullet
|
||||
@item Each instance has its own configuration with its own
|
||||
"Listen" directive. No big deal up to a few tens of addresses. Nice separation
|
||||
between clients.
|
||||
@end itemize
|
||||
@end enumerate
|
||||
|
||||
@item User <username or UID>
|
||||
The name or UID the server should run as. For Boa to attempt this, the
|
||||
server must be started as root.
|
||||
|
||||
@item Group <groupname or GID>
|
||||
The group name or GID the server should run as. For Boa to attempt this,
|
||||
the server must be started as root.
|
||||
|
||||
@item ServerAdmin <email address>
|
||||
The email address where server problems should be sent. Note: this is not
|
||||
currently used.
|
||||
|
||||
@item ErrorLog <filename>
|
||||
The location of the error log file. If this does not start with /, it is
|
||||
considered relative to the server root. Set to /dev/null if you don't want
|
||||
errors logged.
|
||||
|
||||
@item AccessLog <filename>
|
||||
The location of the access log file. If this does not start with /, it is
|
||||
considered relative to the server root. Comment out or set to /dev/null
|
||||
(less effective) to disable access logging.
|
||||
|
||||
@item VerboseCGILogs
|
||||
This is a logical switch and does not take any parameters. Comment out to
|
||||
disable. All it does is switch on or off logging of when CGIs are launched and when
|
||||
the children return.
|
||||
|
||||
@item CgiLog <filename>
|
||||
The location of the CGI error log file. If
|
||||
specified, this is the file that the stderr of CGIs is tied to. Otherwise, writes
|
||||
to stderr meet the bit bucket.
|
||||
|
||||
@item ServerName <server_name>
|
||||
The name of this server that should be sent back to clients if different
|
||||
than that returned by gethostname.
|
||||
|
||||
@item VirtualHost
|
||||
This is a logical switch and does not take any parameters.
|
||||
Comment out to disable. Given DocumentRoot /var/www, requests on interface `A' or
|
||||
IP `IP-A' become /var/www/IP-A. Example: http://localhost/ becomes
|
||||
/var/www/127.0.0.1
|
||||
|
||||
@item DocumentRoot <directory>
|
||||
The root directory of the HTML documents. If this does not start with /,
|
||||
it is considered relative to the server root.
|
||||
|
||||
@item UserDir <directory>
|
||||
The name of the directory which is appended onto a user's home directory
|
||||
if a ~user request is received.
|
||||
|
||||
@item DirectoryIndex <filename>
|
||||
Name of the file to use as a pre-written HTML directory index. Please
|
||||
make and use these files. On the fly creation of directory indexes
|
||||
can be slow.
|
||||
|
||||
@item DirectoryMaker <full pathname to program>
|
||||
Name of the program used
|
||||
to generate on-the-fly directory listings. The program must take one or two
|
||||
command-line arguments, the first being the directory to index (absolute), and the
|
||||
second, which is optional, should be the "title" of the document be. Comment out if
|
||||
you don't want on the fly directory listings. If this does not start with /, it is
|
||||
considered relative to the server root.
|
||||
|
||||
@item DirectoryCache <directory>
|
||||
DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker has been
|
||||
commented out, the the on-the-fly indexing of Boa can be used to generate indexes
|
||||
of directories. Be warned that the output is extremely minimal and can cause
|
||||
delays when slow disks are used. Note: The DirectoryCache must be writable by the
|
||||
same user/group that Boa runs as.
|
||||
|
||||
@item KeepAliveMax <integer>
|
||||
Number of KeepAlive requests to allow per connection. Comment out, or set
|
||||
to 0 to disable keepalive processing.
|
||||
|
||||
@item KeepAliveTimeout <integer>
|
||||
Number of seconds to wait before keepalive connections time out.
|
||||
|
||||
@item MimeTypes <file>
|
||||
The location of the mime.types file. If this does not start with /, it is
|
||||
considered relative to the server root.
|
||||
Comment out to avoid loading mime.types (better use AddType!)
|
||||
|
||||
@item DefaultType <mime type>
|
||||
MIME type used if the file extension is unknown, or there is no file
|
||||
extension.
|
||||
|
||||
@item AddType <mime type> <extension> extension...
|
||||
Associates a MIME type
|
||||
with an extension or extensions.
|
||||
|
||||
@item Redirect, Alias, and ScriptAlias
|
||||
Redirect, Alias, and ScriptAlias all have the same semantics --
|
||||
they match the beginning of a request and take appropriate action.
|
||||
Use Redirect for other servers, Alias for the same server, and
|
||||
ScriptAlias to enable directories for script execution.
|
||||
|
||||
@item Redirect <path1> <path2>
|
||||
allows you to tell clients about documents which used to exist
|
||||
in your server's namespace, but do not anymore. This allows you
|
||||
tell the clients where to look for the relocated document.
|
||||
|
||||
@item Alias <path1> <path2>
|
||||
aliases one path to another. Of course, symbolic links in the
|
||||
file system work fine too.
|
||||
|
||||
@item ScriptAlias <path1> <path2>
|
||||
maps a virtual path to a directory for serving scripts.
|
||||
@end table
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Security, , boa.conf Directives, Installation and Usage
|
||||
@section Security
|
||||
|
||||
Boa has been designed to use the existing file system security. In
|
||||
@file{boa.conf}, the directives @emph{user} and
|
||||
@emph{group} determine who Boa will run as, if launched by root.
|
||||
By default, the user/group is nobody/nogroup. This allows quite a bit
|
||||
of flexibility. For example, if you want to disallow access to otherwise
|
||||
accessible directories or files, simply make them inaccessible to
|
||||
nobody/nogroup. If the user that Boa runs as is "boa" and the groups that
|
||||
"boa" belongs to include "web-stuff" then files/directories accessible
|
||||
by users with group "web-stuff" will also be accessible to Boa.
|
||||
|
||||
The February 2000 hoo-rah from
|
||||
@uref{http://www.cert.org/advisories/CA-2000-02.html,CERT advisory CA-2000-02}
|
||||
has little to do with Boa. As of version 0.94.4, Boa's escaping rules have
|
||||
been cleaned up a little, but they weren't that bad before. The example CGI
|
||||
programs have been updated to show what effort is needed there. If you
|
||||
write, maintain, or use CGI programs under Boa (or any other server) it's
|
||||
worth your while to read and understand this advisory. The real problem,
|
||||
however, boils down to browser and web page designers emphasizing frills
|
||||
over content and security. The market leading browsers assume (incorrectly)
|
||||
that all web pages are trustworthy.
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Limits and Design Philosophy,Appendix, Installation and Usage,top
|
||||
@chapter Limits and Design Philosophy
|
||||
|
||||
There are many issues that become more difficult to resolve in a single
|
||||
tasking web server than in the normal forking model. Here is a partial
|
||||
list -- there are probably others that haven't been encountered yet.
|
||||
|
||||
@menu
|
||||
* Limits::
|
||||
* Differences between Boa and other web servers::
|
||||
* Unexpected Behavior::
|
||||
@end menu
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Limits,Differences between Boa and other web servers,,Limits and Design Philosophy
|
||||
@section Limits
|
||||
|
||||
@itemize @bullet
|
||||
@item Slow file systems
|
||||
|
||||
The file systems being served should be much faster than the
|
||||
network connection to the HTTP requests, or performance will suffer.
|
||||
For instance, if a document is served from a CD-ROM, the whole server
|
||||
(including all other currently incomplete data transfers) will stall
|
||||
while the CD-ROM spins up. This is a consequence of the fact that Boa
|
||||
mmap()'s each file being served, and lets the kernel read and cache
|
||||
pages as best it knows how. When the files come from a local disk
|
||||
(the faster the better), this is no problem, and in fact delivers
|
||||
nearly ideal performance under heavy load. Avoid serving documents
|
||||
from NFS and CD-ROM unless you have even slower inbound net
|
||||
connections (e.g., POTS SLIP).
|
||||
|
||||
@item DNS lookups
|
||||
|
||||
Writing a nonblocking gethostbyaddr is a difficult and not very
|
||||
enjoyable task. Paul Phillips experimented with several methods,
|
||||
including a separate logging process, before removing hostname
|
||||
lookups entirely. There is a companion program with Boa
|
||||
@file{util/resolver.pl} that will postprocess the logfiles and
|
||||
replace IP addresses with hostnames, which is much faster no matter
|
||||
what sort of server you run.
|
||||
|
||||
@item Identd lookups
|
||||
|
||||
Same difficulties as hostname lookups; not included.
|
||||
Boa provides a REMOTE_PORT environment variable, in addition
|
||||
to REMOTE_ADDR, so that a CGI program can do its own ident.
|
||||
See the end of @t{examples/cgi-test.cgi}.
|
||||
|
||||
@item Password file lookups via NIS
|
||||
|
||||
If users are allowed to serve HTML from their home directories,
|
||||
password file lookups can potentially block the process. To lessen
|
||||
the impact, each user's home directory is cached by Boa so it need
|
||||
only be looked up once.
|
||||
|
||||
@item Running out of file descriptors
|
||||
|
||||
Since a file descriptor is needed for every ongoing connection
|
||||
(two for non-nph CGIs, directories, and automatic gunzipping of files),
|
||||
it is possible though highly improbable to run out of file
|
||||
descriptors. The symptoms of this conditions may vary with
|
||||
your particular unix variant, but you will probably see log
|
||||
entries giving an error message for @t{accept}.
|
||||
Try to build your kernel to give an adequate number for
|
||||
your usage - GNU/Linux provides 256 out of the box, more than
|
||||
enough for most people.
|
||||
@end itemize
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Differences between Boa and other web servers,Unexpected Behavior,Limits,Limits and Design Philosophy
|
||||
@section Differences between Boa and other web servers
|
||||
|
||||
In the pursuit of speed and simplicity, some aspects of Boa differ
|
||||
from the popular web servers. In no particular order:
|
||||
|
||||
@itemize @bullet
|
||||
@item @var{REMOTE_HOST} environment variable not set for CGI programs
|
||||
|
||||
The @var{REMOTE_HOST} environment variable is not set for CGI programs,
|
||||
for reasons already described. This is easily worked around because the
|
||||
IP address is provided in the @var{REMOTE_HOST} variable, so (if the CGI
|
||||
program actually cares) gethostbyaddr or a variant can be used.
|
||||
|
||||
@item There are no server side includes (@acronym{SSI}) in Boa
|
||||
|
||||
We don't like them, and they are too slow to parse. We will consider
|
||||
more efficient alternatives.
|
||||
|
||||
@item There are no access control features
|
||||
|
||||
Boa will follow symbolic links, and serve any file that it can
|
||||
read. The expectation is that you will configure Boa to run as user
|
||||
"nobody", and only files configured world readable will come
|
||||
out.
|
||||
|
||||
@item No chroot option
|
||||
|
||||
There is no option to run chrooted. If anybody wants this, and is
|
||||
willing to try out experimental code, contact the maintainers.
|
||||
@end itemize
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Unexpected Behavior,,Differences between Boa and other web servers,Limits and Design Philosophy
|
||||
@section Unexpected Behavior
|
||||
|
||||
@itemize @bullet
|
||||
@item SIGHUP handling
|
||||
|
||||
Like any good server, Boa traps SIGHUP and rereads @file{boa.conf}.
|
||||
However, under normal circumstances, it has already given away
|
||||
permissions, so many items listed in @file{boa.conf} can not take effect.
|
||||
No attempt is made to change uid, gid, log files, or server port.
|
||||
All other configuration changes should take place smoothly.
|
||||
|
||||
@item Relative URL handling
|
||||
|
||||
Not all browsers handle relative URLs correctly. Boa will not
|
||||
cover up for this browser bug, and will typically report 404 Not Found
|
||||
for URL's containing odd combinations of "../" 's.
|
||||
|
||||
Note: As of version 0.95.0 (unreleased) the URL parser has been
|
||||
rewritten and *does* correctly handle relative URLs.
|
||||
@end itemize
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Appendix,,Limits and Design Philosophy,top
|
||||
@appendix Appendix
|
||||
|
||||
@menu
|
||||
* License::
|
||||
* Acknowledgments::
|
||||
* Reference Documents::
|
||||
* Other HTTP Servers::
|
||||
* Benchmarks::
|
||||
* Tools::
|
||||
* Authors::
|
||||
@end menu
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node License,Acknowledgments,,Appendix
|
||||
@section License
|
||||
|
||||
This program is distributed under the
|
||||
@uref{http://www.gnu.org/copyleft/gpl.html,GNU General Public License}.
|
||||
as noted in each source file:
|
||||
@*
|
||||
|
||||
@smallexample
|
||||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <psp@@well.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
@end smallexample
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Acknowledgments,Reference Documents,License,Appendix
|
||||
@section Acknowledgments
|
||||
|
||||
Paul Phillips wrote the first versions of Boa, up to and including
|
||||
version 0.91. Version 0.92 of Boa was officially released December 1996
|
||||
by Larry Doolittle. Version 0.93 was the development version of 0.94,
|
||||
which was released in February 2000.
|
||||
|
||||
The Boa Webserver is currently (Feb 2000) maintained and enhanced by
|
||||
Larry Doolittle (@email{ldoolitt@@boa.org})
|
||||
and Jon Nelson (@email{jnelson@@boa.org}).
|
||||
|
||||
We would like to thank Russ Nelson (@email{nelson@@crynwr.com})
|
||||
for hosting the @uref{http://www.boa.org,web site}.
|
||||
|
||||
We would also like to thank Paul Philips for writing code that is
|
||||
worth maintaining and supporting.
|
||||
|
||||
Many people have contributed to Boa, including (but not
|
||||
limited to) Charles F. Randall (@email{randall@@goldsys.com})
|
||||
Christoph Lameter (@email{<chris@@waterf.org>}),
|
||||
Russ Nelson (@email{<nelson@@crynwr.com>}), Alain Magloire
|
||||
(@email{<alain.magloire@@rcsm.ee.mcgill.ca>}),
|
||||
and more recently, M. Drew Streib (@email{<dtype@@linux.com>}).
|
||||
|
||||
Paul Phillips records his acknowledgments as follows:
|
||||
@quotation
|
||||
Thanks to everyone in the WWW community, in general a great bunch of people.
|
||||
Special thanks to Clem Taylor (@email{<ctaylor@@eecis.udel.edu>}), who
|
||||
provided invaluable feedback on many of my ideas, and offered good
|
||||
ones of his own. Also thanks to John Franks, author of wn, for
|
||||
writing what I believe is the best webserver out there.
|
||||
@end quotation
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Reference Documents,Other HTTP Servers,Acknowledgments,Appendix
|
||||
@section Reference Documents
|
||||
|
||||
Links to documents relevant to
|
||||
@uref{http://www.boa.org/,Boa}
|
||||
development and usage. Incomplete, we're still working on this.
|
||||
NCSA has a decent
|
||||
@uref{http://hoohoo.ncsa.uiuc.edu/docs/Library.html,page} along
|
||||
these lines, too.
|
||||
|
||||
Also see Yahoo's List
|
||||
@* @uref{http://www.yahoo.com/Computers_and_Internet/Software/Internet/World_Wide_Web/Servers/}
|
||||
|
||||
@itemize
|
||||
@item W3O HTTP page
|
||||
@* @uref{http://www.w3.org/pub/WWW/Protocols/}
|
||||
|
||||
@item RFC 1945 HTTP-1.0 (informational)
|
||||
@* @uref{http://ds.internic.net/rfc/rfc1945.txt}
|
||||
|
||||
@item IETF Working Group Draft 07 of HTTP-1.1
|
||||
@* @uref{http://www.w3.org/pub/WWW/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-07.txt}
|
||||
|
||||
@item HTTP: A protocol for networked information
|
||||
@* @uref{http://www.w3.org/pub/WWW/Protocols/HTTP/HTTP2.html}
|
||||
|
||||
@item The Common Gateway Interface (CGI)
|
||||
@* @uref{http://hoohoo.ncsa.uiuc.edu/cgi/overview.html}
|
||||
|
||||
@item RFC 1738 URL syntax and semantics
|
||||
@* @uref{http://ds.internic.net/rfc/rfc1738.txt}
|
||||
|
||||
@item RFC 1808 Relative URL syntax and semantics
|
||||
@* @uref{http://ds.internic.net/rfc/rfc1808.txt}
|
||||
@end itemize
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Other HTTP Servers,Benchmarks,Reference Documents,Appendix
|
||||
@section Other HTTP Servers
|
||||
|
||||
For unix-alike platforms, with published source code.
|
||||
|
||||
@itemize
|
||||
@item tiny/turbo/throttling httpd very similar to Boa, with a throttling
|
||||
feature
|
||||
@* @uref{http://www.acme.com/software/thttpd/}
|
||||
|
||||
@item Roxen: based on ulpc interpreter, non-forking (interpreter implements
|
||||
threading), GPL'd
|
||||
@* @uref{http://www.roxen.com/}
|
||||
|
||||
@item WN: featureful, GPL'd
|
||||
@* @uref{http://hopf.math.nwu.edu/}
|
||||
|
||||
@item Apache: fast, PD
|
||||
@* @uref{http://www.apache.org/}
|
||||
|
||||
@item NCSA: standard, legal status?
|
||||
@* @uref{http://hoohoo.ncsa.uiuc.edu/}
|
||||
|
||||
@item CERN: standard, PD, supports proxy
|
||||
@* @uref{http://www.w3.org/pub/WWW/Daemon/Status.html}
|
||||
|
||||
@item xs-httpd 2.0: small, fast, pseudo-GPL'd
|
||||
@* @uref{http://www.stack.nl/~sven/xs-httpd/}
|
||||
|
||||
@item bozohttpd.tar.gz sources, in perl
|
||||
@* @uref{ftp://ftp.eterna.com.au/bozo/bsf/attware/bozohttpd.tar.gz}
|
||||
|
||||
@item Squid is actually an "Internet Object Cache"
|
||||
@* @uref{http://squid.nlanr.net/Squid/}
|
||||
@end itemize
|
||||
|
||||
Also worth mentioning is Zeus.
|
||||
It is commercial, with a free demo, so it doesn't belong on the list above.
|
||||
Zeus seems to be based on technology similar to Boa and thttpd,
|
||||
but with more bells and whistles.
|
||||
@* @uref{http://www.zeus.co.uk/products/server/}
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Benchmarks,Tools,Other HTTP Servers,Appendix
|
||||
@section Benchmarks
|
||||
|
||||
@itemize
|
||||
@item ZeusBench (broken link)
|
||||
@* @uref{http://www.zeus.co.uk/products/server/intro/bench2/zeusbench.shtml}
|
||||
|
||||
@item WebBench (binary-ware)
|
||||
@* @uref{http://web1.zdnet.com/zdbop/webbench/webbench.html}
|
||||
|
||||
@item WebStone
|
||||
@* @uref{http://www.mindcraft.com/benchmarks/webstone/}
|
||||
|
||||
@item SpecWeb96
|
||||
@* @uref{http://www.specbench.org/osg/web96/}
|
||||
@end itemize
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Tools,Authors,Benchmarks,Appendix
|
||||
@section Tools
|
||||
|
||||
@itemize
|
||||
@item Analog logfile analyzer
|
||||
@* @uref{http://www.statslab.cam.ac.uk/@~sret1/analog/}
|
||||
|
||||
@item wwwstat logfile analyzer
|
||||
@* @uref{http://www.ics.uci.edu/pub/websoft/wwwstat/}
|
||||
|
||||
@item gwstat wwwstat postprocessor
|
||||
@* @uref{http://dis.cs.umass.edu/stats/gwstat.html}
|
||||
|
||||
@item The Webalizer logfile analyzer
|
||||
@* @uref{http://www.usagl.net/webalizer/}
|
||||
|
||||
@item cgiwrap
|
||||
@* @uref{http://www.umr.edu/@~cgiwrap/}
|
||||
|
||||
@item suEXEC (Boa would need to be ..umm.. "adjusted" to support this)
|
||||
@* @uref{http://www.apache.org/docs/suexec.html}
|
||||
@end itemize
|
||||
|
||||
Note: References last checked: 06 October 1997
|
||||
|
||||
@comment node-name, next, previous, up
|
||||
@node Authors,,Tools,Appendix
|
||||
@section Authors
|
||||
|
||||
@itemize
|
||||
@item Conversion from linuxdoc SGML to texinfo by Jon Nelson
|
||||
@item Conversion to linuxdoc SGML by Jon Nelson
|
||||
@item Original HTML documentation by Larry Doolittle
|
||||
@item @value{COPYPHRASE}
|
||||
@end itemize
|
||||
|
||||
@c variable
|
||||
@c @printindex vr
|
||||
@c concept
|
||||
@c @printindex cp
|
||||
@c function
|
||||
@c @printindex fn
|
||||
@c key
|
||||
@c @printindex ky
|
||||
@c program
|
||||
@c @printindex pg
|
||||
@c data type
|
||||
@c @printindex tp
|
||||
|
||||
@bye
|
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
|
@ -0,0 +1,120 @@
|
|||
#! /usr/bin/perl
|
||||
|
||||
# Remember that CGI programs have to close out the HTTP header
|
||||
# (with a pair of newlines), after giving the Content-type:
|
||||
# and any other relevant or available header information.
|
||||
|
||||
# Unlike CGI programs running under Apache, CGI programs under Boa
|
||||
# should understand some simple HTTP options. The header (and the
|
||||
# double-newline) should not be printed if the incoming request was
|
||||
# in HTTP/0.9. Also, we should stop after the header if
|
||||
# REQUEST_METHOD == "HEAD". Under Apache, nph- programs also have
|
||||
# to worry about such stuff.
|
||||
|
||||
# Feb 3, 2000 -- updated to support POST, and avoid passing
|
||||
# Malicious HTML Tags as described in CERT's CA-2000-02 advisory.
|
||||
|
||||
if ($ENV{"SERVER_PROTOCOL"} ne "HTTP/0.9") {
|
||||
print "Content-type: text/html; charset=ISO-8859-1\r\n\r\n";
|
||||
}
|
||||
|
||||
exit 0 if ($ENV{"REQUEST_METHOD"} eq "HEAD");
|
||||
|
||||
print "<html><head><title>Boa CGI test</title></head><body>\n";
|
||||
print "<H2>Boa CGI test</H2>\n\n";
|
||||
|
||||
$now=`date`;
|
||||
chomp($now);
|
||||
|
||||
print "Date: $now\n";
|
||||
print "<p>\n";
|
||||
|
||||
print "Method: $ENV{\"REQUEST_METHOD\"}\n";
|
||||
print "<p>\n";
|
||||
|
||||
print "<table border=1>\n";
|
||||
print "<tr><td>Basic GET Form:<br>";
|
||||
print " <form method=\"get\">\n\
|
||||
<input type=\"text\" name=\"parameter_1\" size=5 maxlength=5>\
|
||||
<select name=\"select_1\">\
|
||||
<option>foo</option>\
|
||||
<option>bar</option>\
|
||||
</select>\
|
||||
<input type=\"submit\" NAME=SUBMIT VALUE=\"Submit\">\
|
||||
</form>";
|
||||
print "</td>";
|
||||
print "<td>Basic POST Form:<br>";
|
||||
print "<form method=\"post\">\n\
|
||||
<input type=\"text\" name=\"parameter_1\" size=5 maxlength=5>\
|
||||
<select name=\"select_1\">\
|
||||
<option>foo</option>\
|
||||
<option>bar</option>\
|
||||
</select>\
|
||||
<input type=\"submit\" NAME=SUBMIT VALUE=\"Submit\">\
|
||||
</form>";
|
||||
print "</td>";
|
||||
print "</tr>\n";
|
||||
print "<tr><td colspan=2>Sample ISINDEX form:<br>\n";
|
||||
print "<a href=\"$ENV{\"SCRIPT_NAME\"}?param1+param2+param3\">$ENV{\"SCRIPT_NAME\"}?param1+param2+param3</a>\n";
|
||||
print "</td></tr>";
|
||||
print "</table>\n";
|
||||
|
||||
print "<p>Query String: $ENV{\"QUERY_STRING\"}\n";
|
||||
|
||||
# arguments list
|
||||
print "<p>\nArguments:\n<ol>\n";
|
||||
if ($#ARGV >= 0) {
|
||||
while ($a=shift(@ARGV)) {
|
||||
$a=~s/&/&/g;
|
||||
$a=~s/</</g;
|
||||
$a=~s/>/>/g;
|
||||
print "<li>$a\n";
|
||||
}
|
||||
}
|
||||
print "</ol>\n";
|
||||
|
||||
# environment list
|
||||
print "<P>\nEnvironment:\n<UL>\n";
|
||||
foreach $i (keys %ENV) {
|
||||
$a=$ENV{$i};
|
||||
$a=~s/&/&/g;
|
||||
$a=~s/</</g;
|
||||
$a=~s/>/>/g;
|
||||
$i=~s/&/&/g;
|
||||
$i=~s/</</g;
|
||||
$i=~s/>/>/g;
|
||||
print "<li>$i = $a\n";
|
||||
}
|
||||
print "</UL>\n";
|
||||
|
||||
if ($ENV{REQUEST_METHOD} eq "POST") {
|
||||
print "Input stream:<br><hr><pre>\n";
|
||||
while (<stdin>) {
|
||||
s/&/&/g;
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
print "$_";
|
||||
}
|
||||
print "</pre><hr>\n";
|
||||
} else {
|
||||
print "No input stream: (not POST)<p>";
|
||||
}
|
||||
|
||||
print "id: ", `id`, "\n<p>\n";
|
||||
|
||||
if ($ENV{"QUERY_STRING"}=~/ident/ && $ENV{"REMOTE_PORT"} ne "") {
|
||||
|
||||
# Uses idlookup-1.2 from Peter Eriksson <pen@lysator.liu.se>
|
||||
# ftp://coast.cs.purdue.edu/pub/tools/unix/ident/tools/idlookup-1.2.tar.gz
|
||||
# Could use modification to timeout and trap stderr messages
|
||||
$a="idlookup ".
|
||||
$ENV{"REMOTE_ADDR"}." ".$ENV{"REMOTE_PORT"}." ".$ENV{"SERVER_PORT"};
|
||||
$b=qx/$a/;
|
||||
print "ident output:<br><pre>\n$b</pre>\n";
|
||||
}
|
||||
|
||||
print "\n<EM>Boa http server</EM>\n";
|
||||
print "</body></html>\n";
|
||||
|
||||
exit 0;
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Remember that CGI programs have to close out the HTTP header
|
||||
# (with a pair of newlines), after giving the Content-type:
|
||||
# and any other relevant or available header information.
|
||||
|
||||
# This test program always reports success (200 OK), and
|
||||
# correctly uses SERVER_PROTOCOL and REQUEST_METHOD to decide
|
||||
# whether or not to send the headers and content.
|
||||
|
||||
# Feb 3, 2000 -- updated to support POST, and avoid passing
|
||||
# Malicious HTML Tags as described in CERT's CA-2000-02 advisory.
|
||||
|
||||
$now=`date`;
|
||||
chomp($now);
|
||||
if ($ENV{"SERVER_PROTOCOL"} ne "HTTP/0.9") {
|
||||
print "HTTP/1.0 200 OK\r\nDate: $now\r\n";
|
||||
print "Connection: close\r\n";
|
||||
print "Content-type: text/html; charset=ISO-8859-1\r\n\r\n";
|
||||
}
|
||||
|
||||
exit 0 if ($ENV{"REQUEST_METHOD"} eq "HEAD");
|
||||
|
||||
print "<html><head><title>Boa nph-CGI test</title></head><body>\n";
|
||||
print "<H2>Boa nph-CGI test</H2>\n\n";
|
||||
|
||||
print "Date: $now\n";
|
||||
|
||||
print "<P>\n\n<UL>\n";
|
||||
|
||||
foreach (keys %ENV) {
|
||||
$a= $ENV{$_};
|
||||
$a=~s/&/&/g;
|
||||
$a=~s/</</g;
|
||||
$a=~s/>/>/g;
|
||||
print "<LI>$_ == $a\n";
|
||||
}
|
||||
|
||||
print "</UL>\n";
|
||||
|
||||
if ($ENV{REQUEST_METHOD} eq "POST") {
|
||||
print "Input stream:<br><hr><pre>\n";
|
||||
while (<stdin>) {
|
||||
s/&/&/g;
|
||||
s/</</g;
|
||||
s/>/>/g;
|
||||
print "$_";
|
||||
}
|
||||
print "</pre><hr>\n";
|
||||
}
|
||||
|
||||
print "id: ", `id`, "\n<p>\n";
|
||||
|
||||
if ($ENV{"QUERY_STRING"}=~/ident/ && $ENV{"REMOTE_PORT"} ne "") {
|
||||
|
||||
# Uses idlookup-1.2 from Peter Eriksson <pen@lysator.liu.se>
|
||||
# ftp://coast.cs.purdue.edu/pub/tools/unix/ident/tools/idlookup-1.2.tar.gz
|
||||
# Could use modification to timeout and trap stderr messages
|
||||
$a="idlookup ".
|
||||
$ENV{"REMOTE_ADDR"}." ".$ENV{"REMOTE_PORT"}." ".$ENV{"SERVER_PORT"};
|
||||
$b=qx/$a/;
|
||||
print "ident output:<br><pre>\n$b</pre>\n";
|
||||
}
|
||||
|
||||
print "\n<EM>Boa http server</EM>\n";
|
||||
print "</body></html>\n";
|
||||
|
||||
exit 0;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# IP address resolver for Boa
|
||||
|
||||
# If you want an "in place" change to the log file,
|
||||
# change the first line to
|
||||
#!/usr/local/bin/perl -i.bak
|
||||
# Otherwise, send the output of this program wherever you want:
|
||||
# resolver.pl access_log >access_log_resolved
|
||||
|
||||
$AF_INET = 2;
|
||||
|
||||
while(<>) {
|
||||
next unless (($ip, $rest) = /([\d\.]+) (.*)/o);
|
||||
|
||||
if(!$hosts{$ip}) {
|
||||
$packed_ip = pack('C4', split(/\./, $ip));
|
||||
$host = (gethostbyaddr($packed_ip, $AF_INET))[0];
|
||||
$hosts{$ip} = ($host ? $host : $ip);
|
||||
}
|
||||
|
||||
print "$hosts{$ip} $rest\n";
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include <string.h>
|
||||
#include "compat.h"
|
||||
|
||||
int alphasort(const struct dirent **a, const struct dirent **b)
|
||||
{
|
||||
return (strcmp((*a)->d_name, (*b)->d_name));
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- Mode: C; c-file-style: "gnu" -*- */
|
||||
/*
|
||||
Copyright (c) 2000 Petter Reinholdtsen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* scandir.c -- if scandir() is missing, make a replacement
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
/*
|
||||
* XXX This is a simple hack version which doesn't sort the data, and
|
||||
* just passes all unsorted.
|
||||
*/
|
||||
|
||||
int
|
||||
scandir(const char *dir, struct dirent ***namelist,
|
||||
int (*select) (const struct dirent *),
|
||||
int (*compar) (const struct dirent **, const struct dirent **))
|
||||
{
|
||||
DIR *d = opendir(dir);
|
||||
struct dirent *current;
|
||||
struct dirent **names;
|
||||
int count = 0;
|
||||
int pos = 0;
|
||||
int result = -1;
|
||||
|
||||
if (NULL == d)
|
||||
return -1;
|
||||
|
||||
while (NULL != readdir(d))
|
||||
count++;
|
||||
|
||||
names = malloc(sizeof (struct dirent *) * count);
|
||||
|
||||
closedir(d);
|
||||
d = opendir(dir);
|
||||
if (NULL == d)
|
||||
return -1;
|
||||
|
||||
while (NULL != (current = readdir(d))) {
|
||||
if (NULL == select || select(current)) {
|
||||
struct dirent *copyentry = malloc(current->d_reclen);
|
||||
|
||||
memcpy(copyentry, current, current->d_reclen);
|
||||
|
||||
names[pos] = copyentry;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
result = closedir(d);
|
||||
|
||||
if (pos != count)
|
||||
names = realloc(names, sizeof (struct dirent *) * pos);
|
||||
|
||||
*namelist = names;
|
||||
|
||||
return pos;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Name: strstr and strdup
|
||||
*
|
||||
* These are the standard library utilities. We define them here for
|
||||
* systems that don't have them.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_STRSTR
|
||||
char *strstr(char *s1, char *s2)
|
||||
{ /* from libiberty */
|
||||
char *p;
|
||||
int len = strlen(s2);
|
||||
|
||||
if (*s2 == '\0') /* everything matches empty string */
|
||||
return s1;
|
||||
for (p = s1; (p = strchr(p, *s2)) != NULL; p = strchr(p + 1, *s2)) {
|
||||
if (strncmp(p, s2, len) == 0)
|
||||
return (p);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
char *strdup(char *s)
|
||||
{
|
||||
char *retval;
|
||||
|
||||
retval = (char *) malloc(strlen(s) + 1);
|
||||
if (retval == NULL) {
|
||||
perror("boa: out of memory in strdup");
|
||||
exit(1);
|
||||
}
|
||||
return strcpy(retval, s);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
alias.o: alias.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
boa.o: boa.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
buffer.o: buffer.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h
|
||||
cgi.o: cgi.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
cgi_header.o: cgi_header.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h
|
||||
config.o: config.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h y.tab.h parse.h
|
||||
escape.o: escape.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h
|
||||
get.o: get.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
hash.o: hash.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
ip.o: ip.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
log.o: log.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
mmap_cache.o: mmap_cache.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h
|
||||
pipe.o: pipe.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
queue.o: queue.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
read.o: read.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
request.o: request.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h
|
||||
response.o: response.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h
|
||||
signals.o: signals.c boa.h config.h compat.h defines.h globals.h \
|
||||
escape.h
|
||||
util.o: util.c boa.h config.h compat.h defines.h globals.h escape.h
|
||||
sublog.o: sublog.c
|
|
@ -0,0 +1,90 @@
|
|||
# Generated automatically from Makefile.in by configure.
|
||||
# $Id: Makefile.in,v 1.59 2002/03/24 22:20:19 jnelson Exp $
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .c
|
||||
.PHONY: clean mrclean distclean depend all dist
|
||||
|
||||
|
||||
|
||||
GCC_FLAGS = -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wcast-qual\
|
||||
-Wtraditional\
|
||||
-Wshadow\
|
||||
-Wconversion\
|
||||
-Waggregate-return\
|
||||
-Wmissing-prototypes\
|
||||
-Wnested-externs\
|
||||
-Wall \
|
||||
-Wundef -Wwrite-strings -Wredundant-decls -Winline
|
||||
|
||||
|
||||
srcdir = .
|
||||
VPATH = .:./../extras
|
||||
LDFLAGS = -g
|
||||
LIBS =
|
||||
CFLAGS = -g -O2 -pipe -Wall -I.
|
||||
|
||||
# Change these if necessary
|
||||
|
||||
YACC = bison -y
|
||||
LEX = lex
|
||||
CC = gcc
|
||||
CPP = gcc -E
|
||||
|
||||
SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \
|
||||
get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c read.c \
|
||||
request.c response.c select.c signals.c util.c sublog.c
|
||||
|
||||
OBJS = y.tab.o lex.yy.o $(SOURCES:.c=.o) timestamp.o
|
||||
|
||||
all: boa boa_indexer
|
||||
|
||||
boa: $(OBJS)
|
||||
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||
|
||||
boa_indexer: index_dir.o escape.o
|
||||
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) boa core lex.yy.c y.tab.c y.tab.h *~ boa_indexer index_dir.o
|
||||
|
||||
distclean: mrclean
|
||||
|
||||
mrclean: clean
|
||||
rm -f config.status config.cache config.h Makefile config.log
|
||||
|
||||
# parser dependencies
|
||||
|
||||
y.tab.c y.tab.h: boa_grammar.y
|
||||
$(YACC) -d $^
|
||||
|
||||
lex.yy.c: boa_lexer.l
|
||||
$(LEX) $^
|
||||
|
||||
# timestamp
|
||||
|
||||
timestamp.o: $(SOURCES) boa_grammar.y boa_lexer.l
|
||||
|
||||
# depend stuff
|
||||
.depend:
|
||||
$(CPP) -MM $(SOURCES) > .depend
|
||||
|
||||
depend:
|
||||
-rm -f .depend
|
||||
$(MAKE) .depend
|
||||
|
||||
include .depend
|
||||
|
||||
# tags
|
||||
tags: $(SOURCES)
|
||||
ctags -o tags $^ *.h
|
||||
|
||||
# dist
|
||||
dist:
|
||||
$(MAKE) clean
|
||||
./makedist.sh
|
||||
|
||||
# object dump
|
||||
boa.objdump: boa
|
||||
objdump --disassemble-all --source boa > $@
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
# $Id: Makefile.in,v 1.59 2002/03/24 22:20:19 jnelson Exp $
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .c
|
||||
.PHONY: clean mrclean distclean depend all dist
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
GCC_FLAGS = -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wcast-qual\
|
||||
-Wtraditional\
|
||||
-Wshadow\
|
||||
-Wconversion\
|
||||
-Waggregate-return\
|
||||
-Wmissing-prototypes\
|
||||
-Wnested-externs\
|
||||
-Wall \
|
||||
-Wundef -Wwrite-strings -Wredundant-decls -Winline
|
||||
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@:@srcdir@/../extras
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
CFLAGS = @CFLAGS@ -I.
|
||||
|
||||
# Change these if necessary
|
||||
|
||||
YACC = @YACC@
|
||||
LEX = @LEX@
|
||||
CC = @CC@
|
||||
CPP = @CPP@
|
||||
|
||||
SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \
|
||||
get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c read.c \
|
||||
request.c response.c select.c signals.c util.c sublog.c
|
||||
|
||||
OBJS = y.tab.o lex.yy.o $(SOURCES:.c=.o) timestamp.o @STRUTIL@
|
||||
|
||||
all: boa boa_indexer
|
||||
|
||||
boa: $(OBJS)
|
||||
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||
|
||||
boa_indexer: index_dir.o escape.o @SCANDIR@ @ALPHASORT@ @STRUTIL@
|
||||
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) boa core lex.yy.c y.tab.c y.tab.h *~ boa_indexer index_dir.o @SCANDIR@ @ALPHASORT@ @STRUTIL@
|
||||
|
||||
distclean: mrclean
|
||||
|
||||
mrclean: clean
|
||||
rm -f config.status config.cache config.h Makefile config.log
|
||||
|
||||
# parser dependencies
|
||||
|
||||
y.tab.c y.tab.h: boa_grammar.y
|
||||
$(YACC) -d $^
|
||||
|
||||
lex.yy.c: boa_lexer.l
|
||||
$(LEX) $^
|
||||
|
||||
# timestamp
|
||||
|
||||
timestamp.o: $(SOURCES) boa_grammar.y boa_lexer.l
|
||||
|
||||
# depend stuff
|
||||
.depend:
|
||||
$(CPP) -MM $(SOURCES) > .depend
|
||||
|
||||
depend:
|
||||
-rm -f .depend
|
||||
$(MAKE) .depend
|
||||
|
||||
include .depend
|
||||
|
||||
# tags
|
||||
tags: $(SOURCES)
|
||||
ctags -o tags $^ *.h
|
||||
|
||||
# dist
|
||||
dist:
|
||||
$(MAKE) clean
|
||||
./makedist.sh
|
||||
|
||||
# object dump
|
||||
boa.objdump: boa
|
||||
objdump --disassemble-all --source boa > $@
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/* define if GUNZIP found */
|
||||
#undef GUNZIP
|
||||
|
||||
/* sockaddr_in has sin_len member */
|
||||
#undef HAVE_SIN_LEN
|
||||
|
||||
/* how many times we shift left for unsigned long */
|
||||
#undef NEEDS_ESCAPE_SHIFT
|
||||
|
||||
/* if struct tm has tm_gmtoff structure */
|
||||
#undef HAVE_TM_GMTOFF
|
||||
|
||||
/* if struct tm has tm_zone structure */
|
||||
#undef HAVE_TM_ZONE
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
dnl aclocal.m4 generated automatically by aclocal 1.4-p5
|
||||
|
||||
dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl This program is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
dnl PARTICULAR PURPOSE.
|
||||
|
||||
AC_DEFUN([AC_CHECK_STRUCT_FOR],[
|
||||
ac_safe_struct=`echo "$2" | sed 'y%./+-%__p_%'`
|
||||
ac_safe_member=`echo "$3" | sed 'y%./+-%__p_%'`
|
||||
ac_safe_all="ac_cv_struct_${ac_safe_struct}_has_${ac_safe_member}"
|
||||
changequote(, )dnl
|
||||
ac_uc_define=STRUCT_`echo "${ac_safe_struct}_HAS_${ac_safe_member}" | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
|
||||
changequote([, ])dnl
|
||||
|
||||
AC_MSG_CHECKING([for $2.$3])
|
||||
AC_CACHE_VAL($ac_safe_all,
|
||||
[
|
||||
if test "x$4" = "x"; then
|
||||
defineit="= 0"
|
||||
elif test "x$4" = "xno"; then
|
||||
defineit=""
|
||||
else
|
||||
defineit="$4"
|
||||
fi
|
||||
AC_TRY_COMPILE([
|
||||
$1
|
||||
],[
|
||||
struct $2 testit;
|
||||
testit.$3 $defineit;
|
||||
], eval "${ac_safe_all}=yes", eval "${ac_safe_all}=no" )
|
||||
])
|
||||
|
||||
if eval "test \"x$`echo ${ac_safe_all}`\" = \"xyes\""; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE_UNQUOTED($ac_uc_define)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
])
|
||||
|
||||
dnl AC_CHECK_STRUCT_FOR(INCLUDES,STRUCT,MEMBER,DEFINE,[no])
|
||||
dnl 1.1 (2000/09/19)
|
||||
dnl Wes Hardaker <wjhardaker@ucdavis.edu>
|
||||
|
||||
dnl ----------------------------------------------------------
|
||||
|
||||
|
|
@ -0,0 +1,632 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996 Russ Nelson <nelson@crynwr.com>
|
||||
* Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: alias.c,v 1.70.2.4 2002/07/28 02:46:52 jnelson Exp $ */
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
static alias *alias_hashtable[ALIAS_HASHTABLE_SIZE];
|
||||
|
||||
int get_alias_hash_value(char *file);
|
||||
|
||||
/*
|
||||
* Name: get_alias_hash_value
|
||||
*
|
||||
* Description: adds the ASCII values of the file letters
|
||||
* and mods by the hashtable size to get the hash value
|
||||
* Note: stops at first '/' (or '\0')
|
||||
*/
|
||||
|
||||
int get_alias_hash_value(char *file)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
unsigned int index = 0;
|
||||
unsigned char c;
|
||||
|
||||
hash = file[index++];
|
||||
while ((c = file[index++]) && c != '/')
|
||||
hash += (unsigned int) c;
|
||||
|
||||
return hash % ALIAS_HASHTABLE_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: add_alias
|
||||
*
|
||||
* Description: add an Alias, Redirect, or ScriptAlias to the
|
||||
* alias hash table.
|
||||
*/
|
||||
|
||||
void add_alias(char *fakename, char *realname, int type)
|
||||
{
|
||||
int hash;
|
||||
alias *old, *new;
|
||||
int fakelen, reallen;
|
||||
|
||||
/* sanity checking */
|
||||
if (fakename == NULL || realname == NULL) {
|
||||
DIE("NULL values sent to add_alias");
|
||||
}
|
||||
|
||||
fakelen = strlen(fakename);
|
||||
reallen = strlen(realname);
|
||||
if (fakelen == 0 || reallen == 0) {
|
||||
DIE("empty values sent to add_alias");
|
||||
}
|
||||
|
||||
hash = get_alias_hash_value(fakename);
|
||||
|
||||
old = alias_hashtable[hash];
|
||||
|
||||
if (old) {
|
||||
while (old->next) {
|
||||
if (!strcmp(fakename, old->fakename)) /* don't add twice */
|
||||
return;
|
||||
old = old->next;
|
||||
}
|
||||
}
|
||||
|
||||
new = (alias *) malloc(sizeof (alias));
|
||||
if (!new) {
|
||||
DIE("out of memory adding alias to hash");
|
||||
}
|
||||
|
||||
if (old)
|
||||
old->next = new;
|
||||
else
|
||||
alias_hashtable[hash] = new;
|
||||
|
||||
new->fakename = strdup(fakename);
|
||||
if (!new->fakename) {
|
||||
DIE("failed strdup");
|
||||
}
|
||||
new->fake_len = fakelen;
|
||||
/* check for "here" */
|
||||
if (realname[0] == '.' && realname[1] == '/') {
|
||||
new->realname = normalize_path(realname+2);
|
||||
if (!new->realname) {
|
||||
/* superfluous - normalize_path checks for NULL return values. */
|
||||
DIE("normalize_path returned NULL");
|
||||
}
|
||||
reallen = strlen(new->realname);
|
||||
} else {
|
||||
new->realname = strdup(realname);
|
||||
if (!new->realname) {
|
||||
DIE("strdup of realname failed");
|
||||
}
|
||||
}
|
||||
new->real_len = reallen;
|
||||
|
||||
new->type = type;
|
||||
new->next = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: find_alias
|
||||
*
|
||||
* Description: Locates uri in the alias hashtable if it exists.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* alias structure or NULL if not found
|
||||
*/
|
||||
|
||||
alias *find_alias(char *uri, int urilen)
|
||||
{
|
||||
alias *current;
|
||||
int hash;
|
||||
|
||||
/* Find ScriptAlias, Alias, or Redirect */
|
||||
|
||||
if (urilen == 0)
|
||||
urilen = strlen(uri);
|
||||
hash = get_alias_hash_value(uri);
|
||||
|
||||
current = alias_hashtable[hash];
|
||||
while (current) {
|
||||
#ifdef FASCIST_LOGGING
|
||||
fprintf(stderr,
|
||||
"%s:%d - comparing \"%s\" (request) to \"%s\" (alias): ",
|
||||
__FILE__, __LINE__, uri, current->fakename);
|
||||
#endif
|
||||
/* current->fake_len must always be:
|
||||
* shorter or equal to the uri
|
||||
*/
|
||||
/*
|
||||
* when performing matches:
|
||||
* If the virtual part of the url ends in '/', and
|
||||
* we get a match, stop there.
|
||||
* Otherwise, we require '/' or '\0' at the end of the url.
|
||||
* We only check if the virtual path does *not* end in '/'
|
||||
*/
|
||||
if (current->fake_len <= urilen &&
|
||||
!memcmp(uri, current->fakename, current->fake_len) &&
|
||||
(current->fakename[current->fake_len - 1] == '/' ||
|
||||
(current->fakename[current->fake_len - 1] != '/' &&
|
||||
(uri[current->fake_len] == '\0' ||
|
||||
uri[current->fake_len] == '/')))) {
|
||||
#ifdef FASCIST_LOGGING
|
||||
fprintf(stderr, "Got it!\n");
|
||||
#endif
|
||||
return current;
|
||||
}
|
||||
#ifdef FASCIST_LOGGING
|
||||
else
|
||||
fprintf(stderr, "Don't Got it!\n");
|
||||
#endif
|
||||
current = current->next;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: translate_uri
|
||||
*
|
||||
* Description: Parse a request's virtual path.
|
||||
* Sets query_string, pathname directly.
|
||||
* Also sets path_info, path_translated, and script_name via
|
||||
* init_script_alias
|
||||
*
|
||||
* Note: NPH in user dir is currently broken
|
||||
*
|
||||
* Note -- this should be broken up.
|
||||
*
|
||||
* Return values:
|
||||
* 0: failure, close it down
|
||||
* 1: success, continue
|
||||
*/
|
||||
|
||||
int translate_uri(request * req)
|
||||
{
|
||||
static char buffer[MAX_HEADER_LENGTH + 1];
|
||||
char *req_urip;
|
||||
alias *current;
|
||||
char *p;
|
||||
int uri_len;
|
||||
|
||||
req_urip = req->request_uri;
|
||||
if (req_urip[0] != '/') {
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uri_len = strlen(req->request_uri);
|
||||
|
||||
current = find_alias(req->request_uri, uri_len);
|
||||
if (current) {
|
||||
|
||||
if (current->type == SCRIPTALIAS) /* Script */
|
||||
return init_script_alias(req, current, uri_len);
|
||||
|
||||
/* not a script alias, therefore begin filling in data */
|
||||
|
||||
{
|
||||
int len;
|
||||
len = current->real_len;
|
||||
len += uri_len - current->fake_len;
|
||||
if (len > MAX_HEADER_LENGTH) {
|
||||
log_error_doc(req);
|
||||
fputs("uri too long!\n", stderr);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
memcpy(buffer, current->realname, current->real_len);
|
||||
memcpy(buffer + current->real_len,
|
||||
req->request_uri + current->fake_len,
|
||||
uri_len - current->fake_len + 1);
|
||||
}
|
||||
|
||||
if (current->type == REDIRECT) { /* Redirect */
|
||||
if (req->method == M_POST) { /* POST to non-script */
|
||||
/* it's not a cgi, but we try to POST??? */
|
||||
send_r_bad_request(req);
|
||||
return 0; /* not a script alias, therefore begin filling in data */
|
||||
}
|
||||
send_r_moved_temp(req, buffer, "");
|
||||
return 0;
|
||||
} else { /* Alias */
|
||||
req->pathname = strdup(buffer);
|
||||
if (!req->pathname) {
|
||||
send_r_error(req);
|
||||
WARN("unable to strdup buffer onto req->pathname");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The reason why this is *not* an 'else if' is that,
|
||||
after aliasing, we still have to check for '~' expansion
|
||||
*/
|
||||
|
||||
if (user_dir && req->request_uri[1] == '~') {
|
||||
char *user_homedir;
|
||||
|
||||
req_urip = req->request_uri + 2;
|
||||
|
||||
/* since we have uri_len which is from strlen(req->request_uri) */
|
||||
p = memchr(req_urip, '/', uri_len - 2);
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
user_homedir = get_home_dir(req_urip);
|
||||
if (p) /* have to restore request_uri in case of error */
|
||||
*p = '/';
|
||||
|
||||
if (!user_homedir) { /*no such user */
|
||||
send_r_not_found(req);
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
int l1 = strlen(user_homedir);
|
||||
int l2 = strlen(user_dir);
|
||||
int l3 = (p ? strlen(p) : 0);
|
||||
|
||||
if (l1 + l2 + l3 + 1 > MAX_HEADER_LENGTH) {
|
||||
log_error_doc(req);
|
||||
fputs("uri too long!\n", stderr);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buffer, user_homedir, l1);
|
||||
buffer[l1] = '/';
|
||||
memcpy(buffer + l1 + 1, user_dir, l2 + 1);
|
||||
if (p)
|
||||
memcpy(buffer + l1 + 1 + l2, p, l3 + 1);
|
||||
}
|
||||
} else if (document_root) {
|
||||
/* no aliasing, no userdir... */
|
||||
int l1, l2, l3;
|
||||
|
||||
l1 = strlen(document_root);
|
||||
l2 = strlen(req->request_uri);
|
||||
if (virtualhost)
|
||||
l3 = strlen(req->local_ip_addr);
|
||||
else
|
||||
l3 = 0;
|
||||
|
||||
if (l1 + l2 + l3 + 1 > MAX_HEADER_LENGTH) {
|
||||
log_error_doc(req);
|
||||
fputs("uri too long!\n", stderr);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the 'l2 + 1' is there so we copy the '\0' as well */
|
||||
memcpy(buffer, document_root, l1);
|
||||
if (virtualhost) {
|
||||
buffer[l1] = '/';
|
||||
memcpy(buffer + l1 + 1, req->local_ip_addr, l3);
|
||||
memcpy(buffer + l1 + 1 + l3, req->request_uri, l2 + 1);
|
||||
} else
|
||||
memcpy(buffer + l1, req->request_uri, l2 + 1);
|
||||
} else {
|
||||
/* not aliased. not userdir. not part of document_root. BAIL */
|
||||
send_r_not_found(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if here,
|
||||
* o it may be aliased but it's not a redirect or a script...
|
||||
* o it may be a homedir
|
||||
* o it may be a document_root resource (with or without virtual host)
|
||||
*/
|
||||
|
||||
req->pathname = strdup(buffer);
|
||||
if (!req->pathname) {
|
||||
WARN("Could not strdup buffer for req->pathname!");
|
||||
send_r_error(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* below we support cgis outside of a ScriptAlias */
|
||||
if (strcmp(CGI_MIME_TYPE, get_mime_type(buffer)) == 0) { /* cgi */
|
||||
#ifdef FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - buffer is: \"%s\"\n",
|
||||
__FILE__, __LINE__, buffer);
|
||||
#endif
|
||||
/* FIXME */
|
||||
/* script_name could end up as /cgi-bin/bob/extra_path */
|
||||
req->script_name = strdup(req->request_uri);
|
||||
if (!req->script_name) {
|
||||
WARN("Could not strdup req->request_uri for req->script_name");
|
||||
send_r_error(req);
|
||||
return 0;
|
||||
}
|
||||
if (req->simple)
|
||||
req->is_cgi = NPH;
|
||||
else
|
||||
req->is_cgi = CGI;
|
||||
return 1;
|
||||
} else if (req->method == M_POST) { /* POST to non-script */
|
||||
/* it's not a cgi, but we try to POST??? */
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
} else /* we are done!! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: init_script_alias
|
||||
*
|
||||
* Description: Performs full parsing on a ScriptAlias request
|
||||
* Sets path_info and script_name
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* 0: failure, shut down
|
||||
* 1: success, continue
|
||||
*/
|
||||
|
||||
int init_script_alias(request * req, alias * current1, int uri_len)
|
||||
{
|
||||
static char pathname[MAX_HEADER_LENGTH + 1];
|
||||
struct stat statbuf;
|
||||
static char buffer[MAX_HEADER_LENGTH + 1];
|
||||
|
||||
int index = 0;
|
||||
char c;
|
||||
int err;
|
||||
|
||||
/* copies the "real" path + the non-alias portion of the
|
||||
uri to pathname.
|
||||
*/
|
||||
|
||||
if (uri_len - current1->fake_len + current1->real_len >
|
||||
MAX_HEADER_LENGTH) {
|
||||
log_error_doc(req);
|
||||
fputs("uri too long!\n", stderr);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pathname, current1->realname, current1->real_len);
|
||||
memcpy(pathname + current1->real_len,
|
||||
&req->request_uri[current1->fake_len],
|
||||
uri_len - current1->fake_len + 1); /* the +1 copies the NUL */
|
||||
#ifdef FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr,
|
||||
"%s:%d - pathname in init_script_alias is: \"%s\" (\"%s\")\n",
|
||||
__FILE__, __LINE__, pathname, pathname + current1->real_len);
|
||||
#endif
|
||||
if (strncmp("nph-", pathname + current1->real_len, 4) == 0
|
||||
|| req->simple) req->is_cgi = NPH;
|
||||
else
|
||||
req->is_cgi = CGI;
|
||||
|
||||
|
||||
/* start at the beginning of the actual uri...
|
||||
(in /cgi-bin/bob, start at the 'b' in bob */
|
||||
index = current1->real_len;
|
||||
|
||||
/* go to first and successive '/' and keep checking
|
||||
* if it is a full pathname
|
||||
* on success (stat (not lstat) of file is a *regular file*)
|
||||
*/
|
||||
do {
|
||||
c = pathname[++index];
|
||||
if (c == '/') {
|
||||
pathname[index] = '\0';
|
||||
err = stat(pathname, &statbuf);
|
||||
pathname[index] = '/';
|
||||
if (err == -1) {
|
||||
send_r_not_found(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* is it a dir? */
|
||||
if (!S_ISDIR(statbuf.st_mode)) {
|
||||
/* check access */
|
||||
if (!(statbuf.st_mode &
|
||||
(S_IFREG | /* regular file */
|
||||
(S_IRUSR | S_IXUSR) | /* u+rx */
|
||||
(S_IRGRP | S_IXGRP) | /* g+rx */
|
||||
(S_IROTH | S_IXOTH)))) { /* o+rx */
|
||||
send_r_forbidden(req);
|
||||
return 0;
|
||||
}
|
||||
/* stop here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (c != '\0');
|
||||
|
||||
req->script_name = strdup(req->request_uri);
|
||||
if (!req->script_name) {
|
||||
send_r_error(req);
|
||||
WARN("unable to strdup req->request_uri for req->script_name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c == '\0') {
|
||||
err = stat(pathname, &statbuf);
|
||||
if (err == -1) {
|
||||
send_r_not_found(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* is it a dir? */
|
||||
if (!S_ISDIR(statbuf.st_mode)) {
|
||||
/* check access */
|
||||
if (!(statbuf.st_mode &
|
||||
(S_IFREG | /* regular file */
|
||||
(S_IRUSR | S_IXUSR) | /* u+rx */
|
||||
(S_IRGRP | S_IXGRP) | /* g+rx */
|
||||
(S_IROTH | S_IXOTH)))) { /* o+rx */
|
||||
send_r_forbidden(req);
|
||||
return 0;
|
||||
}
|
||||
/* stop here */
|
||||
} else {
|
||||
send_r_forbidden(req);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* we have path_info if c == '/'... still have to check for query */
|
||||
else if (c == '/') {
|
||||
int hash;
|
||||
alias *current;
|
||||
int path_len;
|
||||
|
||||
req->path_info = strdup(pathname + index);
|
||||
if (!req->path_info) {
|
||||
send_r_error(req);
|
||||
WARN("unable to strdup pathname + index for req->path_info");
|
||||
return 0;
|
||||
}
|
||||
pathname[index] = '\0'; /* strip path_info from path */
|
||||
path_len = strlen(req->path_info);
|
||||
/* we need to fix script_name here */
|
||||
/* index points into pathname, which is
|
||||
* realname/cginame/foo
|
||||
* and index points to the '/foo' part
|
||||
*/
|
||||
req->script_name[strlen(req->script_name) - path_len] = '\0'; /* zap off the /foo part */
|
||||
|
||||
/* now, we have to re-alias the extra path info....
|
||||
this sucks.
|
||||
*/
|
||||
hash = get_alias_hash_value(req->path_info);
|
||||
current = alias_hashtable[hash];
|
||||
while (current && !req->path_translated) {
|
||||
if (!strncmp(req->path_info, current->fakename,
|
||||
current->fake_len)) {
|
||||
|
||||
if (current->real_len +
|
||||
path_len - current->fake_len > MAX_HEADER_LENGTH) {
|
||||
log_error_doc(req);
|
||||
fputs("uri too long!\n", stderr);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buffer, current->realname, current->real_len);
|
||||
strcpy(buffer + current->real_len,
|
||||
&req->path_info[current->fake_len]);
|
||||
req->path_translated = strdup(buffer);
|
||||
if (!req->path_translated) {
|
||||
send_r_error(req);
|
||||
WARN("unable to strdup buffer for req->path_translated");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
/* no alias... try userdir */
|
||||
if (!req->path_translated && user_dir && req->path_info[1] == '~') {
|
||||
char *user_homedir;
|
||||
char *p;
|
||||
|
||||
p = strchr(pathname + index + 1, '/');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
user_homedir = get_home_dir(pathname + index + 2);
|
||||
if (p)
|
||||
*p = '/';
|
||||
|
||||
if (!user_homedir) { /* no such user */
|
||||
send_r_not_found(req);
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
int l1 = strlen(user_homedir);
|
||||
int l2 = strlen(user_dir);
|
||||
int l3;
|
||||
if (p)
|
||||
l3 = strlen(p);
|
||||
else
|
||||
l3 = 0;
|
||||
|
||||
req->path_translated = malloc(l1 + l2 + l3 + 2);
|
||||
if (req->path_translated == NULL) {
|
||||
send_r_error(req);
|
||||
WARN("unable to malloc memory for req->path_translated");
|
||||
return 0;
|
||||
}
|
||||
memcpy(req->path_translated, user_homedir, l1);
|
||||
req->path_translated[l1] = '/';
|
||||
memcpy(req->path_translated + l1 + 1, user_dir, l2 + 1);
|
||||
if (p)
|
||||
memcpy(req->path_translated + l1 + 1 + l2, p, l3 + 1);
|
||||
}
|
||||
}
|
||||
if (!req->path_translated && document_root) {
|
||||
/* no userdir, no aliasing... try document root */
|
||||
int l1, l2;
|
||||
l1 = strlen(document_root);
|
||||
l2 = path_len;
|
||||
|
||||
req->path_translated = malloc(l1 + l2 + 1);
|
||||
if (req->path_translated == NULL) {
|
||||
send_r_error(req);
|
||||
WARN("unable to malloc memory for req->path_translated");
|
||||
return 0;
|
||||
}
|
||||
memcpy(req->path_translated, document_root, l1);
|
||||
memcpy(req->path_translated + l1, req->path_info, l2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
req->pathname = strdup(pathname);
|
||||
if (!req->pathname) {
|
||||
send_r_error(req);
|
||||
WARN("unable to strdup pathname for req->pathname");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Empties the alias hashtable, deallocating any allocated memory.
|
||||
*/
|
||||
|
||||
void dump_alias(void)
|
||||
{
|
||||
int i;
|
||||
alias *temp;
|
||||
|
||||
for (i = 0; i < ALIAS_HASHTABLE_SIZE; ++i) { /* these limits OK? */
|
||||
if (alias_hashtable[i]) {
|
||||
temp = alias_hashtable[i];
|
||||
while (temp) {
|
||||
alias *temp_next;
|
||||
|
||||
if (temp->fakename)
|
||||
free(temp->fakename);
|
||||
if (temp->realname)
|
||||
free(temp->realname);
|
||||
temp_next = temp->next;
|
||||
free(temp);
|
||||
temp = temp_next;
|
||||
}
|
||||
alias_hashtable[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
|
||||
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: boa.c,v 1.99.2.2 2002/07/23 15:50:29 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
#include <sys/resource.h>
|
||||
|
||||
/* globals */
|
||||
int backlog = SO_MAXCONN;
|
||||
time_t start_time;
|
||||
|
||||
int sighup_flag = 0; /* 1 => signal has happened, needs attention */
|
||||
int sigchld_flag = 0; /* 1 => signal has happened, needs attention */
|
||||
int sigalrm_flag = 0; /* 1 => signal has happened, needs attention */
|
||||
int sigterm_flag = 0; /* lame duck mode */
|
||||
time_t current_time;
|
||||
int max_fd = 0;
|
||||
int pending_requests = 0;
|
||||
|
||||
/* static to boa.c */
|
||||
static void fixup_server_root(void);
|
||||
static int create_server_socket(void);
|
||||
static void drop_privs(void);
|
||||
|
||||
static int sock_opt = 1;
|
||||
static int do_fork = 1;
|
||||
int devnullfd = -1;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c; /* command line arg */
|
||||
int server_s; /* boa socket */
|
||||
|
||||
/* set umask to u+rw, u-x, go-rwx */
|
||||
c = umask(~0600);
|
||||
if (c == -1) {
|
||||
perror("umask");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
devnullfd = open("/dev/null", 0);
|
||||
|
||||
/* make STDIN and STDOUT point to /dev/null */
|
||||
if (devnullfd == -1) {
|
||||
DIE("can't open /dev/null");
|
||||
}
|
||||
|
||||
if (dup2(devnullfd, STDIN_FILENO) == -1) {
|
||||
DIE("can't dup2 /dev/null to STDIN_FILENO");
|
||||
}
|
||||
|
||||
if (dup2(devnullfd, STDOUT_FILENO) == -1) {
|
||||
DIE("can't dup2 /dev/null to STDOUT_FILENO");
|
||||
}
|
||||
|
||||
/* but first, update timestamp, because log_error_time uses it */
|
||||
(void) time(¤t_time);
|
||||
|
||||
while ((c = getopt(argc, argv, "c:r:d")) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
if (server_root)
|
||||
free(server_root);
|
||||
server_root = strdup(optarg);
|
||||
if (!server_root) {
|
||||
perror("strdup (for server_root)");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (chdir(optarg) == -1) {
|
||||
log_error_time();
|
||||
perror("chdir (to chroot)");
|
||||
exit(1);
|
||||
}
|
||||
if (chroot(optarg) == -1) {
|
||||
log_error_time();
|
||||
perror("chroot");
|
||||
exit(1);
|
||||
}
|
||||
if (chdir("/") == -1) {
|
||||
log_error_time();
|
||||
perror("chdir (after chroot)");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
do_fork = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: %s [-c serverroot] [-r chroot] [-d]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fixup_server_root();
|
||||
read_config_files();
|
||||
open_logs();
|
||||
server_s = create_server_socket();
|
||||
init_signals();
|
||||
drop_privs();
|
||||
create_common_env();
|
||||
build_needs_escape();
|
||||
|
||||
if (max_connections < 1) {
|
||||
struct rlimit rl;
|
||||
|
||||
/* has not been set explicitly */
|
||||
c = getrlimit(RLIMIT_NOFILE, &rl);
|
||||
if (c < 0) {
|
||||
perror("getrlimit");
|
||||
exit(1);
|
||||
}
|
||||
max_connections = rl.rlim_cur;
|
||||
}
|
||||
|
||||
/* background ourself */
|
||||
if (do_fork) {
|
||||
switch(fork()) {
|
||||
case -1:
|
||||
/* error */
|
||||
perror("fork");
|
||||
exit(1);
|
||||
break;
|
||||
case 0:
|
||||
/* child, success */
|
||||
break;
|
||||
default:
|
||||
/* parent, success */
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* main loop */
|
||||
timestamp();
|
||||
|
||||
status.requests = 0;
|
||||
status.errors = 0;
|
||||
|
||||
start_time = current_time;
|
||||
select_loop(server_s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_server_socket(void)
|
||||
{
|
||||
int server_s;
|
||||
|
||||
server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (server_s == -1) {
|
||||
DIE("unable to create socket");
|
||||
}
|
||||
|
||||
/* server socket is nonblocking */
|
||||
if (set_nonblock_fd(server_s) == -1) {
|
||||
DIE("fcntl: unable to set server socket to nonblocking");
|
||||
}
|
||||
|
||||
/* close server socket on exec so cgi's can't write to it */
|
||||
if (fcntl(server_s, F_SETFD, 1) == -1) {
|
||||
DIE("can't set close-on-exec on server socket!");
|
||||
}
|
||||
|
||||
/* reuse socket addr */
|
||||
if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
|
||||
sizeof (sock_opt))) == -1) {
|
||||
DIE("setsockopt");
|
||||
}
|
||||
|
||||
/* internet family-specific code encapsulated in bind_server() */
|
||||
if (bind_server(server_s, server_ip) == -1) {
|
||||
DIE("unable to bind");
|
||||
}
|
||||
|
||||
/* listen: large number just in case your kernel is nicely tweaked */
|
||||
if (listen(server_s, backlog) == -1) {
|
||||
DIE("unable to listen");
|
||||
}
|
||||
return server_s;
|
||||
}
|
||||
|
||||
static void drop_privs(void)
|
||||
{
|
||||
/* give away our privs if we can */
|
||||
if (getuid() == 0) {
|
||||
struct passwd *passwdbuf;
|
||||
passwdbuf = getpwuid(server_uid);
|
||||
if (passwdbuf == NULL) {
|
||||
DIE("getpwuid");
|
||||
}
|
||||
if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
|
||||
DIE("initgroups");
|
||||
}
|
||||
if (setgid(server_gid) == -1) {
|
||||
DIE("setgid");
|
||||
}
|
||||
if (setuid(server_uid) == -1) {
|
||||
DIE("setuid");
|
||||
}
|
||||
/* test for failed-but-return-was-successful setuid
|
||||
* http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html
|
||||
*/
|
||||
/*if (setuid(0) != -1) {
|
||||
DIE("icky Linux kernel bug!");
|
||||
}*/
|
||||
} else {
|
||||
if (server_gid || server_uid) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Warning: "
|
||||
"Not running as root: no attempt to change"
|
||||
" to uid %d gid %d\n", server_uid, server_gid);
|
||||
}
|
||||
server_gid = getgid();
|
||||
server_uid = getuid();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: fixup_server_root
|
||||
*
|
||||
* Description: Makes sure the server root is valid.
|
||||
*
|
||||
*/
|
||||
|
||||
static void fixup_server_root()
|
||||
{
|
||||
char *dirbuf;
|
||||
|
||||
if (!server_root) {
|
||||
#ifdef SERVER_ROOT
|
||||
server_root = strdup(SERVER_ROOT);
|
||||
if (!server_root) {
|
||||
perror("strdup (SERVER_ROOT)");
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
fputs("boa: don't know where server root is. Please #define "
|
||||
"SERVER_ROOT in boa.h\n"
|
||||
"and recompile, or use the -c command line option to "
|
||||
"specify it.\n", stderr);
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (chdir(server_root) == -1) {
|
||||
fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
|
||||
server_root);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dirbuf = normalize_path(server_root);
|
||||
free(server_root);
|
||||
server_root = dirbuf;
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996-99 Larry Doolittle <ldoolitt@jlab.org>
|
||||
* Some changes Copyright (C) 1997-99 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: boa.h,v 1.63.2.2 2002/07/26 03:03:44 jnelson Exp $*/
|
||||
|
||||
#ifndef _BOA_H
|
||||
#define _BOA_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h> /* malloc, free, etc. */
|
||||
#include <stdio.h> /* stdin, stdout, stderr */
|
||||
#include <string.h> /* strdup */
|
||||
#include <ctype.h>
|
||||
#include <time.h> /* localtime, time */
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h> /* OPEN_MAX */
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h> /* socket, bind, accept */
|
||||
#include <sys/socket.h> /* socket, bind, accept, setsockopt, */
|
||||
#include <sys/stat.h> /* open */
|
||||
|
||||
#include "compat.h" /* oh what fun is porting */
|
||||
#include "defines.h"
|
||||
#include "globals.h"
|
||||
|
||||
/* alias */
|
||||
void add_alias(char *fakename, char *realname, int script);
|
||||
int translate_uri(request * req);
|
||||
int init_script_alias(request * req, alias * current, int uri_len);
|
||||
void dump_alias(void);
|
||||
|
||||
/* config */
|
||||
void read_config_files(void);
|
||||
|
||||
/* escape */
|
||||
#include "escape.h"
|
||||
|
||||
/* get */
|
||||
|
||||
int init_get(request * req);
|
||||
int process_get(request * req);
|
||||
int get_dir(request * req, struct stat *statbuf);
|
||||
|
||||
/* hash */
|
||||
unsigned get_mime_hash_value(char *extension);
|
||||
char *get_mime_type(char *filename);
|
||||
char *get_home_dir(char *name);
|
||||
void dump_mime(void);
|
||||
void dump_passwd(void);
|
||||
void show_hash_stats(void);
|
||||
|
||||
/* log */
|
||||
void open_logs(void);
|
||||
void close_access_log(void);
|
||||
void log_access(request * req);
|
||||
void log_error_doc(request * req);
|
||||
void boa_perror(request * req, char *message);
|
||||
void log_error_time(void);
|
||||
void log_error_mesg(char *file, int line, char *mesg);
|
||||
|
||||
/* queue */
|
||||
void block_request(request * req);
|
||||
void ready_request(request * req);
|
||||
void dequeue(request ** head, request * req);
|
||||
void enqueue(request ** head, request * req);
|
||||
|
||||
/* read */
|
||||
int read_header(request * req);
|
||||
int read_body(request * req);
|
||||
int write_body(request * req);
|
||||
|
||||
/* request */
|
||||
request *new_request(void);
|
||||
void get_request(int);
|
||||
void process_requests(int server_s);
|
||||
int process_header_end(request * req);
|
||||
int process_header_line(request * req);
|
||||
int process_logline(request * req);
|
||||
int process_option_line(request * req);
|
||||
void add_accept_header(request * req, char *mime_type);
|
||||
void free_requests(void);
|
||||
|
||||
/* response */
|
||||
void print_ka_phrase(request * req);
|
||||
void print_content_type(request * req);
|
||||
void print_content_length(request * req);
|
||||
void print_last_modified(request * req);
|
||||
void print_http_headers(request * req);
|
||||
|
||||
void send_r_request_ok(request * req); /* 200 */
|
||||
void send_r_moved_perm(request * req, char *url); /* 301 */
|
||||
void send_r_moved_temp(request * req, char *url, char *more_hdr); /* 302 */
|
||||
void send_r_not_modified(request * req); /* 304 */
|
||||
void send_r_bad_request(request * req); /* 400 */
|
||||
void send_r_unauthorized(request * req, char *name); /* 401 */
|
||||
void send_r_forbidden(request * req); /* 403 */
|
||||
void send_r_not_found(request * req); /* 404 */
|
||||
void send_r_error(request * req); /* 500 */
|
||||
void send_r_not_implemented(request * req); /* 501 */
|
||||
void send_r_bad_gateway(request * req); /* 502 */
|
||||
void send_r_service_unavailable(request * req); /* 503 */
|
||||
void send_r_bad_version(request * req); /* 505 */
|
||||
|
||||
/* cgi */
|
||||
void create_common_env(void);
|
||||
void clear_common_env(void);
|
||||
int add_cgi_env(request * req, char *key, char *value, int http_prefix);
|
||||
int complete_env(request * req);
|
||||
void create_argv(request * req, char **aargv);
|
||||
int init_cgi(request * req);
|
||||
|
||||
/* signals */
|
||||
void init_signals(void);
|
||||
void sighup_run(void);
|
||||
void sigchld_run(void);
|
||||
void sigalrm_run(void);
|
||||
void sigterm_stage1_run(int);
|
||||
void sigterm_stage2_run();
|
||||
|
||||
/* util.c */
|
||||
void clean_pathname(char *pathname);
|
||||
char *get_commonlog_time(void);
|
||||
void rfc822_time_buf(char *buf, time_t s);
|
||||
char *simple_itoa(unsigned int i);
|
||||
int boa_atoi(char *s);
|
||||
char *escape_string(char *inp, char *buf);
|
||||
int month2int(char *month);
|
||||
int modified_since(time_t * mtime, char *if_modified_since);
|
||||
char *to_upper(char *str);
|
||||
int unescape_uri(char *uri, char **query_string);
|
||||
int create_temporary_file(short want_unlink, char *storage, int size);
|
||||
char * normalize_path(char *path);
|
||||
int real_set_block_fd(int fd);
|
||||
int real_set_nonblock_fd(int fd);
|
||||
|
||||
/* buffer */
|
||||
int req_write(request * req, char *msg);
|
||||
void reset_output_buffer(request *req);
|
||||
int req_write_escape_http(request * req, char *msg);
|
||||
int req_write_escape_html(request * req, char *msg);
|
||||
int req_flush(request * req);
|
||||
char *escape_uri(char *uri);
|
||||
|
||||
/* timestamp */
|
||||
void timestamp(void);
|
||||
|
||||
/* mmap_cache */
|
||||
struct mmap_entry *find_mmap(int data_fd, struct stat *s);
|
||||
void release_mmap(struct mmap_entry *e);
|
||||
|
||||
/* sublog */
|
||||
int open_gen_fd(char *spec);
|
||||
int process_cgi_header(request * req);
|
||||
|
||||
/* pipe */
|
||||
int read_from_pipe(request * req);
|
||||
int write_from_pipe(request * req);
|
||||
|
||||
/* ip */
|
||||
int bind_server(int server_s, char *ip);
|
||||
char *ascii_sockaddr(struct SOCKADDR *s, char *dest, int len);
|
||||
int net_port(struct SOCKADDR *s);
|
||||
|
||||
/* select */
|
||||
void select_loop(int server_s);
|
||||
|
||||
#endif
|
Binary file not shown.
|
@ -0,0 +1,127 @@
|
|||
%{
|
||||
|
||||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <psp@well.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: boa_grammar.y,v 1.14 1999/10/12 14:49:07 jon Exp $*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
/* #include "boa.h" */
|
||||
#include "parse.h"
|
||||
|
||||
int yyerror(char * msg);
|
||||
|
||||
/* yydebug = 1; */
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(x) x
|
||||
#else
|
||||
#define DBG(x)
|
||||
#endif
|
||||
|
||||
char *arg1hold;
|
||||
char mime_type[256]; /* global to inherit */
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
char * sval;
|
||||
int ival;
|
||||
struct ccommand * cval;
|
||||
};
|
||||
|
||||
/* boa.conf tokens */
|
||||
%token <cval> STMT_NO_ARGS STMT_ONE_ARG STMT_TWO_ARGS
|
||||
|
||||
/* mime.type tokens */
|
||||
%token <sval> MIMETYPE
|
||||
%token <sval> STRING
|
||||
%token <ival> INTEGER
|
||||
|
||||
%start ConfigFiles
|
||||
|
||||
%%
|
||||
|
||||
ConfigFiles: BoaConfigStmts MimeTypeStmts
|
||||
;
|
||||
|
||||
BoaConfigStmts: BoaConfigStmts BoaConfigStmt
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
BoaConfigStmt:
|
||||
StmtNoArgs
|
||||
| StmtOneArg
|
||||
| StmtTwoArgs
|
||||
;
|
||||
|
||||
StmtNoArgs: STMT_NO_ARGS
|
||||
{ if ($1->action) {
|
||||
DBG(printf("StmtNoArgs: %s\n",$1->name);)
|
||||
$1->action(NULL,NULL,$1->object);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
StmtOneArg: STMT_ONE_ARG STRING
|
||||
{ if ($1->action) {
|
||||
DBG(printf("StmtOneArg: %s %s\n",$1->name,$2);)
|
||||
$1->action($2,NULL,$1->object);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
StmtTwoArgs: STMT_TWO_ARGS STRING
|
||||
{ arg1hold = strdup($2); }
|
||||
STRING
|
||||
{ if ($1->action) {
|
||||
DBG(printf("StmtTwoArgs: '%s' '%s' '%s'\n",
|
||||
$1->name,arg1hold,$4);)
|
||||
$1->action($4,arg1hold,$1->object);
|
||||
}
|
||||
free(arg1hold);
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
/******************* mime.types **********************/
|
||||
|
||||
MimeTypeStmts: MimeTypeStmts MimeTypeStmt
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
MimeTypeStmt: MIMETYPE
|
||||
{ strcpy(mime_type, $1); }
|
||||
ExtensionList
|
||||
;
|
||||
|
||||
ExtensionList: ExtensionList Extension
|
||||
| /* empty */
|
||||
;
|
||||
|
||||
Extension: STRING
|
||||
{ add_mime_type($1, mime_type); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
Binary file not shown.
|
@ -0,0 +1,155 @@
|
|||
%{
|
||||
|
||||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <psp@well.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: boa_lexer.l,v 1.13.2.1 2002/07/07 23:19:55 jnelson Exp $*/
|
||||
|
||||
#include "y.tab.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "parse.h"
|
||||
|
||||
#define MAX_STR_CONST 1024
|
||||
#define qspush(c) \
|
||||
if (string_buf_ptr < string_buf+MAX_STR_CONST) \
|
||||
*string_buf_ptr++ = c; \
|
||||
else \
|
||||
yyerror("quoted string overflow");
|
||||
|
||||
char *mime_types = NULL;
|
||||
|
||||
static int file = 0;
|
||||
int lineno = 1;
|
||||
struct ccommand *k;
|
||||
char string_buf[MAX_STR_CONST];
|
||||
char *string_buf_ptr;
|
||||
%}
|
||||
|
||||
%s MIME
|
||||
/* Quoted string handling (almost) straight out of
|
||||
the flex 2.5 man page, April 1995 */
|
||||
%x STR
|
||||
|
||||
%%
|
||||
|
||||
[ \t]+ ;
|
||||
#.* ;
|
||||
|
||||
<MIME>[^ \t\n]+\/[^ \t\n]+ { yylval.sval = yytext; return MIMETYPE; }
|
||||
|
||||
[^ \"\t\n]+ { /* XXX could use better checks that we are in a state to
|
||||
* accept keywords; this version matches original behavior */
|
||||
if ((YYSTATE==INITIAL) && (k=lookup_keyword(yytext))) {
|
||||
yylval.cval=k;
|
||||
return (k->type);
|
||||
} else { yylval.sval = yytext; return STRING; }
|
||||
}
|
||||
|
||||
\" {
|
||||
string_buf_ptr = string_buf;
|
||||
BEGIN(STR);
|
||||
}
|
||||
|
||||
<STR>{
|
||||
\" { /* saw closing quote - all done */
|
||||
BEGIN(INITIAL);
|
||||
*string_buf_ptr = '\0';
|
||||
/* return string constant token type and value to parser */
|
||||
yylval.sval = string_buf; return STRING;
|
||||
}
|
||||
|
||||
\n {
|
||||
/* error - unterminated string constant */
|
||||
/* generate error message */
|
||||
yyerror("unterminated string constant");
|
||||
}
|
||||
|
||||
\\[0-7]{1,3} {
|
||||
/* octal escape sequence */
|
||||
int result;
|
||||
|
||||
(void) sscanf( yytext + 1, "%o", &result );
|
||||
|
||||
if ( result > 0xff )
|
||||
{ /* error, constant is out-of-bounds */ }
|
||||
|
||||
qspush(result);
|
||||
}
|
||||
|
||||
\\[0-9]+ {
|
||||
/* generate error - bad escape sequence; something
|
||||
* like '\48' or '\0777777'
|
||||
*/
|
||||
yyerror("bad escape sequence");
|
||||
}
|
||||
|
||||
\\n qspush('\n');
|
||||
\\t qspush('\t');
|
||||
\\r qspush('\r');
|
||||
\\b qspush('\b');
|
||||
\\f qspush('\f');
|
||||
|
||||
\\(.|\n) *string_buf_ptr++ = yytext[1];
|
||||
|
||||
[^\\\n\"]+ {
|
||||
char *yptr = yytext;
|
||||
while ( *yptr )
|
||||
qspush(*yptr++);
|
||||
}
|
||||
}
|
||||
/* End of <STR> dependence */
|
||||
\n { lineno++; }
|
||||
%%
|
||||
|
||||
/* In yywrap we track which file we are on.
|
||||
* 1: close boa.conf, open mime.types
|
||||
* 2: return 1;
|
||||
*/
|
||||
|
||||
int yywrap()
|
||||
{
|
||||
fclose(yyin);
|
||||
file++;
|
||||
|
||||
switch(file) {
|
||||
case 1:
|
||||
yyin = fopen(mime_types, "r");
|
||||
if(!yyin) {
|
||||
fprintf(stderr, "Could not open mime.types file, \"%s\", "
|
||||
"for reading\n", mime_types);
|
||||
exit(1);
|
||||
}
|
||||
BEGIN MIME;
|
||||
return 0;
|
||||
default:
|
||||
BEGIN INITIAL;
|
||||
file = 0; /* in case we reread config files */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int yyerror(char * msg)
|
||||
{
|
||||
fprintf(stderr, "Error on line %d of %s: %s\n", lineno,
|
||||
(file == 0 ? "boa.conf" : "mime.types"), msg);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1999 Jon Nelson <jnelson@boa.org>
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: buffer.c,v 1.10.2.2 2002/07/26 03:03:44 jnelson Exp $ */
|
||||
|
||||
#include "boa.h"
|
||||
#include "escape.h"
|
||||
|
||||
#define INT_TO_HEX(x) \
|
||||
((((x)-10)>=0)?('A'+((x)-10)):('0'+(x)))
|
||||
|
||||
/*
|
||||
* Name: req_write
|
||||
*
|
||||
* Description: Buffers data before sending to client.
|
||||
* Returns: -1 for error, otherwise how much is stored
|
||||
*/
|
||||
|
||||
int req_write(request * req, char *msg)
|
||||
{
|
||||
int msg_len;
|
||||
|
||||
msg_len = strlen(msg);
|
||||
|
||||
if (!msg_len || req->status == DEAD)
|
||||
return req->buffer_end;
|
||||
|
||||
if (req->buffer_end + msg_len > BUFFER_SIZE) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Ran out of Buffer space!\n");
|
||||
req->status = DEAD;
|
||||
return -1;
|
||||
}
|
||||
memcpy(req->buffer + req->buffer_end, msg, msg_len);
|
||||
req->buffer_end += msg_len;
|
||||
return req->buffer_end;
|
||||
}
|
||||
|
||||
void reset_output_buffer(request *req)
|
||||
{
|
||||
req->buffer_end = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: req_write_escape_http
|
||||
* Description: Buffers and "escapes" data before sending to client.
|
||||
* as above, but translates as it copies, into a form suitably
|
||||
* encoded for URLs in HTTP headers.
|
||||
* Returns: -1 for error, otherwise how much is stored
|
||||
*/
|
||||
int req_write_escape_http(request * req, char *msg)
|
||||
{
|
||||
char c, *inp, *dest;
|
||||
int left;
|
||||
inp = msg;
|
||||
dest = req->buffer + req->buffer_end;
|
||||
/* 3 is a guard band, since we don't check the destination pointer
|
||||
* in the middle of a transfer of up to 3 bytes */
|
||||
left = BUFFER_SIZE - req->buffer_end - 3;
|
||||
while ((c = *inp++) && left > 0) {
|
||||
if (needs_escape((unsigned int) c)) {
|
||||
*dest++ = '%';
|
||||
*dest++ = INT_TO_HEX(c >> 4);
|
||||
*dest++ = INT_TO_HEX(c & 15);
|
||||
left -= 3;
|
||||
} else {
|
||||
*dest++ = c;
|
||||
left--;
|
||||
}
|
||||
}
|
||||
req->buffer_end = dest - req->buffer;
|
||||
if (left == 0) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Ran out of Buffer space!\n");
|
||||
req->status = DEAD;
|
||||
return -1;
|
||||
}
|
||||
return req->buffer_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: req_write_escape_html
|
||||
* Description: Buffers and "escapes" data before sending to client.
|
||||
* as above, but translates as it copies, into a form suitably
|
||||
* encoded for HTML bodies.
|
||||
* Returns: -1 for error, otherwise how much is stored
|
||||
*/
|
||||
int req_write_escape_html(request * req, char *msg)
|
||||
{
|
||||
char c, *inp, *dest;
|
||||
int left;
|
||||
inp = msg;
|
||||
dest = req->buffer + req->buffer_end;
|
||||
/* 5 is a guard band, since we don't check the destination pointer
|
||||
* in the middle of a transfer of up to 5 bytes */
|
||||
left = BUFFER_SIZE - req->buffer_end - 5;
|
||||
while ((c = *inp++) && left > 0) {
|
||||
switch (c) {
|
||||
case '>':
|
||||
*dest++ = '&';
|
||||
*dest++ = 'g';
|
||||
*dest++ = 't';
|
||||
*dest++ = ';';
|
||||
left -= 4;
|
||||
break;
|
||||
case '<':
|
||||
*dest++ = '&';
|
||||
*dest++ = 'l';
|
||||
*dest++ = 't';
|
||||
*dest++ = ';';
|
||||
left -= 4;
|
||||
break;
|
||||
case '&':
|
||||
*dest++ = '&';
|
||||
*dest++ = 'a';
|
||||
*dest++ = 'm';
|
||||
*dest++ = 'p';
|
||||
*dest++ = ';';
|
||||
left -= 5;
|
||||
break;
|
||||
case '\"':
|
||||
*dest++ = '&';
|
||||
*dest++ = 'q';
|
||||
*dest++ = 'u';
|
||||
*dest++ = 'o';
|
||||
*dest++ = 't';
|
||||
*dest++ = ';';
|
||||
left -= 6;
|
||||
break;
|
||||
default:
|
||||
*dest++ = c;
|
||||
left--;
|
||||
}
|
||||
}
|
||||
req->buffer_end = dest - req->buffer;
|
||||
if (left == 0) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Ran out of Buffer space!\n");
|
||||
req->status = DEAD;
|
||||
return -1;
|
||||
}
|
||||
return req->buffer_end;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name: flush_req
|
||||
*
|
||||
* Description: Sends any backlogged buffer to client.
|
||||
*
|
||||
* Returns: -2 for error, -1 for blocked, otherwise how much is stored
|
||||
*/
|
||||
|
||||
int req_flush(request * req)
|
||||
{
|
||||
int bytes_to_write;
|
||||
|
||||
bytes_to_write = req->buffer_end - req->buffer_start;
|
||||
if (req->status == DEAD)
|
||||
return -2;
|
||||
|
||||
if (bytes_to_write) {
|
||||
int bytes_written;
|
||||
|
||||
bytes_written = write(req->fd, req->buffer + req->buffer_start,
|
||||
bytes_to_write);
|
||||
|
||||
if (bytes_written < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
return -1; /* request blocked at the pipe level, but keep going */
|
||||
else {
|
||||
req->buffer_start = req->buffer_end = 0;
|
||||
if (errno != EPIPE)
|
||||
perror("buffer flush"); /* OK to disable if your logs get too big */
|
||||
req->status = DEAD;
|
||||
req->buffer_end = 0;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
#ifdef FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - Wrote \"", __FILE__, __LINE__);
|
||||
fwrite(req->buffer + req->buffer_start, sizeof (char),
|
||||
bytes_written, stderr);
|
||||
fprintf(stderr, "\" (%d bytes)\n", bytes_written);
|
||||
#endif
|
||||
req->buffer_start += bytes_written;
|
||||
}
|
||||
if (req->buffer_start == req->buffer_end)
|
||||
req->buffer_start = req->buffer_end = 0;
|
||||
return req->buffer_end; /* successful */
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: escape_string
|
||||
*
|
||||
* Description: escapes the string inp. Uses variable buf. If buf is
|
||||
* NULL when the program starts, it will attempt to dynamically allocate
|
||||
* the space that it needs, otherwise it will assume that the user
|
||||
* has already allocated enough space for the variable buf, which
|
||||
* could be up to 3 times the size of inp. If the routine dynamically
|
||||
* allocates the space, the user is responsible for freeing it afterwords
|
||||
* Returns: NULL on error, pointer to string otherwise.
|
||||
* Note: this function doesn't really belong here, I plopped it here to
|
||||
* work around a "bug" in escape.h (it defines a global, so can't be
|
||||
* used in multiple source files). Actually, this routine shouldn't
|
||||
* exist anywhere, it's only usage is in get.c's handling of on-the-fly
|
||||
* directory generation, which would be better configured to use a combination
|
||||
* of req_write_escape_http and req_write_escape_html. That would involve
|
||||
* more work than I'm willing to put in right now, though, so here we are.
|
||||
*/
|
||||
|
||||
char *escape_string(char *inp, char *buf)
|
||||
{
|
||||
int max;
|
||||
char *index;
|
||||
unsigned char c;
|
||||
|
||||
max = strlen(inp) * 3;
|
||||
|
||||
if (buf == NULL && max)
|
||||
buf = malloc(sizeof (char) * max + 1);
|
||||
|
||||
if (buf == NULL) {
|
||||
log_error_time();
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
index = buf;
|
||||
while ((c = *inp++) && max > 0) {
|
||||
if (needs_escape((unsigned int) c)) {
|
||||
*index++ = '%';
|
||||
*index++ = INT_TO_HEX(c >> 4);
|
||||
*index++ = INT_TO_HEX(c & 15);
|
||||
} else
|
||||
*index++ = c;
|
||||
}
|
||||
*index = '\0';
|
||||
return buf;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,556 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
|
||||
* Some changes Copyright (C) 1997-2002 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: cgi.c,v 1.83.2.3 2002/07/23 15:49:54 jnelson Exp $ */
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
static char *env_gen_extra(const char *key, const char *value, int extra);
|
||||
|
||||
int verbose_cgi_logs = 0;
|
||||
/* The +1 is for the the NULL in complete_env */
|
||||
static char *common_cgi_env[COMMON_CGI_COUNT + 1];
|
||||
|
||||
/*
|
||||
* Name: create_common_env
|
||||
*
|
||||
* Description: Set up the environment variables that are common to
|
||||
* all CGI scripts
|
||||
*/
|
||||
|
||||
void create_common_env()
|
||||
{
|
||||
int index = 0, i;
|
||||
|
||||
|
||||
/* NOTE NOTE NOTE:
|
||||
If you (the reader) someday modify this chunk of code to
|
||||
handle more "common" CGI environment variables, then bump the
|
||||
value COMMON_CGI_COUNT in defines.h UP
|
||||
|
||||
Also, in the case of document_root and server_admin, two variables
|
||||
that may or may not be defined depending on the way the server
|
||||
is configured, we check for null values and use an empty
|
||||
string to denote a NULL value to the environment, as per the
|
||||
specification. The quote for which follows:
|
||||
|
||||
"In all cases, a missing environment variable is
|
||||
equivalent to a zero-length (NULL) value, and vice versa."
|
||||
*/
|
||||
common_cgi_env[index++] = env_gen_extra("PATH",
|
||||
((cgi_path != NULL) ? cgi_path : DEFAULT_PATH), 0);
|
||||
common_cgi_env[index++] = env_gen_extra("SERVER_SOFTWARE", SERVER_VERSION, 0);
|
||||
common_cgi_env[index++] = env_gen_extra("SERVER_NAME", server_name, 0);
|
||||
common_cgi_env[index++] = env_gen_extra("GATEWAY_INTERFACE", CGI_VERSION, 0);
|
||||
|
||||
common_cgi_env[index++] =
|
||||
env_gen_extra("SERVER_PORT", simple_itoa(server_port), 0);
|
||||
|
||||
/* NCSA and APACHE added -- not in CGI spec */
|
||||
/* common_cgi_env[index++] = env_gen_extra("DOCUMENT_ROOT", document_root); */
|
||||
|
||||
/* NCSA added */
|
||||
/* common_cgi_env[index++] = env_gen_extra("SERVER_ROOT", server_root); */
|
||||
|
||||
/* APACHE added */
|
||||
common_cgi_env[index++] = env_gen_extra("SERVER_ADMIN", server_admin, 0);
|
||||
common_cgi_env[index] = NULL;
|
||||
|
||||
/* Sanity checking -- make *sure* the memory got allocated */
|
||||
if (index > COMMON_CGI_COUNT) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "COMMON_CGI_COUNT not high enough.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for(i = 0;i < index;++i) {
|
||||
if (common_cgi_env[i] == NULL) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Unable to allocate a component of common_cgi_env - out of memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear_common_env(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0;i <= COMMON_CGI_COUNT;++i) {
|
||||
if (common_cgi_env[i] != NULL) {
|
||||
free(common_cgi_env[i]);
|
||||
common_cgi_env[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: env_gen_extra
|
||||
* (and via a not-so-tricky #define, env_gen)
|
||||
* This routine calls malloc: please free the memory when you are done
|
||||
*/
|
||||
static char *env_gen_extra(const char *key, const char *value, int extra)
|
||||
{
|
||||
char *result;
|
||||
int key_len, value_len;
|
||||
|
||||
if (value == NULL) /* ServerAdmin may not be defined, eg */
|
||||
value = "";
|
||||
key_len = strlen(key);
|
||||
value_len = strlen(value);
|
||||
/* leave room for '=' sign and null terminator */
|
||||
result = malloc(extra + key_len + value_len + 2);
|
||||
if (result) {
|
||||
memcpy(result + extra, key, key_len);
|
||||
*(result + extra + key_len) = '=';
|
||||
memcpy(result + extra + key_len + 1, value, value_len);
|
||||
*(result + extra + key_len + value_len + 1) = '\0';
|
||||
} else {
|
||||
log_error_time();
|
||||
perror("malloc");
|
||||
log_error_time();
|
||||
fprintf(stderr,
|
||||
"tried to allocate (key=value) extra=%d: %s=%s\n",
|
||||
extra, key, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: add_cgi_env
|
||||
*
|
||||
* Description: adds a variable to CGI's environment
|
||||
* Used for HTTP_ headers
|
||||
*/
|
||||
|
||||
int add_cgi_env(request * req, char *key, char *value, int http_prefix)
|
||||
{
|
||||
char *p;
|
||||
int prefix_len;
|
||||
|
||||
if (http_prefix) {
|
||||
prefix_len = 5;
|
||||
} else {
|
||||
prefix_len = 0;
|
||||
}
|
||||
|
||||
if (req->cgi_env_index < CGI_ENV_MAX) {
|
||||
p = env_gen_extra(key, value, prefix_len);
|
||||
if (!p) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Unable to generate additional CGI Environment"
|
||||
"variable -- ran out of memory!\n");
|
||||
}
|
||||
if (prefix_len)
|
||||
memcpy(p, "HTTP_", 5);
|
||||
req->cgi_env[req->cgi_env_index++] = p;
|
||||
return 1;
|
||||
} else {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Unable to generate additional CGI Environment"
|
||||
"variable -- not enough space!\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define my_add_cgi_env(req, key, value) { \
|
||||
int ok = add_cgi_env(req, key, value, 0); \
|
||||
if (!ok) return 0; \
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: complete_env
|
||||
*
|
||||
* Description: adds the known client header env variables
|
||||
* and terminates the environment array
|
||||
*/
|
||||
|
||||
int complete_env(request * req)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; common_cgi_env[i]; i++)
|
||||
req->cgi_env[i] = common_cgi_env[i];
|
||||
|
||||
{
|
||||
char *w;
|
||||
switch (req->method) {
|
||||
case M_POST:
|
||||
w = "POST";
|
||||
break;
|
||||
case M_HEAD:
|
||||
w = "HEAD";
|
||||
break;
|
||||
case M_GET:
|
||||
w = "GET";
|
||||
break;
|
||||
default:
|
||||
w = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
my_add_cgi_env(req, "REQUEST_METHOD", w);
|
||||
}
|
||||
|
||||
my_add_cgi_env(req, "SERVER_ADDR", req->local_ip_addr);
|
||||
my_add_cgi_env(req, "SERVER_PROTOCOL", req->http_version);
|
||||
my_add_cgi_env(req, "REQUEST_URI", req->request_uri);
|
||||
|
||||
if (req->path_info)
|
||||
my_add_cgi_env(req, "PATH_INFO", req->path_info);
|
||||
|
||||
if (req->path_translated)
|
||||
/* while path_translated depends on path_info,
|
||||
* there are cases when path_translated might
|
||||
* not exist when path_info does
|
||||
*/
|
||||
my_add_cgi_env(req, "PATH_TRANSLATED", req->path_translated);
|
||||
|
||||
my_add_cgi_env(req, "SCRIPT_NAME", req->script_name);
|
||||
|
||||
if (req->query_string)
|
||||
my_add_cgi_env(req, "QUERY_STRING", req->query_string);
|
||||
my_add_cgi_env(req, "REMOTE_ADDR", req->remote_ip_addr);
|
||||
my_add_cgi_env(req, "REMOTE_PORT", simple_itoa(req->remote_port));
|
||||
|
||||
if (req->method == M_POST) {
|
||||
if (req->content_type) {
|
||||
my_add_cgi_env(req, "CONTENT_TYPE", req->content_type);
|
||||
} else {
|
||||
my_add_cgi_env(req, "CONTENT_TYPE", default_type);
|
||||
}
|
||||
if (req->content_length) {
|
||||
my_add_cgi_env(req, "CONTENT_LENGTH", req->content_length);
|
||||
}
|
||||
}
|
||||
#ifdef ACCEPT_ON
|
||||
if (req->accept[0])
|
||||
my_add_cgi_env(req, "HTTP_ACCEPT", req->accept);
|
||||
#endif
|
||||
|
||||
if (req->cgi_env_index < CGI_ENV_MAX + 1) {
|
||||
req->cgi_env[req->cgi_env_index] = NULL; /* terminate */
|
||||
return 1;
|
||||
}
|
||||
log_error_time();
|
||||
fprintf(stderr, "Not enough space in CGI environment for remainder"\
|
||||
" of variables.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: make_args_cgi
|
||||
*
|
||||
* Build argv list for a CGI script according to spec
|
||||
*
|
||||
*/
|
||||
|
||||
void create_argv(request * req, char **aargv)
|
||||
{
|
||||
char *p, *q, *r;
|
||||
int aargc;
|
||||
|
||||
q = req->query_string;
|
||||
aargv[0] = req->pathname;
|
||||
|
||||
/* here, we handle a special "indexed" query string.
|
||||
* Taken from the CGI/1.1 SPEC:
|
||||
* This is identified by a GET or HEAD request with a query string
|
||||
* with no *unencoded* '=' in it.
|
||||
* For such a request, I'm supposed to parse the search string
|
||||
* into words, according to the following rules:
|
||||
|
||||
search-string = search-word *( "+" search-word )
|
||||
search-word = 1*schar
|
||||
schar = xunreserved | escaped | xreserved
|
||||
xunreserved = alpha | digit | xsafe | extra
|
||||
xsafe = "$" | "-" | "_" | "."
|
||||
xreserved = ";" | "/" | "?" | ":" | "@" | "&"
|
||||
|
||||
After parsing, each word is URL-decoded, optionally encoded in a system
|
||||
defined manner, and then the argument list
|
||||
is set to the list of words.
|
||||
|
||||
|
||||
Thus, schar is alpha|digit|"$"|"-"|"_"|"."|";"|"/"|"?"|":"|"@"|"&"
|
||||
|
||||
As of this writing, escape.pl escapes the following chars:
|
||||
|
||||
"-", "_", ".", "!", "~", "*", "'", "(", ")",
|
||||
"0".."9", "A".."Z", "a".."z",
|
||||
";", "/", "?", ":", "@", "&", "=", "+", "\$", ","
|
||||
|
||||
Which therefore means
|
||||
"=", "+", "~", "!", "*", "'", "(", ")", ","
|
||||
are *not* escaped and should be?
|
||||
Wait, we don't do any escaping, and nor should we.
|
||||
According to the RFC draft, we unescape and then re-escape
|
||||
in a "system defined manner" (here: none).
|
||||
|
||||
The CGI/1.1 draft (03, latest is 1999???) is very unclear here.
|
||||
|
||||
I am using the latest published RFC, 2396, for what does and does
|
||||
not need escaping.
|
||||
|
||||
Since boa builds the argument list and does not call /bin/sh,
|
||||
(boa uses execve for CGI)
|
||||
*/
|
||||
|
||||
if (q && !strchr(q, '=')) {
|
||||
/* we have an 'index' style */
|
||||
q = strdup(q);
|
||||
if (!q) {
|
||||
WARN("unable to strdup 'q' in create_argv!");
|
||||
}
|
||||
for (aargc = 1; q && (aargc < CGI_ARGC_MAX);) {
|
||||
r = q;
|
||||
/* for an index-style CGI, + is used to seperate arguments
|
||||
* an escaped '+' is of no concern to us
|
||||
*/
|
||||
if ((p = strchr(q, '+'))) {
|
||||
*p = '\0';
|
||||
q = p + 1;
|
||||
} else {
|
||||
q = NULL;
|
||||
}
|
||||
if (unescape_uri(r, NULL)) {
|
||||
/* printf("parameter %d: %s\n",aargc,r); */
|
||||
aargv[aargc++] = r;
|
||||
}
|
||||
}
|
||||
aargv[aargc] = NULL;
|
||||
} else {
|
||||
aargv[1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: init_cgi
|
||||
*
|
||||
* Description: Called for GET/POST requests that refer to ScriptAlias
|
||||
* directories or application/x-httpd-cgi files. Ties stdout to socket,
|
||||
* stdin to data if POST, and execs CGI.
|
||||
* stderr remains tied to our log file; is this good?
|
||||
*
|
||||
* Returns:
|
||||
* 0 - error or NPH, either way the socket is closed
|
||||
* 1 - success
|
||||
*/
|
||||
|
||||
int init_cgi(request * req)
|
||||
{
|
||||
int child_pid;
|
||||
int pipes[2];
|
||||
int use_pipes = 0;
|
||||
|
||||
SQUASH_KA(req);
|
||||
|
||||
if (req->is_cgi) {
|
||||
if (complete_env(req) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#ifdef FASCIST_LOGGING
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < req->cgi_env_index; ++i)
|
||||
fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
|
||||
__FILE__, req->cgi_env[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (req->is_cgi == CGI || 1) {
|
||||
use_pipes = 1;
|
||||
if (pipe(pipes) == -1) {
|
||||
log_error_time();
|
||||
perror("pipe");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set the read end of the socket to non-blocking */
|
||||
if (set_nonblock_fd(pipes[0]) == -1) {
|
||||
log_error_time();
|
||||
perror("cgi-fcntl");
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
child_pid = fork();
|
||||
switch(child_pid) {
|
||||
case -1:
|
||||
/* fork unsuccessful */
|
||||
log_error_time();
|
||||
perror("fork");
|
||||
|
||||
if (use_pipes) {
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
}
|
||||
send_r_error(req);
|
||||
/* FIXME: There is aproblem here. send_r_error would work
|
||||
for NPH and CGI, but not for GUNZIP. Fix that. */
|
||||
/* i'd like to send_r_error, but.... */
|
||||
return 0;
|
||||
break;
|
||||
case 0:
|
||||
/* child */
|
||||
if (req->is_cgi == CGI || req->is_cgi == NPH) {
|
||||
char *foo = strdup(req->pathname);
|
||||
char *c;
|
||||
|
||||
if (!foo) {
|
||||
WARN("unable to strdup pathname for req->pathname");
|
||||
_exit(1);
|
||||
}
|
||||
c = strrchr(foo, '/');
|
||||
if (c) {
|
||||
++c;
|
||||
*c = '\0';
|
||||
} else {
|
||||
/* we have a serious problem */
|
||||
log_error_time();
|
||||
perror("chdir");
|
||||
if (use_pipes)
|
||||
close(pipes[1]);
|
||||
_exit(1);
|
||||
}
|
||||
if (chdir(foo) != 0) {
|
||||
log_error_time();
|
||||
perror("chdir");
|
||||
if (use_pipes)
|
||||
close(pipes[1]);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
if (use_pipes) {
|
||||
close(pipes[0]);
|
||||
/* tie cgi's STDOUT to it's write end of pipe */
|
||||
if (dup2(pipes[1], STDOUT_FILENO) == -1) {
|
||||
log_error_time();
|
||||
perror("dup2 - pipes");
|
||||
close(pipes[1]);
|
||||
_exit(1);
|
||||
}
|
||||
close(pipes[1]);
|
||||
if (set_block_fd(STDOUT_FILENO) == -1) {
|
||||
log_error_time();
|
||||
perror("cgi-fcntl");
|
||||
_exit(1);
|
||||
}
|
||||
} else {
|
||||
/* tie stdout to socket */
|
||||
if (dup2(req->fd, STDOUT_FILENO) == -1) {
|
||||
log_error_time();
|
||||
perror("dup2 - fd");
|
||||
_exit(1);
|
||||
}
|
||||
/* Switch socket flags back to blocking */
|
||||
if (set_block_fd(req->fd) == -1) {
|
||||
log_error_time();
|
||||
perror("cgi-fcntl");
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
/* tie post_data_fd to POST stdin */
|
||||
if (req->method == M_POST) { /* tie stdin to file */
|
||||
lseek(req->post_data_fd, SEEK_SET, 0);
|
||||
dup2(req->post_data_fd, STDIN_FILENO);
|
||||
close(req->post_data_fd);
|
||||
}
|
||||
/* Close access log, so CGI program can't scribble
|
||||
* where it shouldn't
|
||||
*/
|
||||
close_access_log();
|
||||
|
||||
/*
|
||||
* tie STDERR to cgi_log_fd
|
||||
* cgi_log_fd will automatically close, close-on-exec rocks!
|
||||
* if we don't tied STDERR (current log_error) to cgi_log_fd,
|
||||
* then we ought to close it.
|
||||
*/
|
||||
if (!cgi_log_fd)
|
||||
dup2(devnullfd, STDERR_FILENO);
|
||||
else
|
||||
dup2(cgi_log_fd, STDERR_FILENO);
|
||||
|
||||
if (req->is_cgi) {
|
||||
char *aargv[CGI_ARGC_MAX + 1];
|
||||
create_argv(req, aargv);
|
||||
execve(req->pathname, aargv, req->cgi_env);
|
||||
} else {
|
||||
if (req->pathname[strlen(req->pathname) - 1] == '/')
|
||||
execl(dirmaker, dirmaker, req->pathname, req->request_uri,
|
||||
NULL);
|
||||
#ifdef GUNZIP
|
||||
else
|
||||
execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
|
||||
req->pathname, NULL);
|
||||
#endif
|
||||
}
|
||||
/* execve failed */
|
||||
WARN(req->pathname);
|
||||
_exit(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* parent */
|
||||
/* if here, fork was successful */
|
||||
if (verbose_cgi_logs) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Forked child \"%s\" pid %d\n",
|
||||
req->pathname, child_pid);
|
||||
}
|
||||
|
||||
if (req->method == M_POST) {
|
||||
close(req->post_data_fd); /* child closed it too */
|
||||
req->post_data_fd = 0;
|
||||
}
|
||||
|
||||
/* NPH, GUNZIP, etc... all go straight to the fd */
|
||||
if (!use_pipes)
|
||||
return 0;
|
||||
|
||||
close(pipes[1]);
|
||||
req->data_fd = pipes[0];
|
||||
|
||||
req->status = PIPE_READ;
|
||||
if (req->is_cgi == CGI) {
|
||||
req->cgi_status = CGI_PARSE; /* got to parse cgi header */
|
||||
/* for cgi_header... I get half the buffer! */
|
||||
req->header_line = req->header_end =
|
||||
(req->buffer + BUFFER_SIZE / 2);
|
||||
} else {
|
||||
req->cgi_status = CGI_BUFFER;
|
||||
/* I get all the buffer! */
|
||||
req->header_line = req->header_end = req->buffer;
|
||||
}
|
||||
|
||||
/* reset req->filepos for logging (it's used in pipe.c) */
|
||||
/* still don't know why req->filesize might be reset though */
|
||||
req->filepos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* cgi_header.c - cgi header parsing and control
|
||||
* Copyright (C) 1997-99 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
/* process_cgi_header
|
||||
|
||||
* returns 0 -=> error or HEAD, close down.
|
||||
* returns 1 -=> done processing
|
||||
* leaves req->cgi_status as WRITE
|
||||
*/
|
||||
|
||||
/*
|
||||
The server MUST also resolve any conflicts between header fields returned by
|
||||
the script and header fields that it would otherwise send itself.
|
||||
|
||||
...
|
||||
|
||||
At least one CGI-Field MUST be supplied, but no CGI field name may be used
|
||||
more than once in a response. If a body is supplied, then a
|
||||
"Content-type" header field MUST be supplied by the script,
|
||||
otherwise the script MUST send a "Location" or "Status" header
|
||||
field. If a Location CGI-Field is returned, then the script
|
||||
MUST NOT supply any HTTP-Fields.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
We still need to cycle through the data before the end of the headers,
|
||||
line-by-line, and check for any problems with the CGI
|
||||
outputting overriding http responses, etc...
|
||||
*/
|
||||
|
||||
int process_cgi_header(request * req)
|
||||
{
|
||||
char *buf;
|
||||
char *c;
|
||||
|
||||
if (req->cgi_status != CGI_DONE)
|
||||
req->cgi_status = CGI_BUFFER;
|
||||
|
||||
buf = req->header_line;
|
||||
|
||||
c = strstr(buf, "\n\r\n");
|
||||
if (c == NULL) {
|
||||
c = strstr(buf, "\n\n");
|
||||
if (c == NULL) {
|
||||
log_error_time();
|
||||
fputs("cgi_header: unable to find LFLF\n", stderr);
|
||||
#ifdef FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr, "\"%s\"\n", buf);
|
||||
#endif
|
||||
send_r_bad_gateway(req);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (req->simple) {
|
||||
if (*(c + 1) == '\r')
|
||||
req->header_line = c + 2;
|
||||
else
|
||||
req->header_line = c + 1;
|
||||
return 1;
|
||||
}
|
||||
if (!strncasecmp(buf, "Status: ", 8)) {
|
||||
req->header_line--;
|
||||
memcpy(req->header_line, "HTTP/1.0 ", 9);
|
||||
} else if (!strncasecmp(buf, "Location: ", 10)) { /* got a location header */
|
||||
#ifdef FASCIST_LOGGING
|
||||
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - found Location header \"%s\"\n",
|
||||
__FILE__, __LINE__, buf + 10);
|
||||
#endif
|
||||
|
||||
|
||||
if (buf[10] == '/') { /* virtual path */
|
||||
log_error_time();
|
||||
fprintf(stderr,
|
||||
"server does not support internal redirection: " \
|
||||
"\"%s\"\n", buf + 10);
|
||||
send_r_bad_request(req);
|
||||
|
||||
/*
|
||||
* We (I, Jon) have declined to support absolute-path parsing
|
||||
* because I see it as a major security hole.
|
||||
* Location: /etc/passwd or Location: /etc/shadow is not funny.
|
||||
*
|
||||
* Also, the below code is borked.
|
||||
* request_uri could contain /cgi-bin/bob/extra_path
|
||||
*/
|
||||
|
||||
/*
|
||||
strcpy(req->request_uri, buf + 10);
|
||||
return internal_redirect(req);
|
||||
*/
|
||||
} else { /* URL */
|
||||
char *c2;
|
||||
c2 = strchr(buf + 10, '\n');
|
||||
/* c2 cannot ever equal NULL here because we already have found one */
|
||||
|
||||
--c2;
|
||||
while (*c2 == '\r')
|
||||
--c2;
|
||||
++c2;
|
||||
/* c2 now points to a '\r' or the '\n' */
|
||||
*c2++ = '\0'; /* end header */
|
||||
|
||||
/* first next header, or is at req->header_end */
|
||||
while ((*c2 == '\n' || *c2 == '\r') && c2 < req->header_end)
|
||||
++c2;
|
||||
if (c2 == req->header_end)
|
||||
send_r_moved_temp(req, buf + 10, "");
|
||||
else
|
||||
send_r_moved_temp(req, buf + 10, c2);
|
||||
}
|
||||
req->status = DONE;
|
||||
return 1;
|
||||
} else { /* not location and not status */
|
||||
char *dest;
|
||||
int howmuch;
|
||||
send_r_request_ok(req); /* does not terminate */
|
||||
/* got to do special things because
|
||||
a) we have a single buffer divided into 2 pieces
|
||||
b) we need to merge those pieces
|
||||
Easiest way is to memmove the cgi data backward until
|
||||
it touches the buffered data, then reset the cgi data pointers
|
||||
*/
|
||||
dest = req->buffer + req->buffer_end;
|
||||
if (req->method == M_HEAD) {
|
||||
if (*(c + 1) == '\r')
|
||||
req->header_end = c + 2;
|
||||
else
|
||||
req->header_end = c + 1;
|
||||
req->cgi_status = CGI_DONE;
|
||||
}
|
||||
howmuch = req->header_end - req->header_line;
|
||||
|
||||
if (dest + howmuch > req->buffer + BUFFER_SIZE) {
|
||||
/* big problem */
|
||||
log_error_time();
|
||||
fprintf(stderr, "Too much data to move! Aborting! %s %d\n",
|
||||
__FILE__, __LINE__);
|
||||
/* reset buffer pointers because we already called
|
||||
send_r_request_ok... */
|
||||
req->buffer_start = req->buffer_end = 0;
|
||||
send_r_error(req);
|
||||
return 0;
|
||||
}
|
||||
memmove(dest, req->header_line, howmuch);
|
||||
req->buffer_end += howmuch;
|
||||
req->header_line = req->buffer + req->buffer_end;
|
||||
req->header_end = req->header_line;
|
||||
req_flush(req);
|
||||
if (req->method == M_HEAD)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,40 @@
|
|||
AC_DEFUN([AC_CHECK_STRUCT_FOR],[
|
||||
ac_safe_struct=`echo "$2" | sed 'y%./+-%__p_%'`
|
||||
ac_safe_member=`echo "$3" | sed 'y%./+-%__p_%'`
|
||||
ac_safe_all="ac_cv_struct_${ac_safe_struct}_has_${ac_safe_member}"
|
||||
changequote(, )dnl
|
||||
ac_uc_define=STRUCT_`echo "${ac_safe_struct}_HAS_${ac_safe_member}" | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
|
||||
changequote([, ])dnl
|
||||
|
||||
AC_MSG_CHECKING([for $2.$3])
|
||||
AC_CACHE_VAL($ac_safe_all,
|
||||
[
|
||||
if test "x$4" = "x"; then
|
||||
defineit="= 0"
|
||||
elif test "x$4" = "xno"; then
|
||||
defineit=""
|
||||
else
|
||||
defineit="$4"
|
||||
fi
|
||||
AC_TRY_COMPILE([
|
||||
$1
|
||||
],[
|
||||
struct $2 testit;
|
||||
testit.$3 $defineit;
|
||||
], eval "${ac_safe_all}=yes", eval "${ac_safe_all}=no" )
|
||||
])
|
||||
|
||||
if eval "test \"x$`echo ${ac_safe_all}`\" = \"xyes\""; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE_UNQUOTED($ac_uc_define)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
])
|
||||
|
||||
dnl AC_CHECK_STRUCT_FOR(INCLUDES,STRUCT,MEMBER,DEFINE,[no])
|
||||
dnl 1.1 (2000/09/19)
|
||||
dnl Wes Hardaker <wjhardaker@ucdavis.edu>
|
||||
|
||||
dnl ----------------------------------------------------------
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1999-2000 Jon Nelson <jnelson@boa.org>
|
||||
* and Larry Doolittle <ldoolitt@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: compat.h,v 1.18.2.1 2002/06/06 05:02:28 jnelson Exp $*/
|
||||
|
||||
#ifndef _COMPAT_H
|
||||
#define _COMPAT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_FCNTL_H
|
||||
#include <sys/fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifndef OPEN_MAX
|
||||
#define OPEN_MAX 256
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 20
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#ifndef SO_MAXCONN
|
||||
#define SO_MAXCONN 250
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 2048
|
||||
#endif
|
||||
|
||||
/* Wild guess time, probably better done with configure */
|
||||
#ifdef O_NONBLOCK
|
||||
#define NOBLOCK O_NONBLOCK /* Linux */
|
||||
#else /* O_NONBLOCK */
|
||||
#ifdef O_NDELAY
|
||||
#define NOBLOCK O_NDELAY /* Sun */
|
||||
#else /* O_NDELAY */
|
||||
#error "Can't find a way to #define NOBLOCK"
|
||||
#endif /* O_NDELAY */
|
||||
#endif /* O_NONBLOCK */
|
||||
|
||||
#ifndef MAP_FILE
|
||||
#define MAP_OPTIONS MAP_PRIVATE /* Sun */
|
||||
#else
|
||||
#define MAP_OPTIONS MAP_FILE|MAP_PRIVATE /* Linux */
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
#define SOCKADDR sockaddr_storage
|
||||
#define S_FAMILY __s_family
|
||||
#define SERVER_AF AF_INET6
|
||||
#else
|
||||
#define SOCKADDR sockaddr_in
|
||||
#define S_FAMILY sin_family
|
||||
#define SERVER_AF AF_INET
|
||||
#endif
|
||||
|
||||
#if HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* below here, functions are provided in extras */
|
||||
#ifndef HAVE_SCANDIR
|
||||
int
|
||||
scandir(const char *dir, struct dirent ***namelist,
|
||||
int (*select) (const struct dirent *),
|
||||
int (*compar) (const struct dirent **, const struct dirent **));
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ALPHASORT
|
||||
int alphasort(const struct dirent **a, const struct dirent **b);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRSTR
|
||||
char *strstr(char *s1, char *s2);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
char *strdup(char *s);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
#define TIMEZONE_OFFSET(foo) (foo)->tm_gmtoff
|
||||
#else
|
||||
#define TIMEZONE_OFFSET(foo) timezone
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TM_ZONE
|
||||
#define TIMEZONE(foo) foo##->tm_zone
|
||||
#else
|
||||
#define TIMEZONE(foo) *tzname
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBDMALLOC
|
||||
#define DMALLOC_FUNC_CHECK
|
||||
#include <dmalloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: config.c,v 1.31.2.3 2002/07/26 03:04:29 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
#include "y.tab.h"
|
||||
#include "parse.h"
|
||||
|
||||
int yyparse(void); /* Better match the output of lex */
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(x) x
|
||||
#else
|
||||
#define DBG(x)
|
||||
#endif
|
||||
|
||||
int server_port;
|
||||
uid_t server_uid;
|
||||
gid_t server_gid;
|
||||
char *server_root;
|
||||
char *server_name;
|
||||
char *server_admin;
|
||||
char *server_ip;
|
||||
int virtualhost;
|
||||
long int max_connections;
|
||||
|
||||
char *document_root;
|
||||
char *user_dir;
|
||||
char *directory_index;
|
||||
char *default_type;
|
||||
char *dirmaker;
|
||||
char *cachedir;
|
||||
|
||||
char *tempdir;
|
||||
|
||||
char *cgi_path = NULL;
|
||||
int single_post_limit = SINGLE_POST_LIMIT_DEFAULT;
|
||||
|
||||
int ka_timeout;
|
||||
int ka_max;
|
||||
|
||||
/* These came from log.c */
|
||||
char *error_log_name;
|
||||
char *access_log_name;
|
||||
char *cgi_log_name;
|
||||
|
||||
int use_localtime;
|
||||
|
||||
/* These are new */
|
||||
static void c_set_user(char *v1, char *v2, void *t);
|
||||
static void c_set_group(char *v1, char *v2, void *t);
|
||||
static void c_set_string(char *v1, char *v2, void *t);
|
||||
static void c_set_int(char *v1, char *v2, void *t);
|
||||
static void c_set_unity(char *v1, char *v2, void *t);
|
||||
static void c_add_type(char *v1, char *v2, void *t);
|
||||
static void c_add_alias(char *v1, char *v2, void *t);
|
||||
|
||||
/* Fakery to keep the value passed to action() a void *,
|
||||
see usage in table and c_add_alias() below */
|
||||
static int script_number = SCRIPTALIAS;
|
||||
static int redirect_number = REDIRECT;
|
||||
static int alias_number = ALIAS;
|
||||
static uid_t current_uid=0;
|
||||
|
||||
/* Help keep the table below compact */
|
||||
#define S0A STMT_NO_ARGS
|
||||
#define S1A STMT_ONE_ARG
|
||||
#define S2A STMT_TWO_ARGS
|
||||
|
||||
struct ccommand clist[] = {
|
||||
{"Port", S1A, c_set_int, &server_port},
|
||||
{"Listen", S1A, c_set_string, &server_ip},
|
||||
{"BackLog", S1A, c_set_int, &backlog},
|
||||
{"User", S1A, c_set_user, NULL},
|
||||
{"Group", S1A, c_set_group, NULL},
|
||||
{"ServerAdmin", S1A, c_set_string, &server_admin},
|
||||
{"ServerRoot", S1A, c_set_string, &server_root},
|
||||
{"ErrorLog", S1A, c_set_string, &error_log_name},
|
||||
{"AccessLog", S1A, c_set_string, &access_log_name},
|
||||
{"UseLocaltime", S0A, c_set_unity, &use_localtime},
|
||||
{"CgiLog", S1A, c_set_string, &cgi_log_name},
|
||||
{"VerboseCGILogs", S0A, c_set_unity, &verbose_cgi_logs},
|
||||
{"ServerName", S1A, c_set_string, &server_name},
|
||||
{"VirtualHost", S0A, c_set_unity, &virtualhost},
|
||||
{"DocumentRoot", S1A, c_set_string, &document_root},
|
||||
{"UserDir", S1A, c_set_string, &user_dir},
|
||||
{"DirectoryIndex", S1A, c_set_string, &directory_index},
|
||||
{"DirectoryMaker", S1A, c_set_string, &dirmaker},
|
||||
{"DirectoryCache", S1A, c_set_string, &cachedir},
|
||||
{"KeepAliveMax", S1A, c_set_int, &ka_max},
|
||||
{"KeepAliveTimeout", S1A, c_set_int, &ka_timeout},
|
||||
{"MimeTypes", S1A, c_set_string, &mime_types},
|
||||
{"DefaultType", S1A, c_set_string, &default_type},
|
||||
{"AddType", S2A, c_add_type, NULL},
|
||||
{"ScriptAlias", S2A, c_add_alias, &script_number},
|
||||
{"Redirect", S2A, c_add_alias, &redirect_number},
|
||||
{"Alias", S2A, c_add_alias, &alias_number},
|
||||
{"SinglePostLimit", S1A, c_set_int, &single_post_limit},
|
||||
{"CGIPath", S1A, c_set_string, &cgi_path},
|
||||
{"MaxConnections", S1A, c_set_int, &max_connections},
|
||||
};
|
||||
|
||||
static void c_set_user(char *v1, char *v2, void *t)
|
||||
{
|
||||
struct passwd *passwdbuf;
|
||||
char *endptr;
|
||||
int i;
|
||||
|
||||
DBG(printf("User %s = ", v1);
|
||||
)
|
||||
i = strtol(v1, &endptr, 0);
|
||||
if (*v1 != '\0' && *endptr == '\0') {
|
||||
server_uid = i;
|
||||
} else {
|
||||
passwdbuf = getpwnam(v1);
|
||||
if (!passwdbuf) {
|
||||
if (current_uid)
|
||||
return;
|
||||
fprintf(stderr, "No such user: %s\n", v1);
|
||||
exit(1);
|
||||
}
|
||||
server_uid = passwdbuf->pw_uid;
|
||||
}
|
||||
DBG(printf("%d\n", server_uid);
|
||||
)
|
||||
}
|
||||
|
||||
static void c_set_group(char *v1, char *v2, void *t)
|
||||
{
|
||||
struct group *groupbuf;
|
||||
char *endptr;
|
||||
int i;
|
||||
DBG(printf("Group %s = ", v1);
|
||||
)
|
||||
i = strtol(v1, &endptr, 0);
|
||||
if (*v1 != '\0' && *endptr == '\0') {
|
||||
server_gid = i;
|
||||
} else {
|
||||
groupbuf = getgrnam(v1);
|
||||
if (!groupbuf) {
|
||||
if (current_uid)
|
||||
return;
|
||||
fprintf(stderr, "No such group: %s\n", v1);
|
||||
exit(1);
|
||||
}
|
||||
server_gid = groupbuf->gr_gid;
|
||||
}
|
||||
DBG(printf("%d\n", server_gid);
|
||||
)
|
||||
}
|
||||
|
||||
static void c_set_string(char *v1, char *v2, void *t)
|
||||
{
|
||||
char *s;
|
||||
DBG(printf("Setting pointer %p to string %s ..", t, v1);
|
||||
)
|
||||
if (t) {
|
||||
s = *(char **) t;
|
||||
if (s)
|
||||
free(s);
|
||||
*(char **) t = strdup(v1);
|
||||
if (!*(char **) t) {
|
||||
DIE("Unable to strdup in c_set_string");
|
||||
}
|
||||
DBG(printf("done.\n");
|
||||
)
|
||||
} else {
|
||||
DBG(printf("skipped.\n");
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static void c_set_int(char *v1, char *v2, void *t)
|
||||
{
|
||||
char *endptr;
|
||||
int i;
|
||||
DBG(printf("Setting pointer %p to integer string %s ..", t, v1);
|
||||
)
|
||||
if (t) {
|
||||
i = strtol(v1, &endptr, 0); /* Automatic base 10/16/8 switching */
|
||||
if (*v1 != '\0' && *endptr == '\0') {
|
||||
*(int *) t = i;
|
||||
DBG(printf(" Integer converted as %d, done\n", i);
|
||||
)
|
||||
} else {
|
||||
/* XXX should tell line number to user */
|
||||
fprintf(stderr, "Error: %s found where integer expected\n",
|
||||
v1);
|
||||
}
|
||||
} else {
|
||||
DBG(printf("skipped.\n");
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static void c_set_unity(char *v1, char *v2, void *t)
|
||||
{
|
||||
DBG(printf("Setting pointer %p to unity\n", t);
|
||||
)
|
||||
if (t)
|
||||
*(int *) t = 1;
|
||||
}
|
||||
|
||||
static void c_add_type(char *v1, char *v2, void *t)
|
||||
{
|
||||
add_mime_type(v1, v2);
|
||||
}
|
||||
|
||||
static void c_add_alias(char *v1, char *v2, void *t)
|
||||
{
|
||||
add_alias(v2, v1, *(int *) t);
|
||||
}
|
||||
|
||||
struct ccommand *lookup_keyword(char *c)
|
||||
{
|
||||
struct ccommand *p;
|
||||
DBG(printf("Checking string '%s' against keyword list\n", c);
|
||||
)
|
||||
for (p = clist;
|
||||
p < clist + (sizeof (clist) / sizeof (struct ccommand)); p++) {
|
||||
if (strcmp(c, p->name) == 0)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: read_config_files
|
||||
*
|
||||
* Description: Reads config files via yyparse, then makes sure that
|
||||
* all required variables were set properly.
|
||||
*/
|
||||
void read_config_files(void)
|
||||
{
|
||||
char *temp;
|
||||
current_uid = getuid();
|
||||
yyin = fopen("boa.conf", "r");
|
||||
|
||||
if (!yyin) {
|
||||
fputs("Could not open boa.conf for reading.\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
if (yyparse()) {
|
||||
fputs("Error parsing config files, exiting\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!server_name) {
|
||||
struct hostent *he;
|
||||
char temp_name[100];
|
||||
|
||||
if (gethostname(temp_name, 100) == -1) {
|
||||
perror("gethostname:");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
he = gethostbyname(temp_name);
|
||||
if (he == NULL) {
|
||||
perror("gethostbyname:");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
server_name = strdup(he->h_name);
|
||||
if (server_name == NULL) {
|
||||
perror("strdup:");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
tempdir = getenv("TMP");
|
||||
if (tempdir == NULL)
|
||||
tempdir = "/tmp";
|
||||
|
||||
if (single_post_limit < 0) {
|
||||
fprintf(stderr, "Invalid value for single_post_limit: %d\n",
|
||||
single_post_limit);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (document_root) {
|
||||
temp = normalize_path(document_root);
|
||||
free(document_root);
|
||||
document_root = temp;
|
||||
}
|
||||
|
||||
if (error_log_name) {
|
||||
temp = normalize_path(error_log_name);
|
||||
free(error_log_name);
|
||||
error_log_name = temp;
|
||||
}
|
||||
|
||||
if (access_log_name) {
|
||||
temp = normalize_path(access_log_name);
|
||||
free(access_log_name);
|
||||
access_log_name = temp;
|
||||
}
|
||||
|
||||
if (cgi_log_name) {
|
||||
temp = normalize_path(cgi_log_name);
|
||||
free(cgi_log_name);
|
||||
cgi_log_name = temp;
|
||||
}
|
||||
|
||||
if (dirmaker) {
|
||||
temp = normalize_path(dirmaker);
|
||||
free(dirmaker);
|
||||
dirmaker = temp;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (mime_types) {
|
||||
temp = normalize_path(mime_types);
|
||||
free(mime_types);
|
||||
mime_types = temp;
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
# This file is a shell script that caches the results of configure
|
||||
# tests run on this system so they can be shared between configure
|
||||
# scripts and configure runs. It is not useful on other systems.
|
||||
# If it contains results you don't want to keep, you may remove or edit it.
|
||||
#
|
||||
# By default, configure uses ./config.cache as the cache file,
|
||||
# creating it if it does not exist already. You can give configure
|
||||
# the --cache-file=FILE option to use a different cache file; that is
|
||||
# what configure does when it calls configure scripts in
|
||||
# subdirectories, so they share the cache.
|
||||
# Giving --cache-file=/dev/null disables caching, for debugging configure.
|
||||
# config.status only pays attention to the cache file if you give it the
|
||||
# --recheck option to rerun configure.
|
||||
#
|
||||
ac_cv_c_const=${ac_cv_c_const='yes'}
|
||||
ac_cv_func_alphasort=${ac_cv_func_alphasort='yes'}
|
||||
ac_cv_func_getcwd=${ac_cv_func_getcwd='yes'}
|
||||
ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname='yes'}
|
||||
ac_cv_func_gethostname=${ac_cv_func_gethostname='yes'}
|
||||
ac_cv_func_getpagesize=${ac_cv_func_getpagesize='yes'}
|
||||
ac_cv_func_inet_aton=${ac_cv_func_inet_aton='yes'}
|
||||
ac_cv_func_mmap_fixed_mapped=${ac_cv_func_mmap_fixed_mapped='yes'}
|
||||
ac_cv_func_scandir=${ac_cv_func_scandir='yes'}
|
||||
ac_cv_func_select=${ac_cv_func_select='yes'}
|
||||
ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'}
|
||||
ac_cv_func_socket=${ac_cv_func_socket='yes'}
|
||||
ac_cv_func_strdup=${ac_cv_func_strdup='yes'}
|
||||
ac_cv_func_strstr=${ac_cv_func_strstr='yes'}
|
||||
ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h='yes'}
|
||||
ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h='yes'}
|
||||
ac_cv_header_getopt_h=${ac_cv_header_getopt_h='yes'}
|
||||
ac_cv_header_limits_h=${ac_cv_header_limits_h='yes'}
|
||||
ac_cv_header_stdc=${ac_cv_header_stdc='yes'}
|
||||
ac_cv_header_sys_fcntl_h=${ac_cv_header_sys_fcntl_h='yes'}
|
||||
ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h='yes'}
|
||||
ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h='yes'}
|
||||
ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h='yes'}
|
||||
ac_cv_header_time=${ac_cv_header_time='yes'}
|
||||
ac_cv_header_unistd_h=${ac_cv_header_unistd_h='yes'}
|
||||
ac_cv_lib_dir_opendir=${ac_cv_lib_dir_opendir='no'}
|
||||
ac_cv_lib_l_yywrap=${ac_cv_lib_l_yywrap='no'}
|
||||
ac_cv_path_GUNZIP=${ac_cv_path_GUNZIP='/bin/gunzip'}
|
||||
ac_cv_prog_CC=${ac_cv_prog_CC='gcc'}
|
||||
ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
|
||||
ac_cv_prog_LEX=${ac_cv_prog_LEX='lex'}
|
||||
ac_cv_prog_YACC=${ac_cv_prog_YACC='bison -y'}
|
||||
ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross='no'}
|
||||
ac_cv_prog_cc_g=${ac_cv_prog_cc_g='yes'}
|
||||
ac_cv_prog_cc_works=${ac_cv_prog_cc_works='yes'}
|
||||
ac_cv_prog_gcc=${ac_cv_prog_gcc='yes'}
|
||||
ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set='yes'}
|
||||
ac_cv_struct_sockaddr_in_has_sin_len=${ac_cv_struct_sockaddr_in_has_sin_len='no'}
|
||||
ac_cv_struct_tm_has_tm_gmtoff=${ac_cv_struct_tm_has_tm_gmtoff='yes'}
|
||||
ac_cv_struct_tm_has_tm_zone=${ac_cv_struct_tm_has_tm_zone='yes'}
|
||||
ac_cv_type_pid_t=${ac_cv_type_pid_t='yes'}
|
||||
ac_cv_type_uid_t=${ac_cv_type_uid_t='yes'}
|
|
@ -0,0 +1,118 @@
|
|||
/* config.h. Generated automatically by configure. */
|
||||
/* config.h.in. Generated automatically from configure.in by autoheader. */
|
||||
|
||||
/* Define to empty if the keyword does not work. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
/* #undef gid_t */
|
||||
|
||||
/* Define if you have a working `mmap' system call. */
|
||||
#define HAVE_MMAP 1
|
||||
|
||||
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||
#define HAVE_SYS_WAIT_H 1
|
||||
|
||||
/* Define if your struct tm has tm_zone. */
|
||||
#define HAVE_TM_ZONE 1
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
/* #undef pid_t */
|
||||
|
||||
/* Define if the setvbuf function takes the buffering type as its second
|
||||
argument and the buffer pointer as the third, as on System V
|
||||
before release 3. */
|
||||
/* #undef SETVBUF_REVERSED */
|
||||
|
||||
/* Define if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
/* #undef uid_t */
|
||||
|
||||
/* define if GUNZIP found */
|
||||
#define GUNZIP "/bin/gunzip"
|
||||
|
||||
/* sockaddr_in has sin_len member */
|
||||
/* #undef HAVE_SIN_LEN */
|
||||
|
||||
/* if struct tm has tm_gmtoff structure */
|
||||
#define HAVE_TM_GMTOFF 1
|
||||
|
||||
/* if struct tm has tm_zone structure */
|
||||
#define HAVE_TM_ZONE 1
|
||||
|
||||
/* Define if you have the alphasort function. */
|
||||
#define HAVE_ALPHASORT 1
|
||||
|
||||
/* Define if you have the getcwd function. */
|
||||
#define HAVE_GETCWD 1
|
||||
|
||||
/* Define if you have the gethostbyname function. */
|
||||
#define HAVE_GETHOSTBYNAME 1
|
||||
|
||||
/* Define if you have the gethostname function. */
|
||||
#define HAVE_GETHOSTNAME 1
|
||||
|
||||
/* Define if you have the getpagesize function. */
|
||||
#define HAVE_GETPAGESIZE 1
|
||||
|
||||
/* Define if you have the inet_aton function. */
|
||||
#define HAVE_INET_ATON 1
|
||||
|
||||
/* Define if you have the scandir function. */
|
||||
#define HAVE_SCANDIR 1
|
||||
|
||||
/* Define if you have the select function. */
|
||||
#define HAVE_SELECT 1
|
||||
|
||||
/* Define if you have the socket function. */
|
||||
#define HAVE_SOCKET 1
|
||||
|
||||
/* Define if you have the strdup function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define if you have the strstr function. */
|
||||
#define HAVE_STRSTR 1
|
||||
|
||||
/* Define if you have the <dirent.h> header file. */
|
||||
#define HAVE_DIRENT_H 1
|
||||
|
||||
/* Define if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define if you have the <getopt.h> header file. */
|
||||
#define HAVE_GETOPT_H 1
|
||||
|
||||
/* Define if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define if you have the <ndir.h> header file. */
|
||||
/* #undef HAVE_NDIR_H */
|
||||
|
||||
/* Define if you have the <sys/dir.h> header file. */
|
||||
/* #undef HAVE_SYS_DIR_H */
|
||||
|
||||
/* Define if you have the <sys/fcntl.h> header file. */
|
||||
#define HAVE_SYS_FCNTL_H 1
|
||||
|
||||
/* Define if you have the <sys/ndir.h> header file. */
|
||||
/* #undef HAVE_SYS_NDIR_H */
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#define HAVE_SYS_SELECT_H 1
|
||||
|
||||
/* Define if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define if you have the dmalloc library (-ldmalloc). */
|
||||
/* #undef HAVE_LIBDMALLOC */
|
||||
|
||||
/* Define if you have the efence library (-lefence). */
|
||||
/* #undef HAVE_LIBEFENCE */
|
|
@ -0,0 +1,117 @@
|
|||
/* config.h.in. Generated automatically from configure.in by autoheader. */
|
||||
|
||||
/* Define to empty if the keyword does not work. */
|
||||
#undef const
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* Define if you have a working `mmap' system call. */
|
||||
#undef HAVE_MMAP
|
||||
|
||||
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define if your struct tm has tm_zone. */
|
||||
#undef HAVE_TM_ZONE
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define if the setvbuf function takes the buffering type as its second
|
||||
argument and the buffer pointer as the third, as on System V
|
||||
before release 3. */
|
||||
#undef SETVBUF_REVERSED
|
||||
|
||||
/* Define if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
||||
|
||||
/* define if GUNZIP found */
|
||||
#undef GUNZIP
|
||||
|
||||
/* sockaddr_in has sin_len member */
|
||||
#undef HAVE_SIN_LEN
|
||||
|
||||
/* if struct tm has tm_gmtoff structure */
|
||||
#undef HAVE_TM_GMTOFF
|
||||
|
||||
/* if struct tm has tm_zone structure */
|
||||
#undef HAVE_TM_ZONE
|
||||
|
||||
/* Define if you have the alphasort function. */
|
||||
#undef HAVE_ALPHASORT
|
||||
|
||||
/* Define if you have the getcwd function. */
|
||||
#undef HAVE_GETCWD
|
||||
|
||||
/* Define if you have the gethostbyname function. */
|
||||
#undef HAVE_GETHOSTBYNAME
|
||||
|
||||
/* Define if you have the gethostname function. */
|
||||
#undef HAVE_GETHOSTNAME
|
||||
|
||||
/* Define if you have the getpagesize function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
/* Define if you have the inet_aton function. */
|
||||
#undef HAVE_INET_ATON
|
||||
|
||||
/* Define if you have the scandir function. */
|
||||
#undef HAVE_SCANDIR
|
||||
|
||||
/* Define if you have the select function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
/* Define if you have the socket function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define if you have the strdup function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define if you have the strstr function. */
|
||||
#undef HAVE_STRSTR
|
||||
|
||||
/* Define if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* Define if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define if you have the <ndir.h> header file. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define if you have the <sys/dir.h> header file. */
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define if you have the <sys/fcntl.h> header file. */
|
||||
#undef HAVE_SYS_FCNTL_H
|
||||
|
||||
/* Define if you have the <sys/ndir.h> header file. */
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define if you have the dmalloc library (-ldmalloc). */
|
||||
#undef HAVE_LIBDMALLOC
|
||||
|
||||
/* Define if you have the efence library (-lefence). */
|
||||
#undef HAVE_LIBEFENCE
|
|
@ -0,0 +1,53 @@
|
|||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
configure:537: checking for gunzip
|
||||
configure:577: checking for flex
|
||||
configure:611: checking for yywrap in -ll
|
||||
configure:657: checking for bison
|
||||
configure:690: checking for gcc
|
||||
configure:803: checking whether the C compiler (gcc ) works
|
||||
configure:819: gcc -o conftest conftest.c 1>&5
|
||||
configure:816:1: warning: return type defaults to 'int' [-Wimplicit-int]
|
||||
main(){return(0);}
|
||||
^
|
||||
configure:845: checking whether the C compiler (gcc ) is a cross-compiler
|
||||
configure:850: checking whether we are using GNU C
|
||||
configure:878: checking whether gcc accepts -g
|
||||
configure:910: checking how to run the C preprocessor
|
||||
configure:990: checking whether make sets ${MAKE}
|
||||
configure:1025: checking for dirent.h that defines DIR
|
||||
configure:1063: checking for opendir in -ldir
|
||||
configure:1146: checking for ANSI C header files
|
||||
configure:1250: checking for sys/wait.h that is POSIX.1 compatible
|
||||
configure:1295: checking for fcntl.h
|
||||
configure:1295: checking for sys/fcntl.h
|
||||
configure:1295: checking for limits.h
|
||||
configure:1295: checking for sys/time.h
|
||||
configure:1295: checking for sys/select.h
|
||||
configure:1335: checking for getopt.h
|
||||
configure:1373: checking for working const
|
||||
configure:1448: checking for uid_t in sys/types.h
|
||||
configure:1482: checking for pid_t
|
||||
configure:1515: checking whether time.h and sys/time.h may both be included
|
||||
configure:1551: checking whether setvbuf arguments are reversed
|
||||
configure:1600: checking for unistd.h
|
||||
configure:1639: checking for getpagesize
|
||||
configure:1692: checking for working mmap
|
||||
configure:1865: checking for getcwd
|
||||
configure:1865: checking for strdup
|
||||
configure:1865: checking for strstr
|
||||
configure:1920: checking for gethostname
|
||||
configure:1920: checking for gethostbyname
|
||||
configure:1920: checking for select
|
||||
configure:1920: checking for socket
|
||||
configure:1920: checking for inet_aton
|
||||
configure:1975: checking for scandir
|
||||
configure:1975: checking for alphasort
|
||||
configure:2035: checking for tm.tm_gmtoff
|
||||
configure:2110: checking for tm.tm_zone
|
||||
configure:2186: checking for sockaddr_in.sin_len
|
||||
configure:2441: checking compile and link profiling code
|
||||
configure:2463: checking whether to compile and link debugging code
|
||||
configure:2486: checking whether to link with the Dmalloc memory debugger/profiler
|
||||
configure:2552: checking whether to link with the Electric Fence memory debugger
|
Binary file not shown.
|
@ -0,0 +1,347 @@
|
|||
#! /bin/sh
|
||||
# Generated automatically by configure.
|
||||
# Run this file to recreate the current configuration.
|
||||
# This directory was configured as follows,
|
||||
# on host hkc-VirtualBox:
|
||||
#
|
||||
# ./configure
|
||||
#
|
||||
# Compiler output produced by configure, useful for debugging
|
||||
# configure, is in ./config.log if it exists.
|
||||
|
||||
ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]"
|
||||
for ac_option
|
||||
do
|
||||
case "$ac_option" in
|
||||
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
|
||||
echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion"
|
||||
exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;;
|
||||
-version | --version | --versio | --versi | --vers | --ver | --ve | --v)
|
||||
echo "./config.status generated by autoconf version 2.13"
|
||||
exit 0 ;;
|
||||
-help | --help | --hel | --he | --h)
|
||||
echo "$ac_cs_usage"; exit 0 ;;
|
||||
*) echo "$ac_cs_usage"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
ac_given_srcdir=.
|
||||
|
||||
trap 'rm -fr Makefile config.h conftest*; exit 1' 1 2 15
|
||||
|
||||
# Protect against being on the right side of a sed subst in config.status.
|
||||
sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g;
|
||||
s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
|
||||
/^[ ]*VPATH[ ]*=[^:]*$/d
|
||||
|
||||
s%@SHELL@%/bin/sh%g
|
||||
s%@CFLAGS@%-g -O2 -pipe -Wall%g
|
||||
s%@CPPFLAGS@%%g
|
||||
s%@CXXFLAGS@%%g
|
||||
s%@FFLAGS@%%g
|
||||
s%@DEFS@%-DHAVE_CONFIG_H%g
|
||||
s%@LDFLAGS@% -g%g
|
||||
s%@LIBS@% %g
|
||||
s%@exec_prefix@%${prefix}%g
|
||||
s%@prefix@%/usr/local%g
|
||||
s%@program_transform_name@%s,x,x,%g
|
||||
s%@bindir@%${exec_prefix}/bin%g
|
||||
s%@sbindir@%${exec_prefix}/sbin%g
|
||||
s%@libexecdir@%${exec_prefix}/libexec%g
|
||||
s%@datadir@%${prefix}/share%g
|
||||
s%@sysconfdir@%${prefix}/etc%g
|
||||
s%@sharedstatedir@%${prefix}/com%g
|
||||
s%@localstatedir@%${prefix}/var%g
|
||||
s%@libdir@%${exec_prefix}/lib%g
|
||||
s%@includedir@%${prefix}/include%g
|
||||
s%@oldincludedir@%/usr/include%g
|
||||
s%@infodir@%${prefix}/info%g
|
||||
s%@mandir@%${prefix}/man%g
|
||||
s%@GUNZIP@%/bin/gunzip%g
|
||||
s%@LEX@%lex%g
|
||||
s%@LEXLIB@%%g
|
||||
s%@YACC@%bison -y%g
|
||||
s%@CC@%gcc%g
|
||||
s%@CPP@%gcc -E%g
|
||||
s%@SET_MAKE@%%g
|
||||
s%@STRUTIL@%%g
|
||||
s%@ALPHASORT@%%g
|
||||
s%@SCANDIR@%%g
|
||||
|
||||
CEOF
|
||||
|
||||
# Split the substitutions into bite-sized pieces for seds with
|
||||
# small command number limits, like on Digital OSF/1 and HP-UX.
|
||||
ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
|
||||
ac_file=1 # Number of current file.
|
||||
ac_beg=1 # First line for current file.
|
||||
ac_end=$ac_max_sed_cmds # Line after last line for current file.
|
||||
ac_more_lines=:
|
||||
ac_sed_cmds=""
|
||||
while $ac_more_lines; do
|
||||
if test $ac_beg -gt 1; then
|
||||
sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
|
||||
else
|
||||
sed "${ac_end}q" conftest.subs > conftest.s$ac_file
|
||||
fi
|
||||
if test ! -s conftest.s$ac_file; then
|
||||
ac_more_lines=false
|
||||
rm -f conftest.s$ac_file
|
||||
else
|
||||
if test -z "$ac_sed_cmds"; then
|
||||
ac_sed_cmds="sed -f conftest.s$ac_file"
|
||||
else
|
||||
ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
|
||||
fi
|
||||
ac_file=`expr $ac_file + 1`
|
||||
ac_beg=$ac_end
|
||||
ac_end=`expr $ac_end + $ac_max_sed_cmds`
|
||||
fi
|
||||
done
|
||||
if test -z "$ac_sed_cmds"; then
|
||||
ac_sed_cmds=cat
|
||||
fi
|
||||
|
||||
CONFIG_FILES=${CONFIG_FILES-"Makefile"}
|
||||
for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
|
||||
# Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
|
||||
case "$ac_file" in
|
||||
*:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
|
||||
ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
|
||||
*) ac_file_in="${ac_file}.in" ;;
|
||||
esac
|
||||
|
||||
# Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
|
||||
|
||||
# Remove last slash and all that follows it. Not all systems have dirname.
|
||||
ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
|
||||
if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
|
||||
# The file is in a subdirectory.
|
||||
test ! -d "$ac_dir" && mkdir "$ac_dir"
|
||||
ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
|
||||
# A "../" for each directory in $ac_dir_suffix.
|
||||
ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
|
||||
else
|
||||
ac_dir_suffix= ac_dots=
|
||||
fi
|
||||
|
||||
case "$ac_given_srcdir" in
|
||||
.) srcdir=.
|
||||
if test -z "$ac_dots"; then top_srcdir=.
|
||||
else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
|
||||
/*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
|
||||
*) # Relative path.
|
||||
srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
|
||||
top_srcdir="$ac_dots$ac_given_srcdir" ;;
|
||||
esac
|
||||
|
||||
|
||||
echo creating "$ac_file"
|
||||
rm -f "$ac_file"
|
||||
configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
|
||||
case "$ac_file" in
|
||||
*Makefile*) ac_comsub="1i\\
|
||||
# $configure_input" ;;
|
||||
*) ac_comsub= ;;
|
||||
esac
|
||||
|
||||
ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
|
||||
sed -e "$ac_comsub
|
||||
s%@configure_input@%$configure_input%g
|
||||
s%@srcdir@%$srcdir%g
|
||||
s%@top_srcdir@%$top_srcdir%g
|
||||
" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
|
||||
fi; done
|
||||
rm -f conftest.s*
|
||||
|
||||
# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
|
||||
# NAME is the cpp macro being defined and VALUE is the value it is being given.
|
||||
#
|
||||
# ac_d sets the value in "#define NAME VALUE" lines.
|
||||
ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
|
||||
ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
|
||||
ac_dC='\3'
|
||||
ac_dD='%g'
|
||||
# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
|
||||
ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
|
||||
ac_uB='\([ ]\)%\1#\2define\3'
|
||||
ac_uC=' '
|
||||
ac_uD='\4%g'
|
||||
# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
|
||||
ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
|
||||
ac_eB='$%\1#\2define\3'
|
||||
ac_eC=' '
|
||||
ac_eD='%g'
|
||||
|
||||
if test "${CONFIG_HEADERS+set}" != set; then
|
||||
CONFIG_HEADERS="config.h"
|
||||
fi
|
||||
for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
|
||||
# Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
|
||||
case "$ac_file" in
|
||||
*:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
|
||||
ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
|
||||
*) ac_file_in="${ac_file}.in" ;;
|
||||
esac
|
||||
|
||||
echo creating $ac_file
|
||||
|
||||
rm -f conftest.frag conftest.in conftest.out
|
||||
ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
|
||||
cat $ac_file_inputs > conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
${ac_dA}GUNZIP${ac_dB}GUNZIP${ac_dC}"/bin/gunzip"${ac_dD}
|
||||
${ac_uA}GUNZIP${ac_uB}GUNZIP${ac_uC}"/bin/gunzip"${ac_uD}
|
||||
${ac_eA}GUNZIP${ac_eB}GUNZIP${ac_eC}"/bin/gunzip"${ac_eD}
|
||||
${ac_dA}HAVE_DIRENT_H${ac_dB}HAVE_DIRENT_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_DIRENT_H${ac_uB}HAVE_DIRENT_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_DIRENT_H${ac_eB}HAVE_DIRENT_H${ac_eC}1${ac_eD}
|
||||
${ac_dA}STDC_HEADERS${ac_dB}STDC_HEADERS${ac_dC}1${ac_dD}
|
||||
${ac_uA}STDC_HEADERS${ac_uB}STDC_HEADERS${ac_uC}1${ac_uD}
|
||||
${ac_eA}STDC_HEADERS${ac_eB}STDC_HEADERS${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_SYS_WAIT_H${ac_dB}HAVE_SYS_WAIT_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_SYS_WAIT_H${ac_uB}HAVE_SYS_WAIT_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_SYS_WAIT_H${ac_eB}HAVE_SYS_WAIT_H${ac_eC}1${ac_eD}
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
${ac_dA}HAVE_FCNTL_H${ac_dB}HAVE_FCNTL_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_FCNTL_H${ac_uB}HAVE_FCNTL_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_FCNTL_H${ac_eB}HAVE_FCNTL_H${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_SYS_FCNTL_H${ac_dB}HAVE_SYS_FCNTL_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_SYS_FCNTL_H${ac_uB}HAVE_SYS_FCNTL_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_SYS_FCNTL_H${ac_eB}HAVE_SYS_FCNTL_H${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_LIMITS_H${ac_dB}HAVE_LIMITS_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_LIMITS_H${ac_uB}HAVE_LIMITS_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_LIMITS_H${ac_eB}HAVE_LIMITS_H${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_SYS_TIME_H${ac_dB}HAVE_SYS_TIME_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_SYS_TIME_H${ac_uB}HAVE_SYS_TIME_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_SYS_TIME_H${ac_eB}HAVE_SYS_TIME_H${ac_eC}1${ac_eD}
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
${ac_dA}HAVE_SYS_SELECT_H${ac_dB}HAVE_SYS_SELECT_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_SYS_SELECT_H${ac_uB}HAVE_SYS_SELECT_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_SYS_SELECT_H${ac_eB}HAVE_SYS_SELECT_H${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_GETOPT_H${ac_dB}HAVE_GETOPT_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_GETOPT_H${ac_uB}HAVE_GETOPT_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_GETOPT_H${ac_eB}HAVE_GETOPT_H${ac_eC}1${ac_eD}
|
||||
${ac_dA}TIME_WITH_SYS_TIME${ac_dB}TIME_WITH_SYS_TIME${ac_dC}1${ac_dD}
|
||||
${ac_uA}TIME_WITH_SYS_TIME${ac_uB}TIME_WITH_SYS_TIME${ac_uC}1${ac_uD}
|
||||
${ac_eA}TIME_WITH_SYS_TIME${ac_eB}TIME_WITH_SYS_TIME${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_UNISTD_H${ac_dB}HAVE_UNISTD_H${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_UNISTD_H${ac_uB}HAVE_UNISTD_H${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_UNISTD_H${ac_eB}HAVE_UNISTD_H${ac_eC}1${ac_eD}
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
${ac_dA}HAVE_GETPAGESIZE${ac_dB}HAVE_GETPAGESIZE${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_GETPAGESIZE${ac_uB}HAVE_GETPAGESIZE${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_GETPAGESIZE${ac_eB}HAVE_GETPAGESIZE${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_MMAP${ac_dB}HAVE_MMAP${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_MMAP${ac_uB}HAVE_MMAP${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_MMAP${ac_eB}HAVE_MMAP${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_GETCWD${ac_dB}HAVE_GETCWD${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_GETCWD${ac_uB}HAVE_GETCWD${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_GETCWD${ac_eB}HAVE_GETCWD${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_STRDUP${ac_dB}HAVE_STRDUP${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_STRDUP${ac_uB}HAVE_STRDUP${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_STRDUP${ac_eB}HAVE_STRDUP${ac_eC}1${ac_eD}
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
${ac_dA}HAVE_STRSTR${ac_dB}HAVE_STRSTR${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_STRSTR${ac_uB}HAVE_STRSTR${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_STRSTR${ac_eB}HAVE_STRSTR${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_GETHOSTNAME${ac_dB}HAVE_GETHOSTNAME${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_GETHOSTNAME${ac_uB}HAVE_GETHOSTNAME${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_GETHOSTNAME${ac_eB}HAVE_GETHOSTNAME${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_GETHOSTBYNAME${ac_dB}HAVE_GETHOSTBYNAME${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_GETHOSTBYNAME${ac_uB}HAVE_GETHOSTBYNAME${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_GETHOSTBYNAME${ac_eB}HAVE_GETHOSTBYNAME${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_SELECT${ac_dB}HAVE_SELECT${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_SELECT${ac_uB}HAVE_SELECT${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_SELECT${ac_eB}HAVE_SELECT${ac_eC}1${ac_eD}
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
${ac_dA}HAVE_SOCKET${ac_dB}HAVE_SOCKET${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_SOCKET${ac_uB}HAVE_SOCKET${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_SOCKET${ac_eB}HAVE_SOCKET${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_INET_ATON${ac_dB}HAVE_INET_ATON${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_INET_ATON${ac_uB}HAVE_INET_ATON${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_INET_ATON${ac_eB}HAVE_INET_ATON${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_SCANDIR${ac_dB}HAVE_SCANDIR${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_SCANDIR${ac_uB}HAVE_SCANDIR${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_SCANDIR${ac_eB}HAVE_SCANDIR${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_ALPHASORT${ac_dB}HAVE_ALPHASORT${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_ALPHASORT${ac_uB}HAVE_ALPHASORT${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_ALPHASORT${ac_eB}HAVE_ALPHASORT${ac_eC}1${ac_eD}
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
${ac_dA}STRUCT_TM_HAS_TM_GMTOFF${ac_dB}STRUCT_TM_HAS_TM_GMTOFF${ac_dC}1${ac_dD}
|
||||
${ac_uA}STRUCT_TM_HAS_TM_GMTOFF${ac_uB}STRUCT_TM_HAS_TM_GMTOFF${ac_uC}1${ac_uD}
|
||||
${ac_eA}STRUCT_TM_HAS_TM_GMTOFF${ac_eB}STRUCT_TM_HAS_TM_GMTOFF${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_TM_GMTOFF${ac_dB}HAVE_TM_GMTOFF${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_TM_GMTOFF${ac_uB}HAVE_TM_GMTOFF${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_TM_GMTOFF${ac_eB}HAVE_TM_GMTOFF${ac_eC}1${ac_eD}
|
||||
${ac_dA}STRUCT_TM_HAS_TM_ZONE${ac_dB}STRUCT_TM_HAS_TM_ZONE${ac_dC}1${ac_dD}
|
||||
${ac_uA}STRUCT_TM_HAS_TM_ZONE${ac_uB}STRUCT_TM_HAS_TM_ZONE${ac_uC}1${ac_uD}
|
||||
${ac_eA}STRUCT_TM_HAS_TM_ZONE${ac_eB}STRUCT_TM_HAS_TM_ZONE${ac_eC}1${ac_eD}
|
||||
${ac_dA}HAVE_TM_ZONE${ac_dB}HAVE_TM_ZONE${ac_dC}1${ac_dD}
|
||||
${ac_uA}HAVE_TM_ZONE${ac_uB}HAVE_TM_ZONE${ac_uC}1${ac_uD}
|
||||
${ac_eA}HAVE_TM_ZONE${ac_eB}HAVE_TM_ZONE${ac_eC}1${ac_eD}
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
cat > conftest.frag <<CEOF
|
||||
s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
|
||||
CEOF
|
||||
sed -f conftest.frag conftest.in > conftest.out
|
||||
rm -f conftest.in
|
||||
mv conftest.out conftest.in
|
||||
|
||||
rm -f conftest.frag conftest.h
|
||||
echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
|
||||
cat conftest.in >> conftest.h
|
||||
rm -f conftest.in
|
||||
if cmp -s $ac_file conftest.h 2>/dev/null; then
|
||||
echo "$ac_file is unchanged"
|
||||
rm -f conftest.h
|
||||
else
|
||||
# Remove last slash and all that follows it. Not all systems have dirname.
|
||||
ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
|
||||
if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
|
||||
# The file is in a subdirectory.
|
||||
test ! -d "$ac_dir" && mkdir "$ac_dir"
|
||||
fi
|
||||
rm -f $ac_file
|
||||
mv conftest.h $ac_file
|
||||
fi
|
||||
fi; done
|
||||
|
||||
|
||||
|
||||
exit 0
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,196 @@
|
|||
dnl $Id: configure.in,v 1.21.2.5 2002/07/28 02:38:32 jnelson Exp $
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(boa.c)
|
||||
|
||||
dnl Look for gunzip
|
||||
AC_PATH_PROG(GUNZIP, gunzip)
|
||||
AC_DEFINE_UNQUOTED(GUNZIP, "$ac_cv_path_GUNZIP")
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_LEX
|
||||
AC_PROG_YACC
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
dnl Checks for libraries.
|
||||
|
||||
dnl Make config.h
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(fcntl.h sys/fcntl.h limits.h sys/time.h sys/select.h)
|
||||
AC_CHECK_HEADERS(getopt.h)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_PID_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_FUNC_SETVBUF_REVERSED
|
||||
AC_FUNC_MMAP
|
||||
AC_CHECK_FUNCS(getcwd strdup strstr)
|
||||
AC_CHECK_FUNCS(gethostname gethostbyname select socket inet_aton)
|
||||
AC_CHECK_FUNCS(scandir alphasort)
|
||||
|
||||
AC_CHECK_STRUCT_FOR([
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
],tm,tm_gmtoff)
|
||||
|
||||
if test "$ac_cv_struct_tm_has_tm_gmtoff" = "yes"; then
|
||||
AC_DEFINE(HAVE_TM_GMTOFF)
|
||||
fi
|
||||
|
||||
AC_CHECK_STRUCT_FOR([
|
||||
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
],tm,tm_zone)
|
||||
|
||||
if test "$ac_cv_struct_tm_has_tm_zone" = "yes"; then
|
||||
AC_DEFINE(HAVE_TM_ZONE)
|
||||
fi
|
||||
|
||||
AC_CHECK_STRUCT_FOR([
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
],sockaddr_in,sin_len)
|
||||
|
||||
if test "$ac_cv_struct_sockaddr_in_has_sin_len" = "yes"; then
|
||||
AC_DEFINE(HAVE_SIN_LEN)
|
||||
fi
|
||||
|
||||
if test $ac_cv_func_socket = no; then
|
||||
# socket is not in the default libraries.
|
||||
AC_CHECK_LIB(socket, socket,
|
||||
[ MYLIBS="$MYLIBS -lsocket" ])
|
||||
fi
|
||||
|
||||
if test $ac_cv_func_inet_aton = no; then
|
||||
# inet_aton is not in the default libraries.
|
||||
AC_CHECK_LIB(resolv, inet_aton, MYLIBS="$MYLIBS -lresolv")
|
||||
fi
|
||||
|
||||
if test $ac_cv_func_gethostname = no; then
|
||||
AC_CHECK_LIB(nsl, gethostname, MYLIBS="$MYLIBS -lnsl")
|
||||
fi
|
||||
|
||||
dnl May end up with duplicate -lnsl -- oh well
|
||||
if test $ac_cv_func_gethostbyname = no; then
|
||||
AC_CHECK_LIB(nsl, gethostbyname, MYLIBS="$MYLIBS -lnsl")
|
||||
fi
|
||||
|
||||
LIBS="$LIBS $MYLIBS"
|
||||
|
||||
if test $ac_cv_func_scandir = no; then
|
||||
# scandir not defined, add it
|
||||
SCANDIR="scandir.o"
|
||||
fi
|
||||
|
||||
if test $ac_cv_func_alphasort = no; then
|
||||
# alphasort not defined, add it
|
||||
ALPHASORT="alphasort.o"
|
||||
fi
|
||||
|
||||
if test $ac_cv_func_strdup = no -o $ac_cv_func_strstr = no; then
|
||||
# strdup or strstr not defined
|
||||
STRUTIL="strutil.o"
|
||||
fi
|
||||
|
||||
if test -n "$GCC"; then
|
||||
dnl if we are running gcc, use -pipe
|
||||
test -n "$GCC" && CFLAGS="$CFLAGS -pipe"
|
||||
|
||||
AC_MSG_CHECKING(compile and link profiling code)
|
||||
AC_ARG_ENABLE(profiling,
|
||||
[ --enable-profiling Compile and link profiling code],
|
||||
[
|
||||
if test "$enableval" = "yes" ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
CFLAGS="$CFLAGS -pg"
|
||||
LDFLAGS="$LDFLAGS -g -pg"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(whether to compile and link debugging code)
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --disable-debug Compile and link debugging code],
|
||||
[
|
||||
if test "$enableval" = "yes" ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
LDFLAGS="$LDFLAGS -g"
|
||||
test -n "$GCC" && CFLAGS="$CFLAGS -Wall"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(yes)
|
||||
LDFLAGS="$LDFLAGS -g"
|
||||
test -n "$GCC" && CFLAGS="$CFLAGS -Wall"
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING(whether to link with the Dmalloc memory debugger/profiler)
|
||||
AC_ARG_WITH(dmalloc,
|
||||
[ --with-dmalloc link with the Dmalloc memory debugger/profiler],
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
AC_MSG_RESULT(trying)
|
||||
AC_CHECK_LIB(dmalloc, dmalloc_shutdown)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING(whether to link with the Electric Fence memory debugger)
|
||||
AC_ARG_WITH(efence,
|
||||
[ --with-efence link with the Electric Fence memory debugger ],
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
AC_MSG_RESULT(trying)
|
||||
AC_CHECK_LIB(efence, main)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
dnl For anything that wasn't found but we have source for
|
||||
AC_SUBST(STRUTIL)
|
||||
AC_SUBST(ALPHASORT)
|
||||
AC_SUBST(SCANDIR)
|
||||
|
||||
AC_OUTPUT(Makefile)
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1997 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: defines.h,v 1.107.2.2 2002/06/07 02:57:23 jnelson Exp $*/
|
||||
|
||||
#ifndef _DEFINES_H
|
||||
#define _DEFINES_H
|
||||
|
||||
/***** Change this, or use -c on the command line to specify it *****/
|
||||
|
||||
#ifndef SERVER_ROOT
|
||||
#define SERVER_ROOT "/etc/boa"
|
||||
#endif
|
||||
|
||||
/***** Change this via the CGIPath configuration value in boa.conf *****/
|
||||
#define DEFAULT_PATH "/bin:/usr/bin:/usr/local/bin"
|
||||
|
||||
/***** Change this via the SinglePostLimit configuration value in boa.conf *****/
|
||||
#define SINGLE_POST_LIMIT_DEFAULT 1024 * 1024 /* 1 MB */
|
||||
|
||||
/***** Various stuff that you may want to tweak, but probably shouldn't *****/
|
||||
|
||||
#define SOCKETBUF_SIZE 8192
|
||||
#define MAX_HEADER_LENGTH 1024
|
||||
#define CLIENT_STREAM_SIZE SOCKETBUF_SIZE
|
||||
#define BUFFER_SIZE CLIENT_STREAM_SIZE
|
||||
|
||||
#define MIME_HASHTABLE_SIZE 47
|
||||
#define ALIAS_HASHTABLE_SIZE 17
|
||||
#define PASSWD_HASHTABLE_SIZE 47
|
||||
|
||||
#define REQUEST_TIMEOUT 60
|
||||
|
||||
#define CGI_MIME_TYPE "application/x-httpd-cgi"
|
||||
|
||||
/***** CHANGE ANYTHING BELOW THIS LINE AT YOUR OWN PERIL *****/
|
||||
/***** You will probably introduce buffer overruns unless you know
|
||||
what you are doing *****/
|
||||
|
||||
#define MAX_SITENAME_LENGTH 256
|
||||
#define MAX_LOG_LENGTH MAX_HEADER_LENGTH + 1024
|
||||
#define MAX_FILE_LENGTH NAME_MAX
|
||||
#define MAX_PATH_LENGTH PATH_MAX
|
||||
|
||||
#ifdef ACCEPT_ON
|
||||
#define MAX_ACCEPT_LENGTH MAX_HEADER_LENGTH
|
||||
#else
|
||||
#define MAX_ACCEPT_LENGTH 0
|
||||
#endif
|
||||
|
||||
#ifndef SERVER_VERSION
|
||||
#define SERVER_VERSION "Boa/0.94.13"
|
||||
#endif
|
||||
|
||||
#define CGI_VERSION "CGI/1.1"
|
||||
#define COMMON_CGI_COUNT 6
|
||||
#define CGI_ENV_MAX 50
|
||||
#define CGI_ARGC_MAX 128
|
||||
|
||||
/******************* RESPONSE CLASSES *****************/
|
||||
|
||||
#define R_INFORMATIONAL 1
|
||||
#define R_SUCCESS 2
|
||||
#define R_REDIRECTION 3
|
||||
#define R_CLIENT_ERROR 4
|
||||
#define R_SERVER_ERROR 5
|
||||
|
||||
/******************* RESPONSE CODES ******************/
|
||||
|
||||
#define R_REQUEST_OK 200
|
||||
#define R_CREATED 201
|
||||
#define R_ACCEPTED 202
|
||||
#define R_PROVISIONAL 203 /* provisional information */
|
||||
#define R_NO_CONTENT 204
|
||||
|
||||
#define R_MULTIPLE 300 /* multiple choices */
|
||||
#define R_MOVED_PERM 301
|
||||
#define R_MOVED_TEMP 302
|
||||
#define R_NOT_MODIFIED 304
|
||||
|
||||
#define R_BAD_REQUEST 400
|
||||
#define R_UNAUTHORIZED 401
|
||||
#define R_PAYMENT 402 /* payment required */
|
||||
#define R_FORBIDDEN 403
|
||||
#define R_NOT_FOUND 404
|
||||
#define R_METHOD_NA 405 /* method not allowed */
|
||||
#define R_NONE_ACC 406 /* none acceptable */
|
||||
#define R_PROXY 407 /* proxy authentication required */
|
||||
#define R_REQUEST_TO 408 /* request timeout */
|
||||
#define R_CONFLICT 409
|
||||
#define R_GONE 410
|
||||
|
||||
#define R_ERROR 500 /* internal server error */
|
||||
#define R_NOT_IMP 501 /* not implemented */
|
||||
#define R_BAD_GATEWAY 502
|
||||
#define R_SERVICE_UNAV 503 /* service unavailable */
|
||||
#define R_GATEWAY_TO 504 /* gateway timeout */
|
||||
#define R_BAD_VERSION 505
|
||||
|
||||
/****************** METHODS *****************/
|
||||
|
||||
#define M_GET 1
|
||||
#define M_HEAD 2
|
||||
#define M_PUT 3
|
||||
#define M_POST 4
|
||||
#define M_DELETE 5
|
||||
#define M_LINK 6
|
||||
#define M_UNLINK 7
|
||||
|
||||
/************** REQUEST STATUS (req->status) ***************/
|
||||
|
||||
#define READ_HEADER 0
|
||||
#define ONE_CR 1
|
||||
#define ONE_LF 2
|
||||
#define TWO_CR 3
|
||||
#define BODY_READ 4
|
||||
#define BODY_WRITE 5
|
||||
#define WRITE 6
|
||||
#define PIPE_READ 7
|
||||
#define PIPE_WRITE 8
|
||||
#define DONE 9
|
||||
#define DEAD 10
|
||||
|
||||
/************** CGI TYPE (req->is_cgi) ******************/
|
||||
|
||||
#define CGI 1
|
||||
#define NPH 2
|
||||
|
||||
/************* ALIAS TYPES (aliasp->type) ***************/
|
||||
|
||||
#define ALIAS 0
|
||||
#define SCRIPTALIAS 1
|
||||
#define REDIRECT 2
|
||||
|
||||
/*********** KEEPALIVE CONSTANTS (req->keepalive) *******/
|
||||
|
||||
#define KA_INACTIVE 0
|
||||
#define KA_STOPPED 1
|
||||
#define KA_ACTIVE 2
|
||||
|
||||
/********* CGI STATUS CONSTANTS (req->cgi_status) *******/
|
||||
#define CGI_PARSE 1
|
||||
#define CGI_BUFFER 2
|
||||
#define CGI_DONE 3
|
||||
|
||||
/*********** MMAP_LIST CONSTANTS ************************/
|
||||
#define MMAP_LIST_SIZE 256
|
||||
#define MMAP_LIST_MASK 255
|
||||
#define MMAP_LIST_USE_MAX 128
|
||||
#define MMAP_LIST_NEXT(i) (((i)+1)&MMAP_LIST_MASK)
|
||||
#define MMAP_LIST_HASH(dev,ino,size) ((ino)&MMAP_LIST_MASK)
|
||||
|
||||
#define MAX_FILE_MMAP 100 * 1024 /* 100K */
|
||||
|
||||
/***************** USEFUL MACROS ************************/
|
||||
|
||||
#define SQUASH_KA(req) (req->keepalive=KA_STOPPED)
|
||||
|
||||
#define BOA_FD_SET(fd, where) { FD_SET(fd, where); \
|
||||
if (fd > max_fd) max_fd = fd; \
|
||||
}
|
||||
|
||||
/* If and when everyone has a modern gcc or other near-C99 compiler,
|
||||
* change these to static inline functions. Also note that since
|
||||
* we never fuss with O_APPEND append or O_ASYNC, we shouldn't have
|
||||
* to perform an extra system call to F_GETFL first.
|
||||
*/
|
||||
|
||||
#ifdef BOA_USE_GETFL
|
||||
#define set_block_fd(fd) real_set_block_fd(fd)
|
||||
#define set_nonblock_fd(fd) real_set_nonblock_fd(fd)
|
||||
#else
|
||||
#define set_block_fd(fd) fcntl(fd, F_SETFL, 0)
|
||||
#define set_nonblock_fd(fd) fcntl(fd, F_SETFL, NOBLOCK)
|
||||
#endif
|
||||
|
||||
#define DIE(mesg) log_error_mesg(__FILE__, __LINE__, mesg), exit(1)
|
||||
#define WARN(mesg) log_error_mesg(__FILE__, __LINE__, mesg)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* escape.c
|
||||
* Copyright (C) 2001 Jon Nelson <jnelson@boa.org>
|
||||
* Based on escape.pl, Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Copyright (C) 2001 Larry Doolittle <ldoolitt@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: escape.c,v 1.7 2002/03/22 04:24:09 jnelson Exp $ */
|
||||
|
||||
/*
|
||||
unreserved = alnum | mark
|
||||
alnum = "0".."9" | "A".."Z" | "a".."z"
|
||||
mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
|
||||
noescape = unreserved | ":" | "@" | "&" | "=" | "+" | "$" | "," | "/"
|
||||
*/
|
||||
|
||||
#ifdef TEST
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include "boa.h"
|
||||
#endif
|
||||
|
||||
#include "escape.h"
|
||||
|
||||
unsigned long _needs_escape[(NEEDS_ESCAPE_BITS+NEEDS_ESCAPE_WORD_LENGTH-1)/NEEDS_ESCAPE_WORD_LENGTH];
|
||||
|
||||
void build_needs_escape(void)
|
||||
{
|
||||
unsigned int a, b;
|
||||
const unsigned char special[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789"
|
||||
"-_.!~*'():@&=+$,/?";
|
||||
/* 21 Mar 2002 - jnelson - confirm with Apache 1.3.23 that '?'
|
||||
* is safe to leave unescaped.
|
||||
*/
|
||||
unsigned short i, j;
|
||||
|
||||
b = 1;
|
||||
for (a=0; b!=0; a++) b=b<<1;
|
||||
/* I found $a bit positions available in an unsigned long. */
|
||||
if (a < NEEDS_ESCAPE_WORD_LENGTH) {
|
||||
fprintf(stderr,
|
||||
"NEEDS_ESCAPE_SHIFT configuration error -- "\
|
||||
"%d should be <= log2(%d)\n",
|
||||
NEEDS_ESCAPE_SHIFT, a);
|
||||
exit(1);
|
||||
} else if (a >= 2*NEEDS_ESCAPE_WORD_LENGTH) {
|
||||
/* needs_escape_shift configuration suboptimal */
|
||||
} else {
|
||||
/* Ahh, just right! */;
|
||||
}
|
||||
memset(_needs_escape, ~0, sizeof(_needs_escape));
|
||||
for(i = 0; i < sizeof(special) - 1; ++i) {
|
||||
j=special[i];
|
||||
if (j>=NEEDS_ESCAPE_BITS) {
|
||||
/* warning: character $j will be needlessly escaped. */
|
||||
} else {
|
||||
_needs_escape[NEEDS_ESCAPE_INDEX(j)]&=~NEEDS_ESCAPE_MASK(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
build_needs_escape();
|
||||
for(i = 0; i <= NEEDS_ESCAPE_BITS; ++i) {
|
||||
if (needs_escape(i)) {
|
||||
fprintf(stdout, "%3d needs escape.\n", i);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Copyright (C) 2001 Jon Nelson <jnelson@boa.org>
|
||||
* Copyright (C) 2001 Larry Doolittle <ldoolitt@boa.org>
|
||||
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: escape.h,v 1.18 2002/01/31 03:12:21 jnelson Exp $ */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Highest character number that can possibly be passed through un-escaped */
|
||||
#define NEEDS_ESCAPE_BITS 128
|
||||
|
||||
#ifndef NEEDS_ESCAPE_SHIFT
|
||||
#define NEEDS_ESCAPE_SHIFT 5 /* 1 << 5 is 32 bits */
|
||||
#endif
|
||||
|
||||
#define NEEDS_ESCAPE_WORD_LENGTH (1<<NEEDS_ESCAPE_SHIFT)
|
||||
|
||||
#define NEEDS_ESCAPE_INDEX(c) ((c)>>NEEDS_ESCAPE_SHIFT)
|
||||
|
||||
/* Assume variable shift is fast, otherwise this could be a table lookup */
|
||||
#define NEEDS_ESCAPE_MASK(c) (1<<((c)&(NEEDS_ESCAPE_WORD_LENGTH - 1)))
|
||||
|
||||
/* Newer compilers could use an inline function.
|
||||
* This macro works great, as long as you pass unsigned int or unsigned char.
|
||||
*/
|
||||
#define needs_escape(c) ((c)>=NEEDS_ESCAPE_BITS || _needs_escape[NEEDS_ESCAPE_INDEX(c)]&NEEDS_ESCAPE_MASK(c))
|
||||
|
||||
extern unsigned long _needs_escape[(NEEDS_ESCAPE_BITS+NEEDS_ESCAPE_WORD_LENGTH-1)/NEEDS_ESCAPE_WORD_LENGTH];
|
||||
void build_needs_escape(void);
|
Binary file not shown.
|
@ -0,0 +1,513 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996,99 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: get.c,v 1.76.2.5 2002/07/26 03:05:59 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
/* local prototypes */
|
||||
int get_cachedir_file(request * req, struct stat *statbuf);
|
||||
int index_directory(request * req, char *dest_filename);
|
||||
|
||||
/*
|
||||
* Name: init_get
|
||||
* Description: Initializes a non-script GET or HEAD request.
|
||||
*
|
||||
* Return values:
|
||||
* 0: finished or error, request will be freed
|
||||
* 1: successfully initialized, added to ready queue
|
||||
*/
|
||||
|
||||
int init_get(request * req)
|
||||
{
|
||||
int data_fd, saved_errno;
|
||||
struct stat statbuf;
|
||||
volatile int bytes;
|
||||
|
||||
data_fd = open(req->pathname, O_RDONLY);
|
||||
saved_errno = errno; /* might not get used */
|
||||
|
||||
#ifdef GUNZIP
|
||||
if (data_fd == -1 && errno == ENOENT) {
|
||||
/* cannot open */
|
||||
/* it's either a gunzipped file or a directory */
|
||||
char gzip_pathname[MAX_PATH_LENGTH];
|
||||
int len;
|
||||
|
||||
len = strlen(req->pathname);
|
||||
|
||||
memcpy(gzip_pathname, req->pathname, len);
|
||||
memcpy(gzip_pathname + len, ".gz", 3);
|
||||
gzip_pathname[len + 3] = '\0';
|
||||
data_fd = open(gzip_pathname, O_RDONLY);
|
||||
if (data_fd != -1) {
|
||||
close(data_fd);
|
||||
|
||||
req->response_status = R_REQUEST_OK;
|
||||
if (req->pathname)
|
||||
free(req->pathname);
|
||||
req->pathname = strdup(gzip_pathname);
|
||||
if (!req->pathname) {
|
||||
log_error_time();
|
||||
perror("strdup");
|
||||
send_r_error(req);
|
||||
return 0;
|
||||
}
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n");
|
||||
print_http_headers(req);
|
||||
print_content_type(req);
|
||||
print_last_modified(req);
|
||||
req_write(req, "\r\n");
|
||||
req_flush(req);
|
||||
}
|
||||
if (req->method == M_HEAD)
|
||||
return 0;
|
||||
|
||||
return init_cgi(req);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data_fd == -1) {
|
||||
log_error_doc(req);
|
||||
errno = saved_errno;
|
||||
perror("document open");
|
||||
|
||||
if (saved_errno == ENOENT)
|
||||
send_r_not_found(req);
|
||||
else if (saved_errno == EACCES)
|
||||
send_r_forbidden(req);
|
||||
else
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fstat(data_fd, &statbuf);
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode)) { /* directory */
|
||||
close(data_fd); /* close dir */
|
||||
|
||||
if (req->pathname[strlen(req->pathname) - 1] != '/') {
|
||||
char buffer[3 * MAX_PATH_LENGTH + 128];
|
||||
|
||||
if (server_port != 80)
|
||||
sprintf(buffer, "http://%s:%d%s/", server_name,
|
||||
server_port, req->request_uri);
|
||||
else
|
||||
sprintf(buffer, "http://%s%s/", server_name,
|
||||
req->request_uri);
|
||||
send_r_moved_perm(req, buffer);
|
||||
return 0;
|
||||
}
|
||||
data_fd = get_dir(req, &statbuf); /* updates statbuf */
|
||||
|
||||
if (data_fd == -1) /* couldn't do it */
|
||||
return 0; /* errors reported by get_dir */
|
||||
else if (data_fd <= 1)
|
||||
/* data_fd == 0 -> close it down, 1 -> continue */
|
||||
return data_fd;
|
||||
/* else, data_fd contains the fd of the file... */
|
||||
}
|
||||
if (req->if_modified_since &&
|
||||
!modified_since(&(statbuf.st_mtime), req->if_modified_since)) {
|
||||
send_r_not_modified(req);
|
||||
close(data_fd);
|
||||
return 0;
|
||||
}
|
||||
req->filesize = statbuf.st_size;
|
||||
req->last_modified = statbuf.st_mtime;
|
||||
|
||||
if (req->method == M_HEAD || req->filesize == 0) {
|
||||
send_r_request_ok(req);
|
||||
close(data_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (req->filesize > MAX_FILE_MMAP) {
|
||||
send_r_request_ok(req); /* All's well */
|
||||
req->status = PIPE_READ;
|
||||
req->cgi_status = CGI_BUFFER;
|
||||
req->data_fd = data_fd;
|
||||
req_flush(req); /* this should *always* complete due to
|
||||
the size of the I/O buffers */
|
||||
req->header_line = req->header_end = req->buffer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (req->filesize == 0) { /* done */
|
||||
send_r_request_ok(req); /* All's well *so far* */
|
||||
close(data_fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* NOTE: I (Jon Nelson) tried performing a read(2)
|
||||
* into the output buffer provided the file data would
|
||||
* fit, before mmapping, and if successful, writing that
|
||||
* and stopping there -- all to avoid the cost
|
||||
* of a mmap. Oddly, it was *slower* in benchmarks.
|
||||
*/
|
||||
req->mmap_entry_var = find_mmap(data_fd, &statbuf);
|
||||
if (req->mmap_entry_var == NULL) {
|
||||
req->buffer_end = 0;
|
||||
if (errno == ENOENT)
|
||||
send_r_not_found(req);
|
||||
else if (errno == EACCES)
|
||||
send_r_forbidden(req);
|
||||
else
|
||||
send_r_bad_request(req);
|
||||
close(data_fd);
|
||||
return 0;
|
||||
}
|
||||
req->data_mem = req->mmap_entry_var->mmap;
|
||||
close(data_fd); /* close data file */
|
||||
|
||||
if ((long) req->data_mem == -1) {
|
||||
boa_perror(req, "mmap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
send_r_request_ok(req); /* All's well */
|
||||
|
||||
bytes = BUFFER_SIZE - req->buffer_end;
|
||||
|
||||
/* bytes is now how much the buffer can hold
|
||||
* after the headers
|
||||
*/
|
||||
|
||||
if (bytes > 0) {
|
||||
if (bytes > req->filesize)
|
||||
bytes = req->filesize;
|
||||
|
||||
if (sigsetjmp(env, 1) == 0) {
|
||||
handle_sigbus = 1;
|
||||
memcpy(req->buffer + req->buffer_end, req->data_mem, bytes);
|
||||
handle_sigbus = 0;
|
||||
/* OK, SIGBUS **after** this point is very bad! */
|
||||
} else {
|
||||
/* sigbus! */
|
||||
log_error_doc(req);
|
||||
reset_output_buffer(req);
|
||||
send_r_error(req);
|
||||
fprintf(stderr, "%sGot SIGBUS in memcpy!\n", get_commonlog_time());
|
||||
return 0;
|
||||
}
|
||||
req->buffer_end += bytes;
|
||||
req->filepos += bytes;
|
||||
if (req->filesize == req->filepos) {
|
||||
req_flush(req);
|
||||
req->status = DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We lose statbuf here, so make sure response has been sent */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: process_get
|
||||
* Description: Writes a chunk of data to the socket.
|
||||
*
|
||||
* Return values:
|
||||
* -1: request blocked, move to blocked queue
|
||||
* 0: EOF or error, close it down
|
||||
* 1: successful write, recycle in ready queue
|
||||
*/
|
||||
|
||||
int process_get(request * req)
|
||||
{
|
||||
int bytes_written;
|
||||
volatile int bytes_to_write;
|
||||
|
||||
bytes_to_write = req->filesize - req->filepos;
|
||||
if (bytes_to_write > SOCKETBUF_SIZE)
|
||||
bytes_to_write = SOCKETBUF_SIZE;
|
||||
|
||||
|
||||
if (sigsetjmp(env, 1) == 0) {
|
||||
handle_sigbus = 1;
|
||||
bytes_written = write(req->fd, req->data_mem + req->filepos,
|
||||
bytes_to_write);
|
||||
handle_sigbus = 0;
|
||||
/* OK, SIGBUS **after** this point is very bad! */
|
||||
} else {
|
||||
/* sigbus! */
|
||||
log_error_doc(req);
|
||||
/* sending an error here is inappropriate
|
||||
* if we are here, the file is mmapped, and thus,
|
||||
* a content-length has been sent. If we send fewer bytes
|
||||
* the client knows there has been a problem.
|
||||
* We run the risk of accidentally sending the right number
|
||||
* of bytes (or a few too many) and the client
|
||||
* won't be the wiser.
|
||||
*/
|
||||
req->status = DEAD;
|
||||
fprintf(stderr, "%sGot SIGBUS in write(2)!\n", get_commonlog_time());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bytes_written < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
return -1;
|
||||
/* request blocked at the pipe level, but keep going */
|
||||
else {
|
||||
if (errno != EPIPE) {
|
||||
log_error_doc(req);
|
||||
/* Can generate lots of log entries, */
|
||||
perror("write");
|
||||
/* OK to disable if your logs get too big */
|
||||
}
|
||||
req->status = DEAD;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
req->filepos += bytes_written;
|
||||
|
||||
if (req->filepos == req->filesize) { /* EOF */
|
||||
return 0;
|
||||
} else
|
||||
return 1; /* more to do */
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: get_dir
|
||||
* Description: Called from process_get if the request is a directory.
|
||||
* statbuf must describe directory on input, since we may need its
|
||||
* device, inode, and mtime.
|
||||
* statbuf is updated, since we may need to check mtimes of a cache.
|
||||
* returns:
|
||||
* -1 error
|
||||
* 0 cgi (either gunzip or auto-generated)
|
||||
* >0 file descriptor of file
|
||||
*/
|
||||
|
||||
int get_dir(request * req, struct stat *statbuf)
|
||||
{
|
||||
|
||||
char pathname_with_index[MAX_PATH_LENGTH];
|
||||
int data_fd;
|
||||
|
||||
if (directory_index) { /* look for index.html first?? */
|
||||
strcpy(pathname_with_index, req->pathname);
|
||||
strcat(pathname_with_index, directory_index);
|
||||
/*
|
||||
sprintf(pathname_with_index, "%s%s", req->pathname, directory_index);
|
||||
*/
|
||||
|
||||
data_fd = open(pathname_with_index, O_RDONLY);
|
||||
|
||||
if (data_fd != -1) { /* user's index file */
|
||||
strcpy(req->request_uri, directory_index); /* for mimetype */
|
||||
fstat(data_fd, statbuf);
|
||||
return data_fd;
|
||||
}
|
||||
if (errno == EACCES) {
|
||||
send_r_forbidden(req);
|
||||
return -1;
|
||||
} else if (errno != ENOENT) {
|
||||
/* if there is an error *other* than EACCES or ENOENT */
|
||||
send_r_not_found(req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef GUNZIP
|
||||
/* if we are here, trying index.html didn't work
|
||||
* try index.html.gz
|
||||
*/
|
||||
strcat(pathname_with_index, ".gz");
|
||||
data_fd = open(pathname_with_index, O_RDONLY);
|
||||
if (data_fd != -1) { /* user's index file */
|
||||
close(data_fd);
|
||||
|
||||
req->response_status = R_REQUEST_OK;
|
||||
SQUASH_KA(req);
|
||||
if (req->pathname)
|
||||
free(req->pathname);
|
||||
req->pathname = strdup(pathname_with_index);
|
||||
if (!req->pathname) {
|
||||
log_error_time();
|
||||
perror("strdup");
|
||||
send_r_error(req);
|
||||
return 0;
|
||||
}
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 200 OK-GUNZIP\r\n");
|
||||
print_http_headers(req);
|
||||
print_last_modified(req);
|
||||
req_write(req, "Content-Type: ");
|
||||
req_write(req, get_mime_type(directory_index));
|
||||
req_write(req, "\r\n\r\n");
|
||||
req_flush(req);
|
||||
}
|
||||
if (req->method == M_HEAD)
|
||||
return 0;
|
||||
return init_cgi(req);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* only here if index.html, index.html.gz don't exist */
|
||||
if (dirmaker != NULL) { /* don't look for index.html... maybe automake? */
|
||||
req->response_status = R_REQUEST_OK;
|
||||
SQUASH_KA(req);
|
||||
|
||||
/* the indexer should take care of all headers */
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 200 OK\r\n");
|
||||
print_http_headers(req);
|
||||
print_last_modified(req);
|
||||
req_write(req, "Content-Type: text/html\r\n\r\n");
|
||||
req_flush(req);
|
||||
}
|
||||
if (req->method == M_HEAD)
|
||||
return 0;
|
||||
|
||||
return init_cgi(req);
|
||||
/* in this case, 0 means success */
|
||||
} else if (cachedir) {
|
||||
return get_cachedir_file(req, statbuf);
|
||||
} else { /* neither index.html nor autogenerate are allowed */
|
||||
send_r_forbidden(req);
|
||||
return -1; /* nothing worked */
|
||||
}
|
||||
}
|
||||
|
||||
int get_cachedir_file(request * req, struct stat *statbuf)
|
||||
{
|
||||
|
||||
char pathname_with_index[MAX_PATH_LENGTH];
|
||||
int data_fd;
|
||||
time_t real_dir_mtime;
|
||||
|
||||
real_dir_mtime = statbuf->st_mtime;
|
||||
sprintf(pathname_with_index, "%s/dir.%d.%ld",
|
||||
cachedir, (int) statbuf->st_dev, statbuf->st_ino);
|
||||
data_fd = open(pathname_with_index, O_RDONLY);
|
||||
|
||||
if (data_fd != -1) { /* index cache */
|
||||
|
||||
fstat(data_fd, statbuf);
|
||||
if (statbuf->st_mtime > real_dir_mtime) {
|
||||
statbuf->st_mtime = real_dir_mtime; /* lie */
|
||||
strcpy(req->request_uri, directory_index); /* for mimetype */
|
||||
return data_fd;
|
||||
}
|
||||
close(data_fd);
|
||||
unlink(pathname_with_index); /* cache is stale, delete it */
|
||||
}
|
||||
if (index_directory(req, pathname_with_index) == -1)
|
||||
return -1;
|
||||
|
||||
data_fd = open(pathname_with_index, O_RDONLY); /* Last chance */
|
||||
if (data_fd != -1) {
|
||||
strcpy(req->request_uri, directory_index); /* for mimetype */
|
||||
fstat(data_fd, statbuf);
|
||||
statbuf->st_mtime = real_dir_mtime; /* lie */
|
||||
return data_fd;
|
||||
}
|
||||
|
||||
boa_perror(req, "re-opening dircache");
|
||||
return -1; /* Nothing worked. */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: index_directory
|
||||
* Description: Called from get_cachedir_file if a directory html
|
||||
* has to be generated on the fly
|
||||
* returns -1 for problem, else 0
|
||||
* This version is the fastest, ugliest, and most accurate yet.
|
||||
* It solves the "stale size or type" problem by not ever giving
|
||||
* the size or type. This also speeds it up since no per-file
|
||||
* stat() is required.
|
||||
*/
|
||||
|
||||
int index_directory(request * req, char *dest_filename)
|
||||
{
|
||||
DIR *request_dir;
|
||||
FILE *fdstream;
|
||||
struct dirent *dirbuf;
|
||||
int bytes = 0;
|
||||
char *escname = NULL;
|
||||
|
||||
if (chdir(req->pathname) == -1) {
|
||||
if (errno == EACCES || errno == EPERM) {
|
||||
send_r_forbidden(req);
|
||||
} else {
|
||||
log_error_doc(req);
|
||||
perror("chdir");
|
||||
send_r_bad_request(req);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
request_dir = opendir(".");
|
||||
if (request_dir == NULL) {
|
||||
int errno_save = errno;
|
||||
send_r_error(req);
|
||||
log_error_time();
|
||||
fprintf(stderr, "directory \"%s\": ", req->pathname);
|
||||
errno = errno_save;
|
||||
perror("opendir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdstream = fopen(dest_filename, "w");
|
||||
if (fdstream == NULL) {
|
||||
boa_perror(req, "dircache fopen");
|
||||
closedir(request_dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes += fprintf(fdstream,
|
||||
"<HTML><HEAD>\n<TITLE>Index of %s</TITLE>\n</HEAD>\n\n",
|
||||
req->request_uri);
|
||||
bytes += fprintf(fdstream, "<BODY>\n\n<H2>Index of %s</H2>\n\n<PRE>\n",
|
||||
req->request_uri);
|
||||
|
||||
while ((dirbuf = readdir(request_dir))) {
|
||||
if (!strcmp(dirbuf->d_name, "."))
|
||||
continue;
|
||||
|
||||
if (!strcmp(dirbuf->d_name, "..")) {
|
||||
bytes += fprintf(fdstream,
|
||||
" [DIR] <A HREF=\"../\">Parent Directory</A>\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((escname = escape_string(dirbuf->d_name, NULL)) != NULL) {
|
||||
bytes += fprintf(fdstream, " <A HREF=\"%s\">%s</A>\n",
|
||||
escname, dirbuf->d_name);
|
||||
free(escname);
|
||||
escname = NULL;
|
||||
}
|
||||
}
|
||||
closedir(request_dir);
|
||||
bytes += fprintf(fdstream, "</PRE>\n\n</BODY>\n</HTML>\n");
|
||||
|
||||
fclose(fdstream);
|
||||
|
||||
chdir(server_root);
|
||||
|
||||
req->filesize = bytes; /* for logging transfer size */
|
||||
return 0; /* success */
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@jlab.org>
|
||||
* Some changes Copyright (C) 1997 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: globals.h,v 1.65.2.3 2002/07/24 03:03:59 jnelson Exp $*/
|
||||
|
||||
#ifndef _GLOBALS_H
|
||||
#define _GLOBALS_H
|
||||
|
||||
struct mmap_entry {
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
char *mmap;
|
||||
int use_count;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct alias {
|
||||
char *fakename; /* URI path to file */
|
||||
char *realname; /* Actual path to file */
|
||||
int type; /* ALIAS, SCRIPTALIAS, REDIRECT */
|
||||
int fake_len; /* strlen of fakename */
|
||||
int real_len; /* strlen of realname */
|
||||
struct alias *next;
|
||||
};
|
||||
|
||||
typedef struct alias alias;
|
||||
|
||||
struct request { /* pending requests */
|
||||
int fd; /* client's socket fd */
|
||||
int status; /* see #defines.h */
|
||||
time_t time_last; /* time of last succ. op. */
|
||||
char *pathname; /* pathname of requested file */
|
||||
int simple; /* simple request? */
|
||||
int keepalive; /* keepalive status */
|
||||
int kacount; /* keepalive count */
|
||||
|
||||
int data_fd; /* fd of data */
|
||||
unsigned long filesize; /* filesize */
|
||||
unsigned long filepos; /* position in file */
|
||||
char *data_mem; /* mmapped/malloced char array */
|
||||
int method; /* M_GET, M_POST, etc. */
|
||||
|
||||
char *logline; /* line to log file */
|
||||
|
||||
char *header_line; /* beginning of un or incompletely processed header line */
|
||||
char *header_end; /* last known end of header, or end of processed data */
|
||||
int parse_pos; /* how much have we parsed */
|
||||
int client_stream_pos; /* how much have we read... */
|
||||
|
||||
int buffer_start; /* where the buffer starts */
|
||||
int buffer_end; /* where the buffer ends */
|
||||
|
||||
char *http_version; /* HTTP/?.? of req */
|
||||
int response_status; /* R_NOT_FOUND etc. */
|
||||
|
||||
char *if_modified_since; /* If-Modified-Since */
|
||||
time_t last_modified; /* Last-modified: */
|
||||
|
||||
char local_ip_addr[NI_MAXHOST]; /* for virtualhost */
|
||||
|
||||
/* CGI vars */
|
||||
|
||||
int remote_port; /* could be used for ident */
|
||||
|
||||
char remote_ip_addr[NI_MAXHOST]; /* after inet_ntoa */
|
||||
|
||||
int is_cgi; /* true if CGI/NPH */
|
||||
int cgi_status;
|
||||
int cgi_env_index; /* index into array */
|
||||
|
||||
/* Agent and referer for logfiles */
|
||||
char *header_user_agent;
|
||||
char *header_referer;
|
||||
|
||||
int post_data_fd; /* fd for post data tmpfile */
|
||||
|
||||
char *path_info; /* env variable */
|
||||
char *path_translated; /* env variable */
|
||||
char *script_name; /* env variable */
|
||||
char *query_string; /* env variable */
|
||||
char *content_type; /* env variable */
|
||||
char *content_length; /* env variable */
|
||||
|
||||
struct mmap_entry *mmap_entry_var;
|
||||
|
||||
struct request *next; /* next */
|
||||
struct request *prev; /* previous */
|
||||
|
||||
/* everything below this line is kept regardless */
|
||||
char buffer[BUFFER_SIZE + 1]; /* generic I/O buffer */
|
||||
char request_uri[MAX_HEADER_LENGTH + 1]; /* uri */
|
||||
char client_stream[CLIENT_STREAM_SIZE]; /* data from client - fit or be hosed */
|
||||
char *cgi_env[CGI_ENV_MAX + 4]; /* CGI environment */
|
||||
|
||||
#ifdef ACCEPT_ON
|
||||
char accept[MAX_ACCEPT_LENGTH]; /* Accept: fields */
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct request request;
|
||||
|
||||
struct status {
|
||||
long requests;
|
||||
long errors;
|
||||
};
|
||||
|
||||
extern struct status status;
|
||||
|
||||
extern char *optarg; /* For getopt */
|
||||
extern FILE *yyin; /* yacc input */
|
||||
|
||||
extern request *request_ready; /* first in ready list */
|
||||
extern request *request_block; /* first in blocked list */
|
||||
extern request *request_free; /* first in free list */
|
||||
|
||||
extern fd_set block_read_fdset; /* fds blocked on read */
|
||||
extern fd_set block_write_fdset; /* fds blocked on write */
|
||||
|
||||
/* global server variables */
|
||||
|
||||
extern char *access_log_name;
|
||||
extern char *error_log_name;
|
||||
extern char *cgi_log_name;
|
||||
extern int cgi_log_fd;
|
||||
extern int use_localtime;
|
||||
|
||||
extern int server_port;
|
||||
extern uid_t server_uid;
|
||||
extern gid_t server_gid;
|
||||
extern char *server_admin;
|
||||
extern char *server_root;
|
||||
extern char *server_name;
|
||||
extern char *server_ip;
|
||||
extern int max_fd;
|
||||
extern int devnullfd;
|
||||
|
||||
extern char *document_root;
|
||||
extern char *user_dir;
|
||||
extern char *directory_index;
|
||||
extern char *default_type;
|
||||
extern char *dirmaker;
|
||||
extern char *mime_types;
|
||||
extern char *cachedir;
|
||||
|
||||
extern char *tempdir;
|
||||
|
||||
extern char *cgi_path;
|
||||
extern int single_post_limit;
|
||||
|
||||
extern int ka_timeout;
|
||||
extern int ka_max;
|
||||
|
||||
extern int sighup_flag;
|
||||
extern int sigchld_flag;
|
||||
extern int sigalrm_flag;
|
||||
extern int sigterm_flag;
|
||||
extern time_t start_time;
|
||||
|
||||
extern int pending_requests;
|
||||
extern long int max_connections;
|
||||
|
||||
extern int verbose_cgi_logs;
|
||||
|
||||
extern int backlog;
|
||||
extern time_t current_time;
|
||||
|
||||
extern int virtualhost;
|
||||
|
||||
extern int total_connections;
|
||||
|
||||
extern sigjmp_buf env;
|
||||
extern int handle_sigbus;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1997 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: hash.c,v 1.14.4.4 2002/07/30 03:59:26 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
#include "parse.h"
|
||||
|
||||
/*
|
||||
* There are two hash tables used, each with a key/value pair
|
||||
* stored in a hash_struct. They are:
|
||||
*
|
||||
* mime_hashtable:
|
||||
* key = file extension
|
||||
* value = mime type
|
||||
*
|
||||
* passwd_hashtable:
|
||||
* key = username
|
||||
* value = home directory
|
||||
*
|
||||
*/
|
||||
|
||||
struct _hash_struct_ {
|
||||
char *key;
|
||||
char *value;
|
||||
struct _hash_struct_ *next;
|
||||
};
|
||||
|
||||
typedef struct _hash_struct_ hash_struct;
|
||||
|
||||
static hash_struct *mime_hashtable[MIME_HASHTABLE_SIZE];
|
||||
static hash_struct *passwd_hashtable[PASSWD_HASHTABLE_SIZE];
|
||||
|
||||
#ifdef WANT_ICKY_HASH
|
||||
static unsigned four_char_hash(char *buf);
|
||||
#define boa_hash four_char_hash
|
||||
#else
|
||||
#ifdef WANT_SDBM_HASH
|
||||
static unsigned sdbm_hash(char *str);
|
||||
#define boa_hash sdbm_hash
|
||||
#else
|
||||
static unsigned djb2_hash(char *str);
|
||||
#define boa_hash djb2_hash
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WANT_ICKY_HASH
|
||||
static unsigned four_char_hash(char *buf)
|
||||
{
|
||||
unsigned int hash = (buf[0] +
|
||||
(buf[1] ? buf[1] : 241 +
|
||||
(buf[2] ? buf[2] : 251 +
|
||||
(buf[3] ? buf[3] : 257))));
|
||||
#ifdef DEBUG_HASH
|
||||
log_error_time();
|
||||
fprintf(stderr, "four_char_hash(%s) = %u\n", buf, hash);
|
||||
#endif
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* The next two hashes taken from
|
||||
* http://www.cs.yorku.ca/~oz/hash.html
|
||||
*
|
||||
* In my (admittedly) very brief testing, djb2_hash performed
|
||||
* very slightly better than sdbm_hash.
|
||||
*/
|
||||
|
||||
#else
|
||||
#define MAX_HASH_LENGTH 4
|
||||
#ifdef WANT_SDBM_HASH
|
||||
static unsigned sdbm_hash(char *str)
|
||||
{
|
||||
unsigned hash = 0;
|
||||
int c;
|
||||
short count = MAX_HASH_LENGTH;
|
||||
|
||||
#ifdef DEBUG_HASH
|
||||
log_error_time();
|
||||
fprintf(stderr, "sdbm_hash(%s) = ", str);
|
||||
#endif
|
||||
|
||||
while ((c = *str++) && count--)
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
|
||||
#ifdef DEBUG_HASH
|
||||
fprintf(stderr, "%u\n", hash);
|
||||
#endif
|
||||
return hash;
|
||||
}
|
||||
#else
|
||||
|
||||
static unsigned djb2_hash(char *str)
|
||||
{
|
||||
unsigned hash = 5381;
|
||||
int c;
|
||||
short count = MAX_HASH_LENGTH;
|
||||
|
||||
#ifdef DEBUG_HASH
|
||||
log_error_time();
|
||||
fprintf(stderr, "djb2_hash(%s) = ", str);
|
||||
#endif
|
||||
|
||||
while ((c = *(str++)) && count--)
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
#ifdef DEBUG_HASH
|
||||
fprintf(stderr, "%u\n", hash);
|
||||
#endif
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Name: add_mime_type
|
||||
* Description: Adds a key/value pair to the mime_hashtable
|
||||
*/
|
||||
|
||||
void add_mime_type(char *extension, char *type)
|
||||
{
|
||||
unsigned int hash;
|
||||
hash_struct *current, *next;
|
||||
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
hash = get_mime_hash_value(extension);
|
||||
|
||||
current = mime_hashtable[hash];
|
||||
|
||||
while (current) {
|
||||
if (!strcmp(current->key, extension))
|
||||
return; /* don't add extension twice */
|
||||
if (current->next)
|
||||
current = current->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* if here, we need to add a new one */
|
||||
next = (hash_struct *) malloc(sizeof (hash_struct));
|
||||
if (!next) {
|
||||
DIE("malloc of hash_struct failed!");
|
||||
}
|
||||
next->key = strdup(extension);
|
||||
if (!next->key)
|
||||
DIE("malloc of hash_struct->key failed!");
|
||||
next->value = strdup(type);
|
||||
if (!next->value)
|
||||
DIE("malloc of hash_struct->value failed!");
|
||||
next->next = NULL;
|
||||
|
||||
if (!current) {
|
||||
mime_hashtable[hash] = next;
|
||||
} else {
|
||||
current->next = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: get_mime_hash_value
|
||||
*
|
||||
* Description: adds the ASCII values of the file extension letters
|
||||
* and mods by the hashtable size to get the hash value
|
||||
*/
|
||||
|
||||
unsigned get_mime_hash_value(char *extension)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
|
||||
if (extension == NULL || extension[0] == '\0') {
|
||||
/* FIXME */
|
||||
log_error_time();
|
||||
fprintf(stderr, "Attempt to hash NULL or empty string!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hash = boa_hash(extension);
|
||||
hash %= MIME_HASHTABLE_SIZE;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: get_mime_type
|
||||
*
|
||||
* Description: Returns the mime type for a supplied filename.
|
||||
* Returns default type if not found.
|
||||
*/
|
||||
|
||||
char *get_mime_type(char *filename)
|
||||
{
|
||||
char *extension;
|
||||
hash_struct *current;
|
||||
|
||||
unsigned int hash;
|
||||
|
||||
extension = strrchr(filename, '.');
|
||||
|
||||
if (!extension || *extension++ == '\0')
|
||||
return default_type;
|
||||
|
||||
hash = get_mime_hash_value(extension);
|
||||
current = mime_hashtable[hash];
|
||||
|
||||
while (current) {
|
||||
if (!strcmp(current->key, extension)) /* hit */
|
||||
return current->value;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return default_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: get_homedir_hash_value
|
||||
*
|
||||
* Description: adds the ASCII values of the username letters
|
||||
* and mods by the hashtable size to get the hash value
|
||||
*/
|
||||
|
||||
unsigned get_homedir_hash_value(char *name)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
|
||||
if (name == NULL || name[0] == '\0') {
|
||||
/* FIXME */
|
||||
log_error_time();
|
||||
fprintf(stderr, "Attempt to hash NULL or empty string!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
hash = boa_hash(name);
|
||||
hash %= PASSWD_HASHTABLE_SIZE;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name: get_home_dir
|
||||
*
|
||||
* Description: Returns a point to the supplied user's home directory.
|
||||
* Adds to the hashtable if it's not already present.
|
||||
*
|
||||
*/
|
||||
|
||||
char *get_home_dir(char *name)
|
||||
{
|
||||
struct passwd *passwdbuf;
|
||||
|
||||
hash_struct *current, *next;
|
||||
unsigned int hash;
|
||||
|
||||
/* first check hash table -- if username is less than four characters,
|
||||
just hash to zero (this should be very rare) */
|
||||
|
||||
hash = get_homedir_hash_value(name);
|
||||
|
||||
for(current = passwd_hashtable[hash];current;current = current->next) {
|
||||
if (!strcmp(current->key, name)) /* hit */
|
||||
return current->value;
|
||||
if (!current->next)
|
||||
break;
|
||||
}
|
||||
|
||||
/* if here, we have to add a new one */
|
||||
|
||||
passwdbuf = getpwnam(name);
|
||||
|
||||
if (!passwdbuf) /* does not exist */
|
||||
return NULL;
|
||||
|
||||
next = (hash_struct *) malloc(sizeof (hash_struct));
|
||||
if (!next) {
|
||||
WARN("malloc of hash_struct for passwd_hashtable failed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
next->key = strdup(name);
|
||||
if (!next->key) {
|
||||
WARN("malloc of passwd_hashtable[hash]->key failed!");
|
||||
free(next);
|
||||
return NULL;
|
||||
}
|
||||
next->value = strdup(passwdbuf->pw_dir);
|
||||
if (!next->value) {
|
||||
WARN("malloc of passwd_hashtable[hash]->value failed!");
|
||||
free(next->key);
|
||||
free(next);
|
||||
return NULL;
|
||||
}
|
||||
next->next = NULL;
|
||||
|
||||
if (!current) {
|
||||
passwd_hashtable[hash] = next;
|
||||
} else {
|
||||
current->next = next;
|
||||
}
|
||||
return next->value;
|
||||
}
|
||||
|
||||
void dump_mime(void)
|
||||
{
|
||||
int i;
|
||||
hash_struct *temp;
|
||||
for (i = 0; i < MIME_HASHTABLE_SIZE; ++i) { /* these limits OK? */
|
||||
temp = mime_hashtable[i];
|
||||
while (temp) {
|
||||
hash_struct *temp_next;
|
||||
|
||||
temp_next = temp->next;
|
||||
free(temp->key);
|
||||
free(temp->value);
|
||||
free(temp);
|
||||
|
||||
temp = temp_next;
|
||||
}
|
||||
mime_hashtable[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void dump_passwd(void)
|
||||
{
|
||||
int i;
|
||||
hash_struct *temp;
|
||||
for (i = 0; i < PASSWD_HASHTABLE_SIZE; ++i) { /* these limits OK? */
|
||||
temp = passwd_hashtable[i];
|
||||
while (temp) {
|
||||
hash_struct *temp_next;
|
||||
|
||||
temp_next = temp->next;
|
||||
free(temp->key);
|
||||
free(temp->value);
|
||||
free(temp);
|
||||
|
||||
temp = temp_next;
|
||||
}
|
||||
passwd_hashtable[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void show_hash_stats(void)
|
||||
{
|
||||
int i;
|
||||
hash_struct *temp;
|
||||
int total = 0;
|
||||
int count;
|
||||
|
||||
for (i = 0; i < MIME_HASHTABLE_SIZE; ++i) { /* these limits OK? */
|
||||
if (mime_hashtable[i]) {
|
||||
count = 0;
|
||||
temp = mime_hashtable[i];
|
||||
while (temp) {
|
||||
temp = temp->next;
|
||||
++count;
|
||||
}
|
||||
#ifdef NOISY_SIGALRM
|
||||
log_error_time();
|
||||
fprintf(stderr, "mime_hashtable[%d] has %d entries\n",
|
||||
i, count);
|
||||
#endif
|
||||
total += count;
|
||||
}
|
||||
}
|
||||
log_error_time();
|
||||
fprintf(stderr, "mime_hashtable has %d total entries\n",
|
||||
total);
|
||||
|
||||
total = 0;
|
||||
for (i = 0; i < PASSWD_HASHTABLE_SIZE; ++i) { /* these limits OK? */
|
||||
if (passwd_hashtable[i]) {
|
||||
temp = passwd_hashtable[i];
|
||||
count = 0;
|
||||
while (temp) {
|
||||
temp = temp->next;
|
||||
++count;
|
||||
}
|
||||
#ifdef NOISY_SIGALRM
|
||||
log_error_time();
|
||||
fprintf(stderr, "passwd_hashtable[%d] has %d entries\n",
|
||||
i, count);
|
||||
#endif
|
||||
total += count;
|
||||
}
|
||||
}
|
||||
|
||||
log_error_time();
|
||||
fprintf(stderr, "passwd_hashtable has %d total entries\n",
|
||||
total);
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2002 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: index_dir.c,v 1.32 2002/01/30 03:41:45 jnelson Exp $*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h> /* for PATH_MAX */
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "compat.h"
|
||||
|
||||
#define MAX_FILE_LENGTH MAXNAMLEN
|
||||
#define MAX_PATH_LENGTH PATH_MAX
|
||||
|
||||
#define INT_TO_HEX(x) \
|
||||
((((x)-10)>=0)?('A'+((x)-10)):('0'+(x)))
|
||||
|
||||
#include "escape.h"
|
||||
|
||||
char *html_escape_string(char *inp, char *buf, const int len);
|
||||
char *http_escape_string(char *inp, char *buf, const int len);
|
||||
|
||||
#if defined __GNUC__ && \
|
||||
(__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 0))
|
||||
#define CONST const
|
||||
#else
|
||||
#define CONST
|
||||
#endif
|
||||
|
||||
int select_files(CONST struct dirent *d);
|
||||
int index_directory(char *dir, char *title);
|
||||
|
||||
/*
|
||||
* Name: html_escape_string
|
||||
*/
|
||||
char *html_escape_string(char *inp, char *dest, const int len)
|
||||
{
|
||||
int max;
|
||||
char *buf;
|
||||
unsigned char c;
|
||||
|
||||
max = len * 5;
|
||||
|
||||
if (dest == NULL && max)
|
||||
dest = malloc(sizeof (unsigned char) * (max + 1));
|
||||
|
||||
if (dest == NULL)
|
||||
return NULL;
|
||||
|
||||
buf = dest;
|
||||
while ((c = *inp++)) {
|
||||
switch (c) {
|
||||
case '>':
|
||||
*dest++ = '&';
|
||||
*dest++ = 'g';
|
||||
*dest++ = 't';
|
||||
*dest++ = ';';
|
||||
break;
|
||||
case '<':
|
||||
*dest++ = '&';
|
||||
*dest++ = 'l';
|
||||
*dest++ = 't';
|
||||
*dest++ = ';';
|
||||
break;
|
||||
case '&':
|
||||
*dest++ = '&';
|
||||
*dest++ = 'a';
|
||||
*dest++ = 'm';
|
||||
*dest++ = 'p';
|
||||
*dest++ = ';';
|
||||
break;
|
||||
default:
|
||||
*dest++ = c;
|
||||
}
|
||||
}
|
||||
*dest = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name: escape_string
|
||||
*
|
||||
* Description: escapes the string inp. Uses variable buf. If buf is
|
||||
* NULL when the program starts, it will attempt to dynamically allocate
|
||||
* the space that it needs, otherwise it will assume that the user
|
||||
* has already allocated enough space for the variable buf, which
|
||||
* could be up to 3 times the size of inp. If the routine dynamically
|
||||
* allocates the space, the user is responsible for freeing it afterwords
|
||||
* Returns: NULL on error, pointer to string otherwise.
|
||||
*/
|
||||
|
||||
char *http_escape_string(char *inp, char *buf, const int len)
|
||||
{
|
||||
int max;
|
||||
char *index;
|
||||
unsigned char c;
|
||||
|
||||
max = len * 3;
|
||||
|
||||
if (buf == NULL && max)
|
||||
buf = malloc(sizeof (unsigned char) * (max + 1));
|
||||
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
index = buf;
|
||||
while ((c = *inp++)) {
|
||||
if (needs_escape((unsigned int) c)) {
|
||||
*index++ = '%';
|
||||
*index++ = INT_TO_HEX(c >> 4);
|
||||
*index++ = INT_TO_HEX(c & 15);
|
||||
} else
|
||||
*index++ = c;
|
||||
}
|
||||
*index = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void send_error(int error)
|
||||
{
|
||||
char *the_error;
|
||||
|
||||
switch (error) {
|
||||
|
||||
case 1:
|
||||
the_error = "Not enough arguments were passed to the indexer.";
|
||||
break;
|
||||
case 2:
|
||||
the_error = "The Directory Sorter ran out of Memory";
|
||||
break;
|
||||
case 3:
|
||||
the_error =
|
||||
"The was a problem changing to the appropriate directory.";
|
||||
break;
|
||||
case 4:
|
||||
the_error = "There was an error escaping a string.";
|
||||
case 5:
|
||||
the_error = "Too many arguments were passed to the indexer.";
|
||||
break;
|
||||
case 6:
|
||||
the_error = "No files in this directory.";
|
||||
break;
|
||||
default:
|
||||
the_error = "An unknown error occurred producing the directory.";
|
||||
break;
|
||||
}
|
||||
printf("<html>\n<head>\n<title>\n%s\n</title>\n"
|
||||
"<body>\n%s\n</body>\n</html>\n", the_error, the_error);
|
||||
}
|
||||
|
||||
int select_files(CONST struct dirent *dirbuf)
|
||||
{
|
||||
if (dirbuf->d_name[0] == '.')
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: index_directory
|
||||
* Description: Called from get_dir_mapping if a directory html
|
||||
* has to be generated on the fly
|
||||
* If no_slash is true, prepend slashes to hrefs
|
||||
* returns -1 for problem, else 0
|
||||
*/
|
||||
|
||||
int index_directory(char *dir, char *title)
|
||||
{
|
||||
struct dirent *dirbuf;
|
||||
int numdir;
|
||||
struct dirent **array;
|
||||
struct stat statbuf;
|
||||
char http_filename[MAX_FILE_LENGTH * 3];
|
||||
char html_filename[MAX_FILE_LENGTH * 4];
|
||||
int i;
|
||||
|
||||
if (chdir(dir) == -1) {
|
||||
send_error(3);
|
||||
return -1;
|
||||
}
|
||||
numdir = scandir(".", &array, select_files, alphasort);
|
||||
if (numdir == -1) {
|
||||
send_error(2);
|
||||
return -1;
|
||||
} else if (numdir == -2) {
|
||||
send_error(6);
|
||||
return -1;
|
||||
}
|
||||
printf("<html>\n"
|
||||
"<head>\n<title>Index of %s</title>\n</head>\n\n"
|
||||
"<body bgcolor=\"#ffffff\">\n"
|
||||
"<H2>Index of %s</H2>\n"
|
||||
"<table>\n%s",
|
||||
title, title,
|
||||
(strcmp(title, "/") == 0 ? "" :
|
||||
"<tr><td colspan=3><h3>Directories</h3></td></tr>"
|
||||
"<tr><td colspan=3><a href=\"../\">Parent Directory</a></td></tr>\n"));
|
||||
|
||||
for (i = 0; i < numdir; ++i) {
|
||||
dirbuf = array[i];
|
||||
|
||||
if (stat(dirbuf->d_name, &statbuf) == -1)
|
||||
continue;
|
||||
|
||||
if (!S_ISDIR(statbuf.st_mode))
|
||||
continue;
|
||||
|
||||
if (html_escape_string(dirbuf->d_name, html_filename,
|
||||
NAMLEN(dirbuf)) == NULL) {
|
||||
send_error(4);
|
||||
return -1;
|
||||
}
|
||||
if (http_escape_string(dirbuf->d_name, http_filename,
|
||||
NAMLEN(dirbuf)) == NULL) {
|
||||
send_error(4);
|
||||
return -1;
|
||||
}
|
||||
printf("<tr>"
|
||||
"<td width=\"40%%\"><a href=\"%s/\">%s/</a></td>"
|
||||
"<td align=right>%s</td>"
|
||||
"<td align=right>%ld bytes</td>"
|
||||
"</tr>\n",
|
||||
http_filename, html_filename,
|
||||
ctime(&statbuf.st_mtime), (long) statbuf.st_size);
|
||||
}
|
||||
|
||||
printf
|
||||
("<tr><td colspan=3> </td></tr>\n<tr><td colspan=3><h3>Files</h3></td></tr>\n");
|
||||
|
||||
for (i = 0; i < numdir; ++i) {
|
||||
int len;
|
||||
dirbuf = array[i];
|
||||
|
||||
if (stat(dirbuf->d_name, &statbuf) == -1)
|
||||
continue;
|
||||
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode))
|
||||
continue;
|
||||
|
||||
if (html_escape_string(dirbuf->d_name, html_filename,
|
||||
NAMLEN(dirbuf)) == NULL) {
|
||||
send_error(4);
|
||||
return -1;
|
||||
}
|
||||
if (http_escape_string(dirbuf->d_name, http_filename,
|
||||
NAMLEN(dirbuf)) == NULL) {
|
||||
send_error(4);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(http_filename);
|
||||
#ifdef GUNZIP
|
||||
if (len > 3 && !memcmp(http_filename + len - 3, ".gz", 3)) {
|
||||
http_filename[len - 3] = '\0';
|
||||
html_filename[strlen(html_filename) - 3] = '\0';
|
||||
|
||||
printf("<tr>"
|
||||
"<td width=\"40%%\"><a href=\"%s\">%s</a> "
|
||||
"<a href=\"%s.gz\">(.gz)</a></td>"
|
||||
"<td align=right>%s</td>"
|
||||
"<td align=right>%ld bytes</td>"
|
||||
"</tr>\n",
|
||||
http_filename, html_filename, http_filename,
|
||||
ctime(&statbuf.st_mtime), (long) statbuf.st_size);
|
||||
} else {
|
||||
#endif
|
||||
printf("<tr>"
|
||||
"<td width=\"40%%\"><a href=\"%s\">%s</a></td>"
|
||||
"<td align=right>%s</td>"
|
||||
"<td align=right>%ld bytes</td>"
|
||||
"</tr>\n",
|
||||
http_filename, html_filename,
|
||||
ctime(&statbuf.st_mtime), (long) statbuf.st_size);
|
||||
#ifdef GUNZIP
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* hey -- even though this is a one-shot deal, we should
|
||||
* still free memory we ought to free
|
||||
* You never know -- this code might get used elsewhere!
|
||||
*/
|
||||
for (i = 0; i < numdir; ++i) {
|
||||
free(array[i]);
|
||||
array[i] = NULL;
|
||||
}
|
||||
free(array);
|
||||
array = NULL;
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
time_t timep;
|
||||
struct tm *timeptr;
|
||||
char *now;
|
||||
|
||||
if (argc < 3) {
|
||||
send_error(1);
|
||||
return -1;
|
||||
} else if (argc > 3) {
|
||||
send_error(5);
|
||||
return -1;
|
||||
}
|
||||
|
||||
build_needs_escape();
|
||||
|
||||
if (argv[2] == NULL)
|
||||
index_directory(argv[1], argv[1]);
|
||||
else
|
||||
index_directory(argv[1], argv[2]);
|
||||
|
||||
time(&timep);
|
||||
#ifdef USE_LOCALTIME
|
||||
timeptr = localtime(&timep);
|
||||
#else
|
||||
timeptr = gmtime(&timep);
|
||||
#endif
|
||||
now = strdup(asctime(timeptr));
|
||||
now[strlen(now) - 1] = '\0';
|
||||
#ifdef USE_LOCALTIME
|
||||
printf("</table>\n<hr noshade>\nIndex generated %s %s\n"
|
||||
"<!-- This program is part of the Boa Webserver Copyright (C) 1991-2002 http://www.boa.org -->\n"
|
||||
"</body>\n</html>\n", now, TIMEZONE(timeptr));
|
||||
#else
|
||||
printf("</table>\n<hr noshade>\nIndex generated %s UTC\n"
|
||||
"<!-- This program is part of the Boa Webserver Copyright (C) 1991-2002 http://www.boa.org -->\n"
|
||||
"</body>\n</html>\n", now);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*
|
||||
|
||||
Encapsulation of ipv4 and ipv6 stuff, try to get rid of the ifdef's
|
||||
elsewhere in the code.
|
||||
|
||||
The IPv6 code here is bsed on contributions from Martin Hinner <martin@tdp.cz>
|
||||
and Arkadiusz Miskiewicz <misiek@misiek.eu.org>. This incarnation of that
|
||||
code is untested. The original IPv4 code is based on original Boa code
|
||||
from Paul Phillips <paulp@go2net.com>.
|
||||
|
||||
A goal is to compile in as many families as are supported, and
|
||||
make the final choice at runtime.
|
||||
|
||||
globals.h:
|
||||
#ifdef INET6
|
||||
char remote_ip_addr[NI_MAXHOST];
|
||||
#else
|
||||
char remote_ip_addr[20]; after inet_ntoa
|
||||
#endif
|
||||
|
||||
None of this code interacts with the rest of Boa except through
|
||||
the parameter lists and return values.
|
||||
|
||||
Consider making these functions __inline__ and using this as a .h file
|
||||
*/
|
||||
|
||||
#include "boa.h"
|
||||
#include <arpa/inet.h> /* inet_ntoa */
|
||||
|
||||
/* Binds to the existing server_s, based on the configuration string
|
||||
in server_ip. IPv6 version doesn't pay attention to server_ip yet. */
|
||||
int bind_server(int server_s, char *server_ip)
|
||||
{
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 server_sockaddr;
|
||||
server_sockaddr.sin6_family = AF_INET6;
|
||||
memcpy(&server_sockaddr.sin6_addr, &in6addr_any, sizeof (in6addr_any));
|
||||
server_sockaddr.sin6_port = htons(server_port);
|
||||
#else
|
||||
struct sockaddr_in server_sockaddr;
|
||||
memset(&server_sockaddr, 0, sizeof server_sockaddr);
|
||||
#ifdef HAVE_SIN_LEN /* uncomment for BSDs */
|
||||
server_sockaddr.sin_len = sizeof server_sockaddr;
|
||||
#endif
|
||||
server_sockaddr.sin_family = AF_INET;
|
||||
if (server_ip != NULL) {
|
||||
inet_aton(server_ip, &server_sockaddr.sin_addr);
|
||||
} else {
|
||||
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
server_sockaddr.sin_port = htons(server_port);
|
||||
#endif
|
||||
|
||||
return bind(server_s, (struct sockaddr *) &server_sockaddr,
|
||||
sizeof (server_sockaddr));
|
||||
}
|
||||
|
||||
char *ascii_sockaddr(struct SOCKADDR *s, char *dest, int len)
|
||||
{
|
||||
#ifdef INET6
|
||||
if (getnameinfo((struct sockaddr *) s,
|
||||
sizeof(struct SOCKADDR),
|
||||
dest, len, NULL, 0, NI_NUMERICHOST)) {
|
||||
fprintf(stderr, "[IPv6] getnameinfo failed\n");
|
||||
*dest = '\0';
|
||||
}
|
||||
#ifdef WHEN_DOES_THIS_APPLY
|
||||
if ((s->__ss_family == AF_INET6) &&
|
||||
IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *) s)->sin6_addr))) {
|
||||
memmove(dest, dest+7, NI_MAXHOST);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
memmove(dest, inet_ntoa(s->sin_addr), len);
|
||||
#endif
|
||||
return dest;
|
||||
}
|
||||
|
||||
int net_port(struct SOCKADDR *s)
|
||||
{
|
||||
int p = -1;
|
||||
#ifdef INET6
|
||||
char serv[NI_MAXSERV];
|
||||
|
||||
if (getnameinfo((struct sockaddr *) s,
|
||||
sizeof(struct SOCKADDR),
|
||||
NULL, 0, serv, sizeof(serv), NI_NUMERICSERV)) {
|
||||
fprintf(stderr, "[IPv6] getnameinfo failed\n");
|
||||
} else {
|
||||
p = atoi(serv);
|
||||
}
|
||||
#else
|
||||
p = ntohs(s->sin_port);
|
||||
#endif
|
||||
return p;
|
||||
}
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1999 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: log.c,v 1.36.2.3 2002/07/26 03:04:48 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
FILE *access_log;
|
||||
|
||||
char *error_log_name;
|
||||
char *access_log_name;
|
||||
char *cgi_log_name;
|
||||
int cgi_log_fd;
|
||||
|
||||
FILE *fopen_gen_fd(char *spec, const char *mode);
|
||||
|
||||
FILE *fopen_gen_fd(char *spec, const char *mode)
|
||||
{
|
||||
int fd;
|
||||
if (!spec || *spec == '\0')
|
||||
return NULL;
|
||||
fd = open_gen_fd(spec);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
return fdopen(fd, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: open_logs
|
||||
*
|
||||
* Description: Opens access log, error log, and if specified, cgi log
|
||||
* Ties stderr to error log, except during cgi execution, at which
|
||||
* time cgi log is the stderr for cgis.
|
||||
*
|
||||
* Access log is line buffered, error log is not buffered.
|
||||
*
|
||||
*/
|
||||
|
||||
void open_logs(void)
|
||||
{
|
||||
int error_log;
|
||||
|
||||
/* if error_log_name is set, dup2 stderr to it */
|
||||
/* otherwise, leave stderr alone */
|
||||
/* we don't want to tie stderr to /dev/null */
|
||||
if (error_log_name) {
|
||||
/* open the log file */
|
||||
if (!(error_log = open_gen_fd(error_log_name))) {
|
||||
DIE("unable to open error log");
|
||||
}
|
||||
|
||||
/* redirect stderr to error_log */
|
||||
/*if (dup2(error_log, STDERR_FILENO) == -1) {
|
||||
DIE("unable to dup2 the error log");
|
||||
}*/
|
||||
close(error_log);
|
||||
}
|
||||
|
||||
/* set the close-on-exec to true */
|
||||
if (fcntl(STDERR_FILENO, F_SETFD, 1) == -1) {
|
||||
DIE("unable to fcntl the error log");
|
||||
}
|
||||
|
||||
if (access_log_name) {
|
||||
/* Used the "a" flag with fopen, but fopen_gen_fd builds that in
|
||||
* implicitly when used as a file, and "a" is incompatible with
|
||||
* pipes and network sockets. */
|
||||
if (!(access_log = fopen_gen_fd(access_log_name, "w"))) {
|
||||
int errno_save = errno;
|
||||
fprintf(stderr, "Cannot open %s for logging: ",
|
||||
access_log_name);
|
||||
errno = errno_save;
|
||||
perror("logfile open");
|
||||
exit(errno);
|
||||
}
|
||||
/* line buffer the access log */
|
||||
#ifdef SETVBUF_REVERSED
|
||||
setvbuf(access_log, _IOLBF, (char *) NULL, 0);
|
||||
#else
|
||||
setvbuf(access_log, (char *) NULL, _IOLBF, 0);
|
||||
#endif
|
||||
} else
|
||||
access_log = NULL;
|
||||
|
||||
if (cgi_log_name) {
|
||||
cgi_log_fd = open_gen_fd(cgi_log_name);
|
||||
if (cgi_log_fd == -1) {
|
||||
WARN("open cgi_log");
|
||||
free(cgi_log_name);
|
||||
cgi_log_name = NULL;
|
||||
cgi_log_fd = 0;
|
||||
} else {
|
||||
if (fcntl(cgi_log_fd, F_SETFD, 1) == -1) {
|
||||
WARN("unable to set close-on-exec flag for cgi_log");
|
||||
close(cgi_log_fd);
|
||||
cgi_log_fd = 0;
|
||||
free(cgi_log_name);
|
||||
cgi_log_name = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: close_access_log
|
||||
*
|
||||
* Description: closes access_log file
|
||||
*/
|
||||
void close_access_log(void)
|
||||
{
|
||||
if (access_log)
|
||||
fclose(access_log);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: log_access
|
||||
*
|
||||
* Description: Writes log data to access_log.
|
||||
*/
|
||||
|
||||
void log_access(request * req)
|
||||
{
|
||||
if (access_log) {
|
||||
if (virtualhost)
|
||||
fprintf(access_log, "%s ", req->local_ip_addr);
|
||||
fprintf(access_log, "%s - - %s\"%s\" %d %ld \"%s\" \"%s\"\n",
|
||||
req->remote_ip_addr,
|
||||
get_commonlog_time(),
|
||||
req->logline,
|
||||
req->response_status,
|
||||
req->filepos,
|
||||
(req->header_referer ? req->header_referer : "-"),
|
||||
(req->header_user_agent ? req->header_user_agent : "-"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: log_error_doc
|
||||
*
|
||||
* Description: Logs the current time and transaction identification
|
||||
* to the stderr (the error log):
|
||||
* should always be followed by an fprintf to stderr
|
||||
*
|
||||
* This function used to be implemented with a big fprintf, but not
|
||||
* all fprintf's are reliable in the face of null string pointers
|
||||
* (SunOS, in particular). As long as I had to add the checks for
|
||||
* null pointers, I changed from fprintf to fputs.
|
||||
*
|
||||
* Example output:
|
||||
[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
|
||||
*/
|
||||
|
||||
void log_error_doc(request * req)
|
||||
{
|
||||
int errno_save = errno;
|
||||
|
||||
fprintf(stderr, "%srequest from %s \"%s\" (\"%s\"): ",
|
||||
get_commonlog_time(),
|
||||
req->remote_ip_addr,
|
||||
(req->logline != NULL ?
|
||||
req->logline : "(null)"),
|
||||
(req->pathname != NULL ? req->pathname : "(null)"));
|
||||
|
||||
errno = errno_save;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: boa_perror
|
||||
*
|
||||
* Description: logs an error to user and error file both
|
||||
*
|
||||
*/
|
||||
void boa_perror(request * req, char *message)
|
||||
{
|
||||
log_error_doc(req);
|
||||
perror(message); /* don't need to save errno because log_error_doc does */
|
||||
send_r_error(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: log_error_time
|
||||
*
|
||||
* Description: Logs the current time to the stderr (the error log):
|
||||
* should always be followed by an fprintf to stderr
|
||||
*/
|
||||
|
||||
void log_error_time()
|
||||
{
|
||||
int errno_save = errno;
|
||||
fputs(get_commonlog_time(), stderr);
|
||||
errno = errno_save;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: log_error_mesg
|
||||
*
|
||||
* Description: performs a log_error_time, writes the file and lineno
|
||||
* to stderr (saving errno), and then a perror with message
|
||||
*
|
||||
*/
|
||||
|
||||
void log_error_mesg(char *file, int line, char *mesg)
|
||||
{
|
||||
int errno_save = errno;
|
||||
fprintf(stderr, "%s%s:%d - ", get_commonlog_time(), file, line);
|
||||
errno = errno_save;
|
||||
perror(mesg);
|
||||
errno = errno_save;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: mmap_cache.c,v 1.9 2002/03/24 22:35:34 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
int mmap_list_entries_used = 0;
|
||||
int mmap_list_total_requests = 0;
|
||||
int mmap_list_hash_bounces = 0;
|
||||
|
||||
/* define local table variable */
|
||||
static struct mmap_entry mmap_list[MMAP_LIST_SIZE];
|
||||
|
||||
struct mmap_entry *find_mmap(int data_fd, struct stat *s)
|
||||
{
|
||||
char *m;
|
||||
int i, start;
|
||||
mmap_list_total_requests++;
|
||||
i = start = MMAP_LIST_HASH(s->st_dev, s->st_ino, s->st_size);
|
||||
for (; mmap_list[i].use_count;) {
|
||||
if (mmap_list[i].dev == s->st_dev &&
|
||||
mmap_list[i].ino == s->st_ino &&
|
||||
mmap_list[i].len == s->st_size) {
|
||||
mmap_list[i].use_count++;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"Old mmap_list entry %d use_count now %d (hash was %d)\n",
|
||||
i, mmap_list[i].use_count, start);
|
||||
#endif
|
||||
return mmap_list + i;
|
||||
}
|
||||
mmap_list_hash_bounces++;
|
||||
i = MMAP_LIST_NEXT(i);
|
||||
/* Shouldn't happen, because of size limit enforcement below */
|
||||
if (i == start)
|
||||
return NULL;
|
||||
}
|
||||
/* didn't find an entry that matches our dev/inode/size.
|
||||
There might be an entry that matches later in the table,
|
||||
but that _should_ be rare. The worst case is that we
|
||||
needlessly mmap() a file that is already mmap'd, but we
|
||||
did that all the time before this code was written,
|
||||
so it shouldn't be _too_ bad.
|
||||
*/
|
||||
|
||||
/* Enforce a size limit here */
|
||||
if (mmap_list_entries_used > MMAP_LIST_USE_MAX)
|
||||
return NULL;
|
||||
|
||||
m = mmap(0, s->st_size, PROT_READ, MAP_OPTIONS, data_fd, 0);
|
||||
|
||||
if ((int) m == -1) {
|
||||
/* boa_perror(req,"mmap"); */
|
||||
return NULL;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "New mmap_list entry %d (hash was %d)\n", i, h);
|
||||
#endif
|
||||
mmap_list_entries_used++;
|
||||
mmap_list[i].dev = s->st_dev;
|
||||
mmap_list[i].ino = s->st_ino;
|
||||
mmap_list[i].len = s->st_size;
|
||||
mmap_list[i].mmap = m;
|
||||
mmap_list[i].use_count = 1;
|
||||
return mmap_list + i;
|
||||
}
|
||||
|
||||
void release_mmap(struct mmap_entry *e)
|
||||
{
|
||||
if (!e)
|
||||
return;
|
||||
if (!e->use_count) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "mmap_list(%p)->use_count already zero!\n", e);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (!--(e->use_count)) {
|
||||
munmap(e->mmap, e->len);
|
||||
mmap_list_entries_used--;
|
||||
}
|
||||
}
|
||||
|
||||
struct mmap_entry *find_named_mmap(char *fname)
|
||||
{
|
||||
int data_fd;
|
||||
struct stat statbuf;
|
||||
struct mmap_entry *e;
|
||||
data_fd = open(fname, O_RDONLY);
|
||||
if (data_fd == -1) {
|
||||
perror(fname);
|
||||
return NULL;
|
||||
}
|
||||
fstat(data_fd, &statbuf);
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%s is a directory\n", fname);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e = find_mmap(data_fd, &statbuf);
|
||||
close(data_fd);
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#define MAXTEST 2048
|
||||
struct mmap_entry *mlist[MAXTEST];
|
||||
char name[1024], *s;
|
||||
int i, tests=0;
|
||||
while (fgets(name,sizeof(name),stdin) && tests < MAXTEST) {
|
||||
if (name[0]=='-') {
|
||||
i=atoi(name+1);
|
||||
release_mmap(mlist[i]);
|
||||
mlist[i]=NULL;
|
||||
} else {
|
||||
if ((s=strchr(name,'\n'))) *s='\0';
|
||||
mlist[tests] = find_named_mmap(name);
|
||||
if (mlist[tests]) tests++;
|
||||
else fprintf(stderr, "find_named_mmap(%s) failed\n",name);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "mmap_list entries_used=%d ",mmap_list_entries_used);
|
||||
fprintf(stderr, "total_requests=%d ",mmap_list_total_requests);
|
||||
fprintf(stderr, "hash_bounces=%d\n",mmap_list_hash_bounces);
|
||||
for (i=0; i<tests; i++) release_mmap(mlist[i]);
|
||||
fprintf(stderr, "mmap_list entries_used=%d ",mmap_list_entries_used);
|
||||
fprintf(stderr, "total_requests=%d ",mmap_list_total_requests);
|
||||
fprintf(stderr, "hash_bounces=%d\n",mmap_list_hash_bounces);
|
||||
|
||||
*/
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* parse.h
|
||||
* minimum interaction point between Boa's parser (boa_lexer.l and
|
||||
* boa_grammar.y) and the rest of Boa.
|
||||
*/
|
||||
|
||||
/* $Id: parse.h,v 1.5 2000/02/12 21:52:45 jon Exp $*/
|
||||
|
||||
struct ccommand {
|
||||
char *name;
|
||||
int type;
|
||||
void (*action) (char *, char *, void *);
|
||||
void *object;
|
||||
};
|
||||
struct ccommand *lookup_keyword(char *c);
|
||||
void add_mime_type(char *extension, char *type);
|
|
@ -0,0 +1,136 @@
|
|||
|
||||
/*
|
||||
* Boa, an http server
|
||||
* Based on code Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1997-99 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: pipe.c,v 1.39 2002/01/21 02:19:16 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
/*
|
||||
* Name: read_from_pipe
|
||||
* Description: Reads data from a pipe
|
||||
*
|
||||
* Return values:
|
||||
* -1: request blocked, move to blocked queue
|
||||
* 0: EOF or error, close it down
|
||||
* 1: successful read, recycle in ready queue
|
||||
*/
|
||||
|
||||
int read_from_pipe(request * req)
|
||||
{
|
||||
int bytes_read, bytes_to_read =
|
||||
BUFFER_SIZE - (req->header_end - req->buffer);
|
||||
|
||||
if (bytes_to_read == 0) { /* buffer full */
|
||||
if (req->cgi_status == CGI_PARSE) { /* got+parsed header */
|
||||
req->cgi_status = CGI_BUFFER;
|
||||
*req->header_end = '\0'; /* points to end of read data */
|
||||
/* Could the above statement overwrite data???
|
||||
No, because req->header_end points to where new data
|
||||
should begin, not where old data is.
|
||||
*/
|
||||
return process_cgi_header(req); /* cgi_status will change */
|
||||
}
|
||||
req->status = PIPE_WRITE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bytes_read = read(req->data_fd, req->header_end, bytes_to_read);
|
||||
#ifdef FASCIST_LOGGING
|
||||
if (bytes_read > 0) {
|
||||
*(req->header_end + bytes_read) = '\0';
|
||||
fprintf(stderr, "pipe.c - read %d bytes: \"%s\"\n",
|
||||
bytes_read, req->header_end);
|
||||
} else
|
||||
fprintf(stderr, "pipe.c - read %d bytes\n", bytes_read);
|
||||
fprintf(stderr, "status, cgi_status: %d, %d\n", req->status,
|
||||
req->cgi_status);
|
||||
#endif
|
||||
|
||||
if (bytes_read == -1) {
|
||||
if (errno == EINTR)
|
||||
return 1;
|
||||
else if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
return -1; /* request blocked at the pipe level, but keep going */
|
||||
else {
|
||||
req->status = DEAD;
|
||||
log_error_doc(req);
|
||||
perror("pipe read");
|
||||
return 0;
|
||||
}
|
||||
} else if (bytes_read == 0) { /* eof, write rest of buffer */
|
||||
req->status = PIPE_WRITE;
|
||||
if (req->cgi_status == CGI_PARSE) { /* hasn't processed header yet */
|
||||
req->cgi_status = CGI_DONE;
|
||||
*req->header_end = '\0'; /* points to end of read data */
|
||||
return process_cgi_header(req); /* cgi_status will change */
|
||||
}
|
||||
req->cgi_status = CGI_DONE;
|
||||
return 1;
|
||||
}
|
||||
req->header_end += bytes_read;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: write_from_pipe
|
||||
* Description: Writes data previously read from a pipe
|
||||
*
|
||||
* Return values:
|
||||
* -1: request blocked, move to blocked queue
|
||||
* 0: EOF or error, close it down
|
||||
* 1: successful write, recycle in ready queue
|
||||
*/
|
||||
|
||||
int write_from_pipe(request * req)
|
||||
{
|
||||
int bytes_written, bytes_to_write = req->header_end - req->header_line;
|
||||
|
||||
if (bytes_to_write == 0) {
|
||||
if (req->cgi_status == CGI_DONE)
|
||||
return 0;
|
||||
|
||||
req->status = PIPE_READ;
|
||||
req->header_end = req->header_line = req->buffer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bytes_written = write(req->fd, req->header_line, bytes_to_write);
|
||||
|
||||
if (bytes_written == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
return -1; /* request blocked at the pipe level, but keep going */
|
||||
else if (errno == EINTR)
|
||||
return 1;
|
||||
else {
|
||||
req->status = DEAD;
|
||||
send_r_error(req); /* maybe superfluous */
|
||||
log_error_doc(req);
|
||||
perror("pipe write");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
req->header_line += bytes_written;
|
||||
req->filepos += bytes_written;
|
||||
|
||||
return 1;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1997 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: queue.c,v 1.21 2002/01/21 02:19:16 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
request *request_ready = NULL; /* ready list head */
|
||||
request *request_block = NULL; /* blocked list head */
|
||||
request *request_free = NULL; /* free list head */
|
||||
|
||||
/*
|
||||
* Name: block_request
|
||||
*
|
||||
* Description: Moves a request from the ready queue to the blocked queue
|
||||
*/
|
||||
|
||||
void block_request(request * req)
|
||||
{
|
||||
dequeue(&request_ready, req);
|
||||
enqueue(&request_block, req);
|
||||
|
||||
if (req->buffer_end) {
|
||||
BOA_FD_SET(req->fd, &block_write_fdset);
|
||||
} else {
|
||||
switch (req->status) {
|
||||
case WRITE:
|
||||
case PIPE_WRITE:
|
||||
case DONE:
|
||||
BOA_FD_SET(req->fd, &block_write_fdset);
|
||||
break;
|
||||
case PIPE_READ:
|
||||
BOA_FD_SET(req->data_fd, &block_read_fdset);
|
||||
break;
|
||||
case BODY_WRITE:
|
||||
BOA_FD_SET(req->post_data_fd, &block_write_fdset);
|
||||
break;
|
||||
default:
|
||||
BOA_FD_SET(req->fd, &block_read_fdset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ready_request
|
||||
*
|
||||
* Description: Moves a request from the blocked queue to the ready queue
|
||||
*/
|
||||
|
||||
void ready_request(request * req)
|
||||
{
|
||||
dequeue(&request_block, req);
|
||||
enqueue(&request_ready, req);
|
||||
|
||||
if (req->buffer_end) {
|
||||
FD_CLR(req->fd, &block_write_fdset);
|
||||
} else {
|
||||
switch (req->status) {
|
||||
case WRITE:
|
||||
case PIPE_WRITE:
|
||||
case DONE:
|
||||
FD_CLR(req->fd, &block_write_fdset);
|
||||
break;
|
||||
case PIPE_READ:
|
||||
FD_CLR(req->data_fd, &block_read_fdset);
|
||||
break;
|
||||
case BODY_WRITE:
|
||||
FD_CLR(req->post_data_fd, &block_write_fdset);
|
||||
break;
|
||||
default:
|
||||
FD_CLR(req->fd, &block_read_fdset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name: dequeue
|
||||
*
|
||||
* Description: Removes a request from its current queue
|
||||
*/
|
||||
|
||||
void dequeue(request ** head, request * req)
|
||||
{
|
||||
if (*head == req)
|
||||
*head = req->next;
|
||||
|
||||
if (req->prev)
|
||||
req->prev->next = req->next;
|
||||
if (req->next)
|
||||
req->next->prev = req->prev;
|
||||
|
||||
req->next = NULL;
|
||||
req->prev = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: enqueue
|
||||
*
|
||||
* Description: Adds a request to the head of a queue
|
||||
*/
|
||||
|
||||
void enqueue(request ** head, request * req)
|
||||
{
|
||||
if (*head)
|
||||
(*head)->prev = req; /* previous head's prev is us */
|
||||
|
||||
req->next = *head; /* our next is previous head */
|
||||
req->prev = NULL; /* first in list */
|
||||
|
||||
*head = req; /* now we are head */
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1997,99 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: read.c,v 1.49 2002/03/18 01:53:48 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
/*
|
||||
* Name: read_header
|
||||
* Description: Reads data from a request socket. Manages the current
|
||||
* status via a state machine. Changes status from READ_HEADER to
|
||||
* READ_BODY or WRITE as necessary.
|
||||
*
|
||||
* Return values:
|
||||
* -1: request blocked, move to blocked queue
|
||||
* 0: request done, close it down
|
||||
* 1: more to do, leave on ready list
|
||||
*/
|
||||
|
||||
int read_header(request * req)
|
||||
{
|
||||
int bytes, buf_bytes_left;
|
||||
char *check, *buffer;
|
||||
|
||||
check = req->client_stream + req->parse_pos;
|
||||
buffer = req->client_stream;
|
||||
bytes = req->client_stream_pos;
|
||||
|
||||
#ifdef VERY_FASCIST_LOGGING
|
||||
if (check < (buffer + bytes)) {
|
||||
buffer[bytes] = '\0';
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - Parsing headers (\"%s\")\n",
|
||||
__FILE__, __LINE__, check);
|
||||
}
|
||||
#endif
|
||||
while (check < (buffer + bytes)) {
|
||||
switch (req->status) {
|
||||
case READ_HEADER:
|
||||
if (*check == '\r') {
|
||||
req->status = ONE_CR;
|
||||
req->header_end = check;
|
||||
} else if (*check == '\n') {
|
||||
req->status = ONE_LF;
|
||||
req->header_end = check;
|
||||
}
|
||||
break;
|
||||
|
||||
case ONE_CR:
|
||||
if (*check == '\n')
|
||||
req->status = ONE_LF;
|
||||
else if (*check != '\r')
|
||||
req->status = READ_HEADER;
|
||||
break;
|
||||
|
||||
case ONE_LF:
|
||||
/* if here, we've found the end (for sure) of a header */
|
||||
if (*check == '\r') /* could be end o headers */
|
||||
req->status = TWO_CR;
|
||||
else if (*check == '\n')
|
||||
req->status = BODY_READ;
|
||||
else
|
||||
req->status = READ_HEADER;
|
||||
break;
|
||||
|
||||
case TWO_CR:
|
||||
if (*check == '\n')
|
||||
req->status = BODY_READ;
|
||||
else if (*check != '\r')
|
||||
req->status = READ_HEADER;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VERY_FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr, "status, check: %d, %d\n", req->status, *check);
|
||||
#endif
|
||||
|
||||
req->parse_pos++; /* update parse position */
|
||||
check++;
|
||||
|
||||
if (req->status == ONE_LF) {
|
||||
*req->header_end = '\0';
|
||||
|
||||
/* terminate string that begins at req->header_line */
|
||||
|
||||
if (req->logline) {
|
||||
if (process_option_line(req) == 0) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (process_logline(req) == 0)
|
||||
return 0;
|
||||
if (req->simple)
|
||||
return process_header_end(req);
|
||||
}
|
||||
/* set header_line to point to beginning of new header */
|
||||
req->header_line = check;
|
||||
} else if (req->status == BODY_READ) {
|
||||
#ifdef VERY_FASCIST_LOGGING
|
||||
int retval;
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d -- got to body read.\n",
|
||||
__FILE__, __LINE__);
|
||||
retval = process_header_end(req);
|
||||
#else
|
||||
int retval = process_header_end(req);
|
||||
#endif
|
||||
/* process_header_end inits non-POST cgi's */
|
||||
|
||||
if (retval && req->method == M_POST) {
|
||||
/* for body_{read,write}, set header_line to start of data,
|
||||
and header_end to end of data */
|
||||
req->header_line = check;
|
||||
req->header_end =
|
||||
req->client_stream + req->client_stream_pos;
|
||||
|
||||
req->status = BODY_WRITE;
|
||||
/* so write it */
|
||||
/* have to write first, or read will be confused
|
||||
* because of the special case where the
|
||||
* filesize is less than we have already read.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
As quoted from RFC1945:
|
||||
|
||||
A valid Content-Length is required on all HTTP/1.0 POST requests. An
|
||||
HTTP/1.0 server should respond with a 400 (bad request) message if it
|
||||
cannot determine the length of the request message's content.
|
||||
|
||||
*/
|
||||
|
||||
if (req->content_length) {
|
||||
int content_length;
|
||||
|
||||
content_length = boa_atoi(req->content_length);
|
||||
/* Is a content-length of 0 legal? */
|
||||
if (content_length <= 0) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Invalid Content-Length [%s] on POST!\n",
|
||||
req->content_length);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
if (single_post_limit && content_length > single_post_limit) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Content-Length [%d] > SinglePostLimit [%d] on POST!\n",
|
||||
content_length, single_post_limit);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
req->filesize = content_length;
|
||||
req->filepos = 0;
|
||||
if (req->header_end - req->header_line > req->filesize) {
|
||||
req->header_end = req->header_line + req->filesize;
|
||||
}
|
||||
} else {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Unknown Content-Length POST!\n");
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
} /* either process_header_end failed or req->method != POST */
|
||||
return retval; /* 0 - close it done, 1 - keep on ready */
|
||||
} /* req->status == BODY_READ */
|
||||
} /* done processing available buffer */
|
||||
|
||||
#ifdef VERY_FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - Done processing buffer. Status: %d\n",
|
||||
__FILE__, __LINE__, req->status);
|
||||
#endif
|
||||
|
||||
if (req->status < BODY_READ) {
|
||||
/* only reached if request is split across more than one packet */
|
||||
|
||||
buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos;
|
||||
if (buf_bytes_left < 1) {
|
||||
log_error_time();
|
||||
fputs("buffer overrun - read.c, read_header - closing\n",
|
||||
stderr);
|
||||
req->status = DEAD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes = read(req->fd, buffer + req->client_stream_pos, buf_bytes_left);
|
||||
|
||||
if (bytes < 0) {
|
||||
if (errno == EINTR)
|
||||
return 1;
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) /* request blocked */
|
||||
return -1;
|
||||
/*
|
||||
else if (errno == EBADF || errno == EPIPE) {
|
||||
|
||||
req->status = DEAD;
|
||||
return 0;
|
||||
*/
|
||||
log_error_doc(req);
|
||||
perror("header read"); /* don't need to save errno because log_error_doc does */
|
||||
return 0;
|
||||
} else if (bytes == 0) {
|
||||
/*
|
||||
log_error_time();
|
||||
fputs("unexpected end of headers\n", stderr);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* bytes is positive */
|
||||
req->client_stream_pos += bytes;
|
||||
|
||||
#ifdef FASCIST_LOGGING1
|
||||
log_error_time();
|
||||
req->client_stream[req->client_stream_pos] = '\0';
|
||||
fprintf(stderr, "%s:%d -- We read %d bytes: \"%s\"\n",
|
||||
__FILE__, __LINE__, bytes,
|
||||
#ifdef VERY_FASCIST_LOGGING2
|
||||
req->client_stream + req->client_stream_pos - bytes);
|
||||
#else
|
||||
"");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: read_body
|
||||
* Description: Reads body from a request socket for POST CGI
|
||||
*
|
||||
* Return values:
|
||||
*
|
||||
* -1: request blocked, move to blocked queue
|
||||
* 0: request done, close it down
|
||||
* 1: more to do, leave on ready list
|
||||
*
|
||||
|
||||
As quoted from RFC1945:
|
||||
|
||||
A valid Content-Length is required on all HTTP/1.0 POST requests. An
|
||||
HTTP/1.0 server should respond with a 400 (bad request) message if it
|
||||
cannot determine the length of the request message's content.
|
||||
|
||||
*/
|
||||
|
||||
int read_body(request * req)
|
||||
{
|
||||
int bytes_read, bytes_to_read, bytes_free;
|
||||
|
||||
bytes_free = BUFFER_SIZE - (req->header_end - req->header_line);
|
||||
bytes_to_read = req->filesize - req->filepos;
|
||||
|
||||
if (bytes_to_read > bytes_free)
|
||||
bytes_to_read = bytes_free;
|
||||
|
||||
if (bytes_to_read <= 0) {
|
||||
req->status = BODY_WRITE; /* go write it */
|
||||
return 1;
|
||||
}
|
||||
|
||||
bytes_read = read(req->fd, req->header_end, bytes_to_read);
|
||||
|
||||
if (bytes_read == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
/*
|
||||
req->status = BODY_WRITE;
|
||||
return 1;
|
||||
*/
|
||||
return -1;
|
||||
} else {
|
||||
boa_perror(req, "read body");
|
||||
return 0;
|
||||
}
|
||||
} else if (bytes_read == 0) {
|
||||
/* this is an error. premature end of body! */
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - Premature end of body!!\n",
|
||||
__FILE__, __LINE__);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->status = BODY_WRITE;
|
||||
|
||||
#ifdef FASCIST_LOGGING1
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - read %d bytes.\n",
|
||||
__FILE__, __LINE__, bytes_to_read);
|
||||
#endif
|
||||
|
||||
req->header_end += bytes_read;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: write_body
|
||||
* Description: Writes a chunk of data to a file
|
||||
*
|
||||
* Return values:
|
||||
* -1: request blocked, move to blocked queue
|
||||
* 0: EOF or error, close it down
|
||||
* 1: successful write, recycle in ready queue
|
||||
*/
|
||||
|
||||
int write_body(request * req)
|
||||
{
|
||||
int bytes_written, bytes_to_write = req->header_end - req->header_line;
|
||||
if (req->filepos + bytes_to_write > req->filesize)
|
||||
bytes_to_write = req->filesize - req->filepos;
|
||||
|
||||
if (bytes_to_write == 0) { /* nothing left in buffer to write */
|
||||
req->header_line = req->header_end = req->buffer;
|
||||
if (req->filepos >= req->filesize)
|
||||
return init_cgi(req);
|
||||
/* if here, we can safely assume that there is more to read */
|
||||
req->status = BODY_READ;
|
||||
return 1;
|
||||
}
|
||||
bytes_written = write(req->post_data_fd,
|
||||
req->header_line, bytes_to_write);
|
||||
|
||||
if (bytes_written == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
return -1; /* request blocked at the pipe level, but keep going */
|
||||
else if (errno == EINTR)
|
||||
return 1;
|
||||
else if (errno == ENOSPC) {
|
||||
/* 20010520 - Alfred Fluckiger */
|
||||
/* No test was originally done in this case, which might */
|
||||
/* lead to a "no space left on device" error. */
|
||||
boa_perror(req, "write body"); /* OK to disable if your logs get too big */
|
||||
return 0;
|
||||
} else {
|
||||
boa_perror(req, "write body"); /* OK to disable if your logs get too big */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#ifdef FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - wrote %d bytes. %ld of %ld\n",
|
||||
__FILE__, __LINE__,
|
||||
bytes_written, req->filepos, req->filesize);
|
||||
#endif
|
||||
|
||||
req->filepos += bytes_written;
|
||||
req->header_line += bytes_written;
|
||||
|
||||
return 1; /* more to do */
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,749 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: request.c,v 1.112.2.3 2002/07/24 03:03:59 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
#include <stddef.h> /* for offsetof */
|
||||
|
||||
int total_connections;
|
||||
struct status status;
|
||||
|
||||
static int sockbufsize = SOCKETBUF_SIZE;
|
||||
|
||||
/* function prototypes located in this file only */
|
||||
static void free_request(request ** list_head_addr, request * req);
|
||||
|
||||
/*
|
||||
* Name: new_request
|
||||
* Description: Obtains a request struct off the free list, or if the
|
||||
* free list is empty, allocates memory
|
||||
*
|
||||
* Return value: pointer to initialized request
|
||||
*/
|
||||
|
||||
request *new_request(void)
|
||||
{
|
||||
request *req;
|
||||
|
||||
if (request_free) {
|
||||
req = request_free; /* first on free list */
|
||||
dequeue(&request_free, request_free); /* dequeue the head */
|
||||
} else {
|
||||
req = (request *) malloc(sizeof (request));
|
||||
if (!req) {
|
||||
log_error_time();
|
||||
perror("malloc for new request");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memset(req, 0, offsetof(request, buffer) + 1);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: get_request
|
||||
*
|
||||
* Description: Polls the server socket for a request. If one exists,
|
||||
* does some basic initialization and adds it to the ready queue;.
|
||||
*/
|
||||
|
||||
void get_request(int server_s)
|
||||
{
|
||||
int fd; /* socket */
|
||||
struct SOCKADDR remote_addr; /* address */
|
||||
struct SOCKADDR salocal;
|
||||
int remote_addrlen = sizeof (struct SOCKADDR);
|
||||
request *conn; /* connection */
|
||||
size_t len;
|
||||
static int system_bufsize = 0; /* Default size of SNDBUF given by system */
|
||||
|
||||
remote_addr.S_FAMILY = 0xdead;
|
||||
fd = accept(server_s, (struct sockaddr *) &remote_addr,
|
||||
&remote_addrlen);
|
||||
|
||||
if (fd == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
/* abnormal error */
|
||||
WARN("accept");
|
||||
else
|
||||
/* no requests */
|
||||
pending_requests = 0;
|
||||
return;
|
||||
}
|
||||
if (fd >= FD_SETSIZE) {
|
||||
WARN("Got fd >= FD_SETSIZE.");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUGNONINET
|
||||
/* This shows up due to race conditions in some Linux kernels
|
||||
when the client closes the socket sometime between
|
||||
the select() and accept() syscalls.
|
||||
Code and description by Larry Doolittle <ldoolitt@boa.org>
|
||||
*/
|
||||
#define HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x)))
|
||||
if (remote_addr.sin_family != AF_INET) {
|
||||
struct sockaddr *bogus = (struct sockaddr *) &remote_addr;
|
||||
char *ap, ablock[44];
|
||||
int i;
|
||||
close(fd);
|
||||
log_error_time();
|
||||
for (ap = ablock, i = 0; i < remote_addrlen && i < 14; i++) {
|
||||
*ap++ = ' ';
|
||||
*ap++ = HEX((bogus->sa_data[i] >> 4) & 0x0f);
|
||||
*ap++ = HEX(bogus->sa_data[i] & 0x0f);
|
||||
}
|
||||
*ap = '\0';
|
||||
fprintf(stderr, "non-INET connection attempt: socket %d, "
|
||||
"sa_family = %hu, sa_data[%d] = %s\n",
|
||||
fd, bogus->sa_family, remote_addrlen, ablock);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX Either delete this, or document why it's needed */
|
||||
/* Pointed out 3-Oct-1999 by Paul Saab <paul@mu.org> */
|
||||
#ifdef REUSE_EACH_CLIENT_CONNECTION_SOCKET
|
||||
if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
|
||||
sizeof (sock_opt))) == -1) {
|
||||
DIE("setsockopt: unable to set SO_REUSEADDR");
|
||||
}
|
||||
#endif
|
||||
|
||||
len = sizeof(salocal);
|
||||
|
||||
if (getsockname(fd, (struct sockaddr *) &salocal, &len) != 0) {
|
||||
WARN("getsockname");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
conn = new_request();
|
||||
if (!conn) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
conn->fd = fd;
|
||||
conn->status = READ_HEADER;
|
||||
conn->header_line = conn->client_stream;
|
||||
conn->time_last = current_time;
|
||||
conn->kacount = ka_max;
|
||||
|
||||
ascii_sockaddr(&salocal, conn->local_ip_addr, NI_MAXHOST);
|
||||
|
||||
/* nonblocking socket */
|
||||
if (set_nonblock_fd(conn->fd) == -1)
|
||||
WARN("fcntl: unable to set new socket to non-block");
|
||||
|
||||
/* set close on exec to true */
|
||||
if (fcntl(conn->fd, F_SETFD, 1) == -1)
|
||||
WARN("fctnl: unable to set close-on-exec for new socket");
|
||||
|
||||
/* Increase buffer size if we have to.
|
||||
* Only ask the system the buffer size on the first request,
|
||||
* and assume all subsequent sockets have the same size.
|
||||
*/
|
||||
if (system_bufsize == 0) {
|
||||
len = sizeof (system_bufsize);
|
||||
if (getsockopt
|
||||
(conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0
|
||||
&& len == sizeof (system_bufsize)) {
|
||||
/*
|
||||
fprintf(stderr, "%sgetsockopt reports SNDBUF %d\n",
|
||||
get_commonlog_time(), system_bufsize);
|
||||
*/
|
||||
;
|
||||
} else {
|
||||
WARN("getsockopt(SNDBUF)");
|
||||
system_bufsize = 1;
|
||||
}
|
||||
}
|
||||
if (system_bufsize < sockbufsize) {
|
||||
if (setsockopt
|
||||
(conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &sockbufsize,
|
||||
sizeof (sockbufsize)) == -1) {
|
||||
WARN("setsockopt: unable to set socket buffer size");
|
||||
#ifdef DIE_ON_ERROR_TUNING_SNDBUF
|
||||
exit(errno);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* for log file and possible use by CGI programs */
|
||||
ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);
|
||||
|
||||
/* for possible use by CGI programs */
|
||||
conn->remote_port = net_port(&remote_addr);
|
||||
|
||||
status.requests++;
|
||||
|
||||
#ifdef USE_TCPNODELAY
|
||||
/* Thanks to Jef Poskanzer <jef@acme.com> for this tweak */
|
||||
{
|
||||
int one = 1;
|
||||
if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY,
|
||||
(void *) &one, sizeof (one)) == -1) {
|
||||
DIE("setsockopt: unable to set TCP_NODELAY");
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_RATE_LIMIT
|
||||
if (conn->fd > max_connections) {
|
||||
send_r_service_unavailable(conn);
|
||||
conn->status = DONE;
|
||||
pending_requests = 0;
|
||||
}
|
||||
#endif /* NO_RATE_LIMIT */
|
||||
|
||||
total_connections++;
|
||||
enqueue(&request_ready, conn);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name: free_request
|
||||
*
|
||||
* Description: Deallocates memory for a finished request and closes
|
||||
* down socket.
|
||||
*/
|
||||
|
||||
static void free_request(request ** list_head_addr, request * req)
|
||||
{
|
||||
int i;
|
||||
/* free_request should *never* get called by anything but
|
||||
process_requests */
|
||||
|
||||
if (req->buffer_end && req->status != DEAD) {
|
||||
req->status = DONE;
|
||||
return;
|
||||
}
|
||||
/* put request on the free list */
|
||||
dequeue(list_head_addr, req); /* dequeue from ready or block list */
|
||||
|
||||
if (req->logline) /* access log */
|
||||
log_access(req);
|
||||
|
||||
if (req->mmap_entry_var)
|
||||
release_mmap(req->mmap_entry_var);
|
||||
else if (req->data_mem)
|
||||
munmap(req->data_mem, req->filesize);
|
||||
|
||||
if (req->data_fd)
|
||||
close(req->data_fd);
|
||||
|
||||
if (req->post_data_fd)
|
||||
close(req->post_data_fd);
|
||||
|
||||
if (req->response_status >= 400)
|
||||
status.errors++;
|
||||
|
||||
for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i) {
|
||||
if (req->cgi_env[i]) {
|
||||
free(req->cgi_env[i]);
|
||||
} else {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Warning: CGI Environment contains NULL value" \
|
||||
"(index %d of %d).\n", i, req->cgi_env_index);
|
||||
}
|
||||
}
|
||||
|
||||
if (req->pathname)
|
||||
free(req->pathname);
|
||||
if (req->path_info)
|
||||
free(req->path_info);
|
||||
if (req->path_translated)
|
||||
free(req->path_translated);
|
||||
if (req->script_name)
|
||||
free(req->script_name);
|
||||
|
||||
if ((req->keepalive == KA_ACTIVE) &&
|
||||
(req->response_status < 500) && req->kacount > 0) {
|
||||
int bytes_to_move;
|
||||
|
||||
request *conn = new_request();
|
||||
if (!conn) {
|
||||
/* errors already reported */
|
||||
enqueue(&request_free, req);
|
||||
close(req->fd);
|
||||
total_connections--;
|
||||
return;
|
||||
}
|
||||
conn->fd = req->fd;
|
||||
conn->status = READ_HEADER;
|
||||
conn->header_line = conn->client_stream;
|
||||
conn->kacount = req->kacount - 1;
|
||||
|
||||
/* close enough and we avoid a call to time(NULL) */
|
||||
conn->time_last = req->time_last;
|
||||
|
||||
/* for log file and possible use by CGI programs */
|
||||
memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST);
|
||||
memcpy(conn->local_ip_addr, req->local_ip_addr, NI_MAXHOST);
|
||||
|
||||
/* for possible use by CGI programs */
|
||||
conn->remote_port = req->remote_port;
|
||||
|
||||
status.requests++;
|
||||
|
||||
/* we haven't parsed beyond req->parse_pos, so... */
|
||||
bytes_to_move = req->client_stream_pos - req->parse_pos;
|
||||
|
||||
if (bytes_to_move) {
|
||||
memcpy(conn->client_stream,
|
||||
req->client_stream + req->parse_pos, bytes_to_move);
|
||||
conn->client_stream_pos = bytes_to_move;
|
||||
}
|
||||
enqueue(&request_block, conn);
|
||||
BOA_FD_SET(conn->fd, &block_read_fdset);
|
||||
|
||||
enqueue(&request_free, req);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
While debugging some weird errors, Jon Nelson learned that
|
||||
some versions of Netscape Navigator break the
|
||||
HTTP specification.
|
||||
|
||||
Some research on the issue brought up:
|
||||
|
||||
http://www.apache.org/docs/misc/known_client_problems.html
|
||||
|
||||
As quoted here:
|
||||
|
||||
"
|
||||
Trailing CRLF on POSTs
|
||||
|
||||
This is a legacy issue. The CERN webserver required POST
|
||||
data to have an extra CRLF following it. Thus many
|
||||
clients send an extra CRLF that is not included in the
|
||||
Content-Length of the request. Apache works around this
|
||||
problem by eating any empty lines which appear before a
|
||||
request.
|
||||
"
|
||||
|
||||
Boa will (for now) hack around this stupid bug in Netscape
|
||||
(and Internet Exploder)
|
||||
by reading up to 32k after the connection is all but closed.
|
||||
This should eliminate any remaining spurious crlf sent
|
||||
by the client.
|
||||
|
||||
Building bugs *into* software to be compatable is
|
||||
just plain wrong
|
||||
*/
|
||||
|
||||
if (req->method == M_POST) {
|
||||
char buf[32768];
|
||||
read(req->fd, buf, 32768);
|
||||
}
|
||||
close(req->fd);
|
||||
total_connections--;
|
||||
|
||||
enqueue(&request_free, req);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: process_requests
|
||||
*
|
||||
* Description: Iterates through the ready queue, passing each request
|
||||
* to the appropriate handler for processing. It monitors the
|
||||
* return value from handler functions, all of which return -1
|
||||
* to indicate a block, 0 on completion and 1 to remain on the
|
||||
* ready list for more procesing.
|
||||
*/
|
||||
|
||||
void process_requests(int server_s)
|
||||
{
|
||||
int retval = 0;
|
||||
request *current, *trailer;
|
||||
|
||||
if (pending_requests) {
|
||||
get_request(server_s);
|
||||
#ifdef ORIGINAL_BEHAVIOR
|
||||
pending_requests = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
current = request_ready;
|
||||
|
||||
while (current) {
|
||||
time(¤t_time);
|
||||
if (current->buffer_end && /* there is data in the buffer */
|
||||
current->status != DEAD && current->status != DONE) {
|
||||
retval = req_flush(current);
|
||||
/*
|
||||
* retval can be -2=error, -1=blocked, or bytes left
|
||||
*/
|
||||
if (retval == -2) { /* error */
|
||||
current->status = DEAD;
|
||||
retval = 0;
|
||||
} else if (retval >= 0) {
|
||||
/* notice the >= which is different from below?
|
||||
Here, we may just be flushing headers.
|
||||
We don't want to return 0 because we are not DONE
|
||||
or DEAD */
|
||||
|
||||
retval = 1;
|
||||
}
|
||||
} else {
|
||||
switch (current->status) {
|
||||
case READ_HEADER:
|
||||
case ONE_CR:
|
||||
case ONE_LF:
|
||||
case TWO_CR:
|
||||
retval = read_header(current);
|
||||
break;
|
||||
case BODY_READ:
|
||||
retval = read_body(current);
|
||||
break;
|
||||
case BODY_WRITE:
|
||||
retval = write_body(current);
|
||||
break;
|
||||
case WRITE:
|
||||
retval = process_get(current);
|
||||
break;
|
||||
case PIPE_READ:
|
||||
retval = read_from_pipe(current);
|
||||
break;
|
||||
case PIPE_WRITE:
|
||||
retval = write_from_pipe(current);
|
||||
break;
|
||||
case DONE:
|
||||
/* a non-status that will terminate the request */
|
||||
retval = req_flush(current);
|
||||
/*
|
||||
* retval can be -2=error, -1=blocked, or bytes left
|
||||
*/
|
||||
if (retval == -2) { /* error */
|
||||
current->status = DEAD;
|
||||
retval = 0;
|
||||
} else if (retval > 0) {
|
||||
retval = 1;
|
||||
}
|
||||
break;
|
||||
case DEAD:
|
||||
retval = 0;
|
||||
current->buffer_end = 0;
|
||||
SQUASH_KA(current);
|
||||
break;
|
||||
default:
|
||||
retval = 0;
|
||||
fprintf(stderr, "Unknown status (%d), "
|
||||
"closing!\n", current->status);
|
||||
current->status = DEAD;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (sigterm_flag)
|
||||
SQUASH_KA(current);
|
||||
|
||||
/* we put this here instead of after the switch so that
|
||||
* if we are on the last request, and get_request is successful,
|
||||
* current->next is valid!
|
||||
*/
|
||||
if (pending_requests)
|
||||
get_request(server_s);
|
||||
|
||||
switch (retval) {
|
||||
case -1: /* request blocked */
|
||||
trailer = current;
|
||||
current = current->next;
|
||||
block_request(trailer);
|
||||
break;
|
||||
case 0: /* request complete */
|
||||
current->time_last = current_time;
|
||||
trailer = current;
|
||||
current = current->next;
|
||||
free_request(&request_ready, trailer);
|
||||
break;
|
||||
case 1: /* more to do */
|
||||
current->time_last = current_time;
|
||||
current = current->next;
|
||||
break;
|
||||
default:
|
||||
log_error_time();
|
||||
fprintf(stderr, "Unknown retval in process.c - "
|
||||
"Status: %d, retval: %d\n", current->status, retval);
|
||||
current = current->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: process_logline
|
||||
*
|
||||
* Description: This is called with the first req->header_line received
|
||||
* by a request, called "logline" because it is logged to a file.
|
||||
* It is parsed to determine request type and method, then passed to
|
||||
* translate_uri for further parsing. Also sets up CGI environment if
|
||||
* needed.
|
||||
*/
|
||||
|
||||
int process_logline(request * req)
|
||||
{
|
||||
char *stop, *stop2;
|
||||
static char *SIMPLE_HTTP_VERSION = "HTTP/0.9";
|
||||
|
||||
req->logline = req->client_stream;
|
||||
if (!memcmp(req->logline, "GET ", 4))
|
||||
req->method = M_GET;
|
||||
else if (!memcmp(req->logline, "HEAD ", 5))
|
||||
/* head is just get w/no body */
|
||||
req->method = M_HEAD;
|
||||
else if (!memcmp(req->logline, "POST ", 5))
|
||||
req->method = M_POST;
|
||||
else {
|
||||
log_error_time();
|
||||
fprintf(stderr, "malformed request: \"%s\"\n", req->logline);
|
||||
send_r_not_implemented(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->http_version = SIMPLE_HTTP_VERSION;
|
||||
req->simple = 1;
|
||||
|
||||
/* Guaranteed to find ' ' since we matched a method above */
|
||||
stop = req->logline + 3;
|
||||
if (*stop != ' ')
|
||||
++stop;
|
||||
|
||||
/* scan to start of non-whitespace */
|
||||
while (*(++stop) == ' ');
|
||||
|
||||
stop2 = stop;
|
||||
|
||||
/* scan to end of non-whitespace */
|
||||
while (*stop2 != '\0' && *stop2 != ' ')
|
||||
++stop2;
|
||||
|
||||
if (stop2 - stop > MAX_HEADER_LENGTH) {
|
||||
log_error_time();
|
||||
fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,
|
||||
req->logline);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
memcpy(req->request_uri, stop, stop2 - stop);
|
||||
req->request_uri[stop2 - stop] = '\0';
|
||||
|
||||
if (*stop2 == ' ') {
|
||||
/* if found, we should get an HTTP/x.x */
|
||||
unsigned int p1, p2;
|
||||
|
||||
/* scan to end of whitespace */
|
||||
++stop2;
|
||||
while (*stop2 == ' ' && *stop2 != '\0')
|
||||
++stop2;
|
||||
|
||||
/* scan in HTTP/major.minor */
|
||||
if (sscanf(stop2, "HTTP/%u.%u", &p1, &p2) == 2) {
|
||||
/* HTTP/{0.9,1.0,1.1} */
|
||||
if (p1 == 1 && (p2 == 0 || p2 == 1)) {
|
||||
req->http_version = stop2;
|
||||
req->simple = 0;
|
||||
} else if (p1 > 1 || (p1 != 0 && p2 > 1)) {
|
||||
goto BAD_VERSION;
|
||||
}
|
||||
} else {
|
||||
goto BAD_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
if (req->method == M_HEAD && req->simple) {
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
req->cgi_env_index = COMMON_CGI_COUNT;
|
||||
|
||||
return 1;
|
||||
|
||||
BAD_VERSION:
|
||||
log_error_time();
|
||||
fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: process_header_end
|
||||
*
|
||||
* Description: takes a request and performs some final checking before
|
||||
* init_cgi or init_get
|
||||
* Returns 0 for error or NPH, or 1 for success
|
||||
*/
|
||||
|
||||
int process_header_end(request * req)
|
||||
{
|
||||
if (!req->logline) {
|
||||
send_r_error(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Percent-decode request */
|
||||
if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {
|
||||
log_error_doc(req);
|
||||
fputs("Problem unescaping uri\n", stderr);
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* clean pathname */
|
||||
clean_pathname(req->request_uri);
|
||||
|
||||
if (req->request_uri[0] != '/') {
|
||||
send_r_bad_request(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (translate_uri(req) == 0) { /* unescape, parse uri */
|
||||
SQUASH_KA(req);
|
||||
return 0; /* failure, close down */
|
||||
}
|
||||
|
||||
if (req->method == M_POST) {
|
||||
req->post_data_fd = create_temporary_file(1, NULL, 0);
|
||||
if (req->post_data_fd == 0)
|
||||
return(0);
|
||||
return(1); /* success */
|
||||
}
|
||||
|
||||
if (req->is_cgi) {
|
||||
return init_cgi(req);
|
||||
}
|
||||
|
||||
req->status = WRITE;
|
||||
return init_get(req); /* get and head */
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: process_option_line
|
||||
*
|
||||
* Description: Parses the contents of req->header_line and takes
|
||||
* appropriate action.
|
||||
*/
|
||||
|
||||
int process_option_line(request * req)
|
||||
{
|
||||
char c, *value, *line = req->header_line;
|
||||
|
||||
/* Start by aggressively hacking the in-place copy of the header line */
|
||||
|
||||
#ifdef FASCIST_LOGGING
|
||||
log_error_time();
|
||||
fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
|
||||
#endif
|
||||
|
||||
value = strchr(line, ':');
|
||||
if (value == NULL)
|
||||
return 0;
|
||||
*value++ = '\0'; /* overwrite the : */
|
||||
to_upper(line); /* header types are case-insensitive */
|
||||
while ((c = *value) && (c == ' ' || c == '\t'))
|
||||
value++;
|
||||
|
||||
if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since)
|
||||
req->if_modified_since = value;
|
||||
|
||||
else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
|
||||
req->content_type = value;
|
||||
|
||||
else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
|
||||
req->content_length = value;
|
||||
|
||||
else if (!memcmp(line, "CONNECTION", 11) &&
|
||||
ka_max && req->keepalive != KA_STOPPED) {
|
||||
req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
|
||||
KA_ACTIVE : KA_STOPPED);
|
||||
}
|
||||
/* #ifdef ACCEPT_ON */
|
||||
else if (!memcmp(line, "ACCEPT", 7))
|
||||
add_accept_header(req, value);
|
||||
/* #endif */
|
||||
|
||||
/* Need agent and referer for logs */
|
||||
else if (!memcmp(line, "REFERER", 8)) {
|
||||
req->header_referer = value;
|
||||
if (!add_cgi_env(req, "REFERER", value, 1))
|
||||
return 0;
|
||||
} else if (!memcmp(line, "USER_AGENT", 11)) {
|
||||
req->header_user_agent = value;
|
||||
if (!add_cgi_env(req, "USER_AGENT", value, 1))
|
||||
return 0;
|
||||
} else {
|
||||
if (!add_cgi_env(req, line, value, 1))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: add_accept_header
|
||||
* Description: Adds a mime_type to a requests accept char buffer
|
||||
* silently ignore any that don't fit -
|
||||
* shouldn't happen because of relative buffer sizes
|
||||
*/
|
||||
|
||||
void add_accept_header(request * req, char *mime_type)
|
||||
{
|
||||
#ifdef ACCEPT_ON
|
||||
int l = strlen(req->accept);
|
||||
int l2 = strlen(mime_type);
|
||||
|
||||
if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
|
||||
return;
|
||||
|
||||
if (req->accept[0] == '\0')
|
||||
strcpy(req->accept, mime_type);
|
||||
else {
|
||||
req->accept[l] = ',';
|
||||
req->accept[l + 1] = ' ';
|
||||
memcpy(req->accept + l + 2, mime_type, l2 + 1);
|
||||
/* the +1 is for the '\0' */
|
||||
/*
|
||||
sprintf(req->accept + l, ", %s", mime_type);
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void free_requests(void)
|
||||
{
|
||||
request *ptr, *next;
|
||||
|
||||
ptr = request_free;
|
||||
while (ptr != NULL) {
|
||||
next = ptr->next;
|
||||
free(ptr);
|
||||
ptr = next;
|
||||
}
|
||||
request_free = NULL;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: response.c,v 1.41.2.1 2002/06/06 05:08:54 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
#define HTML "text/html; charset=ISO-8859-1"
|
||||
#define CRLF "\r\n"
|
||||
|
||||
void print_content_type(request * req)
|
||||
{
|
||||
req_write(req, "Content-Type: ");
|
||||
req_write(req, get_mime_type(req->request_uri));
|
||||
req_write(req, "\r\n");
|
||||
}
|
||||
|
||||
void print_content_length(request * req)
|
||||
{
|
||||
req_write(req, "Content-Length: ");
|
||||
req_write(req, simple_itoa(req->filesize));
|
||||
req_write(req, "\r\n");
|
||||
}
|
||||
|
||||
void print_last_modified(request * req)
|
||||
{
|
||||
static char lm[] = "Last-Modified: "
|
||||
" " "\r\n";
|
||||
rfc822_time_buf(lm + 15, req->last_modified);
|
||||
req_write(req, lm);
|
||||
}
|
||||
|
||||
void print_ka_phrase(request * req)
|
||||
{
|
||||
if (req->kacount > 0 &&
|
||||
req->keepalive == KA_ACTIVE && req->response_status < 500) {
|
||||
req_write(req, "Connection: Keep-Alive\r\nKeep-Alive: timeout=");
|
||||
req_write(req, simple_itoa(ka_timeout));
|
||||
req_write(req, ", max=");
|
||||
req_write(req, simple_itoa(req->kacount));
|
||||
req_write(req, "\r\n");
|
||||
} else
|
||||
req_write(req, "Connection: close\r\n");
|
||||
}
|
||||
|
||||
void print_http_headers(request * req)
|
||||
{
|
||||
static char stuff[] = "Date: "
|
||||
" "
|
||||
"\r\nServer: " SERVER_VERSION "\r\n";
|
||||
|
||||
rfc822_time_buf(stuff + 6, 0);
|
||||
req_write(req, stuff);
|
||||
print_ka_phrase(req);
|
||||
}
|
||||
|
||||
/* The routines above are only called by the routines below.
|
||||
* The rest of Boa only enters through the routines below.
|
||||
*/
|
||||
|
||||
/* R_REQUEST_OK: 200 */
|
||||
void send_r_request_ok(request * req)
|
||||
{
|
||||
req->response_status = R_REQUEST_OK;
|
||||
if (req->simple)
|
||||
return;
|
||||
|
||||
req_write(req, "HTTP/1.0 200 OK\r\n");
|
||||
print_http_headers(req);
|
||||
|
||||
if (!req->is_cgi) {
|
||||
print_content_length(req);
|
||||
print_last_modified(req);
|
||||
print_content_type(req);
|
||||
req_write(req, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* R_MOVED_PERM: 301 */
|
||||
void send_r_moved_perm(request * req, char *url)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_MOVED_PERM;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 301 Moved Permanently\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n");
|
||||
|
||||
req_write(req, "Location: ");
|
||||
req_write_escape_http(req, url);
|
||||
req_write(req, "\r\n\r\n");
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>301 Moved Permanently</TITLE></HEAD>\n"
|
||||
"<BODY>\n<H1>301 Moved</H1>The document has moved\n"
|
||||
"<A HREF=\"");
|
||||
req_write_escape_html(req, url);
|
||||
req_write(req, "\">here</A>.\n</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_MOVED_TEMP: 302 */
|
||||
void send_r_moved_temp(request * req, char *url, char *more_hdr)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_MOVED_TEMP;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 302 Moved Temporarily\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n");
|
||||
|
||||
req_write(req, "Location: ");
|
||||
req_write_escape_http(req, url);
|
||||
req_write(req, "\r\n");
|
||||
req_write(req, more_hdr);
|
||||
req_write(req, "\r\n\r\n");
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>302 Moved Temporarily</TITLE></HEAD>\n"
|
||||
"<BODY>\n<H1>302 Moved</H1>The document has moved\n"
|
||||
"<A HREF=\"");
|
||||
req_write_escape_html(req, url);
|
||||
req_write(req, "\">here</A>.\n</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_NOT_MODIFIED: 304 */
|
||||
void send_r_not_modified(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_NOT_MODIFIED;
|
||||
req_write(req, "HTTP/1.0 304 Not Modified\r\n");
|
||||
print_http_headers(req);
|
||||
print_content_type(req);
|
||||
req_write(req, "\r\n");
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_BAD_REQUEST: 400 */
|
||||
void send_r_bad_request(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_BAD_REQUEST;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 400 Bad Request\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD)
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n"
|
||||
"<BODY><H1>400 Bad Request</H1>\nYour client has issued "
|
||||
"a malformed or illegal request.\n</BODY></HTML>\n");
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_UNAUTHORIZED: 401 */
|
||||
void send_r_unauthorized(request * req, char *realm_name)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_UNAUTHORIZED;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 401 Unauthorized\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "WWW-Authenticate: Basic realm=\"");
|
||||
req_write(req, realm_name);
|
||||
req_write(req, "\"\r\n");
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>401 Unauthorized</TITLE></HEAD>\n"
|
||||
"<BODY><H1>401 Unauthorized</H1>\nYour client does not "
|
||||
"have permission to get URL ");
|
||||
req_write_escape_html(req, req->request_uri);
|
||||
req_write(req, " from this server.\n</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_FORBIDDEN: 403 */
|
||||
void send_r_forbidden(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_FORBIDDEN;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 403 Forbidden\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req, "<HTML><HEAD><TITLE>403 Forbidden</TITLE></HEAD>\n"
|
||||
"<BODY><H1>403 Forbidden</H1>\nYour client does not "
|
||||
"have permission to get URL ");
|
||||
req_write_escape_html(req, req->request_uri);
|
||||
req_write(req, " from this server.\n</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_NOT_FOUND: 404 */
|
||||
void send_r_not_found(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_NOT_FOUND;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 404 Not Found\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req, "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
|
||||
"<BODY><H1>404 Not Found</H1>\nThe requested URL ");
|
||||
req_write_escape_html(req, req->request_uri);
|
||||
req_write(req, " was not found on this server.\n</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_ERROR: 500 */
|
||||
void send_r_error(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_ERROR;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 500 Server Error\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>500 Server Error</TITLE></HEAD>\n"
|
||||
"<BODY><H1>500 Server Error</H1>\nThe server encountered "
|
||||
"an internal error and could not complete your request.\n"
|
||||
"</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_NOT_IMP: 501 */
|
||||
void send_r_not_implemented(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_NOT_IMP;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 501 Not Implemented\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>\n"
|
||||
"<BODY><H1>501 Not Implemented</H1>\nPOST to non-script "
|
||||
"is not supported in Boa.\n</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_BAD_GATEWAY: 502 */
|
||||
void send_r_bad_gateway(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_BAD_GATEWAY;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 502 Bad Gateway" CRLF);
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML CRLF CRLF); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>502 Bad Gateway</TITLE></HEAD>\n"
|
||||
"<BODY><H1>502 Bad Gateway</H1>\nThe CGI was "
|
||||
"not CGI/1.1 compliant.\n" "</BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
/* R_SERVICE_UNAVAILABLE: 503 */
|
||||
void send_r_service_unavailable(request * req) /* 503 */
|
||||
{
|
||||
static char body[] =
|
||||
"<HTML><HEAD><TITLE>503 Service Unavailable</TITLE></HEAD>\n"
|
||||
"<BODY><H1>503 Service Unavailable</H1>\n"
|
||||
"There are too many connections in use right now.\r\n"
|
||||
"Please try again later.\r\n</BODY></HTML>\n";
|
||||
static int _body_len;
|
||||
static char *body_len;
|
||||
|
||||
if (!_body_len)
|
||||
_body_len = strlen(body);
|
||||
if (!body_len)
|
||||
body_len = strdup(simple_itoa(_body_len));
|
||||
if (!body_len) {
|
||||
log_error_time();
|
||||
perror("strdup of _body_len from simple_itoa");
|
||||
}
|
||||
|
||||
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_SERVICE_UNAV;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 503 Service Unavailable\r\n");
|
||||
print_http_headers(req);
|
||||
if (body_len) {
|
||||
req_write(req, "Content-Length: ");
|
||||
req_write(req, body_len);
|
||||
req_write(req, "\r\n");
|
||||
}
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header
|
||||
*/
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req, body);
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
||||
|
||||
|
||||
/* R_NOT_IMP: 505 */
|
||||
void send_r_bad_version(request * req)
|
||||
{
|
||||
SQUASH_KA(req);
|
||||
req->response_status = R_BAD_VERSION;
|
||||
if (!req->simple) {
|
||||
req_write(req, "HTTP/1.0 505 HTTP Version Not Supported\r\n");
|
||||
print_http_headers(req);
|
||||
req_write(req, "Content-Type: " HTML "\r\n\r\n"); /* terminate header */
|
||||
}
|
||||
if (req->method != M_HEAD) {
|
||||
req_write(req,
|
||||
"<HTML><HEAD><TITLE>505 HTTP Version Not Supported</TITLE></HEAD>\n"
|
||||
"<BODY><H1>505 HTTP Version Not Supported</H1>\nHTTP versions "
|
||||
"other than 0.9 and 1.0 "
|
||||
"are not supported in Boa.\n<p><p>Version encountered: ");
|
||||
req_write(req, req->http_version);
|
||||
req_write(req, "<p><p></BODY></HTML>\n");
|
||||
}
|
||||
req_flush(req);
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
|
||||
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: select.c,v 1.1.2.2 2002/07/23 15:54:52 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
static void fdset_update(void);
|
||||
fd_set block_read_fdset;
|
||||
fd_set block_write_fdset;
|
||||
static struct timeval req_timeout; /* timeval for select */
|
||||
|
||||
void select_loop(int server_s)
|
||||
{
|
||||
FD_ZERO(&block_read_fdset);
|
||||
FD_ZERO(&block_write_fdset);
|
||||
/* set server_s and req_timeout */
|
||||
req_timeout.tv_sec = (ka_timeout ? ka_timeout : REQUEST_TIMEOUT);
|
||||
req_timeout.tv_usec = 0l; /* reset timeout */
|
||||
|
||||
/* preset max_fd */
|
||||
max_fd = -1;
|
||||
|
||||
while (1) {
|
||||
if (sighup_flag)
|
||||
sighup_run();
|
||||
if (sigchld_flag)
|
||||
sigchld_run();
|
||||
if (sigalrm_flag)
|
||||
sigalrm_run();
|
||||
|
||||
if (sigterm_flag) {
|
||||
if (sigterm_flag == 1)
|
||||
sigterm_stage1_run(server_s);
|
||||
if (sigterm_flag == 2 && !request_ready && !request_block) {
|
||||
sigterm_stage2_run();
|
||||
}
|
||||
}
|
||||
|
||||
/* reset max_fd */
|
||||
max_fd = -1;
|
||||
|
||||
if (request_block)
|
||||
/* move selected req's from request_block to request_ready */
|
||||
fdset_update();
|
||||
|
||||
/* any blocked req's move from request_ready to request_block */
|
||||
process_requests(server_s);
|
||||
|
||||
if (!sigterm_flag && total_connections < (max_connections - 10)) {
|
||||
BOA_FD_SET(server_s, &block_read_fdset); /* server always set */
|
||||
}
|
||||
|
||||
req_timeout.tv_sec = (request_ready ? 0 :
|
||||
(ka_timeout ? ka_timeout : REQUEST_TIMEOUT));
|
||||
req_timeout.tv_usec = 0l; /* reset timeout */
|
||||
|
||||
if (select(max_fd + 1, &block_read_fdset,
|
||||
&block_write_fdset, NULL,
|
||||
(request_ready || request_block ? &req_timeout : NULL)) == -1) {
|
||||
/* what is the appropriate thing to do here on EBADF */
|
||||
if (errno == EINTR)
|
||||
continue; /* while(1) */
|
||||
else if (errno != EBADF) {
|
||||
DIE("select");
|
||||
}
|
||||
}
|
||||
|
||||
time(¤t_time);
|
||||
if (FD_ISSET(server_s, &block_read_fdset))
|
||||
pending_requests = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: fdset_update
|
||||
*
|
||||
* Description: iterate through the blocked requests, checking whether
|
||||
* that file descriptor has been set by select. Update the fd_set to
|
||||
* reflect current status.
|
||||
*
|
||||
* Here, we need to do some things:
|
||||
* - keepalive timeouts simply close
|
||||
* (this is special:: a keepalive timeout is a timeout where
|
||||
keepalive is active but nothing has been read yet)
|
||||
* - regular timeouts close + error
|
||||
* - stuff in buffer and fd ready? write it out
|
||||
* - fd ready for other actions? do them
|
||||
*/
|
||||
|
||||
static void fdset_update(void)
|
||||
{
|
||||
request *current, *next;
|
||||
|
||||
for(current = request_block;current;current = next) {
|
||||
time_t time_since = current_time - current->time_last;
|
||||
next = current->next;
|
||||
|
||||
/* hmm, what if we are in "the middle" of a request and not
|
||||
* just waiting for a new one... perhaps check to see if anything
|
||||
* has been read via header position, etc... */
|
||||
if (current->kacount < ka_max && /* we *are* in a keepalive */
|
||||
(time_since >= ka_timeout) && /* ka timeout */
|
||||
!current->logline) /* haven't read anything yet */
|
||||
current->status = DEAD; /* connection keepalive timed out */
|
||||
else if (time_since > REQUEST_TIMEOUT) {
|
||||
log_error_doc(current);
|
||||
fputs("connection timed out\n", stderr);
|
||||
current->status = DEAD;
|
||||
}
|
||||
if (current->buffer_end && current->status < DEAD) {
|
||||
if (FD_ISSET(current->fd, &block_write_fdset))
|
||||
ready_request(current);
|
||||
else {
|
||||
BOA_FD_SET(current->fd, &block_write_fdset);
|
||||
}
|
||||
} else {
|
||||
switch (current->status) {
|
||||
case WRITE:
|
||||
case PIPE_WRITE:
|
||||
if (FD_ISSET(current->fd, &block_write_fdset))
|
||||
ready_request(current);
|
||||
else {
|
||||
BOA_FD_SET(current->fd, &block_write_fdset);
|
||||
}
|
||||
break;
|
||||
case BODY_WRITE:
|
||||
if (FD_ISSET(current->post_data_fd, &block_write_fdset))
|
||||
ready_request(current);
|
||||
else {
|
||||
BOA_FD_SET(current->post_data_fd, &block_write_fdset);
|
||||
}
|
||||
break;
|
||||
case PIPE_READ:
|
||||
if (FD_ISSET(current->data_fd, &block_read_fdset))
|
||||
ready_request(current);
|
||||
else {
|
||||
BOA_FD_SET(current->data_fd, &block_read_fdset);
|
||||
}
|
||||
break;
|
||||
case DONE:
|
||||
if (FD_ISSET(current->fd, &block_write_fdset))
|
||||
ready_request(current);
|
||||
else {
|
||||
BOA_FD_SET(current->fd, &block_write_fdset);
|
||||
}
|
||||
break;
|
||||
case DEAD:
|
||||
ready_request(current);
|
||||
break;
|
||||
default:
|
||||
if (FD_ISSET(current->fd, &block_read_fdset))
|
||||
ready_request(current);
|
||||
else {
|
||||
BOA_FD_SET(current->fd, &block_read_fdset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org>
|
||||
* Some changes Copyright (C) 1997 Alain Magloire <alain.magloire@rcsm.ee.mcgill.ca>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: signals.c,v 1.37.2.2 2002/07/23 16:03:41 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h> /* wait */
|
||||
#endif
|
||||
#include <signal.h> /* signal */
|
||||
|
||||
sigjmp_buf env;
|
||||
int handle_sigbus;
|
||||
|
||||
void sigsegv(int);
|
||||
void sigbus(int);
|
||||
void sigterm(int);
|
||||
void sighup(int);
|
||||
void sigint(int);
|
||||
void sigchld(int);
|
||||
void sigalrm(int);
|
||||
|
||||
/*
|
||||
* Name: init_signals
|
||||
* Description: Sets up signal handlers for all our friends.
|
||||
*/
|
||||
|
||||
void init_signals(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_flags = 0;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaddset(&sa.sa_mask, SIGSEGV);
|
||||
sigaddset(&sa.sa_mask, SIGBUS);
|
||||
sigaddset(&sa.sa_mask, SIGTERM);
|
||||
sigaddset(&sa.sa_mask, SIGHUP);
|
||||
sigaddset(&sa.sa_mask, SIGINT);
|
||||
sigaddset(&sa.sa_mask, SIGPIPE);
|
||||
sigaddset(&sa.sa_mask, SIGCHLD);
|
||||
sigaddset(&sa.sa_mask, SIGALRM);
|
||||
sigaddset(&sa.sa_mask, SIGUSR1);
|
||||
sigaddset(&sa.sa_mask, SIGUSR2);
|
||||
|
||||
sa.sa_handler = sigsegv;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sigbus;
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sigterm;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sighup;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sigint;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sigchld;
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
|
||||
sa.sa_handler = sigalrm;
|
||||
sigaction(SIGALRM, &sa, NULL);
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGUSR2, &sa, NULL);
|
||||
}
|
||||
|
||||
void sigsegv(int dummy)
|
||||
{
|
||||
time(¤t_time);
|
||||
log_error_time();
|
||||
fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir);
|
||||
fclose(stderr);
|
||||
chdir(tempdir);
|
||||
abort();
|
||||
}
|
||||
|
||||
extern sigjmp_buf env;
|
||||
extern int handle_sigbus;
|
||||
|
||||
void sigbus(int dummy)
|
||||
{
|
||||
if (handle_sigbus) {
|
||||
longjmp(env, dummy);
|
||||
}
|
||||
time(¤t_time);
|
||||
log_error_time();
|
||||
fprintf(stderr, "caught SIGBUS, dumping core in %s\n", tempdir);
|
||||
fclose(stderr);
|
||||
chdir(tempdir);
|
||||
abort();
|
||||
}
|
||||
|
||||
void sigterm(int dummy)
|
||||
{
|
||||
sigterm_flag = 1;
|
||||
}
|
||||
|
||||
void sigterm_stage1_run(int server_s) /* lame duck mode */
|
||||
{
|
||||
time(¤t_time);
|
||||
log_error_time();
|
||||
fputs("caught SIGTERM, starting shutdown\n", stderr);
|
||||
FD_CLR(server_s, &block_read_fdset);
|
||||
close(server_s);
|
||||
sigterm_flag = 2;
|
||||
}
|
||||
|
||||
void sigterm_stage2_run() /* lame duck mode */
|
||||
{
|
||||
log_error_time();
|
||||
fprintf(stderr,
|
||||
"exiting Boa normally (uptime %d seconds)\n",
|
||||
(int) (current_time - start_time));
|
||||
chdir(tempdir);
|
||||
clear_common_env();
|
||||
dump_mime();
|
||||
dump_passwd();
|
||||
dump_alias();
|
||||
free_requests();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
void sighup(int dummy)
|
||||
{
|
||||
sighup_flag = 1;
|
||||
}
|
||||
|
||||
void sighup_run(void)
|
||||
{
|
||||
sighup_flag = 0;
|
||||
time(¤t_time);
|
||||
log_error_time();
|
||||
fputs("caught SIGHUP, restarting\n", stderr);
|
||||
|
||||
/* Philosophy change for 0.92: don't close and attempt reopen of logfiles,
|
||||
* since usual permission structure prevents such reopening.
|
||||
*/
|
||||
|
||||
FD_ZERO(&block_read_fdset);
|
||||
FD_ZERO(&block_write_fdset);
|
||||
/* clear_common_env(); NEVER DO THIS */
|
||||
dump_mime();
|
||||
dump_passwd();
|
||||
dump_alias();
|
||||
free_requests();
|
||||
|
||||
log_error_time();
|
||||
fputs("re-reading configuration files\n", stderr);
|
||||
read_config_files();
|
||||
|
||||
log_error_time();
|
||||
fputs("successful restart\n", stderr);
|
||||
|
||||
}
|
||||
|
||||
void sigint(int dummy)
|
||||
{
|
||||
time(¤t_time);
|
||||
log_error_time();
|
||||
fputs("caught SIGINT: shutting down\n", stderr);
|
||||
fclose(stderr);
|
||||
chdir(tempdir);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void sigchld(int dummy)
|
||||
{
|
||||
sigchld_flag = 1;
|
||||
}
|
||||
|
||||
void sigchld_run(void)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
sigchld_flag = 0;
|
||||
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
if (verbose_cgi_logs) {
|
||||
time(¤t_time);
|
||||
log_error_time();
|
||||
fprintf(stderr, "reaping child %d: status %d\n", (int) pid, status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void sigalrm(int dummy)
|
||||
{
|
||||
sigalrm_flag = 1;
|
||||
}
|
||||
|
||||
void sigalrm_run(void)
|
||||
{
|
||||
time(¤t_time);
|
||||
log_error_time();
|
||||
fprintf(stderr, "%ld requests, %ld errors\n",
|
||||
status.requests, status.errors);
|
||||
show_hash_stats();
|
||||
sigalrm_flag = 0;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: sublog.c,v 1.6 2002/03/24 22:40:31 jnelson Exp $*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
int open_pipe_fd(char *command);
|
||||
int open_net_fd(char *spec);
|
||||
int open_gen_fd(char *spec);
|
||||
|
||||
/* Like popen, but gives fd instead of FILE * */
|
||||
int open_pipe_fd(char *command)
|
||||
{
|
||||
int pipe_fds[2];
|
||||
int pid;
|
||||
/* "man pipe" says "filedes[0] is for reading,
|
||||
* filedes[1] is for writing. */
|
||||
if (pipe(pipe_fds) == -1)
|
||||
return -1;
|
||||
pid = fork();
|
||||
if (pid == 0) { /* child */
|
||||
close(pipe_fds[1]);
|
||||
if (pipe_fds[0] != 0) {
|
||||
dup2(pipe_fds[0], 0);
|
||||
close(pipe_fds[0]);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", command, (char *) 0);
|
||||
exit(127);
|
||||
}
|
||||
close(pipe_fds[0]);
|
||||
if (pid < 0) {
|
||||
close(pipe_fds[1]);
|
||||
return -1;
|
||||
}
|
||||
return pipe_fds[1];
|
||||
}
|
||||
|
||||
int open_net_fd(char *spec)
|
||||
{
|
||||
char *p;
|
||||
int fd, port;
|
||||
struct sockaddr_in sa;
|
||||
struct hostent *he;
|
||||
p = strchr(spec, ':');
|
||||
if (!p)
|
||||
return -1;
|
||||
*p++ = '\0';
|
||||
port = strtol(p, NULL, 10);
|
||||
/* printf("Host %s, port %d\n",spec,port); */
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(port);
|
||||
he = gethostbyname(spec);
|
||||
if (!he) {
|
||||
herror("open_net_fd");
|
||||
return -1;
|
||||
}
|
||||
memcpy(&sa.sin_addr, he->h_addr, he->h_length);
|
||||
/* printf("using ip %s\n",inet_ntoa(sa.sin_addr)); */
|
||||
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
if (connect(fd, (struct sockaddr *) &sa, sizeof (sa)) < 0)
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
int open_gen_fd(char *spec)
|
||||
{
|
||||
int fd;
|
||||
if (*spec == '|') {
|
||||
fd = open_pipe_fd(spec + 1);
|
||||
} else if (*spec == ':') {
|
||||
fd = open_net_fd(spec + 1);
|
||||
} else {
|
||||
fd = open(spec,
|
||||
O_WRONLY | O_CREAT | O_APPEND,
|
||||
S_IRUSR | S_IWUSR | S_IROTH | S_IRGRP);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
#ifdef STANDALONE_TEST
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char buff[1024];
|
||||
int fd, nr, nw;
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,
|
||||
"usage: %s output-filename\n"
|
||||
" %s |output-command\n"
|
||||
" %s :host:port\n", argv[0], argv[0], argv[0]);
|
||||
return 1;
|
||||
}
|
||||
fd = open_gen_fd(argv[1]);
|
||||
if (fd < 0) {
|
||||
perror("open_gen_fd");
|
||||
exit(1);
|
||||
}
|
||||
while ((nr = read(0, buff, sizeof (buff))) != 0) {
|
||||
if (nr < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
nw = write(fd, buff, nr);
|
||||
if (nw < 0) {
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1998 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: timestamp.c,v 1.9 2001/11/06 03:38:50 jnelson Exp $*/
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
void timestamp(void)
|
||||
{
|
||||
log_error_time();
|
||||
fprintf(stderr, "boa: server version %s\n", SERVER_VERSION);
|
||||
log_error_time();
|
||||
fprintf(stderr, "boa: server built " __DATE__ " at " __TIME__ ".\n");
|
||||
log_error_time();
|
||||
fprintf(stderr, "boa: starting server pid=%d, port %d\n",
|
||||
(int) getpid(), server_port);
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* Boa, an http server
|
||||
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
|
||||
* Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org>
|
||||
* Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
|
||||
* Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 1, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id: util.c,v 1.61.2.3 2002/07/07 23:22:18 jnelson Exp $ */
|
||||
|
||||
#include "boa.h"
|
||||
|
||||
#define HEX_TO_DECIMAL(char1, char2) \
|
||||
(((char1 >= 'A') ? (((char1 & 0xdf) - 'A') + 10) : (char1 - '0')) * 16) + \
|
||||
(((char2 >= 'A') ? (((char2 & 0xdf) - 'A') + 10) : (char2 - '0')))
|
||||
|
||||
const char month_tab[48] =
|
||||
"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ";
|
||||
const char day_tab[] = "Sun,Mon,Tue,Wed,Thu,Fri,Sat,";
|
||||
|
||||
/*
|
||||
* Name: clean_pathname
|
||||
*
|
||||
* Description: Replaces unsafe/incorrect instances of:
|
||||
* //[...] with /
|
||||
* /./ with /
|
||||
* /../ with / (technically not what we want, but browsers should deal
|
||||
* with this, not servers)
|
||||
*/
|
||||
|
||||
void clean_pathname(char *pathname)
|
||||
{
|
||||
char *cleanpath, c;
|
||||
|
||||
cleanpath = pathname;
|
||||
while ((c = *pathname++)) {
|
||||
if (c == '/') {
|
||||
while (1) {
|
||||
if (*pathname == '/')
|
||||
pathname++;
|
||||
else if (*pathname == '.' && *(pathname + 1) == '/')
|
||||
pathname += 2;
|
||||
else if (*pathname == '.' && *(pathname + 1) == '.' &&
|
||||
*(pathname + 2) == '/') {
|
||||
pathname += 3;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
c = '/';
|
||||
}
|
||||
*cleanpath++ = c;
|
||||
}
|
||||
|
||||
*cleanpath = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: get_commonlog_time
|
||||
*
|
||||
* Description: Returns the current time in common log format in a static
|
||||
* char buffer.
|
||||
*
|
||||
* commonlog time is exactly 25 characters long
|
||||
* because this is only used in logging, we add " [" before and "] " after
|
||||
* making 29 characters
|
||||
* "[27/Feb/1998:20:20:04 +0000] "
|
||||
*
|
||||
* Constrast with rfc822 time:
|
||||
* "Sun, 06 Nov 1994 08:49:37 GMT"
|
||||
*
|
||||
* Altered 10 Jan 2000 by Jon Nelson ala Drew Streib for non UTC logging
|
||||
*
|
||||
*/
|
||||
|
||||
char *get_commonlog_time(void)
|
||||
{
|
||||
struct tm *t;
|
||||
char *p;
|
||||
unsigned int a;
|
||||
static char buf[30];
|
||||
int time_offset;
|
||||
|
||||
if (use_localtime) {
|
||||
t = localtime(¤t_time);
|
||||
time_offset = TIMEZONE_OFFSET(t);
|
||||
} else {
|
||||
t = gmtime(¤t_time);
|
||||
time_offset = 0;
|
||||
}
|
||||
|
||||
p = buf + 29;
|
||||
*p-- = '\0';
|
||||
*p-- = ' ';
|
||||
*p-- = ']';
|
||||
a = abs(time_offset / 60);
|
||||
*p-- = '0' + a % 10;
|
||||
a /= 10;
|
||||
*p-- = '0' + a % 6;
|
||||
a /= 6;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = (time_offset >= 0) ? '+' : '-';
|
||||
*p-- = ' ';
|
||||
|
||||
a = t->tm_sec;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = ':';
|
||||
a = t->tm_min;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = ':';
|
||||
a = t->tm_hour;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = ':';
|
||||
a = 1900 + t->tm_year;
|
||||
while (a) {
|
||||
*p-- = '0' + a % 10;
|
||||
a /= 10;
|
||||
}
|
||||
/* p points to an unused spot */
|
||||
*p-- = '/';
|
||||
p -= 2;
|
||||
memcpy(p--, month_tab + 4 * (t->tm_mon), 3);
|
||||
*p-- = '/';
|
||||
a = t->tm_mday;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p = '[';
|
||||
return p; /* should be same as returning buf */
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: month2int
|
||||
*
|
||||
* Description: Turns a three letter month into a 0-11 int
|
||||
*
|
||||
* Note: This function is from wn-v1.07 -- it's clever and fast
|
||||
*/
|
||||
|
||||
int month2int(char *monthname)
|
||||
{
|
||||
switch (*monthname) {
|
||||
case 'A':
|
||||
return (*++monthname == 'p' ? 3 : 7);
|
||||
case 'D':
|
||||
return (11);
|
||||
case 'F':
|
||||
return (1);
|
||||
case 'J':
|
||||
if (*++monthname == 'a')
|
||||
return (0);
|
||||
return (*++monthname == 'n' ? 5 : 6);
|
||||
case 'M':
|
||||
return (*(monthname + 2) == 'r' ? 2 : 4);
|
||||
case 'N':
|
||||
return (10);
|
||||
case 'O':
|
||||
return (9);
|
||||
case 'S':
|
||||
return (8);
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: modified_since
|
||||
* Description: Decides whether a file's mtime is newer than the
|
||||
* If-Modified-Since header of a request.
|
||||
*
|
||||
|
||||
Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
|
||||
Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
|
||||
Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
|
||||
31 September 2000 23:59:59 GMT ; non-standard
|
||||
|
||||
* RETURN VALUES:
|
||||
* 0: File has not been modified since specified time.
|
||||
* 1: File has been.
|
||||
* -1: Error!
|
||||
*/
|
||||
|
||||
int modified_since(time_t * mtime, char *if_modified_since)
|
||||
{
|
||||
struct tm *file_gmt;
|
||||
char *ims_info;
|
||||
char monthname[10 + 1];
|
||||
int day, month, year, hour, minute, second;
|
||||
int comp;
|
||||
|
||||
ims_info = if_modified_since;
|
||||
while (*ims_info != ' ' && *ims_info != '\0')
|
||||
++ims_info;
|
||||
if (*ims_info != ' ')
|
||||
return -1;
|
||||
|
||||
/* the pre-space in the third scanf skips whitespace for the string */
|
||||
if (sscanf(ims_info, "%d %3s %d %d:%d:%d GMT", /* RFC 1123 */
|
||||
&day, monthname, &year, &hour, &minute, &second) == 6);
|
||||
else if (sscanf(ims_info, "%d-%3s-%d %d:%d:%d GMT", /* RFC 1036 */
|
||||
&day, monthname, &year, &hour, &minute, &second) == 6)
|
||||
year += 1900;
|
||||
else if (sscanf(ims_info, " %3s %d %d:%d:%d %d", /* asctime() format */
|
||||
monthname, &day, &hour, &minute, &second, &year) == 6);
|
||||
/* allow this non-standard date format: 31 September 2000 23:59:59 GMT */
|
||||
/* NOTE: Use if_modified_since here, because the date *starts*
|
||||
* with the day, versus a throwaway item
|
||||
*/
|
||||
else if (sscanf(if_modified_since, "%d %10s %d %d:%d:%d GMT",
|
||||
&day, monthname, &year, &hour, &minute, &second) == 6);
|
||||
else {
|
||||
log_error_time();
|
||||
fprintf(stderr, "Error in %s, line %d: Unable to sscanf \"%s\"\n",
|
||||
__FILE__, __LINE__, ims_info);
|
||||
return -1; /* error */
|
||||
}
|
||||
|
||||
file_gmt = gmtime(mtime);
|
||||
month = month2int(monthname);
|
||||
|
||||
/* Go through from years to seconds -- if they are ever unequal,
|
||||
we know which one is newer and can return */
|
||||
|
||||
if ((comp = 1900 + file_gmt->tm_year - year))
|
||||
return (comp > 0);
|
||||
if ((comp = file_gmt->tm_mon - month))
|
||||
return (comp > 0);
|
||||
if ((comp = file_gmt->tm_mday - day))
|
||||
return (comp > 0);
|
||||
if ((comp = file_gmt->tm_hour - hour))
|
||||
return (comp > 0);
|
||||
if ((comp = file_gmt->tm_min - minute))
|
||||
return (comp > 0);
|
||||
if ((comp = file_gmt->tm_sec - second))
|
||||
return (comp > 0);
|
||||
|
||||
return 0; /* this person must really be into the latest/greatest */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Name: to_upper
|
||||
*
|
||||
* Description: Turns a string into all upper case (for HTTP_ header forming)
|
||||
* AND changes - into _
|
||||
*/
|
||||
|
||||
char *to_upper(char *str)
|
||||
{
|
||||
char *start = str;
|
||||
|
||||
while (*str) {
|
||||
if (*str == '-')
|
||||
*str = '_';
|
||||
else
|
||||
*str = toupper(*str);
|
||||
|
||||
str++;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: unescape_uri
|
||||
*
|
||||
* Description: Decodes a uri, changing %xx encodings with the actual
|
||||
* character. The query_string should already be gone.
|
||||
*
|
||||
* Return values:
|
||||
* 1: success
|
||||
* 0: illegal string
|
||||
*/
|
||||
|
||||
int unescape_uri(char *uri, char ** query_string)
|
||||
{
|
||||
char c, d;
|
||||
char *uri_old;
|
||||
|
||||
uri_old = uri;
|
||||
|
||||
while ((c = *uri_old)) {
|
||||
if (c == '%') {
|
||||
uri_old++;
|
||||
if ((c = *uri_old++) && (d = *uri_old++))
|
||||
*uri++ = HEX_TO_DECIMAL(c, d);
|
||||
else
|
||||
return 0; /* NULL in chars to be decoded */
|
||||
} else if (c == '?') { /* query string */
|
||||
if (query_string)
|
||||
*query_string = ++uri_old;
|
||||
/* stop here */
|
||||
*uri = '\0';
|
||||
return(1);
|
||||
break;
|
||||
} else if (c == '#') { /* fragment */
|
||||
/* legal part of URL, but we do *not* care.
|
||||
* However, we still have to look for the query string */
|
||||
if (query_string) {
|
||||
++uri_old;
|
||||
while((c = *uri_old)) {
|
||||
if (c == '?') {
|
||||
*query_string = ++uri_old;
|
||||
break;
|
||||
}
|
||||
++uri_old;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
*uri++ = c;
|
||||
uri_old++;
|
||||
}
|
||||
}
|
||||
|
||||
*uri = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* rfc822 (1123) time is exactly 29 characters long
|
||||
* "Sun, 06 Nov 1994 08:49:37 GMT"
|
||||
*/
|
||||
|
||||
void rfc822_time_buf(char *buf, time_t s)
|
||||
{
|
||||
struct tm *t;
|
||||
char *p;
|
||||
unsigned int a;
|
||||
|
||||
if (!s) {
|
||||
t = gmtime(¤t_time);
|
||||
} else
|
||||
t = gmtime(&s);
|
||||
|
||||
p = buf + 28;
|
||||
/* p points to the last char in the buf */
|
||||
|
||||
p -= 3;
|
||||
/* p points to where the ' ' will go */
|
||||
memcpy(p--, " GMT", 4);
|
||||
|
||||
a = t->tm_sec;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = ':';
|
||||
a = t->tm_min;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = ':';
|
||||
a = t->tm_hour;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = ' ';
|
||||
a = 1900 + t->tm_year;
|
||||
while (a) {
|
||||
*p-- = '0' + a % 10;
|
||||
a /= 10;
|
||||
}
|
||||
/* p points to an unused spot to where the space will go */
|
||||
p -= 3;
|
||||
/* p points to where the first char of the month will go */
|
||||
memcpy(p--, month_tab + 4 * (t->tm_mon), 4);
|
||||
*p-- = ' ';
|
||||
a = t->tm_mday;
|
||||
*p-- = '0' + a % 10;
|
||||
*p-- = '0' + a / 10;
|
||||
*p-- = ' ';
|
||||
p -= 3;
|
||||
memcpy(p, day_tab + t->tm_wday * 4, 4);
|
||||
}
|
||||
|
||||
char *simple_itoa(unsigned int i)
|
||||
{
|
||||
/* 21 digits plus null terminator, good for 64-bit or smaller ints
|
||||
* for bigger ints, use a bigger buffer!
|
||||
*
|
||||
* 4294967295 is, incidentally, MAX_UINT (on 32bit systems at this time)
|
||||
* and is 10 bytes long
|
||||
*/
|
||||
static char local[22];
|
||||
char *p = &local[21];
|
||||
*p-- = '\0';
|
||||
do {
|
||||
*p-- = '0' + i % 10;
|
||||
i /= 10;
|
||||
} while (i > 0);
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
/* I don't "do" negative conversions
|
||||
* Therefore, -1 indicates error
|
||||
*/
|
||||
|
||||
int boa_atoi(char *s)
|
||||
{
|
||||
int retval;
|
||||
char *reconv;
|
||||
|
||||
if (!isdigit(*s))
|
||||
return -1;
|
||||
|
||||
retval = atoi(s);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
reconv = simple_itoa(retval);
|
||||
if (memcmp(s,reconv,strlen(s)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int create_temporary_file(short want_unlink, char *storage, int size)
|
||||
{
|
||||
static char boa_tempfile[MAX_PATH_LENGTH + 1];
|
||||
int fd;
|
||||
|
||||
snprintf(boa_tempfile, MAX_PATH_LENGTH,
|
||||
"%s/boa-temp.XXXXXX", tempdir);
|
||||
|
||||
/* open temp file */
|
||||
fd = mkstemp(boa_tempfile);
|
||||
if (fd == -1) {
|
||||
log_error_time();
|
||||
perror("mkstemp");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (storage != NULL) {
|
||||
int len = strlen(boa_tempfile);
|
||||
|
||||
if (len < size) {
|
||||
memcpy(storage, boa_tempfile, len + 1);
|
||||
} else {
|
||||
close(fd);
|
||||
fd = 0;
|
||||
log_error_time();
|
||||
fprintf(stderr, "not enough memory for memcpy in storage\n");
|
||||
want_unlink = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (want_unlink) {
|
||||
if (unlink(boa_tempfile) == -1) {
|
||||
close(fd);
|
||||
fd = 0;
|
||||
log_error_time();
|
||||
fprintf(stderr, "unlink temp file\n");
|
||||
}
|
||||
}
|
||||
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: normalize_path
|
||||
*
|
||||
* Description: Makes sure relative paths are made absolute
|
||||
*
|
||||
*/
|
||||
|
||||
#define DIRBUF_SIZE MAX_PATH_LENGTH * 2 + 1
|
||||
char * normalize_path(char *path)
|
||||
{
|
||||
char dirbuf[DIRBUF_SIZE];
|
||||
int len1, len2;
|
||||
char *endpath;
|
||||
|
||||
if (path[0] == '/') {
|
||||
endpath = strdup(path);
|
||||
} else {
|
||||
|
||||
#ifndef HAVE_GETCWD
|
||||
perror("boa: getcwd() not defined. Aborting.");
|
||||
exit(1);
|
||||
#endif
|
||||
if (getcwd(dirbuf, DIRBUF_SIZE) == NULL) {
|
||||
if (errno == ERANGE)
|
||||
perror
|
||||
("boa: getcwd() failed - unable to get working directory. "
|
||||
"Aborting.");
|
||||
else if (errno == EACCES)
|
||||
perror("boa: getcwd() failed - No read access in current "
|
||||
"directory. Aborting.");
|
||||
else
|
||||
perror("boa: getcwd() failed - unknown error. Aborting.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* OK, now the hard part. */
|
||||
len1 = strlen(dirbuf);
|
||||
len2 = strlen(path);
|
||||
if (len1 + len2 > MAX_PATH_LENGTH * 2) {
|
||||
perror("boa: eek. unable to normalize pathname");
|
||||
exit(1);
|
||||
}
|
||||
if (strcmp(path,".") != 0) {
|
||||
memcpy(dirbuf + len1, "/", 1);
|
||||
memcpy(dirbuf + len1 + 1, path, len2 + 1);
|
||||
}
|
||||
/* fprintf(stderr, "boa: normalize gets \"%s\"\n", dirbuf); */
|
||||
|
||||
endpath = strdup(dirbuf);
|
||||
}
|
||||
|
||||
if (endpath == NULL) {
|
||||
fprintf(stderr,
|
||||
"boa: Cannot strdup path. Aborting.\n");
|
||||
exit(1);
|
||||
}
|
||||
return endpath;
|
||||
}
|
||||
|
||||
int real_set_block_fd(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags == -1)
|
||||
return -1;
|
||||
|
||||
flags &= ~O_NONBLOCK;
|
||||
flags = fcntl(fd, F_SETFL, flags);
|
||||
return flags;
|
||||
}
|
||||
|
||||
int real_set_nonblock_fd(int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags == -1)
|
||||
return -1;
|
||||
|
||||
flags |= O_NONBLOCK;
|
||||
flags = fcntl(fd, F_SETFL, flags);
|
||||
return flags;
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,119 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# webindex, a world wide web directory generating program
|
||||
# Copyright (C) 1997 Larry Doolittle <ldoolitt@jlab.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 1, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# likely future additions:
|
||||
# incorporate user-supplied README files
|
||||
# use config file to supply icons
|
||||
# other formats and sort options, including one giving dates
|
||||
# more robust handling of GCOS field
|
||||
# nicer date format in footer
|
||||
|
||||
# usable as it stands, 11-Feb-1997 lrd
|
||||
# $Id: webindex.pl,v 1.2 1999/10/12 14:49:08 jon Exp $
|
||||
|
||||
|
||||
# *****configure me******
|
||||
$index="INDEX.html";
|
||||
# ^^^^^^^^^^
|
||||
# The line above defines the output file name from webindex.
|
||||
# You should make sure it lines up with the configuration of
|
||||
# the web server on your system, i.e., the DirectoryIndex
|
||||
# directive in NCSA, Apache, or Boa.
|
||||
|
||||
$magic="This file is unmodified webindex output";
|
||||
|
||||
($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell)
|
||||
=getpwuid($<);
|
||||
|
||||
# Title of the page - there is no unique mapping from the unix
|
||||
# filename to URL space. Take an easy way out and just give
|
||||
# the name of the directory.
|
||||
# Even this can be confused, look what happens if user joe
|
||||
# makes a public_html/foo directory, and runs webindex on it.
|
||||
# Now user bill makes a symbolic link from his public_html/bar
|
||||
# ~joe/public_html/foo. This directory now has two URLs,
|
||||
# http://some.server/~joe/foo/ and http://some.server/~bill/bar/ .
|
||||
# The name that we generate is foo, which is only half right :-(
|
||||
|
||||
@A=split("/",`pwd`);
|
||||
$here=pop(@A);
|
||||
|
||||
# We will happily create a new $index file, or overwrite
|
||||
# one if it has the magic comment in it. We won't overwrite
|
||||
# a carefully hand-crafted one, though.
|
||||
|
||||
if (open CHK,"<$index") {
|
||||
while (<CHK>) {
|
||||
last if ($found = / $magic /);
|
||||
}
|
||||
close(CHK);
|
||||
die "existing $index not overwritten" if (!$found);
|
||||
}
|
||||
|
||||
opendir DIR, "." || die "opendir";
|
||||
open OUT,">$index" || die "fopen";
|
||||
|
||||
print OUT "<html><head>\n<title>Index of $here</title>\n</head>\n\n";
|
||||
|
||||
# This comment syntax should be compatible with all HTML versions
|
||||
print OUT "<!-- $magic -->\n";
|
||||
|
||||
print OUT "<body>\n\n<h2>Index of $here</h2>\n\n";
|
||||
|
||||
@A=sort(readdir(DIR));
|
||||
|
||||
print OUT "<h3>Directories</h3>\n<ul>\n";
|
||||
print OUT "<li><A HREF=\"../\">Parent Directory</a>\n";
|
||||
for $a (@A) {
|
||||
next if ($a eq ".");
|
||||
next if ($a eq "..");
|
||||
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
||||
$atime,$mtime,$ctime,$blksize,$blocks) = stat($a);
|
||||
if ( -d _) {
|
||||
print OUT "<li><A HREF=\"$a/\">$a</A>\n";
|
||||
}
|
||||
}
|
||||
print OUT "</ul>\n";
|
||||
|
||||
$found=0;
|
||||
for $a (@A) {
|
||||
next if ($a eq ".");
|
||||
next if ($a eq "..");
|
||||
next if ($a eq $index);
|
||||
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
|
||||
$atime,$mtime,$ctime,$blksize,$blocks) = stat($a);
|
||||
if (! -d _) {
|
||||
if (!$found) {
|
||||
$found=1;
|
||||
print OUT "<h3>Files</h3><ul>\n";
|
||||
}
|
||||
print OUT "<li><A HREF=\"$a\">$a</A> ($size bytes)\n";
|
||||
}
|
||||
}
|
||||
print OUT "</ul>\n" if $found;
|
||||
|
||||
closedir(DIR);
|
||||
$now=localtime();
|
||||
($who)=split(/,/,$gcos);
|
||||
print OUT "<hr>Index created by <a href=\"/~$name/\">$who</a>
|
||||
with <a href=\"http://recycle.jlab.org/webindex/\">webindex</a> at $now<br>\n";
|
||||
|
||||
print OUT "</body>\n</html>\n";
|
||||
|
||||
close OUT;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
/* A Bison parser, made by GNU Bison 3.0.4. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
#ifndef YY_YY_Y_TAB_H_INCLUDED
|
||||
# define YY_YY_Y_TAB_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 0
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
/* Token type. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
enum yytokentype
|
||||
{
|
||||
STMT_NO_ARGS = 258,
|
||||
STMT_ONE_ARG = 259,
|
||||
STMT_TWO_ARGS = 260,
|
||||
MIMETYPE = 261,
|
||||
STRING = 262,
|
||||
INTEGER = 263
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
#define STMT_NO_ARGS 258
|
||||
#define STMT_ONE_ARG 259
|
||||
#define STMT_TWO_ARGS 260
|
||||
#define MIMETYPE 261
|
||||
#define STRING 262
|
||||
#define INTEGER 263
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 47 "boa_grammar.y" /* yacc.c:1909 */
|
||||
|
||||
char * sval;
|
||||
int ival;
|
||||
struct ccommand * cval;
|
||||
|
||||
#line 76 "y.tab.h" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
int yyparse (void);
|
||||
|
||||
#endif /* !YY_YY_Y_TAB_H_INCLUDED */
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
*.a
|
||||
*.o
|
||||
*.cgi
|
||||
capture
|
||||
cgicunittest
|
|
@ -0,0 +1,32 @@
|
|||
CFLAGS=-g -Wall -shared -fPIC
|
||||
CC=gcc
|
||||
AR=ar
|
||||
RANLIB=ranlib
|
||||
LIBS=-L./ -lcgic
|
||||
|
||||
all: libcgic.so cgictest.cgi capture
|
||||
|
||||
install: libcgic.so
|
||||
cp libcgic.so /usr/local/lib
|
||||
cp cgic.h /usr/local/include
|
||||
@echo libcgic.so is in /usr/local/lib. cgic.h is in /usr/local/include.
|
||||
|
||||
libcgic.so: cgic.o cgic.h
|
||||
rm -f libcgic.so
|
||||
#$(AR) rc libcgic.a cgic.o
|
||||
#$(RANLIB) libcgic.so
|
||||
|
||||
#mingw32 and cygwin users: replace .cgi with .exe
|
||||
|
||||
cgictest.cgi: cgictest.o libcgic.so
|
||||
gcc cgictest.o -o cgictest.cgi ${LIBS}
|
||||
|
||||
capture: capture.o libcgic.so
|
||||
gcc capture.o -o capture ${LIBS}
|
||||
|
||||
clean:
|
||||
rm -f *.o *.so cgictest.cgi capture cgicunittest
|
||||
|
||||
test:
|
||||
gcc -D UNIT_TEST=1 cgic.c -o cgicunittest
|
||||
./cgicunittest
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue