[EXAMPLES]

* BUG: Fix Embedded window layout.

[INTERPRETER]
* NEW: The '-H' option now runs the interpreted program as a CGI script
  through an embedded HTTP server.

[GB.HTTPD]
* NEW: New hidden component that embeds an HTTP server that runs the 
  project as a CGI script. It is activated by a new interpreter option.
  Warning! This is highly experimental. The HTTP server is based on the
  thttpd source code.

[GB.WEB]
* BUG: As the _init static class is always executed at startup for exported
  classes, delay the intialization of Session class the first time one of 
  its properties is used.
* BUG: If the SCRIPT_NAME CGI variable equals nothing or "/", set it to 
  "/." so that it can be concatenated to any path and still gives a valid
  url.
* BUG: Support for explicit URL ports.
* NEW: Application.Port is a new property that returns the port used by the 
  HTTP request.


git-svn-id: svn://localhost/gambas/trunk@5209 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
Benoît Minisini 2012-09-27 20:52:08 +00:00
parent dcc327e864
commit 41b6a93cef
68 changed files with 10970 additions and 80 deletions

View File

@ -31,6 +31,7 @@ SUBDIRS = \
@ncurses_dir@ \
@media_dir@ \
@jit_dir@ \
@httpd_dir@ \
comp \
app \
examples \

View File

@ -39,7 +39,7 @@ SearchString=True
File[1]="gambas.sourceforge.net/menu.html:79.149"
File[2]=".src/MChangeLog.module:18.0"
Active=3
File[3]=".src/MMain.module:15.31"
File[3]=".src/MMain.module:16.31"
File[4]="gambas.sourceforge.net/style.css:427.0"
File[5]="gambas.sourceforge.net/style-rtl.css:431.0"
Count=5

View File

@ -14,7 +14,7 @@ Sub InitVar()
'DIM aDev AS String[] = ["92", "91", "90", "51"]
$cVar["OLD_VERSION"] = "2.24.0"
$cVar["DEV_VERSION"] = "3.3.0"
$cVar["DEV_VERSION"] = "3.3.1"
InitAuthor

View File

@ -56,10 +56,10 @@
<img id="logo" src="logo-small-fast.png"/>
<div>
<a class="download-orange" target="_blank" href="http://sourceforge.net/projects/gambas/files/gambas3/gambas3-3.3.0.tar.bz2/download">
{Download}&nbsp;<b>Gambas&nbsp;3.3.0</b>
<a class="download-orange" target="_blank" href="http://sourceforge.net/projects/gambas/files/gambas3/gambas3-3.3.1.tar.bz2/download">
{Download}&nbsp;<b>Gambas&nbsp;3.3.1</b>
</a>
<div class="release-notes" align="center"><a href="http://gambasdoc.org/help/doc/release/3.3.0?view&amp;$(LANG)">{Release Notes}</a></div>
<div class="release-notes" align="center"><a href="http://gambasdoc.org/help/doc/release/3.3.1?view&amp;$(LANG)">{Release Notes}</a></div>
</div>
<div style="display:inline-table;">

View File

@ -2,6 +2,7 @@
# Compiled with Gambas 3.3.0
Title=Gambas 3
Startup=Project
Profiling=1
Icon=img/logo/logo-ide.png
Version=3.3.0
VersionFile=1

View File

@ -1,6 +1,6 @@
[Component]
Key=gb.report
Version=3.2.90
Version=3.3.0
State=1
Authors=Fabien Bodard
Needs=Form,ImageIO

View File

@ -3,12 +3,13 @@
Title=Report designer
Startup=Report1
Icon=printer1.png
Version=3.2.90
Version=3.3.0
VersionFile=1
Component=gb.image
Component=gb.gui
Component=gb.form
Component=gb.db
Component=gb.report
Description="Report engine for gambas"
Authors="Fabien Bodard"
Environment="GB_GUI=gb.gtk"

View File

@ -5,6 +5,10 @@ Host
R
s
Port
R
s
Root
R
s
@ -196,10 +200,6 @@ CookiePath
P
s
_init
M
_exit
M

View File

@ -3,6 +3,7 @@
Export
Property Read Host As String
Property Read Port As String
Property Read Root As String
Property Read Request As String
Property LogFile As String
@ -22,9 +23,9 @@ Private Function Request_Read() As String
Dim sReq As String
sReq = $sProtocol & "://" & CGI["HTTP_HOST"] &/ CGI["SCRIPT_NAME"] &/ CGI["PATH_INFO"]
sReq = CGI["SCRIPT_NAME"] &/ CGI["PATH_INFO"]
If CGI["QUERY_STRING"] Then sReq &= "?" & CGI["QUERY_STRING"]
Return sReq
Return Main.GetAbsoluteURL(sReq)
End
@ -65,3 +66,9 @@ Private Sub Protocol_Write(Value As String)
End
Private Function Port_Read() As String
Return CGI["SERVER_PORT"]
End

View File

@ -69,7 +69,7 @@ Public Sub _init()
sRoot = CGI["SCRIPT_NAME"]
If Right(sRoot) = "/" Then sRoot = Left$(sRoot, -1)
If Not sRoot Then sRoot = "/"
If Not sRoot Then sRoot = "/."
CGI["SCRIPT_NAME"] = sRoot
End

View File

@ -58,6 +58,20 @@ Public Sub DecodeURL(sUrl As String, aField As String[], cVal As Collection)
'
End
Public Sub GetAbsoluteURL(sPath As String) As String
Dim sReq As String
Dim sPort As String
sReq = Application.Protocol & "://" & Application.Host
sPort = Application.Port
If sPort And If sPort <> "80" Then sReq &= ":" & sPort
Return sReq &/ sPath
End
Public Sub Main()

View File

@ -30,7 +30,7 @@ Public Sub Redirect(URL As String)
If URL Like "*://*" Then
AddHeader("Location", URL)
Else
AddHeader("Location", Application.Protocol & "://" & CGI["HTTP_HOST"] &/ URL)
AddHeader("Location", Main.GetAbsoluteURL(URL))
Endif
Response.Begin
@ -113,7 +113,7 @@ Public Sub End()
If ShouldCompress() Then
If Split(CGI["HTTP_ACCEPT_ENCODING"], ",").Exist("gzip*", gb.Like) Then
If Stat(sFile).Size >= 128 Then
If Stat(sFile).Size >= 1024 Then
AddHeader("Content-Encoding", "gzip")
AddHeader("Vary", "Accept-Encoding")
Exec ["gzip", "-9", sFile] Wait
@ -126,6 +126,7 @@ Public Sub End()
'hLog = Open "/tmp/response." & CStr(Application.Id) For Create
AddHeader("Content-Length", Lof($hFile))
Print $sHeader
Main.Log("Header = " & $sHeader)
$sHeader = ""
While Not Eof($hFile)

View File

@ -13,6 +13,7 @@ Private $hLock As File
Private $sPrefix As String
Private $bUnique As Boolean
Private $sCookiePath As String
Private $bInit As Boolean
Property Id As String
Property Timeout As Float
@ -261,11 +262,19 @@ Private Sub SelectSession()
End
Public Sub _init()
Private Sub Init()
If $bInit Then Return
$bInit = True
Main.AllowLog = Exist("/tmp/session.debug")
'Main.Log("Session.Init")
'Main.Log("HTTP_COOKIE = " & CGI["HTTP_COOKIE"] & " / " & Env["HTTP_COOKIE"])
$sId = Request.Cookies["SESSION"]
Main.Log("Cookie = " & $sId)
'$sId = "9E2496B3AB6DDED93ABE6F0CF6E071B3@"
If Not $sId Then Return
@ -278,17 +287,21 @@ End
Public Sub _exit()
Main.Log("Session._exit")
SaveSession
End
Private Sub GetCookiePath() As String
If $sCookiePath Then
Return $sCookiePath
Else
Return CGI["SCRIPT_NAME"]
Endif
Dim sPath As String
If $sCookiePath Then Return $sCookiePath
sPath = CGI["SCRIPT_NAME"]
If sPath = "/." Then sPath = "/"
Return sPath
End
@ -311,12 +324,14 @@ End
Public Sub _get(Key As String) As Variant
Init
If $cVal Then Return $cVal[Key]
End
Public Sub _put(Value As Variant, Key As String)
Init
If Not $cVal Then CreateSession
$cVal[Key] = Value
$bModify = True
@ -326,6 +341,7 @@ End
Private Function Id_Read() As String
Init
Return $sId
End
@ -333,6 +349,7 @@ End
Private Sub Id_Write(Value As String)
Init
Abandon
$sId = Value
SelectSession
@ -341,24 +358,28 @@ End
Private Function Timeout_Read() As Float
Init
Return Int($eTimeout * 86400 + 0.5)
End
Private Sub Timeout_Write(Value As Float)
Init
$eTimeout = Value / 86400
End
Public Sub Save()
Init
SaveSession
End
Public Sub Load()
Init
LoadSession
End
@ -384,6 +405,7 @@ End
Private Sub Unique_Write(Value As Boolean)
Init
$bUnique = Value
CheckUnique
@ -397,6 +419,7 @@ End
Private Sub Modified_Write(Value As Boolean)
Init
$bModify = Value
End

View File

@ -40,6 +40,7 @@ GB_CONFIG_SUBDIRS(gsl, gb.gsl)
GB_CONFIG_SUBDIRS(ncurses, gb.ncurses)
GB_CONFIG_SUBDIRS(media, gb.media)
GB_CONFIG_SUBDIRS(jit, gb.jit)
GB_CONFIG_SUBDIRS(httpd, gb.httpd)
AC_CONFIG_SUBDIRS(comp)
AC_CONFIG_SUBDIRS(app)

View File

@ -1,14 +1,15 @@
# Gambas Project File 3.0
# Compiled with Gambas 3.0.0
# Compiled with Gambas 3.3.0
Title=Embedder
Startup=FMain
Icon=embedder.png
Version=3.0.0
Version=3.3.0
VersionFile=1
Component=gb.image
Component=gb.gui
Component=gb.form
Component=gb.desktop
Environment="GB_GUI=gb.gtk"
TabSize=2
Translate=1
Language=fr
@ -16,3 +17,4 @@ Maintainer=benoit
Vendor=Princeton
Address=benoit@localhost
License=General Public Licence
Packager=1

View File

@ -12,9 +12,9 @@ SearchComment=False
SearchString=True
[OpenFile]
Active=1
File[1]=".src/FMain.form"
Active=2
File[2]=".src/FMain.class:15.30"
File[2]=".src/FMain.class:10.2"
Count=2
[Watches]

View File

@ -6,7 +6,9 @@ Public Sub btnEmbed_Click()
Dim aHandle As Integer[]
Dim iHandle As Integer
sTitle = txtTitle.Text
sTitle = Trim(txtTitle.Text)
If Not sTitle Then Return
If Left(sTitle, 2) = "0x" Then
iHandle = Val("&" & Mid$(sTitle, 3))
Else If Left(sTitle) = "&" Then

View File

@ -1,15 +1,15 @@
# Gambas Form File 3.0
{ Form Form
MoveScaled(32.6667,25,84,60)
MoveScaled(32.7143,25,84,60)
Text = ("Desktop application embedder")
Icon = Picture["embedder.png"]
Arrangement = Arrange.Vertical
{ Panel1 Panel
MoveScaled(0,0,82,5)
MoveScaled(0,0,82,6)
Arrangement = Arrange.Horizontal
Spacing = 8
Padding = 4
Spacing = True
Margin = True
{ Label1 Label
MoveScaled(2,1,16,4)
Font = Font["Bold"]
@ -20,7 +20,6 @@
MoveScaled(19,1,17,4)
ToolTip = ("Enter there the title of the window you want to embed.")
Expand = True
Text = ("")
}
{ btnEmbed Button
MoveScaled(37,1,14,4)
@ -37,7 +36,6 @@
{ lblID Label
MoveScaled(69,1,11,4)
Visible = False
Text = ("")
Alignment = Align.Center
Border = Border.Sunken
}

View File

@ -1,9 +1,9 @@
# Gambas Project File 3.0
# Compiled with Gambas 3.2.0
# Compiled with Gambas 3.3.0
Title=Fractal
Startup=FFractal
Icon=icon.png
Version=3.2.0
Version=3.3.0
VersionFile=1
Component=gb.image
Component=gb.gui

View File

@ -2,7 +2,7 @@ FFractal
Fractal
0
0
3.2.0
3.3.0
gb.image
gb.gui

0
gb.httpd/AUTHORS Normal file
View File

1
gb.httpd/COPYING Symbolic link
View File

@ -0,0 +1 @@
../COPYING

0
gb.httpd/ChangeLog Normal file
View File

1
gb.httpd/INSTALL Symbolic link
View File

@ -0,0 +1 @@
../INSTALL

3
gb.httpd/Makefile.am Normal file
View File

@ -0,0 +1,3 @@
ACLOCAL_AMFLAGS = -I m4 --install
SUBDIRS = @HTTPD_DIR@
EXTRA_DIST = reconf gambas.h gb*.h

0
gb.httpd/NEWS Normal file
View File

0
gb.httpd/README Normal file
View File

1
gb.httpd/acinclude.m4 Symbolic link
View File

@ -0,0 +1 @@
../acinclude.m4

1
gb.httpd/component.am Symbolic link
View File

@ -0,0 +1 @@
../component.am

151
gb.httpd/configure.ac Normal file
View File

@ -0,0 +1,151 @@
dnl ---- configure.ac for gb.httpd
AC_INIT(configure.ac)
AC_CONFIG_MACRO_DIR([m4])
dnl AC_CANONICAL_SYSTEM
dnl AC_PROG_CC
GB_INIT(gb.httpd)
AC_PROG_LIBTOOL
V_CCOPT="-O"
if test "$GCC" = yes ; then
AC_MSG_CHECKING(gcc version)
AC_CACHE_VAL(ac_cv_lbl_gcc_vers,
ac_cv_lbl_gcc_vers=`$CC -dumpversion 2>&1 | \
sed -e 's/\..*//'`)
AC_MSG_RESULT($ac_cv_lbl_gcc_vers)
if test "$ac_cv_lbl_gcc_vers" -gt 1 ; then
V_CCOPT="-O2"
fi
fi
if test -f .devel ; then
V_CCOPT="-g $V_CCOPT -Wall -Wmissing-prototypes -Wstrict-prototypes"
fi
dnl
dnl maybe this should be a loop
dnl
AC_MSG_CHECKING(how to link static binaries)
AC_CACHE_VAL(ac_cv_lbl_static_flag,
ac_cv_lbl_static_flag=unknown
echo 'main() {}' > conftest.c
if test "$GCC" != yes ; then
trial_flag="-Bstatic"
test=`$CC $trial_flag -o conftest conftest.c 2>&1`
if test -z "$test" ; then
ac_cv_lbl_static_flag="$trial_flag"
fi
rm -f conftest
fi
if test "$ac_cv_lbl_static_flag" = unknown ; then
trial_flag="-static"
test=`$CC $trial_flag -o conftest conftest.c 2>&1`
if test -z "$test" ; then
ac_cv_lbl_static_flag="$trial_flag"
fi
rm -f conftest
fi
rm conftest.c)
AC_MSG_RESULT($ac_cv_lbl_static_flag)
if test "$ac_cv_lbl_static_flag" != unknown ; then
V_STATICFLAG="$ac_cv_lbl_static_flag"
fi
AC_MSG_CHECKING(for __progname)
AC_CACHE_VAL(ac_cv_extern__progname,
AC_TRY_LINK([],
[extern char *__progname;
puts(__progname)],
ac_cv_extern__progname=yes,
ac_cv_extern__progname=no))
if test $ac_cv_extern__progname = yes ; then
AC_DEFINE([HAVE__PROGNAME], [], [have __progname])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
AC_CHECK_HEADERS(fcntl.h grp.h memory.h paths.h poll.h sys/poll.h sys/devpoll.h sys/event.h osreldate.h)
AC_HEADER_TIME
AC_HEADER_DIRENT
d="/usr/local/v6/lib"
AC_MSG_CHECKING(for $d)
if test -d $d; then
AC_MSG_RESULT(yes (Adding -L$d to LDFLAGS))
LDFLAGS="$LDFLAGS -L$d"
else
AC_MSG_RESULT(no)
fi
dnl
dnl Most operating systems have gethostbyname() in the default searched
dnl libraries (i.e. libc):
dnl
V_NETLIBS=""
AC_CHECK_FUNC(gethostbyname, ,
# Some OSes (eg. Solaris) place it in libnsl:
GB_AC_LBL_CHECK_LIB(nsl, gethostbyname,
V_NETLIBS="-lnsl $V_NETLIBS",
# Some strange OSes (SINIX) have it in libsocket:
GB_AC_LBL_CHECK_LIB(socket, gethostbyname,
V_NETLIBS="-lsocket $V_NETLIBS",
# Unfortunately libsocket sometimes depends on libnsl.
# AC_CHECK_LIB's API is essentially broken so the
# following ugliness is necessary:
GB_AC_LBL_CHECK_LIB(socket, gethostbyname,
V_NETLIBS="-lsocket -lnsl $V_NETLIBS",
AC_CHECK_LIB(resolv, gethostbyname,
V_NETLIBS="-lresolv $V_NETLIBS"),
-lnsl))))
AC_CHECK_FUNC(socket, ,
AC_CHECK_LIB(socket, socket,
V_NETLIBS="-lsocket $V_NETLIBS",
GB_AC_LBL_CHECK_LIB(socket, socket,
V_NETLIBS="-lsocket -lnsl $V_NETLIBS", , -lnsl)))
AC_CHECK_LIB(inet6, main)
AC_CHECK_FUNC(crypt, , AC_CHECK_LIB(crypt, crypt))
AC_CHECK_FUNC(hstrerror, ,
AC_CHECK_LIB(resolv, hstrerror, V_NETLIBS="-lresolv $V_NETLIBS"))
AC_REPLACE_FUNCS(strerror)
AC_CHECK_FUNCS(waitpid vsnprintf daemon setsid setlogin getaddrinfo getnameinfo gai_strerror kqueue atoll)
AC_FUNC_MMAP
case "$target_os" in
solaris*)
dnl Solaris's select() is a bad wrapper routine.
AC_CHECK_FUNCS(poll)
;;
*)
AC_CHECK_FUNCS(select poll)
;;
esac
GB_AC_ACME_TM_GMTOFF
GB_AC_ACME_INT64T
GB_AC_ACME_SOCKLENT
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_SUBST(DEFS)
AC_SUBST(V_CCOPT)
AC_SUBST(V_STATICFLAG)
AC_SUBST(V_NETLIBS)
GB_COMPONENT(
httpd,
HTTPD,
gb.httpd,
[src],
[],
[],
[],
[])
AC_OUTPUT( Makefile src/Makefile )
GB_PRINT_MESSAGES

1
gb.httpd/gambas.h Symbolic link
View File

@ -0,0 +1 @@
../main/share/gambas.h

1
gb.httpd/gb_common.h Symbolic link
View File

@ -0,0 +1 @@
../main/share/gb_common.h

1
gb.httpd/m4 Symbolic link
View File

@ -0,0 +1 @@
../m4

1
gb.httpd/missing Symbolic link
View File

@ -0,0 +1 @@
../missing

1
gb.httpd/reconf Symbolic link
View File

@ -0,0 +1 @@
../reconf

21
gb.httpd/src/Makefile.am Normal file
View File

@ -0,0 +1,21 @@
COMPONENT = gb.httpd
include $(top_srcdir)/component.am
gblib_LTLIBRARIES = gb.httpd.la
gb_httpd_la_LIBADD = @HTTPD_LIB@
gb_httpd_la_LDFLAGS = -module @LD_FLAGS@ @HTTPD_LDFLAGS@
gb_httpd_la_CPPFLAGS = @HTTPD_INC@
gb_httpd_la_SOURCES = main.c main.h \
fdwatch.h fdwatch.c \
libhttpd.h libhttpd.c \
match.h match.c \
mime_encodings.h \
mime_types.h \
mmc.h mmc.c \
tdate_parse.h tdate_parse.c \
thttpd.h thttpd.c \
timers.h timers.c \
version.h

840
gb.httpd/src/fdwatch.c Normal file
View File

@ -0,0 +1,840 @@
/* fdwatch.c - fd watcher routines, either select() or poll()
**
** Copyright 1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#include "config.h"
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <syslog.h>
#include <fcntl.h>
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#else /* HAVE_POLL_H */
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif /* HAVE_SYS_POLL_H */
#endif /* HAVE_POLL_H */
#ifdef HAVE_SYS_DEVPOLL_H
#include <sys/devpoll.h>
#ifndef HAVE_DEVPOLL
#define HAVE_DEVPOLL
#endif /* !HAVE_DEVPOLL */
#endif /* HAVE_SYS_DEVPOLL_H */
#ifdef HAVE_SYS_EVENT_H
#include <sys/event.h>
#endif /* HAVE_SYS_EVENT_H */
#include "fdwatch.h"
#ifdef HAVE_SELECT
#ifndef FD_SET
#define NFDBITS 32
#define FD_SETSIZE 32
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
#define FD_ZERO(p) bzero((char*)(p), sizeof(*(p)))
#endif /* !FD_SET */
#endif /* HAVE_SELECT */
static int nfiles;
static long nwatches;
static int *fd_rw;
static void **fd_data;
static int nreturned, next_ridx;
#ifdef HAVE_KQUEUE
#define WHICH "kevent"
#define INIT( nfiles ) kqueue_init( nfiles )
#define ADD_FD( fd, rw ) kqueue_add_fd( fd, rw )
#define DEL_FD( fd ) kqueue_del_fd( fd )
#define WATCH( timeout_msecs ) kqueue_watch( timeout_msecs )
#define CHECK_FD( fd ) kqueue_check_fd( fd )
#define GET_FD( ridx ) kqueue_get_fd( ridx )
static int kqueue_init (int nfiles);
static void kqueue_add_fd (int fd, int rw);
static void kqueue_del_fd (int fd);
static int kqueue_watch (long timeout_msecs);
static int kqueue_check_fd (int fd);
static int kqueue_get_fd (int ridx);
#else /* HAVE_KQUEUE */
#ifdef HAVE_DEVPOLL
#define WHICH "devpoll"
#define INIT( nfiles ) devpoll_init( nfiles )
#define ADD_FD( fd, rw ) devpoll_add_fd( fd, rw )
#define DEL_FD( fd ) devpoll_del_fd( fd )
#define WATCH( timeout_msecs ) devpoll_watch( timeout_msecs )
#define CHECK_FD( fd ) devpoll_check_fd( fd )
#define GET_FD( ridx ) devpoll_get_fd( ridx )
static int devpoll_init (int nfiles);
static void devpoll_add_fd (int fd, int rw);
static void devpoll_del_fd (int fd);
static int devpoll_watch (long timeout_msecs);
static int devpoll_check_fd (int fd);
static int devpoll_get_fd (int ridx);
#else /* HAVE_DEVPOLL */
#ifdef HAVE_POLL
#define WHICH "poll"
#define INIT( nfiles ) poll_init( nfiles )
#define ADD_FD( fd, rw ) poll_add_fd( fd, rw )
#define DEL_FD( fd ) poll_del_fd( fd )
#define WATCH( timeout_msecs ) poll_watch( timeout_msecs )
#define CHECK_FD( fd ) poll_check_fd( fd )
#define GET_FD( ridx ) poll_get_fd( ridx )
static int poll_init (int nfiles);
static void poll_add_fd (int fd, int rw);
static void poll_del_fd (int fd);
static int poll_watch (long timeout_msecs);
static int poll_check_fd (int fd);
static int poll_get_fd (int ridx);
#else /* HAVE_POLL */
#ifdef HAVE_SELECT
#define WHICH "select"
#define INIT( nfiles ) select_init( nfiles )
#define ADD_FD( fd, rw ) select_add_fd( fd, rw )
#define DEL_FD( fd ) select_del_fd( fd )
#define WATCH( timeout_msecs ) select_watch( timeout_msecs )
#define CHECK_FD( fd ) select_check_fd( fd )
#define GET_FD( ridx ) select_get_fd( ridx )
static int select_init (int nfiles);
static void select_add_fd (int fd, int rw);
static void select_del_fd (int fd);
static int select_watch (long timeout_msecs);
static int select_check_fd (int fd);
static int select_get_fd (int ridx);
#endif /* HAVE_SELECT */
#endif /* HAVE_POLL */
#endif /* HAVE_DEVPOLL */
#endif /* HAVE_KQUEUE */
/* Routines. */
/* Figure out how many file descriptors the system allows, and
** initialize the fdwatch data structures. Returns -1 on failure.
*/
int fdwatch_get_nfiles (void)
{
int i;
#ifdef RLIMIT_NOFILE
struct rlimit rl;
#endif /* RLIMIT_NOFILE */
/* Figure out how many fd's we can have. */
nfiles = getdtablesize ();
#ifdef RLIMIT_NOFILE
/* If we have getrlimit(), use that, and attempt to raise the limit. */
if (getrlimit (RLIMIT_NOFILE, &rl) == 0)
{
nfiles = rl.rlim_cur;
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_cur = 8192; /* arbitrary */
else if (rl.rlim_max > rl.rlim_cur)
rl.rlim_cur = rl.rlim_max;
if (setrlimit (RLIMIT_NOFILE, &rl) == 0)
nfiles = rl.rlim_cur;
}
#endif /* RLIMIT_NOFILE */
#if defined(HAVE_SELECT) && ! ( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_KQUEUE) )
/* If we use select(), then we must limit ourselves to FD_SETSIZE. */
nfiles = MIN (nfiles, FD_SETSIZE);
#endif /* HAVE_SELECT && ! ( HAVE_POLL || HAVE_DEVPOLL || HAVE_KQUEUE ) */
/* Initialize the fdwatch data structures. */
nwatches = 0;
fd_rw = (int *) malloc (sizeof (int) * nfiles);
fd_data = (void **) malloc (sizeof (void *) * nfiles);
if (fd_rw == (int *) 0 || fd_data == (void **) 0)
return -1;
for (i = 0; i < nfiles; ++i)
fd_rw[i] = -1;
if (INIT (nfiles) == -1)
return -1;
return nfiles;
}
/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */
void fdwatch_add_fd (int fd, void *client_data, int rw)
{
if (fd < 0 || fd >= nfiles || fd_rw[fd] != -1)
{
syslog (LOG_ERR, "bad fd (%d) passed to fdwatch_add_fd!", fd);
return;
}
ADD_FD (fd, rw);
fd_rw[fd] = rw;
fd_data[fd] = client_data;
}
/* Remove a descriptor from the watch list. */
void fdwatch_del_fd (int fd)
{
if (fd < 0 || fd >= nfiles || fd_rw[fd] == -1)
{
syslog (LOG_ERR, "bad fd (%d) passed to fdwatch_del_fd!", fd);
return;
}
DEL_FD (fd);
fd_rw[fd] = -1;
fd_data[fd] = (void *) 0;
}
/* Do the watch. Return value is the number of descriptors that are ready,
** or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means
** wait indefinitely.
*/
int fdwatch (long timeout_msecs)
{
++nwatches;
nreturned = WATCH (timeout_msecs);
next_ridx = 0;
return nreturned;
}
/* Check if a descriptor was ready. */
int fdwatch_check_fd (int fd)
{
if (fd < 0 || fd >= nfiles || fd_rw[fd] == -1)
{
syslog (LOG_ERR, "bad fd (%d) passed to fdwatch_check_fd!", fd);
return 0;
}
return CHECK_FD (fd);
}
void *fdwatch_get_next_client_data (void)
{
int fd;
if (next_ridx >= nreturned)
return (void *) -1;
fd = GET_FD (next_ridx++);
if (fd < 0 || fd >= nfiles)
return (void *) 0;
return fd_data[fd];
}
/* Generate debugging statistics syslog message. */
void fdwatch_logstats (long secs)
{
if (secs > 0)
syslog (LOG_INFO, " fdwatch - %ld %ss (%g/sec)",
nwatches, WHICH, (float) nwatches / secs);
nwatches = 0;
}
#ifdef HAVE_KQUEUE
static int maxkqevents;
static struct kevent *kqevents;
static int nkqevents;
static struct kevent *kqrevents;
static int *kqrfdidx;
static int kq;
static int kqueue_init (int nfiles)
{
kq = kqueue ();
if (kq == -1)
return -1;
maxkqevents = nfiles * 2;
kqevents = (struct kevent *) malloc (sizeof (struct kevent) * maxkqevents);
kqrevents = (struct kevent *) malloc (sizeof (struct kevent) * nfiles);
kqrfdidx = (int *) malloc (sizeof (int) * nfiles);
if (kqevents == (struct kevent *) 0 || kqrevents == (struct kevent *) 0 ||
kqrfdidx == (int *) 0)
return -1;
(void) memset (kqevents, 0, sizeof (struct kevent) * maxkqevents);
(void) memset (kqrfdidx, 0, sizeof (int) * nfiles);
return 0;
}
static void kqueue_add_fd (int fd, int rw)
{
if (nkqevents >= maxkqevents)
{
syslog (LOG_ERR, "too many kqevents in kqueue_add_fd!");
return;
}
kqevents[nkqevents].ident = fd;
kqevents[nkqevents].flags = EV_ADD;
switch (rw)
{
case FDW_READ:
kqevents[nkqevents].filter = EVFILT_READ;
break;
case FDW_WRITE:
kqevents[nkqevents].filter = EVFILT_WRITE;
break;
default:
break;
}
++nkqevents;
}
static void kqueue_del_fd (int fd)
{
if (nkqevents >= maxkqevents)
{
syslog (LOG_ERR, "too many kqevents in kqueue_del_fd!");
return;
}
kqevents[nkqevents].ident = fd;
kqevents[nkqevents].flags = EV_DELETE;
switch (fd_rw[fd])
{
case FDW_READ:
kqevents[nkqevents].filter = EVFILT_READ;
break;
case FDW_WRITE:
kqevents[nkqevents].filter = EVFILT_WRITE;
break;
}
++nkqevents;
}
static int kqueue_watch (long timeout_msecs)
{
int i, r;
if (timeout_msecs == INFTIM)
r =
kevent (kq, kqevents, nkqevents, kqrevents, nfiles,
(struct timespec *) 0);
else
{
struct timespec ts;
ts.tv_sec = timeout_msecs / 1000L;
ts.tv_nsec = (timeout_msecs % 1000L) * 1000000L;
r = kevent (kq, kqevents, nkqevents, kqrevents, nfiles, &ts);
}
nkqevents = 0;
if (r == -1)
return -1;
for (i = 0; i < r; ++i)
kqrfdidx[kqrevents[i].ident] = i;
return r;
}
static int kqueue_check_fd (int fd)
{
int ridx = kqrfdidx[fd];
if (ridx < 0 || ridx >= nfiles)
{
syslog (LOG_ERR, "bad ridx (%d) in kqueue_check_fd!", ridx);
return 0;
}
if (ridx >= nreturned)
return 0;
if (kqrevents[ridx].ident != fd)
return 0;
if (kqrevents[ridx].flags & EV_ERROR)
return 0;
switch (fd_rw[fd])
{
case FDW_READ:
return kqrevents[ridx].filter == EVFILT_READ;
case FDW_WRITE:
return kqrevents[ridx].filter == EVFILT_WRITE;
default:
return 0;
}
}
static int kqueue_get_fd (int ridx)
{
if (ridx < 0 || ridx >= nfiles)
{
syslog (LOG_ERR, "bad ridx (%d) in kqueue_get_fd!", ridx);
return -1;
}
return kqrevents[ridx].ident;
}
#else /* HAVE_KQUEUE */
#ifdef HAVE_DEVPOLL
static int maxdpevents;
static struct pollfd *dpevents;
static int ndpevents;
static struct pollfd *dprevents;
static int *dp_rfdidx;
static int dp;
static int devpoll_init (int nfiles)
{
dp = open ("/dev/poll", O_RDWR);
if (dp == -1)
return -1;
(void) fcntl (dp, F_SETFD, 1);
maxdpevents = nfiles * 2;
dpevents = (struct pollfd *) malloc (sizeof (struct pollfd) * maxdpevents);
dprevents = (struct pollfd *) malloc (sizeof (struct pollfd) * nfiles);
dp_rfdidx = (int *) malloc (sizeof (int) * nfiles);
if (dpevents == (struct pollfd *) 0 || dprevents == (struct pollfd *) 0 ||
dp_rfdidx == (int *) 0)
return -1;
(void) memset (dp_rfdidx, 0, sizeof (int) * nfiles);
return 0;
}
static void devpoll_add_fd (int fd, int rw)
{
if (ndpevents >= maxdpevents)
{
syslog (LOG_ERR, "too many fds in devpoll_add_fd!");
return;
}
dpevents[ndpevents].fd = fd;
switch (rw)
{
case FDW_READ:
dpevents[ndpevents].events = POLLIN;
break;
case FDW_WRITE:
dpevents[ndpevents].events = POLLOUT;
break;
default:
break;
}
++ndpevents;
}
static void devpoll_del_fd (int fd)
{
if (ndpevents >= maxdpevents)
{
syslog (LOG_ERR, "too many fds in devpoll_del_fd!");
return;
}
dpevents[ndpevents].fd = fd;
dpevents[ndpevents].events = POLLREMOVE;
++ndpevents;
}
static int devpoll_watch (long timeout_msecs)
{
int i, r;
struct dvpoll dvp;
r = sizeof (struct pollfd) * ndpevents;
if (r > 0 && write (dp, dpevents, r) != r)
return -1;
ndpevents = 0;
dvp.dp_fds = dprevents;
dvp.dp_nfds = nfiles;
dvp.dp_timeout = (int) timeout_msecs;
r = ioctl (dp, DP_POLL, &dvp);
if (r == -1)
return -1;
for (i = 0; i < r; ++i)
dp_rfdidx[dprevents[i].fd] = i;
return r;
}
static int devpoll_check_fd (int fd)
{
int ridx = dp_rfdidx[fd];
if (ridx < 0 || ridx >= nfiles)
{
syslog (LOG_ERR, "bad ridx (%d) in devpoll_check_fd!", ridx);
return 0;
}
if (ridx >= nreturned)
return 0;
if (dprevents[ridx].fd != fd)
return 0;
if (dprevents[ridx].revents & POLLERR)
return 0;
switch (fd_rw[fd])
{
case FDW_READ:
return dprevents[ridx].revents & (POLLIN | POLLHUP | POLLNVAL);
case FDW_WRITE:
return dprevents[ridx].revents & (POLLOUT | POLLHUP | POLLNVAL);
default:
return 0;
}
}
static int devpoll_get_fd (int ridx)
{
if (ridx < 0 || ridx >= nfiles)
{
syslog (LOG_ERR, "bad ridx (%d) in devpoll_get_fd!", ridx);
return -1;
}
return dprevents[ridx].fd;
}
#else /* HAVE_DEVPOLL */
#ifdef HAVE_POLL
static struct pollfd *pollfds;
static int npoll_fds;
static int *poll_fdidx;
static int *poll_rfdidx;
static int poll_init (int nfiles)
{
int i;
pollfds = (struct pollfd *) malloc (sizeof (struct pollfd) * nfiles);
poll_fdidx = (int *) malloc (sizeof (int) * nfiles);
poll_rfdidx = (int *) malloc (sizeof (int) * nfiles);
if (pollfds == (struct pollfd *) 0 || poll_fdidx == (int *) 0 ||
poll_rfdidx == (int *) 0)
return -1;
for (i = 0; i < nfiles; ++i)
pollfds[i].fd = poll_fdidx[i] = -1;
return 0;
}
static void poll_add_fd (int fd, int rw)
{
if (npoll_fds >= nfiles)
{
syslog (LOG_ERR, "too many fds in poll_add_fd!");
return;
}
pollfds[npoll_fds].fd = fd;
switch (rw)
{
case FDW_READ:
pollfds[npoll_fds].events = POLLIN;
break;
case FDW_WRITE:
pollfds[npoll_fds].events = POLLOUT;
break;
default:
break;
}
poll_fdidx[fd] = npoll_fds;
++npoll_fds;
}
static void poll_del_fd (int fd)
{
int idx = poll_fdidx[fd];
if (idx < 0 || idx >= nfiles)
{
syslog (LOG_ERR, "bad idx (%d) in poll_del_fd!", idx);
return;
}
--npoll_fds;
pollfds[idx] = pollfds[npoll_fds];
poll_fdidx[pollfds[idx].fd] = idx;
pollfds[npoll_fds].fd = -1;
poll_fdidx[fd] = -1;
}
static int poll_watch (long timeout_msecs)
{
int r, ridx, i;
r = poll (pollfds, npoll_fds, (int) timeout_msecs);
if (r <= 0)
return r;
ridx = 0;
for (i = 0; i < npoll_fds; ++i)
if (pollfds[i].revents &
(POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL))
{
poll_rfdidx[ridx++] = pollfds[i].fd;
if (ridx == r)
break;
}
return ridx; /* should be equal to r */
}
static int poll_check_fd (int fd)
{
int fdidx = poll_fdidx[fd];
if (fdidx < 0 || fdidx >= nfiles)
{
syslog (LOG_ERR, "bad fdidx (%d) in poll_check_fd!", fdidx);
return 0;
}
if (pollfds[fdidx].revents & POLLERR)
return 0;
switch (fd_rw[fd])
{
case FDW_READ:
return pollfds[fdidx].revents & (POLLIN | POLLHUP | POLLNVAL);
case FDW_WRITE:
return pollfds[fdidx].revents & (POLLOUT | POLLHUP | POLLNVAL);
default:
return 0;
}
}
static int poll_get_fd (int ridx)
{
if (ridx < 0 || ridx >= nfiles)
{
syslog (LOG_ERR, "bad ridx (%d) in poll_get_fd!", ridx);
return -1;
}
return poll_rfdidx[ridx];
}
#else /* HAVE_POLL */
#ifdef HAVE_SELECT
static fd_set master_rfdset;
static fd_set master_wfdset;
static fd_set working_rfdset;
static fd_set working_wfdset;
static int *select_fds;
static int *select_fdidx;
static int *select_rfdidx;
static int nselect_fds;
static int maxfd;
static int maxfd_changed;
static int select_init (int nfiles)
{
int i;
FD_ZERO (&master_rfdset);
FD_ZERO (&master_wfdset);
select_fds = (int *) malloc (sizeof (int) * nfiles);
select_fdidx = (int *) malloc (sizeof (int) * nfiles);
select_rfdidx = (int *) malloc (sizeof (int) * nfiles);
if (select_fds == (int *) 0 || select_fdidx == (int *) 0 ||
select_rfdidx == (int *) 0)
return -1;
nselect_fds = 0;
maxfd = -1;
maxfd_changed = 0;
for (i = 0; i < nfiles; ++i)
select_fds[i] = select_fdidx[i] = -1;
return 0;
}
static void select_add_fd (int fd, int rw)
{
if (nselect_fds >= nfiles)
{
syslog (LOG_ERR, "too many fds in select_add_fd!");
return;
}
select_fds[nselect_fds] = fd;
switch (rw)
{
case FDW_READ:
FD_SET (fd, &master_rfdset);
break;
case FDW_WRITE:
FD_SET (fd, &master_wfdset);
break;
default:
break;
}
if (fd > maxfd)
maxfd = fd;
select_fdidx[fd] = nselect_fds;
++nselect_fds;
}
static void select_del_fd (int fd)
{
int idx = select_fdidx[fd];
if (idx < 0 || idx >= nfiles)
{
syslog (LOG_ERR, "bad idx (%d) in select_del_fd!", idx);
return;
}
--nselect_fds;
select_fds[idx] = select_fds[nselect_fds];
select_fdidx[select_fds[idx]] = idx;
select_fds[nselect_fds] = -1;
select_fdidx[fd] = -1;
FD_CLR (fd, &master_rfdset);
FD_CLR (fd, &master_wfdset);
if (fd >= maxfd)
maxfd_changed = 1;
}
static int select_get_maxfd (void)
{
if (maxfd_changed)
{
int i;
maxfd = -1;
for (i = 0; i < nselect_fds; ++i)
if (select_fds[i] > maxfd)
maxfd = select_fds[i];
maxfd_changed = 0;
}
return maxfd;
}
static int select_watch (long timeout_msecs)
{
int mfd;
int r, idx, ridx;
working_rfdset = master_rfdset;
working_wfdset = master_wfdset;
mfd = select_get_maxfd ();
if (timeout_msecs == INFTIM)
r = select (mfd + 1, &working_rfdset, &working_wfdset, (fd_set *) 0,
(struct timeval *) 0);
else
{
struct timeval timeout;
timeout.tv_sec = timeout_msecs / 1000L;
timeout.tv_usec = (timeout_msecs % 1000L) * 1000L;
r =
select (mfd + 1, &working_rfdset, &working_wfdset, (fd_set *) 0,
&timeout);
}
if (r <= 0)
return r;
ridx = 0;
for (idx = 0; idx < nselect_fds; ++idx)
if (select_check_fd (select_fds[idx]))
{
select_rfdidx[ridx++] = select_fds[idx];
if (ridx == r)
break;
}
return ridx; /* should be equal to r */
}
static int select_check_fd (int fd)
{
switch (fd_rw[fd])
{
case FDW_READ:
return FD_ISSET (fd, &working_rfdset);
case FDW_WRITE:
return FD_ISSET (fd, &working_wfdset);
default:
return 0;
}
}
static int select_get_fd (int ridx)
{
if (ridx < 0 || ridx >= nfiles)
{
syslog (LOG_ERR, "bad ridx (%d) in select_get_fd!", ridx);
return -1;
}
return select_rfdidx[ridx];
}
#endif /* HAVE_SELECT */
#endif /* HAVE_POLL */
#endif /* HAVE_DEVPOLL */
#endif /* HAVE_KQUEUE */

85
gb.httpd/src/fdwatch.h Normal file
View File

@ -0,0 +1,85 @@
/* fdwatch.h - header file for fdwatch package
**
** This package abstracts the use of the select()/poll()/kqueue()
** system calls. The basic function of these calls is to watch a set
** of file descriptors for activity. select() originated in the BSD world,
** while poll() came from SysV land, and their interfaces are somewhat
** different. fdwatch lets you write your code to a single interface,
** with the portability differences hidden inside the package.
**
** Usage is fairly simple. Call fdwatch_get_nfiles() to initialize
** the package and find out how many fine descriptors are available.
** Then each time through your main loop, call fdwatch_clear(), then
** fdwatch_add_fd() for each of the descriptors you want to watch,
** then call fdwatch() to actually perform the watch. After it returns
** you can check which descriptors are ready via fdwatch_check_fd().
**
** If your descriptor set hasn't changed from the last time through
** the loop, you can skip calling fdwatch_clear() and fdwatch_add_fd()
** to save a little CPU time.
**
**
** Copyright © 1999 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#ifndef _FDWATCH_H_
#define _FDWATCH_H_
#define FDW_READ 0
#define FDW_WRITE 1
#ifndef INFTIM
#define INFTIM -1
#endif /* INFTIM */
/* Figure out how many file descriptors the system allows, and
** initialize the fdwatch data structures. Returns -1 on failure.
*/
extern int fdwatch_get_nfiles (void);
/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */
extern void fdwatch_add_fd (int fd, void *client_data, int rw);
/* Delete a descriptor from the watch list. */
extern void fdwatch_del_fd (int fd);
/* Do the watch. Return value is the number of descriptors that are ready,
** or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means
** wait indefinitely.
*/
extern int fdwatch (long timeout_msecs);
/* Check if a descriptor was ready. */
extern int fdwatch_check_fd (int fd);
/* Get the client data for the next returned event. Returns -1 when there
** are no more events.
*/
extern void *fdwatch_get_next_client_data (void);
/* Generate debugging statistics syslog message. */
extern void fdwatch_logstats (long secs);
#endif /* _FDWATCH_H_ */

View File

@ -0,0 +1,3 @@
[Component]
Author=
Alpha=1

4308
gb.httpd/src/libhttpd.c Normal file

File diff suppressed because it is too large Load Diff

294
gb.httpd/src/libhttpd.h Normal file
View File

@ -0,0 +1,294 @@
/* libhttpd.h - defines for libhttpd
**
** Copyright <EFBFBD> 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#ifndef _LIBHTTPD_H_
#define _LIBHTTPD_H_
#include <sys/types.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
#define USE_IPV6
#endif
/* A few convenient defines. */
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#define NEW(t,n) ((t*) malloc( sizeof(t) * (n) ))
#define RENEW(o,t,n) ((t*) realloc( (void*) o, sizeof(t) * (n) ))
/* The httpd structs. */
/* A multi-family sockaddr. */
typedef union
{
struct sockaddr sa;
struct sockaddr_in sa_in;
#ifdef USE_IPV6
struct sockaddr_in6 sa_in6;
struct sockaddr_storage sa_stor;
#endif /* USE_IPV6 */
} httpd_sockaddr;
/* A server. */
typedef struct
{
char *binding_hostname;
char *server_hostname;
unsigned short port;
char *cgi_pattern;
int cgi_limit, cgi_timelimit, cgi_count;
char *charset;
char *p3p;
int max_age;
char *cwd;
int listen4_fd, listen6_fd;
int no_log;
FILE *logfp;
int no_symlink_check;
int vhost;
int global_passwd;
char *url_pattern;
char *local_pattern;
int no_empty_referers;
} httpd_server;
/* A connection. */
typedef struct
{
int initialized;
httpd_server *hs;
httpd_sockaddr client_addr;
char *read_buf;
size_t read_size, read_idx, checked_idx;
int checked_state;
int method;
int status;
off_t bytes_to_send;
off_t bytes_sent;
char *encodedurl;
char *decodedurl;
char *protocol;
char *origfilename;
char *expnfilename;
char *encodings;
char *pathinfo;
char *query;
char *referer;
char *useragent;
char *accept;
char *accepte;
char *acceptl;
char *cookie;
char *contenttype;
#ifdef X_CGI_HEADER
char *xcgi;
#endif
char *reqhost;
char *hdrhost;
char *hostdir;
char *authorization;
char *remoteuser;
char *response;
size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings,
maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir,
maxremoteuser, maxresponse;
#ifdef TILDE_MAP_2
char *altdir;
size_t maxaltdir;
#endif /* TILDE_MAP_2 */
size_t responselen;
time_t if_modified_since, range_if;
size_t contentlength;
char *type; /* not malloc()ed */
char *hostname; /* not malloc()ed */
int mime_flag;
int one_one; /* HTTP/1.1 or better */
int got_range;
int tildemapped; /* this connection got tilde-mapped */
off_t first_byte_index, last_byte_index;
int keep_alive;
int should_linger;
struct stat sb;
int conn_fd;
char *file_address;
} httpd_conn;
/* Methods. */
#define METHOD_UNKNOWN 0
#define METHOD_GET 1
#define METHOD_HEAD 2
#define METHOD_POST 3
/* States for checked_state. */
#define CHST_FIRSTWORD 0
#define CHST_FIRSTWS 1
#define CHST_SECONDWORD 2
#define CHST_SECONDWS 3
#define CHST_THIRDWORD 4
#define CHST_THIRDWS 5
#define CHST_LINE 6
#define CHST_LF 7
#define CHST_CR 8
#define CHST_CRLF 9
#define CHST_CRLFCR 10
#define CHST_BOGUS 11
/* Initializes. Does the socket(), bind(), and listen(). Returns an
** httpd_server* which includes a socket fd that you can select() on.
** Return (httpd_server*) 0 on error.
*/
extern httpd_server *httpd_initialize (char *hostname, httpd_sockaddr * sa4P,
httpd_sockaddr * sa6P,
unsigned short port, char *cgi_pattern,
int cgi_limit, int cgi_timelimit,
char *charset, char *p3p, int max_age,
char *cwd, int no_log, FILE * logfp,
int no_symlink_check, int vhost,
int global_passwd, char *url_pattern,
char *local_pattern,
int no_empty_referers);
/* Change the log file. */
extern void httpd_set_logfp (httpd_server * hs, FILE * logfp);
/* Call to unlisten/close socket(s) listening for new connections. */
extern void httpd_unlisten (httpd_server * hs);
/* Call to shut down. */
extern void httpd_terminate (httpd_server * hs);
/* When a listen fd is ready to read, call this. It does the accept() and
** returns an httpd_conn* which includes the fd to read the request from and
** write the response to. Returns an indication of whether the accept()
** failed, succeeded, or if there were no more connections to accept.
**
** In order to minimize malloc()s, the caller passes in the httpd_conn.
** The caller is also responsible for setting initialized to zero before the
** first call using each different httpd_conn.
*/
extern int httpd_get_conn (httpd_server * hs, int listen_fd, httpd_conn * hc);
#define GC_FAIL 0
#define GC_OK 1
#define GC_NO_MORE 2
/* Checks whether the data in hc->read_buf constitutes a complete request
** yet. The caller reads data into hc->read_buf[hc->read_idx] and advances
** hc->read_idx. This routine checks what has been read so far, using
** hc->checked_idx and hc->checked_state to keep track, and returns an
** indication of whether there is no complete request yet, there is a
** complete request, or there won't be a valid request due to a syntax error.
*/
extern int httpd_got_request (httpd_conn * hc);
#define GR_NO_REQUEST 0
#define GR_GOT_REQUEST 1
#define GR_BAD_REQUEST 2
/* Parses the request in hc->read_buf. Fills in lots of fields in hc,
** like the URL and the various headers.
**
** Returns -1 on error.
*/
extern int httpd_parse_request (httpd_conn * hc);
/* Starts sending data back to the client. In some cases (directories,
** CGI programs), finishes sending by itself - in those cases, hc->file_fd
** is <0. If there is more data to be sent, then hc->file_fd is a file
** descriptor for the file to send. If you don't have a current timeval
** handy just pass in 0.
**
** Returns -1 on error.
*/
extern int httpd_start_request (httpd_conn * hc, struct timeval *nowP);
/* Actually sends any buffered response text. */
extern void httpd_write_response (httpd_conn * hc);
/* Call this to close down a connection and free the data. A fine point,
** if you fork() with a connection open you should still call this in the
** parent process - the connection will stay open in the child.
** If you don't have a current timeval handy just pass in 0.
*/
extern void httpd_close_conn (httpd_conn * hc, struct timeval *nowP);
/* Call this to de-initialize a connection struct and *really* free the
** mallocced strings.
*/
extern void httpd_destroy_conn (httpd_conn * hc);
/* Send an error message back to the client. */
extern void httpd_send_err (httpd_conn * hc, int status, char *title,
char *extraheads, char *form, char *arg);
/* Some error messages. */
extern char *httpd_err400title;
extern char *httpd_err400form;
extern char *httpd_err408title;
extern char *httpd_err408form;
extern char *httpd_err503title;
extern char *httpd_err503form;
/* Generate a string representation of a method number. */
extern char *httpd_method_str (int method);
/* Reallocate a string. */
extern void httpd_realloc_str (char **strP, size_t * maxsizeP, size_t size);
/* Format a network socket to a string representation. */
extern char *httpd_ntoa (httpd_sockaddr * saP);
/* Set NDELAY mode on a socket. */
extern void httpd_set_ndelay (int fd);
/* Clear NDELAY mode on a socket. */
extern void httpd_clear_ndelay (int fd);
/* Read the requested buffer completely, accounting for interruptions. */
extern int httpd_read_fully (int fd, void *buf, size_t nbytes);
/* Write the requested buffer completely, accounting for interruptions. */
extern int httpd_write_fully (int fd, const void *buf, size_t nbytes);
/* Generate debugging statistics syslog message. */
extern void httpd_logstats (long secs);
#endif /* _LIBHTTPD_H_ */

71
gb.httpd/src/main.c Normal file
View File

@ -0,0 +1,71 @@
/***************************************************************************
main.c
gb.httpd component
(c) 2012 Benoît Minisini <gambas@users.sourceforge.net>
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., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __MAIN_C
#include "gb_common.h"
#include <setjmp.h>
#include "main.h"
int thttpd_main (int argc, char **argv);
const GB_INTERFACE *GB_PTR EXPORT;
static jmp_buf _setjmp_env;
void syslog (int priority, const char *format, ...)
{
va_list args;
va_start (args, format);
fprintf (stderr, "gb.httpd: ");
vfprintf (stderr, format, args);
putc ('\n', stderr);
}
void run_cgi (void)
{
longjmp (_setjmp_env, 1);
}
void EXPORT GB_MAIN (int argc, char **argv)
{
if (setjmp (_setjmp_env) == 0)
thttpd_main (argc, argv);
else
GB.System.HasForked ();
}
int EXPORT GB_INIT ()
{
return 0;
}
void EXPORT GB_EXIT ()
{
}

51
gb.httpd/src/main.h Normal file
View File

@ -0,0 +1,51 @@
/***************************************************************************
main.h
gb.httpd component
(c) 2012 Benoît Minisini <gambas@users.sourceforge.net>
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., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#ifndef __MAIN_H
#define __MAIN_H
#include "gambas.h"
#ifndef __MAIN_C
extern const GB_INTERFACE *GB_PTR;
#endif
#define GB (*GB_PTR)
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
void syslog (int priority, const char *format, ...);
#define closelog()
void run_cgi ();
#endif /* __MAIN_H */

87
gb.httpd/src/match.c Normal file
View File

@ -0,0 +1,87 @@
/* match.c - simple shell-style filename matcher
**
** Only does ? * and **, and multiple patterns separated by |. Returns 1 or 0.
**
** Copyright © 1995,2000 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#include <string.h>
#include "match.h"
static int match_one (const char *pattern, int patternlen,
const char *string);
int match (const char *pattern, const char *string)
{
const char *or;
for (;;)
{
or = strchr (pattern, '|');
if (or == (char *) 0)
return match_one (pattern, strlen (pattern), string);
if (match_one (pattern, or - pattern, string))
return 1;
pattern = or + 1;
}
}
static int match_one (const char *pattern, int patternlen, const char *string)
{
const char *p;
for (p = pattern; p - pattern < patternlen; ++p, ++string)
{
if (*p == '?' && *string != '\0')
continue;
if (*p == '*')
{
int i, pl;
++p;
if (*p == '*')
{
/* Double-wildcard matches anything. */
++p;
i = strlen (string);
}
else
/* Single-wildcard matches anything but slash. */
i = strcspn (string, "/");
pl = patternlen - (p - pattern);
for (; i >= 0; --i)
if (match_one (p, pl, &(string[i])))
return 1;
return 0;
}
if (*p != *string)
return 0;
}
if (*string == '\0')
return 1;
return 0;
}

36
gb.httpd/src/match.h Normal file
View File

@ -0,0 +1,36 @@
/* match.h - simple shell-style filename patcher
**
** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#ifndef _MATCH_H_
#define _MATCH_H_
/* Simple shell-style filename pattern matcher. Only does ? * and **, and
** multiple patterns separated by |. Returns 1 or 0.
*/
extern int match (const char *pattern, const char *string);
#endif /* _MATCH_H_ */

View File

@ -0,0 +1,8 @@
{
"Z", 0, "compress", 0},
{
"gz", 0, "gzip", 0},
{
"uu", 0, "x-uuencode", 0},

569
gb.httpd/src/mime_types.h Normal file
View File

@ -0,0 +1,569 @@
{
"a", 0, "application/octet-stream", 0},
{
"aab", 0, "application/x-authorware-bin", 0},
{
"aam", 0, "application/x-authorware-map", 0},
{
"aas", 0, "application/x-authorware-seg", 0},
{
"ai", 0, "application/postscript", 0},
{
"aif", 0, "audio/x-aiff", 0},
{
"aifc", 0, "audio/x-aiff", 0},
{
"aiff", 0, "audio/x-aiff", 0},
{
"asc", 0, "text/plain", 0},
{
"asf", 0, "video/x-ms-asf", 0},
{
"asx", 0, "video/x-ms-asf", 0},
{
"au", 0, "audio/basic", 0},
{
"avi", 0, "video/x-msvideo", 0},
{
"bcpio", 0, "application/x-bcpio", 0},
{
"bin", 0, "application/octet-stream", 0},
{
"bmp", 0, "image/bmp", 0},
{
"cdf", 0, "application/x-netcdf", 0},
{
"class", 0, "application/x-java-vm", 0},
{
"cpio", 0, "application/x-cpio", 0},
{
"cpt", 0, "application/mac-compactpro", 0},
{
"crl", 0, "application/x-pkcs7-crl", 0},
{
"crt", 0, "application/x-x509-ca-cert", 0},
{
"csh", 0, "application/x-csh", 0},
{
"css", 0, "text/css", 0},
{
"dcr", 0, "application/x-director", 0},
{
"dir", 0, "application/x-director", 0},
{
"djv", 0, "image/vnd.djvu", 0},
{
"djvu", 0, "image/vnd.djvu", 0},
{
"dll", 0, "application/octet-stream", 0},
{
"dms", 0, "application/octet-stream", 0},
{
"doc", 0, "application/msword", 0},
{
"dtd", 0, "text/xml", 0},
{
"dump", 0, "application/octet-stream", 0},
{
"dvi", 0, "application/x-dvi", 0},
{
"dxr", 0, "application/x-director", 0},
{
"eps", 0, "application/postscript", 0},
{
"etx", 0, "text/x-setext", 0},
{
"exe", 0, "application/octet-stream", 0},
{
"ez", 0, "application/andrew-inset", 0},
{
"fgd", 0, "application/x-director", 0},
{
"fh", 0, "image/x-freehand", 0},
{
"fh4", 0, "image/x-freehand", 0},
{
"fh5", 0, "image/x-freehand", 0},
{
"fh7", 0, "image/x-freehand", 0},
{
"fhc", 0, "image/x-freehand", 0},
{
"gif", 0, "image/gif", 0},
{
"gtar", 0, "application/x-gtar", 0},
{
"hdf", 0, "application/x-hdf", 0},
{
"hqx", 0, "application/mac-binhex40", 0},
{
"htm", 0, "text/html; charset=%s", 0},
{
"html", 0, "text/html; charset=%s", 0},
{
"ice", 0, "x-conference/x-cooltalk", 0},
{
"ief", 0, "image/ief", 0},
{
"iges", 0, "model/iges", 0},
{
"igs", 0, "model/iges", 0},
{
"iv", 0, "application/x-inventor", 0},
{
"jar", 0, "application/x-java-archive", 0},
{
"jfif", 0, "image/jpeg", 0},
{
"jpe", 0, "image/jpeg", 0},
{
"jpeg", 0, "image/jpeg", 0},
{
"jpg", 0, "image/jpeg", 0},
{
"js", 0, "application/x-javascript", 0},
{
"kar", 0, "audio/midi", 0},
{
"latex", 0, "application/x-latex", 0},
{
"lha", 0, "application/octet-stream", 0},
{
"lzh", 0, "application/octet-stream", 0},
{
"m3u", 0, "audio/x-mpegurl", 0},
{
"man", 0, "application/x-troff-man", 0},
{
"mathml", 0, "application/mathml+xml", 0},
{
"me", 0, "application/x-troff-me", 0},
{
"mesh", 0, "model/mesh", 0},
{
"mid", 0, "audio/midi", 0},
{
"midi", 0, "audio/midi", 0},
{
"mif", 0, "application/vnd.mif", 0},
{
"mime", 0, "message/rfc822", 0},
{
"mml", 0, "application/mathml+xml", 0},
{
"mov", 0, "video/quicktime", 0},
{
"movie", 0, "video/x-sgi-movie", 0},
{
"mp2", 0, "audio/mpeg", 0},
{
"mp3", 0, "audio/mpeg", 0},
{
"mp4", 0, "video/mp4", 0},
{
"mpe", 0, "video/mpeg", 0},
{
"mpeg", 0, "video/mpeg", 0},
{
"mpg", 0, "video/mpeg", 0},
{
"mpga", 0, "audio/mpeg", 0},
{
"ms", 0, "application/x-troff-ms", 0},
{
"msh", 0, "model/mesh", 0},
{
"mv", 0, "video/x-sgi-movie", 0},
{
"mxu", 0, "video/vnd.mpegurl", 0},
{
"nc", 0, "application/x-netcdf", 0},
{
"o", 0, "application/octet-stream", 0},
{
"oda", 0, "application/oda", 0},
{
"ogg", 0, "application/x-ogg", 0},
{
"pac", 0, "application/x-ns-proxy-autoconfig", 0},
{
"pbm", 0, "image/x-portable-bitmap", 0},
{
"pdb", 0, "chemical/x-pdb", 0},
{
"pdf", 0, "application/pdf", 0},
{
"pgm", 0, "image/x-portable-graymap", 0},
{
"pgn", 0, "application/x-chess-pgn", 0},
{
"png", 0, "image/png", 0},
{
"pnm", 0, "image/x-portable-anymap", 0},
{
"ppm", 0, "image/x-portable-pixmap", 0},
{
"ppt", 0, "application/vnd.ms-powerpoint", 0},
{
"ps", 0, "application/postscript", 0},
{
"qt", 0, "video/quicktime", 0},
{
"ra", 0, "audio/x-realaudio", 0},
{
"ram", 0, "audio/x-pn-realaudio", 0},
{
"ras", 0, "image/x-cmu-raster", 0},
{
"rdf", 0, "application/rdf+xml", 0},
{
"rgb", 0, "image/x-rgb", 0},
{
"rm", 0, "audio/x-pn-realaudio", 0},
{
"roff", 0, "application/x-troff", 0},
{
"rpm", 0, "audio/x-pn-realaudio-plugin", 0},
{
"rss", 0, "application/rss+xml", 0},
{
"rtf", 0, "text/rtf", 0},
{
"rtx", 0, "text/richtext", 0},
{
"sgm", 0, "text/sgml", 0},
{
"sgml", 0, "text/sgml", 0},
{
"sh", 0, "application/x-sh", 0},
{
"shar", 0, "application/x-shar", 0},
{
"silo", 0, "model/mesh", 0},
{
"sit", 0, "application/x-stuffit", 0},
{
"skd", 0, "application/x-koan", 0},
{
"skm", 0, "application/x-koan", 0},
{
"skp", 0, "application/x-koan", 0},
{
"skt", 0, "application/x-koan", 0},
{
"smi", 0, "application/smil", 0},
{
"smil", 0, "application/smil", 0},
{
"snd", 0, "audio/basic", 0},
{
"so", 0, "application/octet-stream", 0},
{
"spl", 0, "application/x-futuresplash", 0},
{
"src", 0, "application/x-wais-source", 0},
{
"stc", 0, "application/vnd.sun.xml.calc.template", 0},
{
"std", 0, "application/vnd.sun.xml.draw.template", 0},
{
"sti", 0, "application/vnd.sun.xml.impress.template", 0},
{
"stw", 0, "application/vnd.sun.xml.writer.template", 0},
{
"sv4cpio", 0, "application/x-sv4cpio", 0},
{
"sv4crc", 0, "application/x-sv4crc", 0},
{
"svg", 0, "image/svg+xml", 0},
{
"svgz", 0, "image/svg+xml", 0},
{
"swf", 0, "application/x-shockwave-flash", 0},
{
"sxc", 0, "application/vnd.sun.xml.calc", 0},
{
"sxd", 0, "application/vnd.sun.xml.draw", 0},
{
"sxg", 0, "application/vnd.sun.xml.writer.global", 0},
{
"sxi", 0, "application/vnd.sun.xml.impress", 0},
{
"sxm", 0, "application/vnd.sun.xml.math", 0},
{
"sxw", 0, "application/vnd.sun.xml.writer", 0},
{
"t", 0, "application/x-troff", 0},
{
"tar", 0, "application/x-tar", 0},
{
"tcl", 0, "application/x-tcl", 0},
{
"tex", 0, "application/x-tex", 0},
{
"texi", 0, "application/x-texinfo", 0},
{
"texinfo", 0, "application/x-texinfo", 0},
{
"tif", 0, "image/tiff", 0},
{
"tiff", 0, "image/tiff", 0},
{
"tr", 0, "application/x-troff", 0},
{
"tsp", 0, "application/dsptype", 0},
{
"tsv", 0, "text/tab-separated-values", 0},
{
"txt", 0, "text/plain; charset=%s", 0},
{
"ustar", 0, "application/x-ustar", 0},
{
"vcd", 0, "application/x-cdlink", 0},
{
"vrml", 0, "model/vrml", 0},
{
"vx", 0, "video/x-rad-screenplay", 0},
{
"wav", 0, "audio/x-wav", 0},
{
"wax", 0, "audio/x-ms-wax", 0},
{
"wbmp", 0, "image/vnd.wap.wbmp", 0},
{
"wbxml", 0, "application/vnd.wap.wbxml", 0},
{
"wm", 0, "video/x-ms-wm", 0},
{
"wma", 0, "audio/x-ms-wma", 0},
{
"wmd", 0, "application/x-ms-wmd", 0},
{
"wml", 0, "text/vnd.wap.wml", 0},
{
"wmlc", 0, "application/vnd.wap.wmlc", 0},
{
"wmls", 0, "text/vnd.wap.wmlscript", 0},
{
"wmlsc", 0, "application/vnd.wap.wmlscriptc", 0},
{
"wmv", 0, "video/x-ms-wmv", 0},
{
"wmx", 0, "video/x-ms-wmx", 0},
{
"wmz", 0, "application/x-ms-wmz", 0},
{
"wrl", 0, "model/vrml", 0},
{
"wsrc", 0, "application/x-wais-source", 0},
{
"wvx", 0, "video/x-ms-wvx", 0},
{
"xbm", 0, "image/x-xbitmap", 0},
{
"xht", 0, "application/xhtml+xml", 0},
{
"xhtml", 0, "application/xhtml+xml", 0},
{
"xls", 0, "application/vnd.ms-excel", 0},
{
"xml", 0, "text/xml", 0},
{
"xpm", 0, "image/x-xpixmap", 0},
{
"xsl", 0, "text/xml", 0},
{
"xwd", 0, "image/x-xwindowdump", 0},
{
"xyz", 0, "chemical/x-xyz", 0},
{
"zip", 0, "application/zip", 0},

521
gb.httpd/src/mmc.c Normal file
View File

@ -0,0 +1,521 @@
/* mmc.c - mmap cache
**
** Copyright 1998,2001 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#include "thttpd.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <syslog.h>
#include <errno.h>
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif /* HAVE_MMAP */
#include "mmc.h"
#include "libhttpd.h"
#ifndef HAVE_INT64T
typedef long long int64_t;
#endif
/* Defines. */
#ifndef DEFAULT_EXPIRE_AGE
#define DEFAULT_EXPIRE_AGE 600
#endif
#ifndef DESIRED_FREE_COUNT
#define DESIRED_FREE_COUNT 100
#endif
#ifndef DESIRED_MAX_MAPPED_FILES
#define DESIRED_MAX_MAPPED_FILES 2000
#endif
#ifndef DESIRED_MAX_MAPPED_BYTES
#define DESIRED_MAX_MAPPED_BYTES 1000000000
#endif
#ifndef INITIAL_HASH_SIZE
#define INITIAL_HASH_SIZE (1 << 10)
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
/* The Map struct. */
typedef struct MapStruct
{
ino_t ino;
dev_t dev;
off_t size;
time_t ctime;
int refcount;
time_t reftime;
void *addr;
unsigned int hash;
int hash_idx;
struct MapStruct *next;
} Map;
/* Globals. */
static Map *maps = (Map *) 0;
static Map *free_maps = (Map *) 0;
static int alloc_count = 0, map_count = 0, free_count = 0;
static Map **hash_table = (Map **) 0;
static int hash_size;
static unsigned int hash_mask;
static time_t expire_age = DEFAULT_EXPIRE_AGE;
static off_t mapped_bytes = 0;
/* Forwards. */
static void panic (void);
static void really_unmap (Map ** mm);
static int check_hash_size (void);
static int add_hash (Map * m);
static Map *find_hash (ino_t ino, dev_t dev, off_t size, time_t ctime);
static unsigned int hash (ino_t ino, dev_t dev, off_t size, time_t ctime);
void *mmc_map (char *filename, struct stat *sbP, struct timeval *nowP)
{
time_t now;
struct stat sb;
Map *m;
int fd;
/* Stat the file, if necessary. */
if (sbP != (struct stat *) 0)
sb = *sbP;
else
{
if (stat (filename, &sb) != 0)
{
syslog (LOG_ERR, "stat - %m");
return (void *) 0;
}
}
/* Get the current time, if necessary. */
if (nowP != (struct timeval *) 0)
now = nowP->tv_sec;
else
now = time ((time_t *) 0);
/* See if we have it mapped already, via the hash table. */
if (check_hash_size () < 0)
{
syslog (LOG_ERR, "check_hash_size() failure");
return (void *) 0;
}
m = find_hash (sb.st_ino, sb.st_dev, sb.st_size, sb.st_ctime);
if (m != (Map *) 0)
{
/* Yep. Just return the existing map */
++m->refcount;
m->reftime = now;
return m->addr;
}
/* Open the file. */
fd = open (filename, O_RDONLY);
if (fd < 0)
{
syslog (LOG_ERR, "open - %m");
return (void *) 0;
}
/* Find a free Map entry or make a new one. */
if (free_maps != (Map *) 0)
{
m = free_maps;
free_maps = m->next;
--free_count;
}
else
{
m = (Map *) malloc (sizeof (Map));
if (m == (Map *) 0)
{
(void) close (fd);
syslog (LOG_ERR, "out of memory allocating a Map");
return (void *) 0;
}
++alloc_count;
}
/* Fill in the Map entry. */
m->ino = sb.st_ino;
m->dev = sb.st_dev;
m->size = sb.st_size;
m->ctime = sb.st_ctime;
m->refcount = 1;
m->reftime = now;
/* Avoid doing anything for zero-length files; some systems don't like
** to mmap them, other systems dislike mallocing zero bytes.
*/
if (m->size == 0)
m->addr = (void *) 1; /* arbitrary non-NULL address */
else
{
size_t size_size = (size_t) m->size; /* loses on files >2GB */
#ifdef HAVE_MMAP
/* Map the file into memory. */
m->addr = mmap (0, size_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (m->addr == (void *) -1 && errno == ENOMEM)
{
/* Ooo, out of address space. Free all unreferenced maps
** and try again.
*/
panic ();
m->addr = mmap (0, size_size, PROT_READ, MAP_PRIVATE, fd, 0);
}
if (m->addr == (void *) -1)
{
syslog (LOG_ERR, "mmap - %m");
(void) close (fd);
free ((void *) m);
--alloc_count;
return (void *) 0;
}
#else /* HAVE_MMAP */
/* Read the file into memory. */
m->addr = (void *) malloc (size_size);
if (m->addr == (void *) 0)
{
/* Ooo, out of memory. Free all unreferenced maps
** and try again.
*/
panic ();
m->addr = (void *) malloc (size_size);
}
if (m->addr == (void *) 0)
{
syslog (LOG_ERR, "out of memory storing a file");
(void) close (fd);
free ((void *) m);
--alloc_count;
return (void *) 0;
}
if (httpd_read_fully (fd, m->addr, size_size) != size_size)
{
syslog (LOG_ERR, "read - %m");
(void) close (fd);
free ((void *) m);
--alloc_count;
return (void *) 0;
}
#endif /* HAVE_MMAP */
}
(void) close (fd);
/* Put the Map into the hash table. */
if (add_hash (m) < 0)
{
syslog (LOG_ERR, "add_hash() failure");
free ((void *) m);
--alloc_count;
return (void *) 0;
}
/* Put the Map on the active list. */
m->next = maps;
maps = m;
++map_count;
/* Update the total byte count. */
mapped_bytes += m->size;
/* And return the address. */
return m->addr;
}
void mmc_unmap (void *addr, struct stat *sbP, struct timeval *nowP)
{
Map *m = (Map *) 0;
/* Find the Map entry for this address. First try a hash. */
if (sbP != (struct stat *) 0)
{
m = find_hash (sbP->st_ino, sbP->st_dev, sbP->st_size, sbP->st_ctime);
if (m != (Map *) 0 && m->addr != addr)
m = (Map *) 0;
}
/* If that didn't work, try a full search. */
if (m == (Map *) 0)
for (m = maps; m != (Map *) 0; m = m->next)
if (m->addr == addr)
break;
if (m == (Map *) 0)
syslog (LOG_ERR, "mmc_unmap failed to find entry!");
else if (m->refcount <= 0)
syslog (LOG_ERR, "mmc_unmap found zero or negative refcount!");
else
{
--m->refcount;
if (nowP != (struct timeval *) 0)
m->reftime = nowP->tv_sec;
else
m->reftime = time ((time_t *) 0);
}
}
void mmc_cleanup (struct timeval *nowP)
{
time_t now;
Map **mm;
Map *m;
/* Get the current time, if necessary. */
if (nowP != (struct timeval *) 0)
now = nowP->tv_sec;
else
now = time ((time_t *) 0);
/* Really unmap any unreferenced entries older than the age limit. */
for (mm = &maps; *mm != (Map *) 0;)
{
m = *mm;
if (m->refcount == 0 && now - m->reftime >= expire_age)
really_unmap (mm);
else
mm = &(*mm)->next;
}
/* Adjust the age limit if there are too many bytes mapped, or
** too many or too few files mapped.
*/
if (mapped_bytes > DESIRED_MAX_MAPPED_BYTES)
expire_age = MAX ((expire_age * 2) / 3, DEFAULT_EXPIRE_AGE / 10);
else if (map_count > DESIRED_MAX_MAPPED_FILES)
expire_age = MAX ((expire_age * 2) / 3, DEFAULT_EXPIRE_AGE / 10);
else if (map_count < DESIRED_MAX_MAPPED_FILES / 2)
expire_age = MIN ((expire_age * 5) / 4, DEFAULT_EXPIRE_AGE * 3);
/* Really free excess blocks on the free list. */
while (free_count > DESIRED_FREE_COUNT)
{
m = free_maps;
free_maps = m->next;
--free_count;
free ((void *) m);
--alloc_count;
}
}
static void panic (void)
{
Map **mm;
Map *m;
syslog (LOG_ERR, "mmc panic - freeing all unreferenced maps");
/* Really unmap all unreferenced entries. */
for (mm = &maps; *mm != (Map *) 0;)
{
m = *mm;
if (m->refcount == 0)
really_unmap (mm);
else
mm = &(*mm)->next;
}
}
static void really_unmap (Map ** mm)
{
Map *m;
m = *mm;
if (m->size != 0)
{
#ifdef HAVE_MMAP
if (munmap (m->addr, m->size) < 0)
syslog (LOG_ERR, "munmap - %m");
#else /* HAVE_MMAP */
free ((void *) m->addr);
#endif /* HAVE_MMAP */
}
/* Update the total byte count. */
mapped_bytes -= m->size;
/* And move the Map to the free list. */
*mm = m->next;
--map_count;
m->next = free_maps;
free_maps = m;
++free_count;
/* This will sometimes break hash chains, but that's harmless; the
** unmapping code that searches the hash table knows to keep searching.
*/
hash_table[m->hash_idx] = (Map *) 0;
}
void mmc_destroy (void)
{
Map *m;
while (maps != (Map *) 0)
really_unmap (&maps);
while (free_maps != (Map *) 0)
{
m = free_maps;
free_maps = m->next;
--free_count;
free ((void *) m);
--alloc_count;
}
}
/* Make sure the hash table is big enough. */
static int check_hash_size (void)
{
int i;
Map *m;
/* Are we just starting out? */
if (hash_table == (Map **) 0)
{
hash_size = INITIAL_HASH_SIZE;
hash_mask = hash_size - 1;
}
/* Is it at least three times bigger than the number of entries? */
else if (hash_size >= map_count * 3)
return 0;
else
{
/* No, got to expand. */
free ((void *) hash_table);
/* Double the hash size until it's big enough. */
do
{
hash_size = hash_size << 1;
}
while (hash_size < map_count * 6);
hash_mask = hash_size - 1;
}
/* Make the new table. */
hash_table = (Map **) malloc (hash_size * sizeof (Map *));
if (hash_table == (Map **) 0)
return -1;
/* Clear it. */
for (i = 0; i < hash_size; ++i)
hash_table[i] = (Map *) 0;
/* And rehash all entries. */
for (m = maps; m != (Map *) 0; m = m->next)
if (add_hash (m) < 0)
return -1;
return 0;
}
static int add_hash (Map * m)
{
unsigned int h, he, i;
h = hash (m->ino, m->dev, m->size, m->ctime);
he = (h + hash_size - 1) & hash_mask;
for (i = h;; i = (i + 1) & hash_mask)
{
if (hash_table[i] == (Map *) 0)
{
hash_table[i] = m;
m->hash = h;
m->hash_idx = i;
return 0;
}
if (i == he)
break;
}
return -1;
}
static Map *find_hash (ino_t ino, dev_t dev, off_t size, time_t ctime)
{
unsigned int h, he, i;
Map *m;
h = hash (ino, dev, size, ctime);
he = (h + hash_size - 1) & hash_mask;
for (i = h;; i = (i + 1) & hash_mask)
{
m = hash_table[i];
if (m == (Map *) 0)
break;
if (m->hash == h && m->ino == ino && m->dev == dev &&
m->size == size && m->ctime == ctime)
return m;
if (i == he)
break;
}
return (Map *) 0;
}
static unsigned int hash (ino_t ino, dev_t dev, off_t size, time_t ctime)
{
unsigned int h = 177573;
h ^= ino;
h += h << 5;
h ^= dev;
h += h << 5;
h ^= size;
h += h << 5;
h ^= ctime;
return h & hash_mask;
}
/* Generate debugging statistics syslog message. */
void mmc_logstats (long secs)
{
syslog (LOG_INFO,
" map cache - %d allocated, %d active (%ld bytes), %d free; hash size: %d; expire age: %ld",
alloc_count, map_count, (int64_t) mapped_bytes, free_count,
hash_size, expire_age);
if (map_count + free_count != alloc_count)
syslog (LOG_ERR, "map counts don't add up!");
}

55
gb.httpd/src/mmc.h Normal file
View File

@ -0,0 +1,55 @@
/* mmc.h - header file for mmap cache package
**
** Copyright © 1998 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#ifndef _MMC_H_
#define _MMC_H_
/* Returns an mmap()ed area for the given file, or (void*) 0 on errors.
** If you have a stat buffer on the file, pass it in, otherwise pass 0.
** Same for the current time.
*/
extern void *mmc_map (char *filename, struct stat *sbP, struct timeval *nowP);
/* Done with an mmap()ed area that was returned by mmc_map().
** If you have a stat buffer on the file, pass it in, otherwise pass 0.
** Same for the current time.
*/
extern void mmc_unmap (void *addr, struct stat *sbP, struct timeval *nowP);
/* Clean up the mmc package, freeing any unused storage.
** This should be called periodically, say every five minutes.
** If you have the current time, pass it in, otherwise pass 0.
*/
extern void mmc_cleanup (struct timeval *nowP);
/* Free all storage, usually in preparation for exitting. */
extern void mmc_destroy (void);
/* Generate debugging statistics syslog message. */
extern void mmc_logstats (long secs);
#endif /* _MMC_H_ */

37
gb.httpd/src/strerror.c Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strerror.c 5.1 (Berkeley) 4/9/89";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <stdio.h>
char *strerror (errnum)
int errnum;
{
extern int sys_nerr;
extern char *sys_errlist[];
static char ebuf[20];
if ((unsigned int) errnum < sys_nerr)
return (sys_errlist[errnum]);
(void) sprintf (ebuf, "Unknown error: %d", errnum);
return (ebuf);
}

313
gb.httpd/src/tdate_parse.c Normal file
View File

@ -0,0 +1,313 @@
/* tdate_parse - parse string dates into internal form, stripped-down version
**
** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
/* This is a stripped-down version of date_parse.c, available at
** http://www.acme.com/software/date_parse/
*/
#include <sys/types.h>
#include <ctype.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tdate_parse.h"
struct strlong
{
char *s;
long l;
};
static void pound_case (char *str)
{
for (; *str != '\0'; ++str)
{
if (isupper ((int) *str))
*str = tolower ((int) *str);
}
}
static int strlong_compare (v1, v2)
char *v1;
char *v2;
{
return strcmp (((struct strlong *) v1)->s, ((struct strlong *) v2)->s);
}
static int strlong_search (char *str, struct strlong *tab, int n, long *lP)
{
int i, h, l, r;
l = 0;
h = n - 1;
for (;;)
{
i = (h + l) / 2;
r = strcmp (str, tab[i].s);
if (r < 0)
h = i - 1;
else if (r > 0)
l = i + 1;
else
{
*lP = tab[i].l;
return 1;
}
if (h < l)
return 0;
}
}
static int scan_wday (char *str_wday, long *tm_wdayP)
{
static struct strlong wday_tab[] = {
{"sun", 0}, {"sunday", 0},
{"mon", 1}, {"monday", 1},
{"tue", 2}, {"tuesday", 2},
{"wed", 3}, {"wednesday", 3},
{"thu", 4}, {"thursday", 4},
{"fri", 5}, {"friday", 5},
{"sat", 6}, {"saturday", 6},
};
static int sorted = 0;
if (!sorted)
{
(void) qsort (wday_tab, sizeof (wday_tab) / sizeof (struct strlong),
sizeof (struct strlong), strlong_compare);
sorted = 1;
}
pound_case (str_wday);
return strlong_search (str_wday, wday_tab,
sizeof (wday_tab) / sizeof (struct strlong),
tm_wdayP);
}
static int scan_mon (char *str_mon, long *tm_monP)
{
static struct strlong mon_tab[] = {
{"jan", 0}, {"january", 0},
{"feb", 1}, {"february", 1},
{"mar", 2}, {"march", 2},
{"apr", 3}, {"april", 3},
{"may", 4},
{"jun", 5}, {"june", 5},
{"jul", 6}, {"july", 6},
{"aug", 7}, {"august", 7},
{"sep", 8}, {"september", 8},
{"oct", 9}, {"october", 9},
{"nov", 10}, {"november", 10},
{"dec", 11}, {"december", 11},
};
static int sorted = 0;
if (!sorted)
{
(void) qsort (mon_tab, sizeof (mon_tab) / sizeof (struct strlong),
sizeof (struct strlong), strlong_compare);
sorted = 1;
}
pound_case (str_mon);
return strlong_search (str_mon, mon_tab,
sizeof (mon_tab) / sizeof (struct strlong), tm_monP);
}
static int is_leap (int year)
{
return year % 400 ? (year % 100 ? (year % 4 ? 0 : 1) : 0) : 1;
}
/* Basically the same as mktime(). */
static time_t tm_to_time (struct tm *tmP)
{
time_t t;
static int monthtab[12] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
/* Years since epoch, converted to days. */
t = (tmP->tm_year - 70) * 365;
/* Leap days for previous years. */
t += (tmP->tm_year - 69) / 4;
/* Days for the beginning of this month. */
t += monthtab[tmP->tm_mon];
/* Leap day for this year. */
if (tmP->tm_mon >= 2 && is_leap (tmP->tm_year + 1900))
++t;
/* Days since the beginning of this month. */
t += tmP->tm_mday - 1; /* 1-based field */
/* Hours, minutes, and seconds. */
t = t * 24 + tmP->tm_hour;
t = t * 60 + tmP->tm_min;
t = t * 60 + tmP->tm_sec;
return t;
}
time_t tdate_parse (char *str)
{
struct tm tm;
char *cp;
char str_mon[500], str_wday[500];
int tm_sec, tm_min, tm_hour, tm_mday, tm_year;
long tm_mon, tm_wday;
time_t t;
/* Initialize. */
(void) memset ((char *) &tm, 0, sizeof (struct tm));
/* Skip initial whitespace ourselves - sscanf is clumsy at this. */
for (cp = str; *cp == ' ' || *cp == '\t'; ++cp)
continue;
/* And do the sscanfs. WARNING: you can add more formats here,
** but be careful! You can easily screw up the parsing of existing
** formats when you add new ones. The order is important.
*/
/* DD-mth-YY HH:MM:SS GMT */
if (sscanf (cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
&tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 6 && scan_mon (str_mon, &tm_mon))
{
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
/* DD mth YY HH:MM:SS GMT */
else if (sscanf (cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
&tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 6 && scan_mon (str_mon, &tm_mon))
{
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
/* HH:MM:SS GMT DD-mth-YY */
else if (sscanf (cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
&tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
&tm_year) == 6 && scan_mon (str_mon, &tm_mon))
{
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
}
/* HH:MM:SS GMT DD mth YY */
else if (sscanf (cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
&tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
&tm_year) == 6 && scan_mon (str_mon, &tm_mon))
{
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
}
/* wdy, DD-mth-YY HH:MM:SS GMT */
else if (sscanf (cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 7 &&
scan_wday (str_wday, &tm_wday) && scan_mon (str_mon, &tm_mon))
{
tm.tm_wday = tm_wday;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
/* wdy, DD mth YY HH:MM:SS GMT */
else if (sscanf (cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
&tm_sec) == 7 &&
scan_wday (str_wday, &tm_wday) && scan_mon (str_mon, &tm_mon))
{
tm.tm_wday = tm_wday;
tm.tm_mday = tm_mday;
tm.tm_mon = tm_mon;
tm.tm_year = tm_year;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
}
/* wdy mth DD HH:MM:SS GMT YY */
else if (sscanf (cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
&tm_year) == 7 &&
scan_wday (str_wday, &tm_wday) && scan_mon (str_mon, &tm_mon))
{
tm.tm_wday = tm_wday;
tm.tm_mon = tm_mon;
tm.tm_mday = tm_mday;
tm.tm_hour = tm_hour;
tm.tm_min = tm_min;
tm.tm_sec = tm_sec;
tm.tm_year = tm_year;
}
else
return (time_t) - 1;
if (tm.tm_year > 1900)
tm.tm_year -= 1900;
else if (tm.tm_year < 70)
tm.tm_year += 100;
t = tm_to_time (&tm);
return t;
}

View File

@ -0,0 +1,33 @@
/* tdate_parse.h - parse string dates into internal form, stripped-down version
**
** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#ifndef _TDATE_PARSE_H_
#define _TDATE_PARSE_H_
extern time_t tdate_parse (char *str);
#endif /* _TDATE_PARSE_H_ */

2235
gb.httpd/src/thttpd.c Normal file

File diff suppressed because it is too large Load Diff

403
gb.httpd/src/thttpd.h Normal file
View File

@ -0,0 +1,403 @@
/* config.h - configuration defines for thttpd and libhttpd
**
** Copyright <EFBFBD> 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#ifndef _THTTPD_H_
#define _THTTPD_H_
#include "config.h"
/* The following configuration settings are sorted in order of decreasing
** likelihood that you'd want to change them - most likely first, least
** likely last.
**
** In case you're not familiar with the convention, "#ifdef notdef"
** is a Berkeleyism used to indicate temporarily disabled code.
** The idea here is that you re-enable it by just moving it outside
** of the ifdef.
*/
/* CONFIGURE: CGI programs must match this pattern to get executed. It's
** a simple shell-style wildcard pattern, with * meaning any string not
** containing a slash, ** meaning any string at all, and ? meaning any
** single character; or multiple such patterns separated by |. The
** patterns get checked against the filename part of the incoming URL.
**
** Restricting CGI programs to a single directory lets the site administrator
** review them for security holes, and is strongly recommended. If there
** are individual users that you trust, you can enable their directories too.
**
** You can also specify a CGI pattern on the command line, with the -c flag.
** Such a pattern overrides this compiled-in default.
**
** If no CGI pattern is specified, neither here nor on the command line,
** then CGI programs cannot be run at all. If you want to disable CGI
** as a security measure that's how you do it, just don't define any
** pattern here and don't run with the -c flag.
*/
#ifdef notdef
/* Some sample patterns. Allow programs only in one central directory: */
#define CGI_PATTERN "/cgi-bin/*"
/* Allow programs in a central directory, or anywhere in a trusted
** user's tree: */
#define CGI_PATTERN "/cgi-bin/*|/jef/**"
/* Allow any program ending with a .cgi: */
#define CGI_PATTERN "**.cgi"
/* When virtual hosting, enable the central directory on every host: */
#define CGI_PATTERN "/*/cgi-bin/*"
#endif
/* CONFIGURE: How many seconds to allow CGI programs to run before killing
** them. This is in case someone writes a CGI program that goes into an
** infinite loop, or does a massive database lookup that would take hours,
** or whatever. If you don't want any limit, comment this out, but that's
** probably a really bad idea.
*/
#define CGI_TIMELIMIT 30
/* CONFIGURE: Maximum number of simultaneous CGI programs allowed.
** If this many are already running, then attempts to run more will
** return an HTTP 503 error. If this is not defined then there's
** no limit (and you'd better have a lot of memory). This can also be
** set in the runtime config file.
*/
#ifdef notdef
#define CGI_LIMIT 50
#endif
/* CONFIGURE: How many seconds to allow for reading the initial request
** on a new connection.
*/
#define IDLE_READ_TIMELIMIT 60
/* CONFIGURE: How many seconds before an idle connection gets closed.
*/
#define IDLE_SEND_TIMELIMIT 300
/* CONFIGURE: The syslog facility to use. Using this you can set up your
** syslog.conf so that all thttpd messages go into a separate file. Note
** that even if you use the -l command line flag to send logging to a
** file, errors still get sent via syslog.
*/
#define LOG_FACILITY LOG_DAEMON
/* CONFIGURE: Tilde mapping. Many URLs use ~username to indicate a
** user's home directory. thttpd provides two options for mapping
** this construct to an actual filename.
**
** 1) Map ~username to <prefix>/username. This is the recommended choice.
** Each user gets a subdirectory in the main chrootable web tree, and
** the tilde construct points there. The prefix could be something
** like "users", or it could be empty. See also the makeweb program
** for letting users create their own web subdirectories.
**
** 2) Map ~username to <user's homedir>/<postfix>. The postfix would be
** the name of a subdirectory off of the user's actual home dir, something
** like "public_html". This is what Apache and other servers do. The problem
** is, you can't do this and chroot() at the same time, so it's inherently
** a security hole. This is strongly dis-recommended, but it's here because
** some people really want it. Use at your own risk.
**
** You can also leave both options undefined, and thttpd will not do
** anything special about tildes. Enabling both options is an error.
*/
#ifdef notdef
#define TILDE_MAP_1 "users"
#define TILDE_MAP_2 "public_html"
#endif
/* CONFIGURE: The file to use for authentication. If this is defined then
** thttpd checks for this file in the local directory before every fetch.
** If the file exists then authentication is done, otherwise the fetch
** proceeds as usual.
**
** If you undefine this then thttpd will not implement authentication
** at all and will not check for auth files, which saves a bit of CPU time.
*/
//#define AUTH_FILE ".htpasswd"
/* CONFIGURE: The default character set name to use with text MIME types.
** This gets substituted into the MIME types where they have a "%s".
**
** You can override this in the config file with the "charset" setting,
** or on the command like with the -T flag.
*/
#define DEFAULT_CHARSET "iso-8859-1"
/* Most people won't want to change anything below here. */
/* CONFIGURE: This controls the SERVER_NAME environment variable that gets
** passed to CGI programs. By default thttpd does a gethostname(), which
** gives the host's canonical name. If you want to always use some other name
** you can define it here.
**
** Alternately, if you want to run the same thttpd binary on multiple
** machines, and want to build in alternate names for some or all of
** them, you can define a list of canonical name to altername name
** mappings. thttpd seatches the list and when it finds a match on
** the canonical name, that alternate name gets used. If no match
** is found, the canonical name gets used.
**
** If both SERVER_NAME and SERVER_NAME_LIST are defined here, thttpd searches
** the list as above, and if no match is found then SERVER_NAME gets used.
**
** In any case, if thttpd is started with the -h flag, that name always
** gets used.
*/
#ifdef notdef
#define SERVER_NAME "your.hostname.here"
#define SERVER_NAME_LIST \
"canonical.name.here/alternate.name.here", \
"canonical.name.two/alternate.name.two"
#endif
/* CONFIGURE: Undefine this if you want thttpd to hide its specific version
** when returning into to browsers. Instead it'll just say "thttpd" with
** no version.
*/
#define SHOW_SERVER_VERSION
/* CONFIGURE: Define this if you want to always chroot(), without having
** to give the -r command line flag. Some people like this as a security
** measure, to prevent inadvertant exposure by accidentally running without -r.
** You can still disable it at runtime with the -nor flag.
*/
#ifdef notdef
#define ALWAYS_CHROOT
#endif
/* CONFIGURE: Define this if you want to always do virtual hosting, without
** having to give the -v command line flag. You can still disable it at
** runtime with the -nov flag.
*/
#ifdef notdef
#define ALWAYS_VHOST
#endif
/* CONFIGURE: If you're using the vhost feature and you have a LOT of
** virtual hostnames (like, hundreds or thousands), you will want to
** enable this feature. It avoids a problem with most Unix filesystems,
** where if there are a whole lot of items in a directory then name lookup
** becomes very slow. This feature makes thttpd use subdirectories
** based on the first characters of each hostname. You can set it to use
** from one to three characters. If the hostname starts with "www.", that
** part is skipped over. Dots are also skipped over, and if the name isn't
** long enough then "_"s are used. Here are some examples of how hostnames
** would get turned into directory paths, for each different setting:
** 1: www.acme.com -> a/www.acme.com
** 1: foobar.acme.com -> f/foobar.acme.com
** 2: www.acme.com -> a/c/www.acme.com
** 2: foobar.acme.com -> f/o/foobar.acme.com
** 3: www.acme.com -> a/c/m/www.acme.com
** 3: foobar.acme.com -> f/o/o/foobar.acme.com
** 3: m.tv -> m/t/v/m.tv
** 4: m.tv -> m/t/v/_/m.tv
** Note that if you compile this setting in but then forget to set up
** the corresponding subdirectories, the only error indication you'll
** get is a "404 Not Found" when you try to visit a site. So be careful.
*/
#ifdef notdef
#define VHOST_DIRLEVELS 1
#define VHOST_DIRLEVELS 2
#define VHOST_DIRLEVELS 3
#endif
/* CONFIGURE: Define this if you want to always use a global passwd file,
** without having to give the -P command line flag. You can still disable
** it at runtime with the -noP flag.
*/
#ifdef notdef
#define ALWAYS_GLOBAL_PASSWD
#endif
/* CONFIGURE: When started as root, the default username to switch to after
** initializing. If this user (or the one specified by the -u flag) does
** not exist, the program will refuse to run.
*/
#define DEFAULT_USER "nobody"
/* CONFIGURE: When started as root, the program can automatically chdir()
** to the home directory of the user specified by -u or DEFAULT_USER.
** An explicit -d still overrides this.
*/
#ifdef notdef
#define USE_USER_DIR
#endif
/* CONFIGURE: If this is defined, some of the built-in error pages will
** have more explicit information about exactly what the problem is.
** Some sysadmins don't like this, for security reasons.
*/
#define EXPLICIT_ERROR_PAGES
/* CONFIGURE: Subdirectory for custom error pages. The error filenames are
** $WEBDIR/$ERR_DIR/err%d.html - if virtual hosting is enabled then
** $WEBDIR/hostname/$ERR_DIR/err%d.html is searched first. This allows
** different custom error pages for each virtual hosting web server. If
** no custom page for a given error can be found, the built-in error page
** is generated. If ERR_DIR is not defined at all, only the built-in error
** pages will be generated.
*/
#define ERR_DIR "errors"
/* CONFIGURE: Define this if you want a standard HTML tail containing
** $SERVER_SOFTWARE and $SERVER_ADDRESS to be appended to the custom error
** pages. (It is always appended to the built-in error pages.)
*/
#define ERR_APPEND_SERVER_INFO
/* CONFIGURE: nice(2) value to use for CGI programs. If this is undefined,
** CGI programs run at normal priority.
*/
#define CGI_NICE 10
/* CONFIGURE: $PATH to use for CGI programs.
*/
#define CGI_PATH "/usr/local/bin:/usr/ucb:/bin:/usr/bin"
/* CONFIGURE: If defined, $LD_LIBRARY_PATH to use for CGI programs.
*/
#ifdef notdef
#define CGI_LD_LIBRARY_PATH "/usr/local/lib:/usr/lib"
#endif
/* CONFIGURE: How often to run the occasional cleanup job.
*/
#define OCCASIONAL_TIME 120
/* CONFIGURE: Seconds between stats syslogs. If this is undefined then
** no stats are accumulated and no stats syslogs are done.
*/
//#define STATS_TIME 3600
/* CONFIGURE: The mmap cache tries to keep the total number of mapped
** files below this number, so you don't run out of kernel file descriptors.
** If you have reconfigured your kernel to have more descriptors, you can
** raise this and thttpd will keep more maps cached. However it's not
** a hard limit, thttpd will go over it if you really are accessing
** a whole lot of files.
*/
#define DESIRED_MAX_MAPPED_FILES 1000
/* CONFIGURE: The mmap cache also tries to keep the total mapped bytes
** below this number, so you don't run out of address space. Again
** it's not a hard limit, thttpd will go over it if you really are
** accessing a bunch of large files.
*/
#define DESIRED_MAX_MAPPED_BYTES 1000000000
/* CONFIGURE: Minimum and maximum intervals between child-process reaping,
** in seconds.
*/
#define MIN_REAP_TIME 30
#define MAX_REAP_TIME 900
/* You almost certainly don't want to change anything below here. */
/* CONFIGURE: When throttling CGI programs, we don't know how many bytes
** they send back to the client because it would be inefficient to
** interpose a counter. CGI programs are much more expensive than
** regular files to serve, so we set an arbitrary and high byte count
** that gets applied to all CGI programs for throttling purposes.
*/
#define CGI_BYTECOUNT 25000
/* CONFIGURE: The default port to listen on. 80 is the standard HTTP port.
*/
#define DEFAULT_PORT 80
/* CONFIGURE: A list of index filenames to check. The files are searched
** for in this order.
*/
#define INDEX_NAMES "index.html", "index.htm", "index.xhtml", "index.xht", "Default.htm", "index.cgi"
/* CONFIGURE: If this is defined then thttpd will automatically generate
** index pages for directories that don't have an explicit index file.
** If you want to disable this behavior site-wide, perhaps for security
** reasons, just undefine this. Note that you can disable indexing of
** individual directories by merely doing a "chmod 711" on them - the
** standard Unix file permission to allow file access but disable "ls".
*/
//#define GENERATE_INDEXES
/* CONFIGURE: Whether to log unknown request headers. Most sites will not
** want to log them, which will save them a bit of CPU time.
*/
#ifdef notdef
#define LOG_UNKNOWN_HEADERS
#endif
/* CONFIGURE: Whether to fflush() the log file after each request. If
** this is turned off there's a slight savings in CPU cycles.
*/
//#define FLUSH_LOG_EVERY_TIME
/* CONFIGURE: Time between updates of the throttle table's rolling averages. */
#define THROTTLE_TIME 2
/* CONFIGURE: The listen() backlog queue length. The 1024 doesn't actually
** get used, the kernel uses its maximum allowed value. This is a config
** parameter only in case there's some OS where asking for too high a queue
** length causes an error. Note that on many systems the maximum length is
** way too small - see http://www.acme.com/software/thttpd/notes.html
*/
#define LISTEN_BACKLOG 1024
/* CONFIGURE: Maximum number of throttle patterns that any single URL can
** be included in. This has nothing to do with the number of throttle
** patterns that you can define, which is unlimited.
*/
#define MAXTHROTTLENUMS 10
/* CONFIGURE: Number of file descriptors to reserve for uses other than
** connections. Currently this is 10, representing one for the listen fd,
** one for dup()ing at connection startup time, one for reading the file,
** one for syslog, and possibly one for the regular log file, which is
** five, plus a factor of two for who knows what.
*/
#define SPARE_FDS 10
/* CONFIGURE: How many milliseconds to leave a connection open while doing a
** lingering close.
*/
#define LINGER_TIME 500
/* CONFIGURE: Maximum number of symbolic links to follow before
** assuming there's a loop.
*/
#define MAX_LINKS 32
/* CONFIGURE: You don't even want to know.
*/
#define MIN_WOULDBLOCK_DELAY 100L
/* CONFIGURE: Pass the X-Cgi header to the CGI script
*/
#define X_CGI_HEADER
#endif /* _THTTPD_H_ */

334
gb.httpd/src/timers.c Normal file
View File

@ -0,0 +1,334 @@
/* timers.c - simple timer routines
**
** Copyright © 1995,1998,2000 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
//#include <syslog.h>
#include "main.h"
#include "timers.h"
#define HASH_SIZE 67
static Timer *timers[HASH_SIZE];
static Timer *free_timers;
static int alloc_count, active_count, free_count;
ClientData JunkClientData;
static unsigned int hash (Timer * t)
{
/* We can hash on the trigger time, even though it can change over
** the life of a timer via either the periodic bit or the tmr_reset()
** call. This is because both of those guys call l_resort(), which
** recomputes the hash and moves the timer to the appropriate list.
*/
return ((unsigned int) t->time.tv_sec ^
(unsigned int) t->time.tv_usec) % HASH_SIZE;
}
static void l_add (Timer * t)
{
int h = t->hash;
register Timer *t2;
register Timer *t2prev;
t2 = timers[h];
if (t2 == (Timer *) 0)
{
/* The list is empty. */
timers[h] = t;
t->prev = t->next = (Timer *) 0;
}
else
{
if (t->time.tv_sec < t2->time.tv_sec ||
(t->time.tv_sec == t2->time.tv_sec &&
t->time.tv_usec <= t2->time.tv_usec))
{
/* The new timer goes at the head of the list. */
timers[h] = t;
t->prev = (Timer *) 0;
t->next = t2;
t2->prev = t;
}
else
{
/* Walk the list to find the insertion point. */
for (t2prev = t2, t2 = t2->next; t2 != (Timer *) 0;
t2prev = t2, t2 = t2->next)
{
if (t->time.tv_sec < t2->time.tv_sec ||
(t->time.tv_sec == t2->time.tv_sec &&
t->time.tv_usec <= t2->time.tv_usec))
{
/* Found it. */
t2prev->next = t;
t->prev = t2prev;
t->next = t2;
t2->prev = t;
return;
}
}
/* Oops, got to the end of the list. Add to tail. */
t2prev->next = t;
t->prev = t2prev;
t->next = (Timer *) 0;
}
}
}
static void l_remove (Timer * t)
{
int h = t->hash;
if (t->prev == (Timer *) 0)
timers[h] = t->next;
else
t->prev->next = t->next;
if (t->next != (Timer *) 0)
t->next->prev = t->prev;
}
static void l_resort (Timer * t)
{
/* Remove the timer from its old list. */
l_remove (t);
/* Recompute the hash. */
t->hash = hash (t);
/* And add it back in to its new list, sorted correctly. */
l_add (t);
}
void tmr_init (void)
{
int h;
for (h = 0; h < HASH_SIZE; ++h)
timers[h] = (Timer *) 0;
free_timers = (Timer *) 0;
alloc_count = active_count = free_count = 0;
}
Timer *tmr_create (struct timeval *nowP, TimerProc * timer_proc,
ClientData client_data, long msecs, int periodic)
{
Timer *t;
if (free_timers != (Timer *) 0)
{
t = free_timers;
free_timers = t->next;
--free_count;
}
else
{
t = (Timer *) malloc (sizeof (Timer));
if (t == (Timer *) 0)
return (Timer *) 0;
++alloc_count;
}
t->timer_proc = timer_proc;
t->client_data = client_data;
t->msecs = msecs;
t->periodic = periodic;
if (nowP != (struct timeval *) 0)
t->time = *nowP;
else
(void) gettimeofday (&t->time, (struct timezone *) 0);
t->time.tv_sec += msecs / 1000L;
t->time.tv_usec += (msecs % 1000L) * 1000L;
if (t->time.tv_usec >= 1000000L)
{
t->time.tv_sec += t->time.tv_usec / 1000000L;
t->time.tv_usec %= 1000000L;
}
t->hash = hash (t);
/* Add the new timer to the proper active list. */
l_add (t);
++active_count;
return t;
}
struct timeval *tmr_timeout (struct timeval *nowP)
{
long msecs;
static struct timeval timeout;
msecs = tmr_mstimeout (nowP);
if (msecs == INFTIM)
return (struct timeval *) 0;
timeout.tv_sec = msecs / 1000L;
timeout.tv_usec = (msecs % 1000L) * 1000L;
return &timeout;
}
long tmr_mstimeout (struct timeval *nowP)
{
int h;
int gotone;
long msecs, m;
register Timer *t;
gotone = 0;
msecs = 0; /* make lint happy */
/* Since the lists are sorted, we only need to look at the
** first timer on each one.
*/
for (h = 0; h < HASH_SIZE; ++h)
{
t = timers[h];
if (t != (Timer *) 0)
{
m = (t->time.tv_sec - nowP->tv_sec) * 1000L +
(t->time.tv_usec - nowP->tv_usec) / 1000L;
if (!gotone)
{
msecs = m;
gotone = 1;
}
else if (m < msecs)
msecs = m;
}
}
if (!gotone)
return INFTIM;
if (msecs <= 0)
msecs = 0;
return msecs;
}
void tmr_run (struct timeval *nowP)
{
int h;
Timer *t;
Timer *next;
for (h = 0; h < HASH_SIZE; ++h)
for (t = timers[h]; t != (Timer *) 0; t = next)
{
next = t->next;
/* Since the lists are sorted, as soon as we find a timer
** that isn't ready yet, we can go on to the next list.
*/
if (t->time.tv_sec > nowP->tv_sec ||
(t->time.tv_sec == nowP->tv_sec && t->time.tv_usec > nowP->tv_usec))
break;
(t->timer_proc) (t->client_data, nowP);
if (t->periodic)
{
/* Reschedule. */
t->time.tv_sec += t->msecs / 1000L;
t->time.tv_usec += (t->msecs % 1000L) * 1000L;
if (t->time.tv_usec >= 1000000L)
{
t->time.tv_sec += t->time.tv_usec / 1000000L;
t->time.tv_usec %= 1000000L;
}
l_resort (t);
}
else
tmr_cancel (t);
}
}
void tmr_reset (struct timeval *nowP, Timer * t)
{
t->time = *nowP;
t->time.tv_sec += t->msecs / 1000L;
t->time.tv_usec += (t->msecs % 1000L) * 1000L;
if (t->time.tv_usec >= 1000000L)
{
t->time.tv_sec += t->time.tv_usec / 1000000L;
t->time.tv_usec %= 1000000L;
}
l_resort (t);
}
void tmr_cancel (Timer * t)
{
/* Remove it from its active list. */
l_remove (t);
--active_count;
/* And put it on the free list. */
t->next = free_timers;
free_timers = t;
++free_count;
t->prev = (Timer *) 0;
}
void tmr_cleanup (void)
{
Timer *t;
while (free_timers != (Timer *) 0)
{
t = free_timers;
free_timers = t->next;
--free_count;
free ((void *) t);
--alloc_count;
}
}
void tmr_destroy (void)
{
int h;
for (h = 0; h < HASH_SIZE; ++h)
while (timers[h] != (Timer *) 0)
tmr_cancel (timers[h]);
tmr_cleanup ();
}
/* Generate debugging statistics syslog message. */
void tmr_logstats (long secs)
{
syslog (LOG_INFO, " timers - %d allocated, %d active, %d free",
alloc_count, active_count, free_count);
if (active_count + free_count != alloc_count)
syslog (LOG_ERR, "timer counts don't add up!");
}

110
gb.httpd/src/timers.h Normal file
View File

@ -0,0 +1,110 @@
/* timers.h - header file for timers package
**
** Copyright © 1995,1998,1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/
#ifndef _TIMERS_H_
#define _TIMERS_H_
#include <sys/time.h>
#ifndef INFTIM
#define INFTIM -1
#endif /* INFTIM */
/* ClientData is a random value that tags along with a timer. The client
** can use it for whatever, and it gets passed to the callback when the
** timer triggers.
*/
typedef union
{
void *p;
int i;
long l;
} ClientData;
extern ClientData JunkClientData; /* for use when you don't care */
/* The TimerProc gets called when the timer expires. It gets passed
** the ClientData associated with the timer, and a timeval in case
** it wants to schedule another timer.
*/
typedef void TimerProc (ClientData client_data, struct timeval *nowP);
/* The Timer struct. */
typedef struct TimerStruct
{
TimerProc *timer_proc;
ClientData client_data;
long msecs;
int periodic;
struct timeval time;
struct TimerStruct *prev;
struct TimerStruct *next;
int hash;
} Timer;
/* Initialize the timer package. */
extern void tmr_init (void);
/* Set up a timer, either periodic or one-shot. Returns (Timer*) 0 on errors. */
extern Timer *tmr_create (struct timeval *nowP, TimerProc * timer_proc,
ClientData client_data, long msecs, int periodic);
/* Returns a timeout indicating how long until the next timer triggers. You
** can just put the call to this routine right in your select(). Returns
** (struct timeval*) 0 if no timers are pending.
*/
extern struct timeval *tmr_timeout (struct timeval *nowP);
/* Returns a timeout in milliseconds indicating how long until the next timer
** triggers. You can just put the call to this routine right in your poll().
** Returns INFTIM (-1) if no timers are pending.
*/
extern long tmr_mstimeout (struct timeval *nowP);
/* Run the list of timers. Your main program needs to call this every so often,
** or as indicated by tmr_timeout().
*/
extern void tmr_run (struct timeval *nowP);
/* Reset the clock on a timer, to current time plus the original timeout. */
extern void tmr_reset (struct timeval *nowP, Timer * timer);
/* Deschedule a timer. Note that non-periodic timers are automatically
** descheduled when they run, so you don't have to call this on them.
*/
extern void tmr_cancel (Timer * timer);
/* Clean up the timers package, freeing any unused storage. */
extern void tmr_cleanup (void);
/* Cancel all timers and free storage, usually in preparation for exitting. */
extern void tmr_destroy (void);
/* Generate debugging statistics syslog message. */
extern void tmr_logstats (long secs);
#endif /* _TIMERS_H_ */

9
gb.httpd/src/version.h Normal file
View File

@ -0,0 +1,9 @@
/* version.h - version defines for thttpd and libhttpd */
#ifndef _VERSION_H_
#define _VERSION_H_
#define SERVER_SOFTWARE "thttpd/2.25b.patch2 " __DATE__
#define SERVER_ADDRESS "http://www.acme.com/software/thttpd/"
#endif /* _VERSION_H_ */

188
m4/gbhttpd.m4 Normal file
View File

@ -0,0 +1,188 @@
dnl
dnl Improved version of AC_CHECK_LIB
dnl
dnl Thanks to John Hawkinson (jhawk@mit.edu)
dnl
dnl usage:
dnl
dnl GB_AC_LBL_CHECK_LIB(LIBRARY, FUNCTION [, ACTION-IF-FOUND [,
dnl ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]])
dnl
dnl results:
dnl
dnl LIBS
dnl
define(GB_AC_LBL_CHECK_LIB,
[AC_MSG_CHECKING([for $2 in -l$1])
dnl Use a cache variable name containing both the library and function name,
dnl because the test really is for library $1 defining function $2, not
dnl just for library $1. Separate tests with the same $1 and different $2's
dnl may have different results.
ac_lib_var=`echo $1['_']$2['_']$5 | sed 'y%./+- %__p__%'`
AC_CACHE_VAL(ac_cv_lbl_lib_$ac_lib_var,
[ac_save_LIBS="$LIBS"
LIBS="-l$1 $5 $LIBS"
AC_TRY_LINK(dnl
ifelse([$2], [main], , dnl Avoid conflicting decl of main.
[/* Override any gcc2 internal prototype to avoid an error. */
]ifelse(_AC_LANG_CURRENT, CPLUSPLUS, [#ifdef __cplusplus
extern "C"
#endif
])dnl
[/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char $2();
]),
[$2()],
eval "ac_cv_lbl_lib_$ac_lib_var=yes",
eval "ac_cv_lbl_lib_$ac_lib_var=no")
LIBS="$ac_save_LIBS"
])dnl
if eval "test \"`echo '$ac_cv_lbl_lib_'$ac_lib_var`\" = yes"; then
AC_MSG_RESULT(yes)
ifelse([$3], ,
[changequote(, )dnl
ac_tr_lib=HAVE_LIB`echo $1 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
changequote([, ])dnl
AC_DEFINE_UNQUOTED($ac_tr_lib, [], [])
LIBS="-l$1 $LIBS"
], [$3])
else
AC_MSG_RESULT(no)
ifelse([$4], , , [$4
])dnl
fi
])
dnl
dnl GB_AC_LBL_LIBRARY_NET
dnl
dnl This test is for network applications that need socket() and
dnl gethostbyname() -ish functions. Under Solaris, those applications
dnl need to link with "-lsocket -lnsl". Under IRIX, they need to link
dnl with "-lnsl" but should *not* link with "-lsocket" because
dnl libsocket.a breaks a number of things (for instance:
dnl gethostbyname() under IRIX 5.2, and snoop sockets under most
dnl versions of IRIX).
dnl
dnl Unfortunately, many application developers are not aware of this,
dnl and mistakenly write tests that cause -lsocket to be used under
dnl IRIX. It is also easy to write tests that cause -lnsl to be used
dnl under operating systems where neither are necessary (or useful),
dnl such as SunOS 4.1.4, which uses -lnsl for TLI.
dnl
dnl This test exists so that every application developer does not test
dnl this in a different, and subtly broken fashion.
dnl It has been argued that this test should be broken up into two
dnl seperate tests, one for the resolver libraries, and one for the
dnl libraries necessary for using Sockets API. Unfortunately, the two
dnl are carefully intertwined and allowing the autoconf user to use
dnl them independantly potentially results in unfortunate ordering
dnl dependancies -- as such, such component macros would have to
dnl carefully use indirection and be aware if the other components were
dnl executed. Since other autoconf macros do not go to this trouble,
dnl and almost no applications use sockets without the resolver, this
dnl complexity has not been implemented.
dnl
dnl The check for libresolv is in case you are attempting to link
dnl statically and happen to have a libresolv.a lying around (and no
dnl libnsl.a).
dnl
AC_DEFUN([GB_AC_LBL_LIBRARY_NET], [
# Most operating systems have gethostbyname() in the default searched
# libraries (i.e. libc):
AC_CHECK_FUNC(gethostbyname, ,
# Some OSes (eg. Solaris) place it in libnsl:
GB_AC_LBL_CHECK_LIB(nsl, gethostbyname, ,
# Some strange OSes (SINIX) have it in libsocket:
GB_AC_LBL_CHECK_LIB(socket, gethostbyname, ,
# Unfortunately libsocket sometimes depends on libnsl.
# AC_CHECK_LIB's API is essentially broken so the
# following ugliness is necessary:
GB_AC_LBL_CHECK_LIB(socket, gethostbyname,
LIBS="-lsocket -lnsl $LIBS",
AC_CHECK_LIB(resolv, gethostbyname),
-lnsl))))
AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
GB_AC_LBL_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", ,
-lnsl)))
# DLPI needs putmsg under HPUX so test for -lstr while we're at it
AC_CHECK_LIB(str, putmsg)
])
dnl
dnl Checks to see if struct tm has the BSD tm_gmtoff member
dnl
dnl usage:
dnl
dnl GB_AC_ACME_TM_GMTOFF
dnl
dnl results:
dnl
dnl HAVE_TM_GMTOFF (defined)
dnl
AC_DEFUN([GB_AC_ACME_TM_GMTOFF],
[AC_MSG_CHECKING(if struct tm has tm_gmtoff member)
AC_CACHE_VAL(ac_cv_acme_tm_has_tm_gmtoff,
AC_TRY_COMPILE([
# include <sys/types.h>
# include <time.h>],
[u_int i = sizeof(((struct tm *)0)->tm_gmtoff)],
ac_cv_acme_tm_has_tm_gmtoff=yes,
ac_cv_acme_tm_has_tm_gmtoff=no))
AC_MSG_RESULT($ac_cv_acme_tm_has_tm_gmtoff)
if test $ac_cv_acme_tm_has_tm_gmtoff = yes ; then
AC_DEFINE([HAVE_TM_GMTOFF], [], [if struct tm has the BSD tm_gmtoff member])
fi])
dnl
dnl Checks to see if int64_t exists
dnl
dnl usage:
dnl
dnl GB_AC_ACME_INT64T
dnl
dnl results:
dnl
dnl HAVE_INT64T (defined)
dnl
AC_DEFUN([GB_AC_ACME_INT64T],
[AC_MSG_CHECKING(if int64_t exists)
AC_CACHE_VAL(ac_cv_acme_int64_t,
AC_TRY_COMPILE([
# include <sys/types.h>],
[int64_t i64],
ac_cv_acme_int64_t=yes,
ac_cv_acme_int64_t=no))
AC_MSG_RESULT($ac_cv_acme_int64_t)
if test $ac_cv_acme_int64_t = yes ; then
AC_DEFINE([HAVE_INT64T], [], [if int64_t exists])
fi])
dnl
dnl Checks to see if socklen_t exists
dnl
dnl usage:
dnl
dnl GB_AC_ACME_SOCKLENT
dnl
dnl results:
dnl
dnl HAVE_SOCKLENT (defined)
dnl
AC_DEFUN([GB_AC_ACME_SOCKLENT],
[AC_MSG_CHECKING(if socklen_t exists)
AC_CACHE_VAL(ac_cv_acme_socklen_t,
AC_TRY_COMPILE([
# include <sys/types.h>
# include <sys/socket.h>],
[socklen_t slen],
ac_cv_acme_socklen_t=yes,
ac_cv_acme_socklen_t=no))
AC_MSG_RESULT($ac_cv_acme_socklen_t)
if test $ac_cv_acme_socklen_t = yes ; then
AC_DEFINE([HAVE_SOCKLENT], [], [if socklen_t exists])
fi])

View File

@ -66,6 +66,7 @@ FILE *log_file;
static bool _welcome = FALSE;
static bool _quit_after_main = FALSE;
static bool _run_httpd = FALSE;
static void NORETURN my_exit(int ret)
{
@ -89,10 +90,11 @@ static void NORETURN fatal(const char *msg, ...)
my_exit(1);
}
static void init(const char *file)
static void init(const char *file, int argc, char **argv)
{
COMPONENT_init();
FILE_init();
EXEC_init();
CLASS_init();
CFILE_init();
@ -112,6 +114,11 @@ static void init(const char *file)
else
fatal("no project file in '%s'.", file);
}
if (_run_httpd)
COMPONENT_exec("gb.httpd", argc, argv);
PROJECT_load_finish();
}
else
STACK_init();
@ -127,7 +134,7 @@ static void init(const char *file)
static void main_exit(bool silent)
{
// If the stack has not been initialized because the project could not be started, do it know
// If the stack has not been initialized because the project could not be started, do it now
if (!SP)
STACK_init();
@ -207,17 +214,6 @@ int main(int argc, char *argv[])
if (setrlimit(RLIMIT_CORE, &rl))
perror(strerror(errno));*/
/*VALUE c, s, a, b, r;
double v = (argc - 2) / 2.0;
c._float.value = cos(v);
s._float.value = __builtin_sin(v);
a._float.value = c._float.value * c._float.value;
b._float.value = s._float.value * s._float.value;
r._float.value = a._float.value + b._float.value;
fprintf(stderr, "%.24g %.24g / %.24g + %.24g = %.24g %d\n", c._float.value, s._float.value, a._float.value, b._float.value, r._float.value, r._float.value == 1.0);
*/
MEMORY_init();
COMMON_init();
//STRING_init();
@ -245,18 +241,19 @@ int main(int argc, char *argv[])
}
printf(
"Options:\n"
" -g enter debugging mode\n"
" -p <path> activate profiling and debugging mode\n"
" -k do not unload shared libraries\n"
" -g enter debugging mode\n"
" -p <path> activate profiling and debugging mode\n"
" -k do not unload shared libraries\n"
" -H --httpd run through an embedded http server\n"
);
if (!EXEC_arch)
{
printf(" -e evaluate an expression\n");
printf(" -e evaluate an expression\n");
}
printf(
" -V --version display version\n"
" -L --license display license\n"
" -h --help display this help\n"
" -V --version display version\n"
" -L --license display license\n"
" -h --help display this help\n"
"\n"
);
@ -284,7 +281,7 @@ int main(int argc, char *argv[])
TRY
{
init(NULL);
init(NULL, argc, argv);
EVAL_string(argv[2]);
}
CATCH
@ -323,6 +320,10 @@ int main(int argc, char *argv[])
{
_quit_after_main = TRUE;
}
else if (is_long_option(argv[i], 'H', "httpd"))
{
_run_httpd = TRUE;
}
else if (is_option(argv[i], '-'))
{
i++;
@ -359,7 +360,7 @@ int main(int argc, char *argv[])
TRY
{
init(file);
init(file, argc, argv);
if (!EXEC_arch)
argv[0] = PROJECT_name;

View File

@ -75,7 +75,7 @@ ARCHIVE *ARCHIVE_create(const char *name, const char *path)
return arch;
}
static void load_exported_class(ARCHIVE *arch)
void ARCHIVE_load_exported_class(ARCHIVE *arch)
{
/*STREAM stream;*/
char *buffer;
@ -84,11 +84,19 @@ static void load_exported_class(ARCHIVE *arch)
CLASS *class;
CLASS **exported = NULL;
int i;
COMPONENT *current;
if (arch->exported_classes_loaded)
return;
current = COMPONENT_current;
COMPONENT_current = (COMPONENT *)arch->current_component;
/* COMPONENT_current is set => it will look in the archive */
#if DEBUG_COMP
fprintf(stderr, "load_exported_class: %s (component: %s)\n", arch->name, COMPONENT_current ? COMPONENT_current->name : "?");
fprintf(stderr, "load_exported_class: %s (component: %s)\n", arch->name, COMPONENT_current ? COMPONENT_current->name : "?");
#endif
if (!FILE_exist(".list"))
@ -139,6 +147,10 @@ static void load_exported_class(ARCHIVE *arch)
ARRAY_delete(&exported);
FREE(&buffer, "load_exported_class");
arch->exported_classes_loaded = TRUE;
COMPONENT_current = current;
}
#if 0
@ -161,14 +173,6 @@ static void load_component(char *name)
FREE(&buffer, "load_dependencies");
}*/
static void load_archive(ARCHIVE *arch, const char *path) //, bool dep)
{
arch->arch = ARCH_open(path);
load_exported_class(arch);
//if (dep)
// load_dependencies(arch);
}
static char *exist_library(const char *dir, const char *name)
{
char *path;
@ -180,7 +184,7 @@ static char *exist_library(const char *dir, const char *name)
return NULL;
}
void ARCHIVE_load(ARCHIVE *arch) //, bool dep)
void ARCHIVE_load(ARCHIVE *arch, bool load_exp)
{
char *path;
@ -204,7 +208,11 @@ void ARCHIVE_load(ARCHIVE *arch) //, bool dep)
sprintf(path, ARCH_PATTERN, COMPONENT_path, arch->name);
}
load_archive(arch, path); //, dep);
arch->arch = ARCH_open(path);
arch->current_component = COMPONENT_current;
if (load_exp)
ARCHIVE_load_exported_class(arch); //, dep);
}
@ -221,7 +229,7 @@ void ARCHIVE_create_main(const char *path)
void ARCHIVE_load_main()
{
load_exported_class(ARCHIVE_main);
ARCHIVE_load_exported_class(ARCHIVE_main);
}

View File

@ -39,7 +39,9 @@ typedef
char *domain;
TABLE *classes;
const char *path;
void *current_component;
unsigned translation_loaded : 1;
unsigned exported_classes_loaded : 1;
}
ARCHIVE;
@ -65,7 +67,8 @@ void ARCHIVE_load_main(void);
ARCHIVE *ARCHIVE_create(const char *name, const char *path);
void ARCHIVE_delete(ARCHIVE *arch);
void ARCHIVE_load(ARCHIVE *arch);
void ARCHIVE_load(ARCHIVE *arch, bool load_exp);
void ARCHIVE_load_exported_class(ARCHIVE *arch);
bool ARCHIVE_get(ARCHIVE *arch, const char **ppath, ARCHIVE_FIND *find);

View File

@ -65,6 +65,7 @@ char *COMPONENT_path;
static COMPONENT *_component_list = NULL;
static bool _load_all = FALSE;
void COMPONENT_init(void)
{
@ -123,11 +124,26 @@ void COMPONENT_load_all(void)
COMPONENT_create("gb.debug");
}
_load_all = TRUE;
LIST_for_each(comp, _component_list)
{
comp->preload = TRUE;
COMPONENT_load(comp);
}
_load_all = FALSE;
}
void COMPONENT_load_all_finish(void)
{
COMPONENT *comp;
LIST_for_each(comp, _component_list)
{
if (comp->preload && comp->archive)
ARCHIVE_load_exported_class(comp->archive);
}
}
@ -265,7 +281,7 @@ void COMPONENT_load(COMPONENT *comp)
}
if (comp->archive)
ARCHIVE_load(comp->archive);
ARCHIVE_load(comp->archive, !_load_all);
comp->loading = FALSE;
comp->loaded = TRUE;
@ -341,3 +357,16 @@ bool COMPONENT_get_info(const char *key, void **value)
return TRUE;
}
void COMPONENT_exec(const char *name, int argc, char **argv)
{
COMPONENT *comp;
comp = COMPONENT_create(name);
COMPONENT_load(comp);
if (comp->library)
LIBRARY_exec(comp->library, argc, argv);
}

View File

@ -67,9 +67,12 @@ COMPONENT *COMPONENT_find(const char *name);
bool COMPONENT_exist(const char *name);
void COMPONENT_load(COMPONENT *comp);
void COMPONENT_load_all(void);
void COMPONENT_unload(COMPONENT *comp);
void COMPONENT_load_all(void);
void COMPONENT_load_all_finish(void);
COMPONENT *COMPONENT_next(COMPONENT *comp);
void COMPONENT_translation_must_be_reloaded(void);
@ -80,4 +83,6 @@ void COMPONENT_signal(int signal, void *param);
bool COMPONENT_get_info(const char *key, void **value);
void COMPONENT_exec(const char *name, int argc, char **argv);
#endif

View File

@ -274,6 +274,15 @@ int LIBRARY_load(LIBRARY *lib)
return order;
}
void LIBRARY_exec(LIBRARY *lib, int argc, char **argv)
{
void (*func)();
func = get_symbol(lib, LIB_MAIN, FALSE);
if (func)
(*func)(argc, argv);
}
void LIBRARY_declare(GB_DESC **desc)
{

View File

@ -71,4 +71,6 @@ void LIBRARY_declare(GB_DESC **desc);
bool LIBRARY_get_interface_by_name(const char *name, int version, void *iface);
void LIBRARY_get_interface(LIBRARY *lib, int version, void *iface);
void LIBRARY_exec(LIBRARY *lib, int argc, char **argv);
#endif

View File

@ -461,17 +461,23 @@ bool PROJECT_load()
if (len < 0)
return TRUE;
/* Loads all component */
// Loads all component
COMPONENT_load_all();
/* Loads main archive */
ARCHIVE_load_main();
/* Startup class */
PROJECT_class = CLASS_find(PROJECT_startup);
return FALSE;
}
void PROJECT_load_finish(void)
{
// Load exported class of components written in Gambas
COMPONENT_load_all_finish();
// Loads main archive
ARCHIVE_load_main();
// Startup class
PROJECT_class = CLASS_find(PROJECT_startup);
}
void PROJECT_exit(void)
{

View File

@ -52,6 +52,7 @@ EXTERN char *PROJECT_user_home;
void PROJECT_init(const char *file);
bool PROJECT_load(void);
void PROJECT_load_finish(void);
void PROJECT_exit(void);
char *PROJECT_get_home(void);
void PROJECT_analyze_startup(char *addr, int len, PROJECT_COMPONENT_CALLBACK cb);

View File

@ -43,6 +43,7 @@ typedef
#define LIB_NEED "GB_NEED"
#define LIB_GAMBAS "GB"
#define LIB_GAMBAS_PTR "GB_PTR"
#define LIB_MAIN "GB_MAIN"
#ifdef DONT_USE_LTDL
#if defined(OS_MACOSX)