[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:
parent
dcc327e864
commit
41b6a93cef
@ -31,6 +31,7 @@ SUBDIRS = \
|
||||
@ncurses_dir@ \
|
||||
@media_dir@ \
|
||||
@jit_dir@ \
|
||||
@httpd_dir@ \
|
||||
comp \
|
||||
app \
|
||||
examples \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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} <b>Gambas 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} <b>Gambas 3.3.1</b>
|
||||
</a>
|
||||
<div class="release-notes" align="center"><a href="http://gambasdoc.org/help/doc/release/3.3.0?view&$(LANG)">{Release Notes}</a></div>
|
||||
<div class="release-notes" align="center"><a href="http://gambasdoc.org/help/doc/release/3.3.1?view&$(LANG)">{Release Notes}</a></div>
|
||||
</div>
|
||||
|
||||
<div style="display:inline-table;">
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
[Component]
|
||||
Key=gb.report
|
||||
Version=3.2.90
|
||||
Version=3.3.0
|
||||
State=1
|
||||
Authors=Fabien Bodard
|
||||
Needs=Form,ImageIO
|
||||
|
@ -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"
|
||||
|
@ -5,6 +5,10 @@ Host
|
||||
R
|
||||
s
|
||||
|
||||
Port
|
||||
R
|
||||
s
|
||||
|
||||
Root
|
||||
R
|
||||
s
|
||||
@ -196,10 +200,6 @@ CookiePath
|
||||
P
|
||||
s
|
||||
|
||||
_init
|
||||
M
|
||||
|
||||
|
||||
_exit
|
||||
M
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -2,7 +2,7 @@ FFractal
|
||||
Fractal
|
||||
0
|
||||
0
|
||||
3.2.0
|
||||
3.3.0
|
||||
|
||||
gb.image
|
||||
gb.gui
|
||||
|
0
gb.httpd/AUTHORS
Normal file
0
gb.httpd/AUTHORS
Normal file
1
gb.httpd/COPYING
Symbolic link
1
gb.httpd/COPYING
Symbolic link
@ -0,0 +1 @@
|
||||
../COPYING
|
0
gb.httpd/ChangeLog
Normal file
0
gb.httpd/ChangeLog
Normal file
1
gb.httpd/INSTALL
Symbolic link
1
gb.httpd/INSTALL
Symbolic link
@ -0,0 +1 @@
|
||||
../INSTALL
|
3
gb.httpd/Makefile.am
Normal file
3
gb.httpd/Makefile.am
Normal 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
0
gb.httpd/NEWS
Normal file
0
gb.httpd/README
Normal file
0
gb.httpd/README
Normal file
1
gb.httpd/acinclude.m4
Symbolic link
1
gb.httpd/acinclude.m4
Symbolic link
@ -0,0 +1 @@
|
||||
../acinclude.m4
|
1
gb.httpd/component.am
Symbolic link
1
gb.httpd/component.am
Symbolic link
@ -0,0 +1 @@
|
||||
../component.am
|
151
gb.httpd/configure.ac
Normal file
151
gb.httpd/configure.ac
Normal 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
1
gb.httpd/gambas.h
Symbolic link
@ -0,0 +1 @@
|
||||
../main/share/gambas.h
|
1
gb.httpd/gb_common.h
Symbolic link
1
gb.httpd/gb_common.h
Symbolic link
@ -0,0 +1 @@
|
||||
../main/share/gb_common.h
|
1
gb.httpd/m4
Symbolic link
1
gb.httpd/m4
Symbolic link
@ -0,0 +1 @@
|
||||
../m4
|
1
gb.httpd/missing
Symbolic link
1
gb.httpd/missing
Symbolic link
@ -0,0 +1 @@
|
||||
../missing
|
1
gb.httpd/reconf
Symbolic link
1
gb.httpd/reconf
Symbolic link
@ -0,0 +1 @@
|
||||
../reconf
|
21
gb.httpd/src/Makefile.am
Normal file
21
gb.httpd/src/Makefile.am
Normal 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
840
gb.httpd/src/fdwatch.c
Normal 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
85
gb.httpd/src/fdwatch.h
Normal 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_ */
|
3
gb.httpd/src/gb.httpd.component
Normal file
3
gb.httpd/src/gb.httpd.component
Normal file
@ -0,0 +1,3 @@
|
||||
[Component]
|
||||
Author=
|
||||
Alpha=1
|
4308
gb.httpd/src/libhttpd.c
Normal file
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
294
gb.httpd/src/libhttpd.h
Normal 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
71
gb.httpd/src/main.c
Normal 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
51
gb.httpd/src/main.h
Normal 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
87
gb.httpd/src/match.c
Normal 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
36
gb.httpd/src/match.h
Normal 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_ */
|
8
gb.httpd/src/mime_encodings.h
Normal file
8
gb.httpd/src/mime_encodings.h
Normal 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
569
gb.httpd/src/mime_types.h
Normal 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
521
gb.httpd/src/mmc.c
Normal 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
55
gb.httpd/src/mmc.h
Normal 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
37
gb.httpd/src/strerror.c
Normal 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
313
gb.httpd/src/tdate_parse.c
Normal 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;
|
||||
}
|
33
gb.httpd/src/tdate_parse.h
Normal file
33
gb.httpd/src/tdate_parse.h
Normal 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
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
403
gb.httpd/src/thttpd.h
Normal 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
334
gb.httpd/src/timers.c
Normal 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
110
gb.httpd/src/timers.h
Normal 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
9
gb.httpd/src/version.h
Normal 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
188
m4/gbhttpd.m4
Normal 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])
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user