From cb69b4c7ba398e7771cc53d2a75831950a7ebc71 Mon Sep 17 00:00:00 2001
From: rousskov <>
Date: Sat, 21 Feb 1998 07:56:32 +0000
Subject: [PATCH] Dirty and buggy alex_2.
---
configure | 370 +++---
configure.in | 14 +-
errors/English/ERR_CACHE_ACCESS_DENIED | 32 +
include/MemPool.h | 64 +
include/Stack.h | 56 +
include/autoconf.h.in | 3 +
include/util.h | 3 +-
include/version.h | 3 +-
lib/Makefile.in | 4 +-
lib/MemPool.c | 193 +++
lib/Stack.c | 116 ++
lib/util.c | 37 +-
src/HttpBody.cc | 89 ++
src/HttpHeader.cc | 1690 ++++++++++++++++++++++++
src/HttpReply.cc | 402 ++++++
src/HttpStatusLine.cc | 213 +++
src/Makefile.in | 8 +-
src/MemBuf.cc | 186 +++
src/Packer.cc | 127 ++
src/cache_manager.cc | 13 +-
src/client_side.cc | 126 +-
src/comm.cc | 9 +-
src/defines.h | 10 +
src/enums.h | 11 +-
src/errorpage.cc | 93 +-
src/ftp.cc | 46 +-
src/globals.h | 3 +-
src/http.cc | 74 +-
src/main.cc | 3 +-
src/mem.cc | 5 +-
src/mime.cc | 15 +-
src/protos.h | 10 +-
src/store.cc | 52 +-
src/store_client.cc | 8 +-
src/store_log.cc | 16 +-
src/structs.h | 39 +-
src/typedefs.h | 4 +
src/urn.cc | 27 +-
38 files changed, 3868 insertions(+), 306 deletions(-)
create mode 100644 errors/English/ERR_CACHE_ACCESS_DENIED
create mode 100644 include/MemPool.h
create mode 100644 include/Stack.h
create mode 100644 lib/MemPool.c
create mode 100644 lib/Stack.c
create mode 100644 src/HttpBody.cc
create mode 100644 src/HttpHeader.cc
create mode 100644 src/HttpReply.cc
create mode 100644 src/HttpStatusLine.cc
create mode 100644 src/MemBuf.cc
create mode 100644 src/Packer.cc
diff --git a/configure b/configure
index 35c9076bd1..cf5a3e5d6c 100755
--- a/configure
+++ b/configure
@@ -47,6 +47,8 @@ ac_help="$ac_help
Make cachemgr.cgi default to this host"
ac_help="$ac_help
--enable-arp-acl Enable use of ARP ACL lists (ether address)"
+ac_help="$ac_help
+ --enable-alex_code Enable Alex's code"
# Initialize some variables set by options.
# The variables have the same names as the options, with
@@ -555,7 +557,7 @@ fi
-# From configure.in Revision: 1.98
+# From configure.in Revision: 1.99
ac_aux_dir=
for ac_dir in aux $srcdir/aux; do
if test -f $ac_dir/install-sh; then
@@ -583,7 +585,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
fi
echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:587: checking host system type" >&5
+echo "configure:589: checking host system type" >&5
host_alias=$host
case "$host_alias" in
@@ -638,7 +640,7 @@ PRESET_CFLAGS="$CFLAGS"
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:642: checking for $ac_word" >&5
+echo "configure:644: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -667,7 +669,7 @@ if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:671: checking for $ac_word" >&5
+echo "configure:673: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -715,7 +717,7 @@ fi
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:719: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:721: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -725,11 +727,11 @@ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS
cross_compiling=$ac_cv_prog_cc_cross
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:735: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
ac_cv_prog_cc_works=yes
# If we can't run a trivial program, we are probably using a cross compiler.
if (./conftest; exit) 2>/dev/null; then
@@ -749,12 +751,12 @@ if test $ac_cv_prog_cc_works = no; then
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:753: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:755: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:758: checking whether we are using GNU C" >&5
+echo "configure:760: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -763,7 +765,7 @@ else
yes;
#endif
EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:767: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:769: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
@@ -778,7 +780,7 @@ if test $ac_cv_prog_gcc = yes; then
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:782: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:784: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1138,8 +1140,24 @@ EOF
fi
+# Check whether --enable-alex_code or --disable-alex_code was given.
+if test "${enable_alex_code+set}" = set; then
+ enableval="$enable_alex_code"
+ if test "$enableval" = "yes" ; then
+ echo "Alex's code enabled"
+ cat >> confdefs.h <<\EOF
+#define USE_ALEX_CODE 1
+EOF
+
+ else
+ echo "Alex's code DISABLED"
+ fi
+
+fi
+
+
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1143: checking how to run the C preprocessor" >&5
+echo "configure:1161: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
@@ -1154,13 +1172,13 @@ else
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1164: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1182: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
@@ -1171,13 +1189,13 @@ else
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1181: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1199: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
@@ -1210,7 +1228,7 @@ echo "$ac_t""$CPP" 1>&6
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1214: checking for a BSD compatible install" >&5
+echo "configure:1232: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1262,7 +1280,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1266: checking for $ac_word" >&5
+echo "configure:1284: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1289,7 +1307,7 @@ else
fi
echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:1293: checking whether ln -s works" >&5
+echo "configure:1311: checking whether ln -s works" >&5
if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1312,7 +1330,7 @@ fi
# Extract the first word of "sh", so it can be a program name with args.
set dummy sh; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1316: checking for $ac_word" >&5
+echo "configure:1334: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_SH'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1344,7 +1362,7 @@ fi
# Extract the first word of "false", so it can be a program name with args.
set dummy false; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1348: checking for $ac_word" >&5
+echo "configure:1366: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_FALSE'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1376,7 +1394,7 @@ fi
# Extract the first word of "true", so it can be a program name with args.
set dummy true; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1380: checking for $ac_word" >&5
+echo "configure:1398: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_TRUE'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1408,7 +1426,7 @@ fi
# Extract the first word of "rm", so it can be a program name with args.
set dummy rm; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1412: checking for $ac_word" >&5
+echo "configure:1430: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_RM'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1440,7 +1458,7 @@ fi
# Extract the first word of "mv", so it can be a program name with args.
set dummy mv; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1444: checking for $ac_word" >&5
+echo "configure:1462: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_MV'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1472,7 +1490,7 @@ fi
# Extract the first word of "mkdir", so it can be a program name with args.
set dummy mkdir; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1476: checking for $ac_word" >&5
+echo "configure:1494: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_MKDIR'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1504,7 +1522,7 @@ fi
# Extract the first word of "ln", so it can be a program name with args.
set dummy ln; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1508: checking for $ac_word" >&5
+echo "configure:1526: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_LN'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1536,7 +1554,7 @@ fi
# Extract the first word of "perl", so it can be a program name with args.
set dummy perl; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1540: checking for $ac_word" >&5
+echo "configure:1558: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1568,7 +1586,7 @@ fi
# Extract the first word of "makedepend", so it can be a program name with args.
set dummy makedepend; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1572: checking for $ac_word" >&5
+echo "configure:1590: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_MAKEDEPEND'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1600,7 +1618,7 @@ fi
# Extract the first word of "ar", so it can be a program name with args.
set dummy ar; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1604: checking for $ac_word" >&5
+echo "configure:1622: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_AR'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1650,12 +1668,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
-echo "configure:1654: checking for $ac_hdr that defines DIR" >&5
+echo "configure:1672: checking for $ac_hdr that defines DIR" >&5
if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#include <$ac_hdr>
@@ -1663,7 +1681,7 @@ int main() {
DIR *dirp = 0;
; return 0; }
EOF
-if { (eval echo configure:1667: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1685: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
eval "ac_cv_header_dirent_$ac_safe=yes"
else
@@ -1688,7 +1706,7 @@ done
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
if test $ac_header_dirent = dirent.h; then
echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
-echo "configure:1692: checking for opendir in -ldir" >&5
+echo "configure:1710: checking for opendir in -ldir" >&5
ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1696,7 +1714,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-ldir $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1729: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -1729,7 +1747,7 @@ fi
else
echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
-echo "configure:1733: checking for opendir in -lx" >&5
+echo "configure:1751: checking for opendir in -lx" >&5
ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1737,7 +1755,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lx $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1770: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -1771,12 +1789,12 @@ fi
fi
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1775: checking for ANSI C header files" >&5
+echo "configure:1793: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#include
@@ -1784,7 +1802,7 @@ else
#include
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1788: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1806: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -1801,7 +1819,7 @@ rm -f conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <
EOF
@@ -1819,7 +1837,7 @@ fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <
EOF
@@ -1840,7 +1858,7 @@ if test "$cross_compiling" = yes; then
:
else
cat > conftest.$ac_ext <
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1851,7 +1869,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
exit (0); }
EOF
-if { (eval echo configure:1855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1873: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
:
else
@@ -1927,17 +1945,17 @@ for ac_hdr in \
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1931: checking for $ac_hdr" >&5
+echo "configure:1949: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1941: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1959: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -1965,12 +1983,12 @@ done
echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:1969: checking for working const" >&5
+echo "configure:1987: checking for working const" >&5
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2041: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_const=yes
else
@@ -2040,14 +2058,14 @@ EOF
fi
echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:2044: checking whether byte ordering is bigendian" >&5
+echo "configure:2062: checking whether byte ordering is bigendian" >&5
if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_cv_c_bigendian=unknown
# See if sys/param.h defines the BYTE_ORDER macro.
cat > conftest.$ac_ext <
#include
@@ -2058,11 +2076,11 @@ int main() {
#endif
; return 0; }
EOF
-if { (eval echo configure:2062: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2080: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
# It does; now see whether it defined to BIG_ENDIAN or not.
cat > conftest.$ac_ext <
#include
@@ -2073,7 +2091,7 @@ int main() {
#endif
; return 0; }
EOF
-if { (eval echo configure:2077: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2095: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_bigendian=yes
else
@@ -2093,7 +2111,7 @@ if test "$cross_compiling" = yes; then
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2128: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
ac_cv_c_bigendian=no
else
@@ -2131,20 +2149,20 @@ fi
echo $ac_n "checking if ANSI prototypes work""... $ac_c" 1>&6
-echo "configure:2135: checking if ANSI prototypes work" >&5
+echo "configure:2153: checking if ANSI prototypes work" >&5
if eval "test \"`echo '$''{'ac_cv_have_ansi_prototypes'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2166: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_have_ansi_prototypes="yes"
else
@@ -2166,13 +2184,13 @@ EOF
fi
echo $ac_n "checking for tm->tm_gmtoff""... $ac_c" 1>&6
-echo "configure:2170: checking for tm->tm_gmtoff" >&5
+echo "configure:2188: checking for tm->tm_gmtoff" >&5
if eval "test \"`echo '$''{'ac_cv_have_tm_gmoff'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#include
@@ -2181,7 +2199,7 @@ struct tm foo;
foo.tm_gmtoff = 0;
; return 0; }
EOF
-if { (eval echo configure:2185: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2203: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_have_tm_gmoff="yes"
else
@@ -2203,13 +2221,13 @@ EOF
fi
echo $ac_n "checking for extended mallinfo""... $ac_c" 1>&6
-echo "configure:2207: checking for extended mallinfo" >&5
+echo "configure:2225: checking for extended mallinfo" >&5
if eval "test \"`echo '$''{'ac_cv_have_ext_mallinfo'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#include
@@ -2218,7 +2236,7 @@ struct mallinfo foo;
foo.mxfast = 0;
; return 0; }
EOF
-if { (eval echo configure:2222: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2240: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_have_ext_mallinfo="yes"
else
@@ -2240,13 +2258,13 @@ EOF
fi
echo $ac_n "checking for struct rusage""... $ac_c" 1>&6
-echo "configure:2244: checking for struct rusage" >&5
+echo "configure:2262: checking for struct rusage" >&5
if eval "test \"`echo '$''{'ac_cv_have_struct_rusage'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2281: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_have_struct_rusage="yes"
else
@@ -2281,13 +2299,13 @@ EOF
fi
echo $ac_n "checking for ip->ip_hl""... $ac_c" 1>&6
-echo "configure:2285: checking for ip->ip_hl" >&5
+echo "configure:2303: checking for ip->ip_hl" >&5
if eval "test \"`echo '$''{'ac_cv_have_ip_hl'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#include
@@ -2304,7 +2322,7 @@ struct iphdr ip;
ip.ip_hl= 0;
; return 0; }
EOF
-if { (eval echo configure:2308: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2326: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_have_ip_hl="yes"
else
@@ -2326,7 +2344,7 @@ EOF
fi
echo $ac_n "checking size of int""... $ac_c" 1>&6
-echo "configure:2330: checking size of int" >&5
+echo "configure:2348: checking size of int" >&5
if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2334,7 +2352,7 @@ else
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <
main()
@@ -2345,7 +2363,7 @@ main()
exit(0);
}
EOF
-if { (eval echo configure:2349: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2367: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
ac_cv_sizeof_int=`cat conftestval`
else
@@ -2365,7 +2383,7 @@ EOF
echo $ac_n "checking size of long""... $ac_c" 1>&6
-echo "configure:2369: checking size of long" >&5
+echo "configure:2387: checking size of long" >&5
if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2373,7 +2391,7 @@ else
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <
main()
@@ -2384,7 +2402,7 @@ main()
exit(0);
}
EOF
-if { (eval echo configure:2388: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2406: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
ac_cv_sizeof_long=`cat conftestval`
else
@@ -2407,19 +2425,19 @@ EOF
# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
# for constant arguments. Useless!
echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
-echo "configure:2411: checking for working alloca.h" >&5
+echo "configure:2429: checking for working alloca.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
int main() {
char *p = alloca(2 * sizeof(int));
; return 0; }
EOF
-if { (eval echo configure:2423: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2441: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
ac_cv_header_alloca_h=yes
else
@@ -2440,12 +2458,12 @@ EOF
fi
echo $ac_n "checking for alloca""... $ac_c" 1>&6
-echo "configure:2444: checking for alloca" >&5
+echo "configure:2462: checking for alloca" >&5
if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2490: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
ac_cv_func_alloca_works=yes
else
@@ -2500,12 +2518,12 @@ EOF
echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
-echo "configure:2504: checking whether alloca needs Cray hooks" >&5
+echo "configure:2522: checking whether alloca needs Cray hooks" >&5
if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&6
if test $ac_cv_os_cray = yes; then
for ac_func in _getb67 GETB67 getb67; do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2534: checking for $ac_func" >&5
+echo "configure:2552: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2580: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -2585,7 +2603,7 @@ done
fi
echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
-echo "configure:2589: checking stack direction for C alloca" >&5
+echo "configure:2607: checking stack direction for C alloca" >&5
if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2593,7 +2611,7 @@ else
ac_cv_c_stack_direction=0
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2634: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
ac_cv_c_stack_direction=1
else
@@ -2635,12 +2653,12 @@ fi
echo $ac_n "checking for pid_t""... $ac_c" 1>&6
-echo "configure:2639: checking for pid_t" >&5
+echo "configure:2657: checking for pid_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#if STDC_HEADERS
@@ -2668,12 +2686,12 @@ EOF
fi
echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:2672: checking for size_t" >&5
+echo "configure:2690: checking for size_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#if STDC_HEADERS
@@ -2701,12 +2719,12 @@ EOF
fi
echo $ac_n "checking for ssize_t""... $ac_c" 1>&6
-echo "configure:2705: checking for ssize_t" >&5
+echo "configure:2723: checking for ssize_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_ssize_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#if STDC_HEADERS
@@ -2734,12 +2752,12 @@ EOF
fi
echo $ac_n "checking for off_t""... $ac_c" 1>&6
-echo "configure:2738: checking for off_t" >&5
+echo "configure:2756: checking for off_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#if STDC_HEADERS
@@ -2767,12 +2785,12 @@ EOF
fi
echo $ac_n "checking for mode_t""... $ac_c" 1>&6
-echo "configure:2771: checking for mode_t" >&5
+echo "configure:2789: checking for mode_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
#if STDC_HEADERS
@@ -2801,7 +2819,7 @@ fi
echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6
-echo "configure:2805: checking for main in -lnsl" >&5
+echo "configure:2823: checking for main in -lnsl" >&5
ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -2809,14 +2827,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lnsl $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2838: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -2844,7 +2862,7 @@ else
fi
echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6
-echo "configure:2848: checking for main in -lsocket" >&5
+echo "configure:2866: checking for main in -lsocket" >&5
ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -2852,14 +2870,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lsocket $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2881: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -2887,7 +2905,7 @@ else
fi
echo $ac_n "checking for main in -lgnumalloc""... $ac_c" 1>&6
-echo "configure:2891: checking for main in -lgnumalloc" >&5
+echo "configure:2909: checking for main in -lgnumalloc" >&5
ac_lib_var=`echo gnumalloc'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -2895,14 +2913,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lgnumalloc $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2924: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -2944,7 +2962,7 @@ else
;;
*)
echo $ac_n "checking for main in -lmalloc""... $ac_c" 1>&6
-echo "configure:2948: checking for main in -lmalloc" >&5
+echo "configure:2966: checking for main in -lmalloc" >&5
ac_lib_var=`echo malloc'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -2952,14 +2970,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lmalloc $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2981: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -2990,7 +3008,7 @@ fi
esac
fi
echo $ac_n "checking for main in -lbsd""... $ac_c" 1>&6
-echo "configure:2994: checking for main in -lbsd" >&5
+echo "configure:3012: checking for main in -lbsd" >&5
ac_lib_var=`echo bsd'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -2998,14 +3016,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lbsd $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3027: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3033,7 +3051,7 @@ else
fi
echo $ac_n "checking for main in -lregex""... $ac_c" 1>&6
-echo "configure:3037: checking for main in -lregex" >&5
+echo "configure:3055: checking for main in -lregex" >&5
ac_lib_var=`echo regex'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -3041,14 +3059,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lregex $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3074,7 +3092,7 @@ case "$host" in
;;
*)
echo $ac_n "checking for inet_aton in -lresolv""... $ac_c" 1>&6
-echo "configure:3078: checking for inet_aton in -lresolv" >&5
+echo "configure:3096: checking for inet_aton in -lresolv" >&5
ac_lib_var=`echo resolv'_'inet_aton | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -3082,7 +3100,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lresolv $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3115: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3109,7 +3127,7 @@ fi
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
echo "$ac_t""yes" 1>&6
echo $ac_n "checking for inet_aton in -l44bsd""... $ac_c" 1>&6
-echo "configure:3113: checking for inet_aton in -l44bsd" >&5
+echo "configure:3131: checking for inet_aton in -l44bsd" >&5
ac_lib_var=`echo 44bsd'_'inet_aton | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -3117,7 +3135,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-l44bsd $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3150: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3160,7 +3178,7 @@ else
fi
echo $ac_n "checking for main in -lresolv""... $ac_c" 1>&6
-echo "configure:3164: checking for main in -lresolv" >&5
+echo "configure:3182: checking for main in -lresolv" >&5
ac_lib_var=`echo resolv'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -3168,14 +3186,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lresolv $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3197: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3205,7 +3223,7 @@ fi
;;
esac
echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
-echo "configure:3209: checking for main in -lm" >&5
+echo "configure:3227: checking for main in -lm" >&5
ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -3213,14 +3231,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lm $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3242: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3249,7 +3267,7 @@ fi
echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
-echo "configure:3253: checking for crypt in -lcrypt" >&5
+echo "configure:3271: checking for crypt in -lcrypt" >&5
ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -3257,7 +3275,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lcrypt $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3290: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3291,7 +3309,7 @@ fi
echo $ac_n "checking for main in -lpthread""... $ac_c" 1>&6
-echo "configure:3295: checking for main in -lpthread" >&5
+echo "configure:3313: checking for main in -lpthread" >&5
ac_lib_var=`echo pthread'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -3299,14 +3317,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lpthread $LIBS"
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -3409,12 +3427,12 @@ for ac_func in \
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:3413: checking for $ac_func" >&5
+echo "configure:3431: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3459: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -3475,12 +3493,12 @@ case "$host" in
;;
*)
echo $ac_n "checking for poll""... $ac_c" 1>&6
-echo "configure:3479: checking for poll" >&5
+echo "configure:3497: checking for poll" >&5
if eval "test \"`echo '$''{'ac_cv_func_poll'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3525: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_poll=yes"
else
@@ -3526,7 +3544,7 @@ fi
esac
echo $ac_n "checking if setresuid is implemented""... $ac_c" 1>&6
-echo "configure:3530: checking if setresuid is implemented" >&5
+echo "configure:3548: checking if setresuid is implemented" >&5
if eval "test \"`echo '$''{'ac_cv_func_setresuid'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -3534,7 +3552,7 @@ else
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <
@@ -3547,7 +3565,7 @@ else
}
EOF
-if { (eval echo configure:3551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3569: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
ac_cv_func_setresuid="yes"
else
@@ -3571,7 +3589,7 @@ EOF
fi
echo $ac_n "checking if GNUregex needs to be compiled""... $ac_c" 1>&6
-echo "configure:3575: checking if GNUregex needs to be compiled" >&5
+echo "configure:3593: checking if GNUregex needs to be compiled" >&5
if test "$ac_cv_func_regcomp" = "no" ; then
USE_GNUREGEX="yes"
else
@@ -3603,12 +3621,12 @@ for ac_func in \
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:3607: checking for $ac_func" >&5
+echo "configure:3625: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:3653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -3659,12 +3677,12 @@ done
echo $ac_n "checking Default FD_SETSIZE value""... $ac_c" 1>&6
-echo "configure:3663: checking Default FD_SETSIZE value" >&5
+echo "configure:3681: checking Default FD_SETSIZE value" >&5
if test "$cross_compiling" = yes; then
DEFAULT_FD_SETSIZE=256
else
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3710: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
DEFAULT_FD_SETSIZE=`cat conftestval`
else
@@ -3707,12 +3725,12 @@ EOF
echo $ac_n "checking Maximum number of filedescriptors we can open""... $ac_c" 1>&6
-echo "configure:3711: checking Maximum number of filedescriptors we can open" >&5
+echo "configure:3729: checking Maximum number of filedescriptors we can open" >&5
if test "$cross_compiling" = yes; then
SQUID_MAXFD=256
else
cat > conftest.$ac_ext <
@@ -3764,7 +3782,7 @@ main() {
}
EOF
-if { (eval echo configure:3768: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3786: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
SQUID_MAXFD=`cat conftestval`
else
@@ -3783,12 +3801,12 @@ EOF
echo $ac_n "checking Default UDP send buffer size""... $ac_c" 1>&6
-echo "configure:3787: checking Default UDP send buffer size" >&5
+echo "configure:3805: checking Default UDP send buffer size" >&5
if test "$cross_compiling" = yes; then
SQUID_UDP_SO_SNDBUF=16384
else
cat > conftest.$ac_ext <
@@ -3807,7 +3825,7 @@ main ()
}
EOF
-if { (eval echo configure:3811: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3829: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
SQUID_UDP_SO_SNDBUF=`cat conftestval`
else
@@ -3826,12 +3844,12 @@ EOF
echo $ac_n "checking Default UDP receive buffer size""... $ac_c" 1>&6
-echo "configure:3830: checking Default UDP receive buffer size" >&5
+echo "configure:3848: checking Default UDP receive buffer size" >&5
if test "$cross_compiling" = yes; then
SQUID_UDP_SO_RCVBUF=16384
else
cat > conftest.$ac_ext <
@@ -3850,7 +3868,7 @@ main ()
}
EOF
-if { (eval echo configure:3854: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3872: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
SQUID_UDP_SO_RCVBUF=`cat conftestval`
else
@@ -3869,12 +3887,12 @@ EOF
echo $ac_n "checking Default TCP send buffer size""... $ac_c" 1>&6
-echo "configure:3873: checking Default TCP send buffer size" >&5
+echo "configure:3891: checking Default TCP send buffer size" >&5
if test "$cross_compiling" = yes; then
SQUID_TCP_SO_SNDBUF=16384
else
cat > conftest.$ac_ext <
@@ -3893,7 +3911,7 @@ main ()
}
EOF
-if { (eval echo configure:3897: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
SQUID_TCP_SO_SNDBUF=`cat conftestval`
else
@@ -3912,12 +3930,12 @@ EOF
echo $ac_n "checking Default TCP receive buffer size""... $ac_c" 1>&6
-echo "configure:3916: checking Default TCP receive buffer size" >&5
+echo "configure:3934: checking Default TCP receive buffer size" >&5
if test "$cross_compiling" = yes; then
SQUID_TCP_SO_RCVBUF=16384
else
cat > conftest.$ac_ext <
@@ -3936,7 +3954,7 @@ main ()
}
EOF
-if { (eval echo configure:3940: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3958: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
SQUID_TCP_SO_RCVBUF=`cat conftestval`
else
@@ -3955,19 +3973,19 @@ EOF
echo $ac_n "checking if sys_errlist is already defined""... $ac_c" 1>&6
-echo "configure:3959: checking if sys_errlist is already defined" >&5
+echo "configure:3977: checking if sys_errlist is already defined" >&5
if eval "test \"`echo '$''{'ac_cv_needs_sys_errlist'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <
int main() {
char *s = sys_errlist0;
; return 0; }
EOF
-if { (eval echo configure:3971: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3989: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_needs_sys_errlist="no"
else
@@ -3989,16 +4007,16 @@ EOF
fi
echo $ac_n "checking for libresolv _dns_ttl_ hack""... $ac_c" 1>&6
-echo "configure:3993: checking for libresolv _dns_ttl_ hack" >&5
+echo "configure:4011: checking for libresolv _dns_ttl_ hack" >&5
cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:4020: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
echo "$ac_t""yes" 1>&6
cat >> confdefs.h <<\EOF
diff --git a/configure.in b/configure.in
index e5978bd5ce..d3a33284c0 100644
--- a/configure.in
+++ b/configure.in
@@ -3,13 +3,13 @@ dnl Configuration input file for Squid
dnl
dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
dnl
-dnl $Id: configure.in,v 1.99 1998/02/06 00:55:59 wessels Exp $
+dnl $Id: configure.in,v 1.100 1998/02/21 00:56:32 rousskov Exp $
dnl
dnl
dnl
AC_INIT(src/main.c)
AC_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.99 $)dnl
+AC_REVISION($Revision: 1.100 $)dnl
AC_PREFIX_DEFAULT(/usr/local/squid)
AC_CONFIG_AUX_DIR(aux)
@@ -307,6 +307,16 @@ AC_ARG_ENABLE(arp_acl,
fi
])
+AC_ARG_ENABLE(alex_code,
+[ --enable-alex_code Enable Alex's code],
+[ if test "$enableval" = "yes" ; then
+ echo "Alex's code enabled"
+ AC_DEFINE(USE_ALEX_CODE)
+ else
+ echo "Alex's code DISABLED"
+ fi
+])
+
dnl Check for programs
AC_PROG_CPP
AC_PROG_INSTALL
diff --git a/errors/English/ERR_CACHE_ACCESS_DENIED b/errors/English/ERR_CACHE_ACCESS_DENIED
new file mode 100644
index 0000000000..0ae61b0142
--- /dev/null
+++ b/errors/English/ERR_CACHE_ACCESS_DENIED
@@ -0,0 +1,32 @@
+
+ERROR: Cache Access Denied
+
+
+ERROR
+Cache Access Denied
+
+
+While trying to retrieve the URL:
+%U
+
+The following error was encountered:
+
+-
+
+Cache Access Denied.
+
+
+
+
+Sorry, you are not currently allowed to request:
+
%U
+from this cache until you have authenticated yourself.
+
+
+
+You need to use Netscape version 2.0 or greater, or Microsoft Internet
+Explorer 3.0, or an HTTP/1.1 compliant browser for this to work. Please
+contact the cache administrator if you have
+difficulties authenticating yourself or
+change your default password.
+
diff --git a/include/MemPool.h b/include/MemPool.h
new file mode 100644
index 0000000000..a890cb0e11
--- /dev/null
+++ b/include/MemPool.h
@@ -0,0 +1,64 @@
+/*
+ * $Id: MemPool.h,v 1.2 1998/02/21 00:56:34 rousskov Exp $
+ *
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _MEM_POOL_H_
+#define _MEM_POOL_H_
+
+#include "Stack.h"
+
+/* see MemPool.c for documentation */
+
+struct _MemPool {
+ /* public, read only */
+ char *name; /* an optional label or name for this pool */
+ size_t obj_size;
+
+ /* protected, do not use these, use interface functions instead */
+ char *buf;
+ Stack *static_stack;
+ Stack *dynamic_stack;
+
+ size_t alloc_count;
+ size_t free_count;
+ size_t alloc_high_water;
+
+ /* private, never touch this */
+ char *_buf_end;
+};
+
+typedef struct _MemPool MemPool;
+
+extern MemPool *memPoolCreate(size_t preallocCnt, size_t dynStackCnt, size_t objSz, const char *poolName);
+extern void memPoolDestroy(MemPool *mp);
+extern void *memPoolGetObj(MemPool *mp);
+extern void memPoolPutObj(MemPool *mp, void *obj);
+extern const char *memPoolReport(MemPool *mp);
+
+
+#endif /* ndef _MEM_POOL_H_ */
diff --git a/include/Stack.h b/include/Stack.h
new file mode 100644
index 0000000000..042c201194
--- /dev/null
+++ b/include/Stack.h
@@ -0,0 +1,56 @@
+/*
+ * $Id: Stack.h,v 1.2 1998/02/21 00:56:35 rousskov Exp $
+ *
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _STACK_H_
+#define _STACK_H_
+
+/* see Stack.c for more documentation */
+
+struct _Stack {
+ /* public, read only */
+ size_t capacity;
+ int is_full; /* true if the stack is full */
+
+ u_num32 push_count; /* always grows, might overflow, use for stats only */
+ u_num32 pop_count; /* always grows, might overflow, use for stats only */
+
+ /* protected, do not use these, use interface functions instead */
+ size_t count;
+ void **buf;
+};
+
+typedef struct _Stack Stack;
+
+extern Stack *stackCreate(size_t capacity);
+extern void stackDestroy(Stack *s);
+extern void *stackPop(Stack *s);
+extern void stackPush(Stack *s, void *obj);
+
+
+#endif /* ndef _STACK_H_ */
diff --git a/include/autoconf.h.in b/include/autoconf.h.in
index a31c2fe47b..2326734248 100644
--- a/include/autoconf.h.in
+++ b/include/autoconf.h.in
@@ -86,6 +86,9 @@
/* Define to use async disk I/O operations */
#undef USE_ASYNC_IO
+/* Define to use alex's code */
+#undef USE_ALEX_CODE
+
/*
* If you want to use Squid's ICMP features (highly recommended!) then
* define this. When USE_ICMP is defined, Squid will send ICMP pings
diff --git a/include/util.h b/include/util.h
index 64cdc2f4a1..4a4b53aa24 100644
--- a/include/util.h
+++ b/include/util.h
@@ -1,5 +1,5 @@
/*
- * $Id: util.h,v 1.39 1998/02/13 18:26:52 wessels Exp $
+ * $Id: util.h,v 1.40 1998/02/21 00:56:36 rousskov Exp $
*
* AUTHOR: Harvest Derived
*
@@ -138,6 +138,7 @@ extern int tvSubMsec(struct timeval, struct timeval);
extern int tvSubUsec(struct timeval, struct timeval);
extern double tvSubDsec(struct timeval, struct timeval);
extern char *xstrncpy(char *, const char *, size_t);
+extern size_t xcountws(const char *str);
extern time_t parse_rfc1123(const char *str);
extern void *xcalloc(int, size_t);
extern void *xmalloc(size_t);
diff --git a/include/version.h b/include/version.h
index 0b0f13ba9c..01baa8e2ae 100644
--- a/include/version.h
+++ b/include/version.h
@@ -1,4 +1,5 @@
-/* $Id: version.h,v 1.100 1998/02/13 18:47:35 wessels Exp $
+/*
+ * $Id: version.h,v 1.101 1998/02/21 00:56:37 rousskov Exp $
*
* SQUID_VERSION - String for version id of this distribution
*/
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 55148d4f11..a6c216e653 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -1,5 +1,5 @@
#
-# $Id: Makefile.in,v 1.32 1998/02/02 19:39:26 wessels Exp $
+# $Id: Makefile.in,v 1.33 1998/02/21 00:56:37 rousskov Exp $
#
prefix = @prefix@
top_srcdir = @top_srcdir@
@@ -37,6 +37,8 @@ UTILOBJS = rfc1123.o \
radix.o \
String.o \
stub_memaccount.o \
+ MemPool.o \
+ Stack.o \
$(LIBOBJS)
REGEXOBJS = GNUregex.o
DLMALLOCOBJS = malloc-2.6.4.o
diff --git a/lib/MemPool.c b/lib/MemPool.c
new file mode 100644
index 0000000000..ae8d1a498c
--- /dev/null
+++ b/lib/MemPool.c
@@ -0,0 +1,193 @@
+/*
+ * $Id: MemPool.c,v 1.2 1998/02/21 00:56:38 rousskov Exp $
+ *
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * MemPool handles allocation and accounting for fixed size objects or buffers.
+ * It optimizes run-time allocation using a pre-allocated continuos pool of free
+ * buffers. MemPool does not know about the contents of a buffer.
+ */
+
+/*
+ * Warning: Never use *alloc or *free on objects maintained by MemPool!
+ */
+
+/*
+ * To-do:
+ * - src/stmem routines could use some of lib/MemPool stuff
+ */
+
+
+#if 0
+
+Synopsis:
+
+ /*
+ * creating a pool named "urls" for objects of size objSz with objCnt
+ * pre-allocated objects and 10% for dynamic stack. Any of the first two
+ * parameters can be 0. If name is NULL "anonymous" will be used instead
+ */
+ MemPool *mp1 = memPoolCreate(objCnt, objCnt/10, objSz, "urls");
+
+ /*
+ * getting a new object from a pool; object buffer is initialized with 0s
+ */
+ void *buf = memPoolGetObj(mp1);
+
+ /*
+ * returning an object back
+ */
+ memPoolPutObj(mp1, buf);
+
+ /*
+ * accounting: generate report as an ASCII string
+ * warning: static buffer is used, strdup your copy!
+ */
+ char *report = xstrdup(memPoolReport());
+
+ /* destroy your pools when done playing! */
+ memPoolDestroy(mp1);
+
+#endif /* synopsis */
+
+#include "config.h"
+#if HAVE_ASSERT_H
+#include
+#endif
+#include "util.h"
+#include "snprintf.h"
+#include "MemPool.h"
+
+
+MemPool *
+memPoolCreate(size_t preallocCnt, size_t dynStackCnt, size_t objSz, const char *poolName)
+{
+ MemPool *mp = xcalloc(1, sizeof(MemPool));
+ mp->buf = xcalloc(preallocCnt, objSz);
+ mp->obj_size = objSz;
+ mp->name = xstrdup(poolName ? poolName : "anonymous");
+ mp->_buf_end = mp->buf + objSz*preallocCnt; /* internal, never dereference this! */
+ mp->static_stack = stackCreate(preallocCnt);
+ mp->dynamic_stack = stackCreate(dynStackCnt);
+ /* other members are initialized with 0 because of calloc() */
+ /* push all pre-allocated memory on stack because it is currently free */
+ while(preallocCnt-- > 0)
+ stackPush(mp->static_stack, mp->buf + objSz*preallocCnt);
+ return mp;
+}
+
+void
+memPoolDestroy(MemPool *mp)
+{
+ assert(mp);
+ /* could also warn if some objects are left */
+ stackDestroy(mp->static_stack);
+ stackDestroy(mp->dynamic_stack);
+ xfree(mp->buf);
+ xfree(mp->name);
+ xfree(mp);
+}
+
+/*
+ * find a free buffer:
+ * if none on the pool stack, use alloc stack;
+ * if none there, use alloc
+ * never fails
+ */
+void *
+memPoolGetObj2(MemPool *mp)
+{
+ assert(mp);
+ if (mp->static_stack->count)
+ return stackPop(mp->static_stack);
+ else
+ if (mp->dynamic_stack->count)
+ return stackPop(mp->dynamic_stack);
+ /* have to alloc, monitor high whater mark */
+ if (++mp->alloc_count - mp->free_count > mp->alloc_high_water)
+ mp->alloc_high_water = mp->alloc_count - mp->free_count;
+ return xcalloc(1, mp->obj_size);
+}
+
+void *
+memPoolGetObj(MemPool *mp)
+{
+ void *obj = memPoolGetObj2(mp);
+ /*printf("memPoolGetObj: %p : %d -> %d , %d >= %d\n", obj, mp->static_stack->count, mp->dynamic_stack->count, mp->alloc_count, mp->free_count);*/
+ return obj;
+}
+
+/*
+ * return object to the pool; put on the corresponding stack or free if
+ * corresponding stack is full
+ */
+void
+memPoolPutObj(MemPool *mp, void *obj)
+{
+ assert(mp);
+ /*printf("memPoolPutObj: %p : %d >= %d\n", obj, mp->alloc_count, mp->free_count);*/
+ /* static object? */
+ if (mp->buf <= (char*)obj && mp->_buf_end > (char*)obj) {
+ assert(!mp->static_stack->is_full); /* never full if we got here! */
+ stackPush(mp->static_stack, obj);
+ } else
+ /* dynamic object, but stack may be full */
+ if (!mp->dynamic_stack->is_full) {
+ assert(mp->alloc_count);
+ stackPush(mp->dynamic_stack, obj);
+ } else {
+ /* free-ing is the last option */
+ mp->free_count++;
+ assert(mp->free_count <= mp->alloc_count);
+ xfree(obj); /* do this after assert */
+ }
+}
+
+const char *
+memPoolReport(MemPool *mp)
+{
+ static char buf[512]; /* we do not use LOCALL_ARRAY in squid/lib, do we? */
+
+ assert(mp);
+ snprintf(buf, sizeof(buf),
+ "pool %s: obj_sz: %ud cap: %ud/%ud "
+ "stat: +%uld-%uld dyn: +%uld-%uld alloc: +%uld/-%uld<%uld",
+ mp->name,
+ mp->obj_size,
+ mp->static_stack->capacity,
+ mp->dynamic_stack->capacity,
+ mp->static_stack->push_count,
+ mp->static_stack->pop_count,
+ mp->dynamic_stack->push_count,
+ mp->dynamic_stack->pop_count,
+ mp->alloc_count,
+ mp->free_count,
+ mp->alloc_high_water);
+
+ return buf;
+}
diff --git a/lib/Stack.c b/lib/Stack.c
new file mode 100644
index 0000000000..cc55683bd6
--- /dev/null
+++ b/lib/Stack.c
@@ -0,0 +1,116 @@
+/*
+ * $Id: Stack.c,v 1.2 1998/02/21 00:56:38 rousskov Exp $
+ *
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Stack is a (void*) stack with fixed capacity with limited accounting.
+ * Errors are handled with asserts.
+ */
+
+
+/*
+ * To-do:
+ * - stack that grows as needed if a given delta is non zero
+ */
+
+
+#if 0
+
+Synopsis:
+
+ /*
+ * creating a stack that can hold up to objCnt pointers.
+ * If objCnt is zero, the stack is always full (disabled)
+ */
+ Stack *s1 = stackCreate(objCnt);
+ Stack *s2 = stackCreate(objCnt*2);
+
+ /*
+ * pop/push works as expected; it is OK to push a null pointer
+ */
+ if (!s2->is_full && s1->count)
+ stackPush(s2, stackPop(s1));
+
+ /* destroying a stack */
+ stackDestroy(s1);
+
+#endif /* Synopsis */
+
+#include "config.h"
+#if HAVE_ASSERT_H
+#include
+#endif
+#include "util.h"
+#include "Stack.h"
+
+/* performance hack instead of non-ANSI inline function */
+#define stackIsFull(s) (s->count >= s->capacity)
+
+Stack *
+stackCreate(size_t capacity)
+{
+ Stack *s = xcalloc(1, sizeof(Stack));
+ s->buf = capacity > 0 ? xcalloc(capacity, sizeof(void*)) : NULL;
+ s->capacity = capacity;
+ s->count = 0;
+ s->is_full = stackIsFull(s);
+ /* other members are set to 0 in calloc */
+ return s;
+}
+
+void
+stackDestroy(Stack *s)
+{
+ assert(s);
+ /* could also warn if some objects are left */
+ if (s->buf)
+ xfree(s->buf);
+ xfree(s);
+}
+
+void *
+stackPop(Stack *s)
+{
+ void *popped;
+ assert(s);
+ assert(s->count);
+ popped = s->buf[--s->count];
+ s->is_full = stackIsFull(s);
+ s->pop_count++; /* might overflow eventually, but ok */
+ return popped;
+}
+
+void
+stackPush(Stack *s, void *obj)
+{
+ assert(s);
+ assert(!s->is_full);
+ s->buf[s->count++] = obj;
+ s->is_full = stackIsFull(s);
+ s->push_count++; /* might overflow eventually, but ok */
+}
diff --git a/lib/util.c b/lib/util.c
index bc962a0f30..083bca4903 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -1,6 +1,6 @@
/*
- * $Id: util.c,v 1.44 1998/02/18 08:21:31 wessels Exp $
+ * $Id: util.c,v 1.45 1998/02/21 00:56:39 rousskov Exp $
*
* DEBUG:
* AUTHOR: Harvest Derived
@@ -587,11 +587,10 @@ xstrdup(const char *s)
}
exit(1);
}
- sz = strlen(s);
- p = xmalloc((size_t) sz + 1);
- memcpy(p, s, sz); /* copy string */
- p[sz] = '\0'; /* terminate string */
- return (p);
+ sz = strlen(s)+1;
+ p = xmalloc(sz);
+ memcpy(p, s, sz); /* copy string, including terminating character */
+ return p;
}
/*
@@ -655,17 +654,31 @@ tvSubDsec(struct timeval t1, struct timeval t2)
/*
* xstrncpy() - similar to strncpy(3) but terminates string
- * always with '\0' if n != 0, and doesn't do padding
+ * always with '\0' if (n != 0 and dst != NULL),
+ * and doesn't do padding
*/
char *
xstrncpy(char *dst, const char *src, size_t n)
{
- if (n == 0)
- return dst;
- if (src == NULL)
+ if (!n || !dst)
return dst;
- while (--n != 0 && *src != '\0')
- *dst++ = *src++;
+ if (src)
+ while (--n != 0 && *src != '\0')
+ *dst++ = *src++;
*dst = '\0';
return dst;
}
+
+/* returns the number of leading white spaces in str; handy in skipping ws */
+size_t
+xcountws(const char *str)
+{
+ size_t count = 0;
+ if (str) {
+ while (isspace(*str)) {
+ str++;
+ count++;
+ }
+ }
+ return count;
+}
diff --git a/src/HttpBody.cc b/src/HttpBody.cc
new file mode 100644
index 0000000000..ad3e827692
--- /dev/null
+++ b/src/HttpBody.cc
@@ -0,0 +1,89 @@
+/*
+ * $Id: HttpBody.cc,v 1.2 1998/02/21 00:56:40 rousskov Exp $
+ *
+ * DEBUG: section ?? HTTP Body
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "squid.h"
+
+
+/* local constants */
+
+/* local routines */
+
+
+void
+httpBodyInit(HttpBody *body)
+{
+ body->buf = NULL;
+ body->size = 0;
+ body->freefunc = NULL;
+}
+
+void
+httpBodyClean(HttpBody *body)
+{
+ assert(body);
+ if (body->buf) {
+ assert(body->freefunc);
+ (*body->freefunc)(body->buf);
+ }
+ body->buf = NULL;
+ body->size = 0;
+}
+
+void
+httpBodySet(HttpBody *body, const char *buf, int size, FREE *freefunc)
+{
+ assert(body);
+ assert(!body->buf);
+ assert(buf);
+ assert(size);
+ assert(buf[size-1] == '\0'); /* paranoid */
+ if (!freefunc) { /* they want us to make our own copy */
+ body->buf = xmalloc(size);
+ xmemcpy(body->buf, buf, size);
+ freefunc = &xfree;
+ }
+ body->freefunc = freefunc;
+ body->size = size;
+}
+
+void
+httpBodyPackInto(const HttpBody *body, Packer *p)
+{
+ assert(body && p);
+ /* assume it was a 0-terminating buffer */
+ if (body->size)
+ packerAppend(p, body->buf, body->size-1);
+}
+
+const char *
+httpBodyPtr(const HttpBody *body)
+{
+ return body->buf ? body->buf : "";
+}
diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc
new file mode 100644
index 0000000000..b55fddda47
--- /dev/null
+++ b/src/HttpHeader.cc
@@ -0,0 +1,1690 @@
+/*
+ * $Id: HttpHeader.cc,v 1.2 1998/02/21 00:56:41 rousskov Exp $
+ *
+ * DEBUG: section 55 General HTTP Header
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "squid.h"
+#include "MemPool.h"
+#include "HttpHeader.h"
+
+/*
+ On naming conventions:
+
+ HTTP/1.1 defines message-header as
+
+ message-header = field-name ":" [ field-value ] CRLF
+ field-name = token
+ field-value = *( field-content | LWS )
+
+ HTTP/1.1 does not give a name name a group of all message-headers in a message.
+ Squid 1.1 seems to refer to that group _plus_ start-line as "headers".
+
+ HttpHeader is an object that represents all message-headers in a message.
+ HttpHeader does not manage start-line.
+
+ HttpHeader is implemented as a collection of header "entries"
+ An entry is a (field_id, field) pair where
+ - field_id is one of the http_hdr_type ids,
+ - field is a compiled(parsed) image of message-header.
+*/
+
+
+/*
+ * local types
+ */
+
+/* HTTP/1.1 extension-header */
+struct _HttpHeaderExtField {
+ char *name; /* field-name from HTTP/1.1 (no column after name!) */
+ char *value; /* field-value from HTTP/1.1 */
+};
+
+/* possible types for fields */
+typedef enum {
+ ftInvalid = HDR_ENUM_END, /* to catch nasty errors with hdr_id<->fld_type clashes */
+ ftInt,
+ ftPChar,
+ ftDate_1123,
+ ftPSCC,
+ ftPExtField,
+} field_type;
+
+/*
+ * HttpHeader entry
+ * ( the concrete type of entry.field is Headers[id].type )
+ */
+struct _HttpHeaderEntry {
+ field_store field;
+ http_hdr_type id;
+};
+
+/* constant attributes of fields */
+typedef struct {
+ const char *name;
+ http_hdr_type id;
+ field_type type;
+ int name_len;
+} field_attrs_t;
+
+/* use HttpHeaderPos as opaque type, do not interpret */
+typedef ssize_t HttpHeaderPos;
+/* use this and only this to initialize HttpHeaderPos */
+#define HttpHeaderInitPos (-1)
+
+
+#if 0 /* moved to HttpHeader.h */
+typedef struct _HttpHeaderEntry HttpHeaderEntry;
+struct _HttpHeader {
+ /* public, read only */
+ int emask; /* bits set for present entries */
+
+ /* protected, do not use these, use interface functions instead */
+ int capacity; /* max #entries before we have to grow */
+ int ucount; /* #entries used, including holes */
+ HttpHeaderEntry *entries;
+};
+#endif
+
+
+/*
+ * local constants and vars
+ */
+
+/*
+ * A table with major attributes for every known field.
+ * We calculate name lengths and reorganize this array on start up.
+ * After reorganization, field id can be used as an index to the table.
+ */
+static field_attrs_t Headers[] = {
+ { "Accept", HDR_ACCEPT, ftPChar },
+ { "Age", HDR_AGE, ftInt },
+ { "Cache-Control", HDR_CACHE_CONTROL, ftPSCC },
+ { "Connection", HDR_CONNECTION, ftPChar }, /* for now */
+ { "Content-Encoding", HDR_CONTENT_ENCODING,ftPChar },
+ { "Content-Length", HDR_CONTENT_LENGTH, ftInt },
+ { "Content-MD5", HDR_CONTENT_MD5, ftPChar }, /* for now */
+ { "Content-Type", HDR_CONTENT_TYPE, ftPChar },
+ { "Date", HDR_DATE, ftDate_1123 },
+ { "Etag", HDR_ETAG, ftPChar }, /* for now */
+ { "Expires", HDR_EXPIRES, ftDate_1123 },
+ { "Host", HDR_HOST, ftPChar },
+ { "If-Modified-Since", HDR_IMS, ftDate_1123 },
+ { "Last-Modified", HDR_LAST_MODIFIED, ftDate_1123 },
+ { "Location", HDR_LOCATION, ftPChar },
+ { "Max-Forwards", HDR_MAX_FORWARDS, ftInt },
+ { "Proxy-Authenticate",HDR_PROXY_AUTHENTICATE,ftPChar },
+ { "Public", HDR_PUBLIC, ftPChar },
+ { "Retry-After", HDR_RETRY_AFTER, ftPChar }, /* for now */
+ /* fix this: make count-but-treat as OTHER mask @?@ @?@ */
+ { "Set-Cookie:", HDR_SET_COOKIE, ftPChar },
+ { "Upgrade", HDR_UPGRADE, ftPChar }, /* for now */
+ { "Warning", HDR_WARNING, ftPChar }, /* for now */
+ { "WWW-Authenticate", HDR_WWW_AUTHENTICATE,ftPChar },
+ { "Proxy-Connection", HDR_PROXY_KEEPALIVE, ftInt }, /* true/false */
+ { "Other:", HDR_OTHER, ftPExtField } /* ':' will not allow matches */
+};
+
+/* this table is used for parsing server cache control header */
+static field_attrs_t SccAttrs[] = {
+ { "public", SCC_PUBLIC },
+ { "private", SCC_PRIVATE },
+ { "no-cache", SCC_NO_CACHE },
+ { "no-store", SCC_NO_STORE },
+ { "no-transform", SCC_NO_TRANSFORM },
+ { "must-revalidate", SCC_MUST_REVALIDATE },
+ { "proxy-revalidate", SCC_PROXY_REVALIDATE },
+ { "max-age", SCC_MAX_AGE }
+};
+
+/*
+ * headers with field values defined as #(values) in HTTP/1.1
+ *
+ * We have listed all possible list headers according to
+ * draft-ietf-http-v11-spec-rev-01.txt. Headers that are currently not
+ * recognized, are commented out.
+ */
+static int ListHeadersMask = 0; /* set run-time using ListHeaders */
+static http_hdr_type ListHeaders[] = {
+ HDR_ACCEPT,
+ /* HDR_ACCEPT_CHARSET, HDR_ACCEPT_ENCODING, HDR_ACCEPT_LANGUAGE, */
+ /* HDR_ACCEPT_RANGES, */
+ /* HDR_ALLOW, */
+ HDR_CACHE_CONTROL, HDR_CONNECTION,
+ HDR_CONTENT_ENCODING,
+ /* HDR_CONTENT_LANGUAGE, HDR_IF_MATCH, HDR_IF_NONE_MATCH,
+ HDR_PRAGMA, HDR_TRANSFER_ENCODING, */
+ HDR_UPGRADE, /* HDR_VARY, */
+ /* HDR_VIA, HDR_WARNING, */
+ HDR_WWW_AUTHENTICATE,
+ /* HDR_EXPECT, HDR_TE, HDR_TRAILER */
+};
+
+static int ReplyHeadersMask = 0; /* set run-time using ReplyHeaders */
+static http_hdr_type ReplyHeaders[] = {
+ HDR_ACCEPT, HDR_AGE, HDR_CACHE_CONTROL, HDR_CONTENT_LENGTH,
+ HDR_CONTENT_MD5, HDR_CONTENT_TYPE, HDR_DATE, HDR_ETAG, HDR_EXPIRES,
+ HDR_LAST_MODIFIED, HDR_LOCATION, HDR_MAX_FORWARDS, HDR_PUBLIC, HDR_RETRY_AFTER,
+ HDR_SET_COOKIE, HDR_UPGRADE, HDR_WARNING, HDR_PROXY_KEEPALIVE, HDR_OTHER
+};
+
+static int RequestHeadersMask = 0; /* set run-time using RequestHeaders */
+static http_hdr_type RequestHeaders[] = {
+ HDR_OTHER
+};
+
+static const char *KnownSplitableFields[] = {
+ "Connection", "Range"
+};
+/* if you must have KnownSplitableFields empty, set KnownSplitableFieldCount to 0 */
+static const int KnownSplitableFieldCount = sizeof(KnownSplitableFields)/sizeof(*KnownSplitableFields);
+
+/* headers accounting */
+#define INIT_FIELDS_PER_HEADER 8
+static u_num32 shortHeadersCount = 0;
+static u_num32 longHeadersCount = 0;
+
+typedef struct {
+ const char *label;
+ int parsed;
+ int misc[HDR_ENUM_END];
+} HttpHeaderStats;
+
+#if 0 /* not used, add them later @?@ */
+static struct {
+ int parsed;
+ int misc[HDR_MISC_END];
+ int cc[SCC_ENUM_END];
+} ReplyHeaderStats;
+
+#endif /* if 0 */
+
+/* recycle bin for short strings (32KB only) */
+static const size_t shortStrSize = 32; /* max size of a recyclable string */
+static const size_t shortStrPoolCount = (32*1024)/32; /* sync this with shortStrSize */
+static MemPool *shortStrings = NULL;
+
+/* long strings accounting */
+static u_num32 longStrAllocCount = 0;
+static u_num32 longStrFreeCount = 0;
+static u_num32 longStrHighWaterCount = 0;
+static size_t longStrAllocSize = 0;
+static size_t longStrFreeSize = 0;
+static size_t longStrHighWaterSize = 0;
+
+
+/* local routines */
+
+#define assert_eid(id) assert((id) >= 0 && (id) < HDR_ENUM_END)
+
+static void httpHeaderInitAttrTable(field_attrs_t *table, int count);
+static int httpHeaderCalcMask(const int *enums, int count);
+static HttpHeaderEntry *httpHeaderGetEntry(const HttpHeader *hdr, HttpHeaderPos *pos);
+static void httpHeaderDelAt(HttpHeader *hdr, HttpHeaderPos pos);
+static void httpHeaderAddParsedEntry(HttpHeader *hdr, HttpHeaderEntry *e);
+static void httpHeaderAddNewEntry(HttpHeader *hdr, const HttpHeaderEntry *e);
+static void httpHeaderSet(HttpHeader *hdr, http_hdr_type id, const field_store value);
+static void httpHeaderSyncMasks(HttpHeader *hdr, const HttpHeaderEntry *e, int add);
+static void httpHeaderSyncStats(HttpHeader *hdr, const HttpHeaderEntry *e);
+static int httpHeaderIdByName(const char *name, int name_len, const field_attrs_t *attrs, int end, int mask);
+static void httpHeaderGrow(HttpHeader *hdr);
+
+static void httpHeaderEntryInit(HttpHeaderEntry *e, http_hdr_type id, field_store field);
+static void httpHeaderEntryClean(HttpHeaderEntry *e);
+static int httpHeaderEntryParseInit(HttpHeaderEntry *e, const char *field_start, const char *field_end, int mask);
+static int httpHeaderEntryParseExtFieldInit(HttpHeaderEntry *e, int id, const HttpHeaderExtField *f);
+static int httpHeaderEntryParseByTypeInit(HttpHeaderEntry *e, int id, const HttpHeaderExtField *f);
+static HttpHeaderEntry httpHeaderEntryClone(const HttpHeaderEntry *e);
+static void httpHeaderEntryPackInto(const HttpHeaderEntry *e, Packer *p);
+static void httpHeaderEntryPackByType(const HttpHeaderEntry *e, Packer *p);
+static void httpHeaderEntryJoinWith(HttpHeaderEntry *e, const HttpHeaderEntry *newe);
+static int httpHeaderEntryIsValid(const HttpHeaderEntry *e);
+static const char *httpHeaderEntryName(const HttpHeaderEntry *e);
+
+static void httpHeaderFieldInit(field_store *field);
+static field_store httpHeaderFieldDup(field_type type, field_store value);
+static field_store httpHeaderFieldBadValue(field_type type);
+
+static HttpScc *httpSccCreate();
+static HttpScc *httpSccParseCreate(const char *str);
+static void httpSccParseInit(HttpScc *scc, const char *str);
+static void httpSccDestroy(HttpScc *scc);
+static HttpScc *httpSccDup(HttpScc *scc);
+static void httpSccPackValueInto(HttpScc *scc, Packer *p);
+static void httpSccJoinWith(HttpScc *scc, HttpScc *new_scc);
+
+static HttpHeaderExtField *httpHeaderExtFieldCreate(const char *name, const char *value);
+static HttpHeaderExtField *httpHeaderExtFieldParseCreate(const char *field_start, const char *field_end);
+static void httpHeaderExtFieldDestroy(HttpHeaderExtField *f);
+static HttpHeaderExtField *httpHeaderExtFieldDup(HttpHeaderExtField *f);
+
+static void httpHeaderStoreAReport(StoreEntry *e, void (*reportPacker)(Packer *p));
+static void httpHeaderPackReport(Packer *p);
+static void httpHeaderPackReqReport(Packer *p);
+static void httpHeaderPackRepReport(Packer *p);
+
+
+#if 0
+static void httpHeaderAddField(HttpHeader *hdr, HttpHeaderField *fld);
+static void httpHeaderAddSingleField(HttpHeader *hdr, HttpHeaderField *fld);
+static void httpHeaderAddListField(HttpHeader *hdr, HttpHeaderField *fld);
+static void httpHeaderCountField(HttpHeader *hdr, HttpHeaderField *fld);
+static void httpHeaderCountSCCField(HttpHeader *hdr, HttpHeaderField *fld);
+static int httpHeaderFindFieldType(HttpHeaderField *fld, const field_attrs_t *attrs, int end, int mask);
+static HttpHeaderField *httpHeaderFieldCreate(const char *name, const char *value);
+static HttpHeaderField *httpHeaderFieldParseCreate(const char *field_start, const char *field_end);
+static void httpHeaderFieldDestroy(HttpHeaderField *f);
+static size_t httpHeaderFieldBufSize(const HttpHeaderField *fld);
+static int httpHeaderFieldIsList(const HttpHeaderField *fld);
+static void httpHeaderStoreAReport(Packer *p, HttpHeaderStats *stats);
+#endif
+
+static char *dupShortStr(const char *str);
+static char *dupShortBuf(const char *str, size_t len);
+static char *appShortStr(char *str, const char *app_str);
+static char *allocShortBuf(size_t size);
+static void freeShortString(char *str);
+
+static int strListGetItem(const char *str, char del, const char **item, int *ilen, const char **pos);
+static const char *getStringPrefix(const char *str);
+
+
+/* delete this when everybody remembers that ':' is not a part of a name */
+#define conversion_period_name_check(name) assert(!strchr((name), ':'))
+
+/* handy to determine the #elements in a static array */
+#define countof(arr) (sizeof(arr)/sizeof(*arr))
+
+/*
+ * Module initialization routines
+ */
+
+void
+httpHeaderInitModule()
+{
+ /* paranoid check if smbd put a big object into field_store */
+ assert(sizeof(field_store) == 4);
+ /* have to force removal of const here */
+ httpHeaderInitAttrTable((field_attrs_t *)Headers, countof(Headers));
+ httpHeaderInitAttrTable((field_attrs_t *)SccAttrs, countof(SccAttrs));
+ /* create masks */
+ ListHeadersMask = httpHeaderCalcMask((const int*)ListHeaders, countof(ListHeaders));
+ ReplyHeadersMask = httpHeaderCalcMask((const int*)ReplyHeaders, countof(ReplyHeaders));
+ RequestHeadersMask = httpHeaderCalcMask((const int*)RequestHeaders, countof(RequestHeaders));
+ /* create a pool of short strings @?@ we never destroy it! */
+ shortStrings = memPoolCreate(shortStrPoolCount, shortStrPoolCount/10, shortStrSize, "shortStr");
+}
+
+static void
+httpHeaderInitAttrTable(field_attrs_t *table, int count)
+{
+ int i;
+ assert(table);
+ assert(count > 1); /* to protect from buggy "countof" implementations */
+
+ /* reorder so that .id becomes an index */
+ for (i = 0; i < count;) {
+ const int id = table[i].id;
+ assert(id >= 0 && id < count); /* sanity check */
+ assert(id >= i); /* entries prior to i have been indexed already */
+ if (id != i) { /* out of order */
+ const field_attrs_t fa = table[id];
+ assert(fa.id != id); /* avoid endless loops */
+ table[id] = table[i]; /* swap */
+ table[i] = fa;
+ } else
+ i++; /* make progress */
+ }
+
+ /* calculate name lengths */
+ for (i = 0; i < count; ++i) {
+ assert(table[i].name);
+ table[i].name_len = strlen(table[i].name);
+ tmp_debug(here) ("hdr table entry[%d]: %s (%d)\n", i, table[i].name, table[i].name_len);
+ assert(table[i].name_len);
+ }
+}
+
+/* calculates a bit mask of a given array (move this to lib/uitils) @?@ */
+static int
+httpHeaderCalcMask(const int *enums, int count)
+{
+ int i;
+ int mask = 0;
+ assert(enums);
+ assert(count < sizeof(int)*8); /* check for overflow */
+
+ for (i = 0; i < count; ++i) {
+ assert(enums[i] < sizeof(int)*8); /* check for overflow again */
+ assert(!EBIT_TEST(mask,enums[i])); /* check for duplicates */
+ EBIT_SET(mask, enums[i]);
+ }
+ return mask;
+}
+
+
+/*
+ * HttpHeader Implementation
+ */
+
+
+HttpHeader *
+httpHeaderCreate()
+{
+ HttpHeader *hdr = xmalloc(sizeof(HttpHeader));
+ httpHeaderInit(hdr);
+ return hdr;
+}
+
+
+/* "create" for non-alloc objects; also used by real Create */
+void
+httpHeaderInit(HttpHeader *hdr)
+{
+ assert(hdr);
+ memset(hdr, 0, sizeof(*hdr));
+ tmp_debug(here) ("init hdr: %p\n", hdr);
+}
+
+void
+httpHeaderClean(HttpHeader *hdr)
+{
+ HttpHeaderPos pos = HttpHeaderInitPos;
+
+ tmp_debug(here) ("cleaning hdr: %p\n", hdr);
+ assert(hdr);
+
+ if (hdr->capacity > INIT_FIELDS_PER_HEADER)
+ longHeadersCount++;
+ else
+ shortHeadersCount++;
+
+ while (httpHeaderGetEntry(hdr, &pos))
+ httpHeaderDelAt(hdr, pos);
+ xfree(hdr->entries);
+ hdr->emask = 0;
+ hdr->entries = NULL;
+ hdr->capacity = hdr->ucount = 0;
+}
+
+void
+httpHeaderDestroy(HttpHeader *hdr)
+{
+ httpHeaderClean(hdr);
+ xfree(hdr);
+}
+
+/* create a copy of self */
+HttpHeader *
+httpHeaderClone(HttpHeader *hdr)
+{
+ HttpHeader *clone = httpHeaderCreate();
+ HttpHeaderEntry *e;
+ HttpHeaderPos pos = HttpHeaderInitPos;
+
+ tmp_debug(here) ("cloning hdr: %p -> %p\n", hdr, clone);
+
+ while ((e = httpHeaderGetEntry(hdr, &pos))) {
+ HttpHeaderEntry e_clone = httpHeaderEntryClone(e);
+ httpHeaderAddNewEntry(clone, &e_clone);
+ }
+
+ return clone;
+}
+
+/* just handy in parsing: resets and returns false */
+static int
+httpHeaderReset(HttpHeader *hdr) {
+ httpHeaderClean(hdr);
+ httpHeaderInit(hdr);
+ return 0;
+}
+
+/*
+ * Note: currently, in most cases, we discard a field if we cannot parse it. We
+ * also truncate some field values (e.g. content-type). Thus, we may not
+ * forward exactly what was received. However, Squid keeps a copy of "raw"
+ * headers anyway, so we are safe until that changes. A possible alternative
+ * would be to store any buggy field as HDR_OTHER, but that still leaves a
+ * problem with truncated fields. The later one requires a better parser and
+ * additional storage, I guess.
+ */
+int
+httpHeaderParse(HttpHeader *hdr, const char *header_start, const char *header_end)
+{
+ const char *field_start = header_start;
+ HttpHeaderEntry e;
+ int mask = 0;
+
+ assert(hdr);
+ assert(header_start && header_end);
+ tmp_debug(here) ("parsing hdr: %p\n", hdr);
+ /* select appropriate field mask */
+ mask = (/* fix this @?@ @?@ */ 1 ) ? ReplyHeadersMask : RequestHeadersMask;
+ /* commonn format headers are ":[ws]" lines delimited by */
+ while (field_start < header_end) {
+ const char *field_end = field_start + strcspn(field_start, "\r\n");
+ /*tmp_debug(here) ("found end of field: %d\n", (int)*field_end);*/
+ if (!*field_end)
+ return httpHeaderReset(hdr); /* missing */
+ /*
+ * If we fail to parse a field, we ignore that field. We also could
+ * claim that the whole header is invalid. The latter is safer, but less
+ * robust. Note that we should be able to parse any commonn format field
+ */
+ if (!httpHeaderEntryParseInit(&e, field_start, field_end, mask))
+ debug(55, 1) ("warning: ignoring unparseable http header field near '%s'\n",
+ getStringPrefix(field_start));
+ else
+ httpHeaderAddParsedEntry(hdr, &e);
+ /*
+ * Note that we init() e, bit never clean() it which is equivalent to *
+ * creating a fresh entry on each loop iteration; thus, it is safe to *
+ * add e without dup()-ing it.
+ */
+ field_start = field_end;
+ /* skip CRLF */
+ if (*field_start == '\r') field_start++;
+ if (*field_start == '\n') field_start++;
+ }
+ return 1; /* even if no fields where found, they could be optional! */
+}
+
+/*
+ * packs all the entries into the buffer,
+ * returns number of bytes packed including terminating '\0'
+ */
+void
+httpHeaderPackInto(const HttpHeader *hdr, Packer *p)
+{
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ const HttpHeaderEntry *e;
+ assert(hdr && p);
+ tmp_debug(here) ("packing hdr: %p\n", hdr);
+ /* pack all entries one by one */
+ while ((e = httpHeaderGetEntry(hdr, &pos))) {
+ httpHeaderEntryPackInto(e, p);
+ }
+}
+
+/* returns next valid entry */
+static HttpHeaderEntry *
+httpHeaderGetEntry(const HttpHeader *hdr, HttpHeaderPos *pos)
+{
+ assert(hdr && pos);
+ assert(*pos >= HttpHeaderInitPos && *pos < hdr->capacity);
+ tmp_debug(here) ("searching next e in hdr %p from %d\n", hdr, *pos);
+ for ((*pos)++; *pos < hdr->ucount; (*pos)++) {
+ HttpHeaderEntry *e = hdr->entries + *pos;
+ if (httpHeaderEntryIsValid(e)) {
+ tmp_debug(here)("%p returning: %s at %d\n",
+ hdr, httpHeaderEntryName(e), *pos);
+ return e;
+ }
+ }
+ tmp_debug(here) ("failed to find entry in hdr %p\n", hdr);
+ return NULL;
+}
+
+/*
+ * returns a pointer to a specified entry and updates pos;
+ * note that we search from the very begining so it does not make much sense to
+ * ask for HDR_OTHER entries since there could be more than one.
+ */
+static HttpHeaderEntry *
+httpHeaderFindEntry(const HttpHeader *hdr, http_hdr_type id, HttpHeaderPos *pos)
+{
+ HttpHeaderPos p;
+ HttpHeaderEntry *e;
+ int is_absent;
+ assert(hdr);
+ assert_eid(id);
+ assert(id != HDR_OTHER);
+
+ tmp_debug(here) ("finding entry %d in hdr %p\n", id, hdr);
+ /* check mask first @?@ @?@ remove double checking and asserts when done */
+ is_absent = (id != HDR_OTHER && !EBIT_TEST(hdr->emask, id));
+ if (!pos) pos = &p;
+ *pos = HttpHeaderInitPos;
+ while ((e = httpHeaderGetEntry(hdr, pos))) {
+ if (e->id == id) {
+ assert(!is_absent);
+ return e;
+ }
+ }
+ assert(!EBIT_TEST(hdr->emask, id));
+ return NULL;
+}
+
+/*
+ * deletes all field(s) with a given name if any, returns #fields deleted;
+ * used to process Connection: header and delete fields in "paranoid" setup
+ */
+int
+httpHeaderDelFields(HttpHeader *hdr, const char *name)
+{
+ int count = 0;
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ HttpHeaderEntry *e;
+
+ tmp_debug(here) ("deleting '%s' fields in hdr %p\n", name, hdr);
+ while ((e = httpHeaderGetEntry(hdr, &pos))) {
+ if (!strcmp(httpHeaderEntryName(e), name)) {
+ httpHeaderDelAt(hdr, pos);
+ count++;
+ }
+ }
+ return count;
+}
+
+/*
+ * deletes an entry at pos and leaves a gap; leaving a gap makes it
+ * possible to iterate(search) and delete fields at the same time
+ */
+static void
+httpHeaderDelAt(HttpHeader *hdr, HttpHeaderPos pos)
+{
+ HttpHeaderEntry *e;
+ assert(hdr);
+ assert(pos >= 0 && pos < hdr->ucount);
+ e = hdr->entries + pos;
+ tmp_debug(here) ("%p deling entry at %d: id: %d (%p:%p)\n",
+ hdr, pos, e->id, hdr->entries, e);
+ /* sync masks */
+ httpHeaderSyncMasks(hdr, e, 0);
+ httpHeaderEntryClean(e);
+ if (pos == hdr->ucount)
+ hdr->ucount--;
+}
+
+/*
+ * adds parsed entry (joins entries if neeeded); assumes e.value is dup()-ed and
+ * clean()s it if needed. Thus, "e" should be treated as uninitialized after
+ * this function returns.
+ */
+static void
+httpHeaderAddParsedEntry(HttpHeader *hdr, HttpHeaderEntry *e)
+{
+ HttpHeaderEntry *olde;
+ assert(hdr);
+ assert_eid(e->id);
+
+ tmp_debug(here) ("%p adding parsed entry %d\n", hdr, e->id);
+
+ /* there is no good reason to add invalid entries */
+ if (!httpHeaderEntryIsValid(e))
+ return;
+
+ olde = (e->id == HDR_OTHER) ? NULL : httpHeaderFindEntry(hdr, e->id, NULL);
+ if (olde) {
+ if (EBIT_TEST(ListHeadersMask, e->id))
+ httpHeaderEntryJoinWith(olde, e);
+ else
+ debug(55, 1) ("ignoring duplicate header: %s\n", httpHeaderEntryName(e));
+ httpHeaderEntryClean(e);
+ } else {
+ /* actual add */
+ httpHeaderAddNewEntry(hdr, e);
+ }
+ tmp_debug(here) ("%p done adding parsed entry %d\n", hdr, e->id);
+}
+
+/*
+ * adds a new entry (low level append, does not check if entry is new) note: we
+ * copy e value, thus, e can point to a tmp variable (but e->field is not dupped!)
+ */
+static void
+httpHeaderAddNewEntry(HttpHeader *hdr, const HttpHeaderEntry *e)
+{
+ assert(hdr && e);
+ if (hdr->ucount >= hdr->capacity)
+ httpHeaderGrow(hdr);
+ tmp_debug(here) ("%p adding entry: %d at %d, (%p:%p)\n",
+ hdr, e->id, hdr->ucount,
+ hdr->entries, hdr->entries + hdr->ucount);
+ hdr->entries[hdr->ucount++] = *e;
+ /* sync masks */
+ httpHeaderSyncMasks(hdr, e, 1);
+ /* sync accounting */
+ httpHeaderSyncStats(hdr, e);
+}
+
+#if 0 /* save for parts */
+/*
+ * Splits list field and appends all entries separately;
+ * Warning: This is internal function, never call this directly,
+ * only for httpHeaderAddField use.
+ */
+static void
+httpHeaderAddListField(HttpHeader *hdr, HttpHeaderField *fld)
+{
+ const char *v;
+ assert(hdr);
+ assert(fld);
+ /*
+ * Note: assume that somebody already checked that we can split. The danger
+ * is in splitting something that is not a list field but contains ','s in
+ * its value.
+ */
+ /* we got a fld.value that is a list of values separated by ',' */
+ v = strtok(fld->value, ",");
+ httpHeaderAddSingleField(hdr, fld); /* first strtok() did its job! */
+ while ((v = strtok(NULL, ","))) {
+ /* ltrim and skip empty fields */
+ while (isspace(*v) || *v == ',') v++;
+ if (*v)
+ httpHeaderAddSingleField(hdr, httpHeaderFieldCreate(fld->name, v));
+ }
+}
+#endif
+
+/*
+ * Global (user level) routines
+ */
+
+/* test if a field is present */
+int httpHeaderHas(const HttpHeader *hdr, http_hdr_type id)
+{
+ assert(hdr);
+ assert_eid(id);
+ assert(id != HDR_OTHER);
+ tmp_debug(here) ("%p lookup for %d\n", hdr, id);
+ return EBIT_TEST(hdr->emask, id);
+
+#ifdef SLOW_BUT_SAFE
+ return httpHeaderFindEntry(hdr, id, NULL) != NULL;
+#endif
+}
+
+/* delete a field if any */
+void httpHeaderDel(HttpHeader *hdr, http_hdr_type id)
+{
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ assert(id != HDR_OTHER);
+ tmp_debug(here) ("%p del-by-id %d\n", hdr, id);
+ if (httpHeaderFindEntry(hdr, id, &pos)) {
+ httpHeaderDelAt(hdr, pos);
+ }
+}
+
+/*
+ * set a field
+ * setting an invaid value is equivalent to deleting a field
+ * (if field is not present, it is added; otherwise, old content is destroyed).
+ */
+static void
+httpHeaderSet(HttpHeader *hdr, http_hdr_type id, const field_store value)
+{
+ HttpHeaderPos pos;
+ HttpHeaderEntry e;
+ assert(hdr);
+ assert_eid(id);
+
+ tmp_debug(here) ("%p sets with id: %d\n", hdr, id);
+ if (httpHeaderFindEntry(hdr, id, &pos)) /* delete old entry */
+ httpHeaderDelAt(hdr, pos);
+
+ httpHeaderEntryInit(&e, id, httpHeaderFieldDup(Headers[id].type, value));
+ if (httpHeaderEntryIsValid(&e))
+ httpHeaderAddNewEntry(hdr, &e);
+ else
+ httpHeaderEntryClean(&e);
+}
+
+void
+httpHeaderSetInt(HttpHeader *hdr, http_hdr_type id, int number)
+{
+ field_store value;
+ assert_eid(id);
+ assert(Headers[id].type == ftInt); /* must be of an appropriatre type */
+ value.v_int = number;
+ httpHeaderSet(hdr, id, value);
+}
+
+void
+httpHeaderSetTime(HttpHeader *hdr, http_hdr_type id, time_t time)
+{
+ field_store value;
+ assert_eid(id);
+ assert(Headers[id].type == ftDate_1123); /* must be of an appropriatre type */
+ value.v_time = time;
+ httpHeaderSet(hdr, id, value);
+}
+void
+httpHeaderSetStr(HttpHeader *hdr, http_hdr_type id, const char *str)
+{
+ field_store value;
+ assert_eid(id);
+ assert(Headers[id].type == ftPChar); /* must be of a string type */
+ value.v_pcchar = str;
+ httpHeaderSet(hdr, id, value);
+}
+
+/* add extension header (these fields are not parsed/analyzed/joined, etc.) */
+void
+httpHeaderAddExt(HttpHeader *hdr, const char *name, const char* value)
+{
+ HttpHeaderExtField *ext = httpHeaderExtFieldCreate(name, value);
+ HttpHeaderEntry e;
+
+ tmp_debug(here) ("%p ads exte '%s:%s'\n", hdr, name, value);
+ httpHeaderEntryInit(&e, HDR_OTHER, ext);
+ httpHeaderAddNewEntry(hdr, &e);
+}
+
+/* get a value of a field (not lvalue though) */
+field_store
+httpHeaderGet(const HttpHeader *hdr, http_hdr_type id)
+{
+ HttpHeaderEntry *e;
+ assert_eid(id);
+ assert(id != HDR_OTHER); /* there is no single value for HDR_OTHER */
+
+ tmp_debug(here) ("%p get for id %d\n", hdr, id);
+ if ((e = httpHeaderFindEntry(hdr, id, NULL)))
+ return e->field;
+ else
+ return httpHeaderFieldBadValue(Headers[id].type);
+}
+
+const char *
+httpHeaderGetStr(const HttpHeader *hdr, http_hdr_type id)
+{
+ assert_eid(id);
+ assert(Headers[id].type == ftPChar); /* must be of an apropriate type */
+ return httpHeaderGet(hdr, id).v_pchar;
+}
+
+time_t
+httpHeaderGetTime(const HttpHeader *hdr, http_hdr_type id)
+{
+ assert_eid(id);
+ assert(Headers[id].type == ftDate_1123); /* must be of an apropriate type */
+ return httpHeaderGet(hdr, id).v_time;
+}
+
+HttpScc *
+httpHeaderGetScc(const HttpHeader *hdr)
+{
+ return httpHeaderGet(hdr, HDR_CACHE_CONTROL).v_pscc;
+}
+
+/* updates header masks */
+static void
+httpHeaderSyncMasks(HttpHeader *hdr, const HttpHeaderEntry *e, int add)
+{
+ int isSet;
+ assert(hdr && e);
+ assert_eid(e->id);
+
+ /* we cannot mask HDR_OTHER because it may not be unique */
+ if (e->id == HDR_OTHER)
+ return;
+ isSet = EBIT_TEST(hdr->emask, e->id) != 0;
+ add = add != 0;
+ assert(isSet ^ add);
+ add ? EBIT_SET(hdr->emask, e->id) : EBIT_CLR(hdr->emask, e->id);
+}
+
+/* updates header stats */
+static void
+httpHeaderSyncStats(HttpHeader *hdr, const HttpHeaderEntry *e)
+{
+#if 0 /* implement it @?@ */
+ assert(0); /* implement it */
+ /* add Req/Pep detection here @?@ */
+ int type = httpHeaderFindFieldType(fld,
+ HdrFieldAttrs, HDR_ENUM_END,
+ (1) ? ReplyHeadersMask : RequestHeadersMask);
+ /* exception */
+ if (type == HDR_PROXY_KEEPALIVE && strcasecmp("Keep-Alive", fld->value))
+ type = -1;
+ if (type < 0)
+ type = HDR_OTHER;
+ /* @?@ update stats for req/resp:type @?@ */
+ /* process scc @?@ check if we need to do that for requests or not */
+ if (1 && type == HDR_CACHE_CONTROL)
+ httpHeaderCountSCCField(hdr, fld);
+#endif
+}
+
+#if 0 /* move it */
+/* updates scc mask and stats for an scc field */
+static void
+httpHeaderCountSCCField(HttpHeader *hdr, HttpHeaderField *fld)
+{
+ int type = httpHeaderFindFieldType(fld,
+ SccFieldAttrs, SCC_ENUM_END, -1);
+ if (type < 0)
+ type = SCC_OTHER;
+ /* update mask */
+ EBIT_SET(hdr->scc_mask, type);
+ /* @?@ update stats for scc @?@ */
+ SccFieldAttrs[type].dummy.test1++;
+}
+#endif
+
+static int
+httpHeaderIdByName(const char *name, int name_len, const field_attrs_t *attrs, int end, int mask)
+{
+ int i;
+ for (i = 0; i < end; ++i) {
+ if (mask < 0 || EBIT_TEST(mask, i)) {
+ if (name_len >= 0 && name_len != attrs[i].name_len)
+ continue;
+ if (!strncasecmp(name, attrs[i].name,
+ name_len < 0 ? attrs[i].name_len+1 : name_len))
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* doubles the size of the fields index, starts with INIT_FIELDS_PER_HEADER */
+static void
+httpHeaderGrow(HttpHeader *hdr)
+{
+ int new_cap;
+ int new_size;
+ assert(hdr);
+ new_cap = (hdr->capacity) ? 2*hdr->capacity : INIT_FIELDS_PER_HEADER;
+ new_size = new_cap*sizeof(HttpHeaderEntry);
+
+ tmp_debug(here) ("%p grow (%p) %d->%d\n", hdr, hdr->entries, hdr->capacity, new_cap);
+ hdr->entries = hdr->entries ?
+ xrealloc(hdr->entries, new_size) :
+ xmalloc(new_size);
+ memset(hdr->entries+hdr->capacity, 0, (new_cap-hdr->capacity)*sizeof(HttpHeaderEntry));
+ hdr->capacity = new_cap;
+ tmp_debug(here) ("%p grew (%p)\n", hdr, hdr->entries);
+}
+
+/*
+ * HttpHeaderEntry
+ */
+
+static void
+httpHeaderEntryInit(HttpHeaderEntry *e, http_hdr_type id, field_store field)
+{
+ assert(e);
+ assert_eid(id);
+ e->id = id;
+ e->field = field;
+}
+
+static void
+httpHeaderEntryClean(HttpHeaderEntry *e) {
+ assert(e);
+ assert_eid(e->id);
+ /* type-based cleanup */
+ switch (Headers[e->id].type) {
+ case ftInvalid:
+ case ftInt:
+ case ftDate_1123:
+ /* no special cleaning is necessary */
+ break;
+ case ftPChar:
+ freeShortString(e->field.v_pchar);
+ break;
+ case ftPSCC:
+ if (e->field.v_pscc)
+ httpSccDestroy(e->field.v_pscc);
+ break;
+ case ftPExtField:
+ if (e->field.v_pefield)
+ httpHeaderExtFieldDestroy(e->field.v_pefield);
+ break;
+ default:
+ assert(0); /* somebody added a new type? */
+ }
+ /* we have to do that so entry will be _invlaid_ */
+ e->id = -1;
+ e->field.v_pchar = NULL;
+}
+
+/* parses and inits header entry, returns true on success */
+static int
+httpHeaderEntryParseInit(HttpHeaderEntry *e, const char *field_start, const char *field_end, int mask)
+{
+ HttpHeaderExtField *f;
+ int id;
+ int result;
+
+ /* first assume it is just an extension field */
+ f = httpHeaderExtFieldParseCreate(field_start, field_end);
+ if (!f) /* parsing failure */
+ return 0;
+ id = httpHeaderIdByName(f->name, -1, Headers, countof(Headers), mask);
+ if (id < 0)
+ id = HDR_OTHER;
+ if (id == HDR_OTHER) {
+ /* hm.. it is an extension field indeed */
+ httpHeaderEntryInit(e, id, f);
+ return 1;
+ }
+ /* ok, we got something interesting, parse it further */
+ result = httpHeaderEntryParseExtFieldInit(e, id, f);
+ /* do not need it anymore */
+ httpHeaderExtFieldDestroy(f);
+ return result;
+}
+
+static int
+httpHeaderEntryParseExtFieldInit(HttpHeaderEntry *e, int id, const HttpHeaderExtField *f)
+{
+ /*
+ * check for exceptions first (parsing is not determined by value type)
+ * then parse using value type if needed
+ */
+ switch (id) {
+ case HDR_PROXY_KEEPALIVE:
+ /* we treat Proxy-Connection as "keep alive" only if it says so */
+ e->field.v_int = !strcasecmp(f->value, "Keep-Alive");
+ break;
+ default:
+ /* if we got here, it is something that can be parsed based on value type */
+ if (!httpHeaderEntryParseByTypeInit(e, id, f))
+ return 0;
+ }
+ /* parsing was successful, post-processing maybe required */
+ switch (id) {
+ case HDR_CONTENT_TYPE: {
+ /* cut off "; parameter" from Content-Type @?@ why? */
+ const int l = strcspn(e->field.v_pchar, ";\t ");
+ if (l > 0)
+ e->field.v_pchar[l] = '\0';
+ break;
+ }
+ case HDR_EXPIRES:
+ /*
+ * The HTTP/1.0 specs says that robust implementations should
+ * consider bad or malformed Expires header as equivalent to
+ * "expires immediately."
+ */
+ if (!httpHeaderEntryIsValid(e))
+ e->field.v_time = squid_curtime;
+ /*
+ * real expiration value also depends on max-age too, but it is not
+ * of our business (HttpReply should handle it)
+ */
+ break;
+ }
+ return 1;
+}
+
+static int
+httpHeaderEntryParseByTypeInit(HttpHeaderEntry *e, int id, const HttpHeaderExtField *f)
+{
+ int type;
+ field_store field;
+ assert(e && f);
+ assert_eid(id);
+ type = Headers[id].type;
+
+ httpHeaderFieldInit(&field);
+ switch(type) {
+ case ftInt:
+ field.v_int = atoi(f->value);
+ if (!field.v_int && !isdigit(*f->value)) {
+ debug(55, 1) ("cannot parse an int header field: id: %d, field: '%s: %s'\n",
+ id, f->name, f->value);
+ return 0;
+ }
+ break;
+
+ case ftPChar:
+ field.v_pchar = dupShortStr(f->value);
+ break;
+
+ case ftDate_1123:
+ field.v_time = parse_rfc1123(f->value);
+ /*
+ * if parse_rfc1123 fails we fall through anyway so upper levels
+ * will notice invalid date
+ */
+ break;
+
+ case ftPSCC:
+ field.v_pscc = httpSccParseCreate(f->value);
+ if (!field.v_pscc) {
+ debug(55, 0) ("failed to parse scc hdr: id: %d, field: '%s: %s'\n",
+ id, f->name, f->value);
+ return 0;
+ }
+ break;
+
+ default:
+ debug(55, 0) ("something went wrong with hdr field type analysis: id: %d, type: %d, field: '%s: %s'\n",
+ id, type, f->name, f->value);
+ return 0;
+ }
+ /* success, do actual init */
+ httpHeaderEntryInit(e, id, field);
+ return 1;
+}
+
+
+static HttpHeaderEntry
+httpHeaderEntryClone(const HttpHeaderEntry *e)
+{
+ HttpHeaderEntry clone;
+ assert(e);
+ assert_eid(e->id);
+ httpHeaderEntryInit(&clone, e->id,
+ httpHeaderFieldDup(Headers[e->id].type, e->field));
+ return clone;
+}
+
+static void
+httpHeaderEntryPackInto(const HttpHeaderEntry *e, Packer *p)
+{
+ assert(e && p);
+
+ /* swap the field_name: */
+ packerPrintf(p, "%s: ", httpHeaderEntryName(e));
+ /*
+ * swap the value
+ * check for exceptions (packing is not determined by value type)
+ * then swap using value type
+ */
+ switch (e->id) {
+ case HDR_PROXY_KEEPALIVE:
+ packerPrintf(p, "%s", "Keep-Alive");
+ break;
+ default:
+ /* if we got here, it is something that can be swap based on value type */
+ httpHeaderEntryPackByType(e, p);
+ }
+ /* add CRLF */
+ packerPrintf(p, "%s", "\r\n");
+}
+
+static void
+httpHeaderEntryPackByType(const HttpHeaderEntry *e, Packer *p)
+{
+ field_type type;
+ assert(e && p);
+ assert_eid(e->id);
+ type = Headers[e->id].type;
+ switch(type) {
+ case ftInt:
+ packerPrintf(p, "%d", e->field.v_int);
+ break;
+ case ftPChar:
+ packerPrintf(p, "%s", e->field.v_pchar);
+ break;
+ case ftDate_1123:
+ packerPrintf(p, "%s", mkrfc1123(e->field.v_time));
+ break;
+ case ftPSCC:
+ httpSccPackValueInto(e->field.v_pscc, p);
+ break;
+ case ftPExtField:
+ packerPrintf(p, "%s", e->field.v_pefield->value);
+ break;
+ default:
+ assert(0 && type); /* pack for invalid/unknown type */
+ }
+}
+
+static void
+httpHeaderEntryJoinWith(HttpHeaderEntry *e, const HttpHeaderEntry *newe)
+{
+ field_type type;
+ assert(e && newe);
+ assert_eid(e->id);
+ assert(e->id == newe->id);
+
+ /* type-based join */
+ type = Headers[e->id].type;
+ switch(type) {
+ case ftPChar:
+ e->field.v_pchar = appShortStr(e->field.v_pchar, newe->field.v_pchar);
+ break;
+ case ftPSCC:
+ httpSccJoinWith(e->field.v_pscc, newe->field.v_pscc);
+ break;
+ default:
+ debug(55, 0) ("join for invalid/unknown type: id: %d, type: %d\n", e->id, type);
+ assert(0);
+ }
+}
+
+
+static int
+httpHeaderEntryIsValid(const HttpHeaderEntry *e)
+{
+ assert(e);
+ if (e->id == -1)
+ return 0;
+ assert_eid(e->id);
+ /* type-based analysis */
+ switch(Headers[e->id].type) {
+ case ftInvalid:
+ return 0;
+ case ftInt:
+ return e->field.v_int >= 0;
+ case ftPChar:
+ return e->field.v_pchar != NULL;
+ break;
+ case ftDate_1123:
+ return e->field.v_time >= 0;
+ break;
+ case ftPSCC:
+ return e->field.v_pscc != NULL;
+ break;
+ case ftPExtField:
+ return e->field.v_pefield != NULL;
+ break;
+ default:
+ assert(0); /* query for invalid/unknown type */
+ }
+ return 0; /* not reached */
+}
+
+static const char *
+httpHeaderEntryName(const HttpHeaderEntry *e)
+{
+ assert(e);
+ assert_eid(e->id);
+
+ return (e->id == HDR_OTHER) ?
+ e->field.v_pefield->name : Headers[e->id].name;
+}
+
+/*
+ * HttpHeaderField
+ */
+
+static void
+httpHeaderFieldInit(field_store *field)
+{
+ assert(field);
+ memset(field, 0, sizeof(field_store));
+}
+
+static field_store
+httpHeaderFieldDup(field_type type, field_store value)
+{
+ /* type based duplication */
+ switch(type) {
+ case ftInt:
+ return value.v_int;
+ case ftPChar:
+ return dupShortStr(value.v_pchar);
+ break;
+ case ftDate_1123:
+ return value.v_time;
+ break;
+ case ftPSCC:
+ return httpSccDup(value.v_pscc);
+ break;
+ case ftPExtField:
+ return httpHeaderExtFieldDup(value.v_pefield);
+ break;
+ default:
+ assert(0); /* dup of invalid/unknown type */
+ }
+ return NULL; /* not reached */
+}
+
+/*
+ * bad value table; currently bad values are determined by field type, but this
+ * can be changed in the future to reflect dependence on entry id if any
+ */
+static field_store
+httpHeaderFieldBadValue(field_type type)
+{
+ switch(type) {
+ case ftInt:
+ case ftDate_1123:
+ return -1;
+ case ftPChar:
+ case ftPSCC:
+ case ftPExtField:
+ return NULL;
+ case ftInvalid:
+ default:
+ assert(0); /* query for invalid/unknown type */
+ }
+ return NULL; /* not reached */
+}
+
+/*
+ * HttpScc (server cache control)
+ */
+
+static HttpScc *
+httpSccCreate()
+{
+ HttpScc *scc = memAllocate(MEM_HTTP_SCC, 1);
+ scc->max_age = -1;
+ return scc;
+}
+
+/* creates an scc object from a 0-terminating string*/
+static HttpScc *
+httpSccParseCreate(const char *str)
+{
+ HttpScc *scc = httpSccCreate();
+ httpSccParseInit(scc, str);
+ return scc;
+}
+
+/* parses a 0-terminating string and inits scc */
+static void
+httpSccParseInit(HttpScc *scc, const char *str)
+{
+ const char *item;
+ const char *p; /* '=' parameter */
+ const char *pos = NULL;
+ int type;
+ int ilen;
+ assert(scc && str);
+
+ /* iterate through comma separated list */
+ while(strListGetItem(str, ',', &item, &ilen, &pos)) {
+ /* strip '=' statements @?@ */
+ if ((p = strchr(item, '=')) && (p-item < ilen))
+ ilen = p++ - item;
+ /* find type */
+ type = httpHeaderIdByName(item, ilen,
+ SccAttrs, SCC_ENUM_END, -1);
+ if (type < 0) {
+ debug(55, 0) ("cc: unknown cache-directive: near '%s' in '%s'\n", item, str);
+ continue;
+ }
+ if (EBIT_TEST(scc->mask, type)) {
+ debug(55, 0) ("cc: ignoring duplicate cache-directive: near '%s' in '%s'\n", item, str);
+ continue;
+ }
+ /* update mask */
+ EBIT_SET(scc->mask, type);
+ /* post-processing special cases */
+ switch (type) {
+ case SCC_MAX_AGE:
+ if (p)
+ scc->max_age = (time_t) atoi(p);
+ if (scc->max_age < 0) {
+ debug(55, 0) ("scc: invalid max-age specs near '%s'\n", item);
+ scc->max_age = -1;
+ EBIT_CLR(scc->mask, type);
+ }
+ break;
+ default:
+ /* note that we ignore most of '=' specs @?@ */
+ break;
+ }
+ }
+ return;
+}
+
+static void
+httpSccDestroy(HttpScc *scc)
+{
+ assert(scc);
+ memFree(MEM_HTTP_SCC, scc);
+}
+
+static HttpScc *
+httpSccDup(HttpScc *scc)
+{
+ HttpScc *dup;
+ assert(scc);
+ dup = httpSccCreate();
+ dup->mask = scc->mask;
+ dup->max_age = scc->max_age;
+ return dup;
+}
+
+static void
+httpSccPackValueInto(HttpScc *scc, Packer *p)
+{
+ http_scc_type flag;
+ int pcount = 0;
+ assert(scc && p);
+ if (scc->max_age >= 0) {
+ packerPrintf(p, "max-age=%d", scc->max_age);
+ pcount++;
+ }
+ for (flag = 0; flag < SCC_ENUM_END; flag++) {
+ if (EBIT_TEST(scc->mask, flag)) {
+ packerPrintf(p, pcount ? ", %s" : "%s", SccAttrs[flag].name);
+ pcount++;
+ }
+ }
+}
+
+static void
+httpSccJoinWith(HttpScc *scc, HttpScc *new_scc)
+{
+ assert(scc && new_scc);
+ if (scc->max_age < 0)
+ scc->max_age = new_scc->max_age;
+ scc->mask |= new_scc->mask;
+}
+
+
+
+/*
+ * HttpHeaderExtField
+ */
+
+static HttpHeaderExtField *
+httpHeaderExtFieldCreate(const char *name, const char *value)
+{
+ HttpHeaderExtField *f = xcalloc(1, sizeof(HttpHeaderExtField));
+ f->name = dupShortStr(name);
+ f->value = dupShortStr(value);
+ return f;
+}
+
+/* parses ext field; returns fresh ext field on success and NULL on failure */
+static HttpHeaderExtField *
+httpHeaderExtFieldParseCreate(const char *field_start, const char *field_end)
+{
+ HttpHeaderExtField *f = NULL;
+ /* note: name_start == field_start */
+ const char *name_end = strchr(field_start, ':');
+ const char *value_start;
+ /* note: value_end == field_end */
+
+ if (!name_end || name_end <= field_start || name_end > field_end)
+ return NULL;
+
+ tmp_debug(here) ("got field len: %d\n", field_end-field_start);
+
+ value_start = name_end + 1; /* skip ':' */
+ /* skip white space */
+ while (value_start < field_end && isspace(*value_start))
+ value_start++;
+
+ /* cut off "; parameter" from Content-Type @?@ why? */
+ if (!strncasecmp(field_start, "Content-Type:", 13)) {
+ const int l = strcspn(value_start, ";\t ");
+ if (l > 0 && value_start + l < field_end)
+ field_end = value_start + l;
+ }
+
+ f = xcalloc(1, sizeof(HttpHeaderExtField));
+ f->name = dupShortBuf(field_start, name_end-field_start);
+ f->value = dupShortBuf(value_start, field_end-value_start);
+ tmp_debug(here) ("%p got field: '%s: %s'\n", f, f->name, f->value);
+ return f;
+}
+
+static void
+httpHeaderExtFieldDestroy(HttpHeaderExtField *f)
+{
+ assert(f);
+ freeShortString(f->name);
+ freeShortString(f->value);
+ xfree(f);
+}
+
+static HttpHeaderExtField *
+httpHeaderExtFieldDup(HttpHeaderExtField *f)
+{
+ assert(f);
+ return httpHeaderExtFieldCreate(f->name, f->value);
+}
+
+#if 0 /* save for parts */
+
+/*
+ * returns the space requred to put a field (and terminating !) into a
+ * buffer
+ */
+static size_t
+httpHeaderFieldBufSize(const HttpHeaderExtField *fld)
+{
+ return strlen(fld->name)+2+strlen(fld->value)+2;
+}
+
+/*
+ * returns true if fld.name is a "known" splitable field;
+ * always call this function to check because the detection algortihm may change
+ */
+static int
+httpHeaderFieldIsList(const HttpHeaderExtField *fld) {
+ int i;
+ assert(fld);
+ /* "onten" should not match "Content"! */
+ for (i = 0; i < KnownSplitableFieldCount; ++i)
+ if (strcasecmp(KnownSplitableFields[i], fld->name))
+ return 1;
+ return 0;
+}
+
+#endif
+
+static void
+httpHeaderStoreAReport(StoreEntry *e, void (*reportPacker)(Packer *p))
+{
+ Packer p;
+ assert(e);
+ packerToStoreInit(&p, e);
+ (*reportPacker)(&p);
+ packerClean(&p);
+}
+
+void
+httpHeaderStoreReport(StoreEntry *e)
+{
+ httpHeaderStoreAReport(e, &httpHeaderPackReport);
+}
+
+void
+httpHeaderStoreReqReport(StoreEntry *e)
+{
+ httpHeaderStoreAReport(e, &httpHeaderPackReqReport);
+}
+
+void
+httpHeaderStoreRepReport(StoreEntry *e)
+{
+ httpHeaderStoreAReport(e, &httpHeaderPackRepReport);
+}
+
+
+static void
+httpHeaderPackReport(Packer *p)
+{
+ assert(p);
+
+ httpHeaderPackRepReport(p);
+ httpHeaderPackReqReport(p);
+
+ /* low level totals; reformat this? @?@ */
+ packerPrintf(p,
+ "hdrs totals: %uld+%uld %s lstr: +%uld-%uld<(%uld=%uld)\n",
+ shortHeadersCount,
+ longHeadersCount,
+ memPoolReport(shortStrings),
+ longStrAllocCount,
+ longStrFreeCount,
+ longStrHighWaterCount,
+ longStrHighWaterSize);
+}
+
+static void
+httpHeaderPackRepReport(Packer *p)
+{
+ assert(p);
+#if 0 /* implement this */
+ httpHeaderPackAReport(p, &ReplyHeaderStats);
+ for (i = SCC_PUBLIC; i < SCC_ENUM_END; i++)
+ storeAppendPrintf(entry, "Cache-Control %s: %d\n",
+ HttpServerCCStr[i],
+ ReplyHeaderStats.cc[i]);
+#endif
+}
+
+static void
+httpHeaderPackReqReport(Packer *p)
+{
+ assert(p);
+#if 0 /* implement this */
+ httpHeaderPackAReport(p, &RequestHeaderStats);
+#endif
+}
+
+#if 0 /* implement this */
+static void
+httpHeaderPackAReport(Packer *p, HttpHeaderStats *stats)
+{
+ assert(p);
+ assert(stats);
+ assert(0);
+ http_server_cc_t i;
+ http_hdr_misc_t j;
+ storeAppendPrintf(entry, "HTTP Reply Headers:\n");
+ storeAppendPrintf(entry, " Headers parsed: %d\n",
+ ReplyHeaderStats.parsed);
+ for (j = HDR_AGE; j < HDR_MISC_END; j++)
+ storeAppendPrintf(entry, "%21.21s: %d\n",
+ HttpHdrMiscStr[j],
+ ReplyHeaderStats.misc[j]);
+}
+#endif
+
+/* "short string" routines below are trying to recycle memory for short strings */
+static char *
+dupShortStr(const char *str)
+{
+ return dupShortBuf(str, strlen(str));
+}
+
+static char *
+dupShortBuf(const char *str, size_t len)
+{
+ char *buf;
+ assert(str);
+ assert(len >= 0);
+ buf = allocShortBuf(len + 1);
+ assert(buf);
+ if (len)
+ xmemcpy(buf, str, len); /* may not have terminating 0 */
+ buf[len] = '\0'; /* terminate */
+ tmp_debug(here) ("dupped short buf[%d]: '%s'\n", len, buf);
+ return buf;
+}
+
+static char *
+appShortStr(char *str, const char *app_str)
+{
+ const size_t size = strlen(str)+strlen(app_str)+1;
+ char *buf = allocShortBuf(size);
+ snprintf(buf, size, "%s, %s", str, app_str);
+ freeShortString(str);
+ return buf;
+}
+
+static char *
+allocShortBuf(size_t sz)
+{
+ char *buf = NULL;
+ assert(shortStrings);
+ /* tmp_debug(here) ("allocating short buffer of size %d (max: %d)\n", sz, shortStrings->obj_size); @?@ */
+ if (sz > shortStrings->obj_size) {
+ buf = xmalloc(sz);
+ longStrAllocCount++;
+ longStrAllocSize += sz;
+ if (longStrHighWaterCount < longStrAllocCount - longStrFreeCount)
+ longStrHighWaterCount = longStrAllocCount - longStrFreeCount;
+ if (longStrHighWaterSize < longStrAllocSize - longStrFreeSize)
+ longStrHighWaterSize = longStrAllocSize - longStrFreeSize;
+ } else
+ buf = memPoolGetObj(shortStrings);
+ return buf;
+}
+
+static void
+freeShortString(char *str)
+{
+ assert(shortStrings);
+ if (str) {
+ const size_t sz = strlen(str)+1;
+ /* tmp_debug(here) ("freeing short str of size %d (max: %d)'%s'\n", sz, shortStrings->obj_size, str); @?@ */
+ if (sz > shortStrings->obj_size) {
+ tmp_debug(here) ("LONG short string[%d>%d]: %s\n", sz, shortStrings->obj_size, str);
+ xfree(str);
+ longStrFreeCount++;
+ longStrFreeSize += sz;
+ } else
+ memPoolPutObj(shortStrings, str);
+ }
+}
+
+/*
+ * other routines (move these into lib if you need them somewhere else?)
+ */
+
+/*
+ * iterates through a 0-terminated string of items separated by 'del'
+ * white space around 'del' is considered to be a part of 'del'
+ * like strtok, but preserves the source
+ *
+ * returns true if next item is found
+ * init pos with NULL to start iteration
+ */
+static int
+strListGetItem(const char *str, char del, const char **item, int *ilen, const char **pos)
+{
+ size_t len;
+ assert(str && item && pos);
+ if (*pos)
+ if (!**pos) /* end of string */
+ return 0;
+ else
+ (*pos)++;
+ else
+ *pos = str;
+
+ /* skip leading ws (ltrim) */
+ *pos += xcountws(*pos);
+ *item = *pos; /* remember item's start */
+ /* find next delimiter */
+ *pos = strchr(*item, del);
+ if (!*pos) /* last item */
+ *pos = *item + strlen(*item);
+ len = *pos - *item; /* *pos points to del or '\0' */
+ /* rtrim */
+ while (len > 0 && isspace((*item)[len-1])) len--;
+ if (ilen)
+ *ilen = len;
+ return len > 0;
+}
+
+/* handy to printf prefixes of potentially very long buffers */
+static const char *
+getStringPrefix(const char *str) {
+#define SHORT_PREFIX_SIZE 256
+ LOCAL_ARRAY(char, buf, SHORT_PREFIX_SIZE);
+ xstrncpy(buf, str, SHORT_PREFIX_SIZE);
+ return buf;
+}
diff --git a/src/HttpReply.cc b/src/HttpReply.cc
new file mode 100644
index 0000000000..2f3bda5c9d
--- /dev/null
+++ b/src/HttpReply.cc
@@ -0,0 +1,402 @@
+/*
+ * $Id: HttpReply.cc,v 1.2 1998/02/21 00:56:43 rousskov Exp $
+ *
+ * DEBUG: section ?? HTTP Reply
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* tmp hack, delete it @?@ */
+#define Const
+
+#include "squid.h"
+
+
+/* local constants */
+
+/* local routines */
+static int httpReplyParseStep(HttpReply *rep, const char *parse_start, int atEnd);
+static int httpReplyParseError(HttpReply *rep);
+static int httpReplyIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end);
+static int httpReplyIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end);
+
+
+HttpReply *
+httpReplyCreate()
+{
+ HttpReply *rep = memAllocate(MEM_HTTPREPLY, 1);
+ tmp_debug(here) ("creating rep: %p\n", rep);
+ httpReplyInit(rep);
+ return rep;
+}
+
+void
+httpReplyInit(HttpReply *rep)
+{
+ assert(rep);
+ rep->hdr_sz = 0;
+ rep->pstate = psReadyToParseStartLine;
+ httpBodyInit(&rep->body);
+ httpHeaderInit(&rep->hdr);
+ httpStatusLineInit(&rep->sline);
+}
+
+void
+httpReplyClean(HttpReply *rep)
+{
+ assert(rep);
+ httpBodyClean(&rep->body);
+ httpHeaderClean(&rep->hdr);
+ httpStatusLineClean(&rep->sline);
+}
+
+void
+httpReplyDestroy(HttpReply *rep)
+{
+ assert(rep);
+ tmp_debug(here) ("destroying rep: %p\n", rep);
+ httpReplyClean(rep);
+ memFree(MEM_HTTPREPLY, rep);
+}
+
+void
+httpReplyReset(HttpReply *rep)
+{
+ httpReplyClean(rep);
+ httpReplyInit(rep);
+}
+
+/* parses a buffer that may not be 0-terminated */
+int
+httpReplyParse(HttpReply *rep, const char *buf)
+{
+ /*
+ * this extra buffer/copy will be eliminated when headers become meta-data
+ * in store. Currently we have to xstrncpy the buffer becuase store.c may
+ * feed a non 0-terminated buffer to us @?@.
+ */
+ char *headers = memAllocate(MEM_4K_BUF, 1);
+ int success;
+ /* reset current state, because we are not used in incremental fashion */
+ httpReplyReset(rep);
+ /* put a 0-terminator */
+ xstrncpy(headers, buf, 4096);
+ success = httpReplyParseStep(rep, headers, 0);
+ memFree(MEM_4K_BUF, headers);
+ return success == 1;
+}
+
+void
+httpReplyPackInto(const HttpReply *rep, Packer *p)
+{
+ assert(rep);
+ httpStatusLinePackInto(&rep->sline, p);
+ httpHeaderPackInto(&rep->hdr, p);
+ packerAppend(p, "\r\n", 2);
+ httpBodyPackInto(&rep->body, p);
+}
+
+/* create memBuf, create mem-based packer, pack, destroy packer, return MemBuf */
+MemBuf
+httpReplyPack(const HttpReply *rep)
+{
+ MemBuf mb;
+ Packer p;
+ assert(rep);
+
+ memBufDefInit(&mb);
+ packerToMemInit(&p, &mb);
+ httpReplyPackInto(rep, &p);
+ packerClean(&p);
+ return mb;
+}
+
+/* swap: create swap-based packer, pack, destroy packer */
+void
+httpReplySwapOut(const HttpReply *rep, StoreEntry *e)
+{
+ Packer p;
+ assert(rep && e);
+
+ packerToStoreInit(&p, e);
+ httpReplyPackInto(rep, &p);
+ packerClean(&p);
+}
+
+MemBuf
+httpPackedReply(double ver, http_status status, const char *ctype,
+ int clen, time_t lmt, time_t expires)
+{
+ HttpReply *rep = httpReplyCreate();
+ MemBuf mb;
+ httpReplySetHeaders(rep, ver, status, ctype, NULL, clen, lmt, expires);
+ mb = httpReplyPack(rep);
+ httpReplyDestroy(rep);
+ return mb;
+}
+
+MemBuf
+httpPacked304Reply(const HttpReply *rep)
+{
+ MemBuf mb;
+ assert(rep);
+
+#if 0
+ /* construct reply */
+ assert(0); /* implement: rep304 = httpReply304Create(rep); */
+
+ mb = httpReplyPack(rep304);
+ httpReplyDestroy(rep304);
+#endif
+
+ memBufDefInit(&mb);
+
+ memBufPrintf(&mb, "%s", "HTTP/1.0 304 Not Modified\r\n");
+
+ if (httpHeaderHas(&rep->hdr, HDR_DATE))
+ memBufPrintf(&mb, "Date: %s\r\n", mkrfc1123(
+ httpHeaderGetTime(&rep->hdr, HDR_DATE)));
+
+ if (httpHeaderHas(&rep->hdr, HDR_CONTENT_TYPE))
+ memBufPrintf(&mb, "Content-type: %s\r\n",
+ httpHeaderGetStr(&rep->hdr, HDR_CONTENT_TYPE));
+
+ if (httpHeaderHas(&rep->hdr, HDR_CONTENT_LENGTH))
+ memBufPrintf(&mb, "Content-Length: %d\r\n",
+ httpReplyContentLen(rep));
+
+ if (httpHeaderHas(&rep->hdr, HDR_EXPIRES))
+ memBufPrintf(&mb, "Expires: %s\r\n", mkrfc1123(
+ httpHeaderGetTime(&rep->hdr, HDR_EXPIRES)));
+
+ if (httpHeaderHas(&rep->hdr, HDR_LAST_MODIFIED))
+ memBufPrintf(&mb, "Last-modified: %s\r\n", mkrfc1123(
+ httpHeaderGetTime(&rep->hdr, HDR_LAST_MODIFIED)));
+
+ memBufAppend(&mb, "\r\n", 2);
+ return mb;
+}
+
+void
+httpReplySetHeaders(HttpReply *reply, double ver, http_status status, const char *reason,
+ const char *ctype, int clen, time_t lmt, time_t expires)
+{
+ HttpHeader *hdr;
+ assert(reply);
+ httpStatusLineSet(&reply->sline, ver, status, reason);
+ hdr = &reply->hdr;
+ httpHeaderAddExt(hdr, "Server", full_appname_string);
+ httpHeaderAddExt(hdr, "MIME-Version", "1.0"); /* do we need this? @?@ */
+ httpHeaderSetTime(hdr, HDR_DATE, squid_curtime);
+ if (ctype)
+ httpHeaderSetStr(hdr, HDR_CONTENT_TYPE, ctype);
+ if (clen > 0)
+ httpHeaderSetInt(hdr, HDR_CONTENT_LENGTH, clen);
+ if (expires >= 0)
+ httpHeaderSetTime(hdr, HDR_EXPIRES, expires);
+ if (lmt > 0) /* this used to be lmt != 0 @?@ */
+ httpHeaderSetTime(hdr, HDR_LAST_MODIFIED, lmt);
+}
+
+void
+httpReplyUpdateOnNotModified(HttpReply *rep, HttpReply *freshRep)
+{
+#if 0 /* this is what we want: */
+ rep->cache_control = freshRep->cache_control;
+ rep->misc_headers = freshRep->misc_headers;
+ if (freshRep->date > -1)
+ rep->date = freshRep->date;
+ if (freshRep->last_modified > -1)
+ rep->last_modified = freshRep->last_modified;
+ if (freshRep->expires > -1)
+ rep->expires = freshRep->expires;
+#endif
+ time_t date;
+ time_t expires;
+ time_t lmt;
+ assert(rep && freshRep);
+ /* save precious info */
+ date = httpHeaderGetTime(&rep->hdr, HDR_DATE);
+ expires= httpReplyExpires(rep);
+ lmt = httpHeaderGetTime(&rep->hdr, HDR_LAST_MODIFIED);
+ /* clean old headers */
+ httpHeaderClean(&rep->hdr);
+ /* clone */
+ rep->hdr = *httpHeaderClone(&freshRep->hdr);
+ /* restore missing info if needed */
+ if (!httpHeaderHas(&rep->hdr, HDR_DATE))
+ httpHeaderSetTime(&rep->hdr, HDR_DATE, date);
+ if (!httpHeaderHas(&rep->hdr, HDR_EXPIRES))
+ httpHeaderSetTime(&rep->hdr, HDR_EXPIRES, expires);
+ if (!httpHeaderHas(&rep->hdr, HDR_LAST_MODIFIED))
+ httpHeaderSetTime(&rep->hdr, HDR_LAST_MODIFIED, lmt);
+}
+
+int
+httpReplyContentLen(const HttpReply *rep) {
+ assert(rep);
+ return httpHeaderGet(&rep->hdr, HDR_CONTENT_LENGTH).v_int;
+}
+
+/* should we return "" or NULL if no content-type? Return NULL for now @?@ */
+const char *
+httpReplyContentType(const HttpReply *rep) {
+ assert(rep);
+ return httpHeaderGetStr(&rep->hdr, HDR_CONTENT_TYPE);
+}
+
+/* does it make sense to cache these computations ? @?@ */
+time_t
+httpReplyExpires(const HttpReply *rep)
+{
+ HttpScc *scc;
+ time_t exp = -1;
+ assert(rep);
+ /* The max-age directive takes priority over Expires, check it first */
+ scc = httpHeaderGetScc(&rep->hdr);
+ if (scc)
+ exp = scc -> max_age;
+ if (exp < 0)
+ exp = httpHeaderGetTime(&rep->hdr, HDR_EXPIRES);
+ return exp;
+}
+
+int
+httpReplyHasScc(const HttpReply *rep, http_scc_type type)
+{
+ HttpScc *scc;
+ assert(rep);
+ assert(type >= 0 && type < SCC_ENUM_END);
+
+ scc = httpHeaderGetScc(&rep->hdr);
+ return scc && /* scc header is present */
+ EBIT_TEST(scc->mask, type);
+}
+
+
+/* internal routines */
+
+
+/*
+ * parses a 0-terminating buffer into HttpReply.
+ * Returns:
+ * +1 -- success
+ * 0 -- need more data (partial parse)
+ * -1 -- parse error
+ */
+static int
+httpReplyParseStep(HttpReply *rep, const char *buf, int atEnd)
+{
+ const char *parse_start = buf;
+ const char *blk_start, *blk_end;
+ const char **parse_end_ptr = &blk_end;
+ assert(rep);
+ assert(parse_start);
+ assert(rep->pstate < psParsed);
+
+ *parse_end_ptr = parse_start;
+ if (rep->pstate == psReadyToParseStartLine) {
+ if (!httpReplyIsolateStart(&parse_start, &blk_start, &blk_end))
+ return 0;
+ if (!httpStatusLineParse(&rep->sline, blk_start, blk_end))
+ return httpReplyParseError(rep);
+
+ *parse_end_ptr = parse_start;
+ rep->hdr_sz = *parse_end_ptr - buf;
+ rep->pstate++;
+ }
+
+ if (rep->pstate == psReadyToParseHeaders) {
+ if (!httpReplyIsolateHeaders(&parse_start, &blk_start, &blk_end))
+ if (atEnd)
+ blk_start = parse_start, blk_end = blk_start + strlen(blk_start);
+ else
+ return 0;
+ if (!httpHeaderParse(&rep->hdr, blk_start, blk_end))
+ return httpReplyParseError(rep);
+
+ *parse_end_ptr = parse_start;
+ rep->hdr_sz = *parse_end_ptr - buf;
+ rep->pstate++;
+ }
+
+ /* could check here for a _small_ body that we could parse right away?? @?@ */
+
+ return 1;
+}
+
+
+/* handy: resets and returns -1 */
+static int
+httpReplyParseError(HttpReply *rep)
+{
+ assert(rep);
+ /* reset */
+ httpReplyReset(rep);
+ /* indicate an error */
+ rep->sline.status = HTTP_INVALID_HEADER;
+ return -1;
+}
+
+/* find first CRLF */
+static int
+httpReplyIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end)
+{
+ int slen = strcspn(*parse_start, "\r\n");
+ if (!(*parse_start)[slen]) /* no CRLF found */
+ return 0;
+
+ *blk_start = *parse_start;
+ *blk_end = *blk_start + slen;
+ if (**blk_end == '\r') /* CR */
+ (*blk_end)++;
+ if (**blk_end == '\n') /* LF */
+ (*blk_end)++;
+
+ *parse_start = *blk_end;
+ return 1;
+}
+
+/* find end of headers */
+static int
+httpReplyIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end)
+{
+ /* adopted with mods from mime_headers_end() */
+ const char *p1 = strstr(*parse_start, "\n\r\n");
+ const char *p2 = strstr(*parse_start, "\n\n");
+ const char *end = NULL;
+
+ if (p1 && p2)
+ end = p1 < p2 ? p1 : p2;
+ else
+ end = p1 ? p1 : p2;
+
+ if (end) {
+ *blk_start = *parse_start;
+ *blk_end = end + 1;
+ *parse_start = end + (end == p1 ? 3 : 2);
+ }
+ return end != NULL;
+}
diff --git a/src/HttpStatusLine.cc b/src/HttpStatusLine.cc
new file mode 100644
index 0000000000..f334318c82
--- /dev/null
+++ b/src/HttpStatusLine.cc
@@ -0,0 +1,213 @@
+/*
+ * $Id: HttpStatusLine.cc,v 1.2 1998/02/21 00:56:44 rousskov Exp $
+ *
+ * DEBUG: section ?? HTTP Status-line
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "squid.h"
+
+
+/* local constants */
+const char *HttpStatusLineFormat = "HTTP/%3.1f %3d %s\r\n";
+
+/* local routines */
+static const char *httpStatusString(http_status status);
+
+void
+httpStatusLineInit(HttpStatusLine *sline) {
+ httpStatusLineSet(sline, 0.0, 0, NULL);
+}
+
+void
+httpStatusLineClean(HttpStatusLine *sline) {
+ httpStatusLineSet(sline, 0.0, 500, NULL);
+}
+
+void httpStatusLineSet(HttpStatusLine *sline, double version, http_status status, const char *reason) {
+ assert(sline);
+ sline->version = version;
+ sline->status = status;
+ /* Note: no xstrdup for 'reason', assumes constant 'reasons' */
+ sline->reason = reason;
+}
+
+void
+httpStatusLinePackInto(const HttpStatusLine *sline, Packer *p)
+{
+ assert(sline && p);
+ tmp_debug(here) ("packing sline %p using %p:\n", sline, p);
+ tmp_debug(here) (HttpStatusLineFormat, sline->version, sline->status,
+ sline->reason ? sline->reason : httpStatusString(sline->status));
+ packerPrintf(p, HttpStatusLineFormat,
+ sline->version, sline->status,
+ sline->reason ? sline->reason : httpStatusString(sline->status));
+}
+
+int
+httpStatusLineParse(HttpStatusLine *sline, const char *start, const char *end) {
+ assert(sline);
+ sline->status = HTTP_INVALID_HEADER; /* Squid header parsing error */
+ if (strncasecmp(start, "HTTP/", 5))
+ return 0;
+ start += 5;
+ if (!isdigit(*start))
+ return 0;
+ sline->version = atof(start);
+ if (!(start = strchr(start, ' ')))
+ return 0;
+ sline->status = atoi(++start);
+ /* we ignore 'reason-phrase' */
+ return 1; /* success */
+}
+
+static const char *
+httpStatusString(http_status status)
+{
+ /* why not to return matching string instead of using "p" ? @?@ */
+ const char *p = NULL;
+ switch (status) {
+ case 0:
+ p = "Init"; /* we init .status with code 0 */
+ break;
+ case 100:
+ p = "Continue";
+ break;
+ case 101:
+ p = "Switching Protocols";
+ break;
+ case 200:
+ p = "OK";
+ break;
+ case 201:
+ p = "Created";
+ break;
+ case 202:
+ p = "Accepted";
+ break;
+ case 203:
+ p = "Non-Authoritative Information";
+ break;
+ case 204:
+ p = "No Content";
+ break;
+ case 205:
+ p = "Reset Content";
+ break;
+ case 206:
+ p = "Partial Content";
+ break;
+ case 300:
+ p = "Multiple Choices";
+ break;
+ case 301:
+ p = "Moved Permanently";
+ break;
+ case 302:
+ p = "Moved Temporarily";
+ break;
+ case 303:
+ p = "See Other";
+ break;
+ case 304:
+ p = "Not Modified";
+ break;
+ case 305:
+ p = "Use Proxy";
+ break;
+ case 400:
+ p = "Bad Request";
+ break;
+ case 401:
+ p = "Unauthorized";
+ break;
+ case 402:
+ p = "Payment Required";
+ break;
+ case 403:
+ p = "Forbidden";
+ break;
+ case 404:
+ p = "Not Found";
+ break;
+ case 405:
+ p = "Method Not Allowed";
+ break;
+ case 406:
+ p = "Not Acceptable";
+ break;
+ case 407:
+ p = "Proxy Authentication Required";
+ break;
+ case 408:
+ p = "Request Time-out";
+ break;
+ case 409:
+ p = "Conflict";
+ break;
+ case 410:
+ p = "Gone";
+ break;
+ case 411:
+ p = "Length Required";
+ break;
+ case 412:
+ p = "Precondition Failed";
+ break;
+ case 413:
+ p = "Request Entity Too Large";
+ break;
+ case 414:
+ p = "Request-URI Too Large";
+ break;
+ case 415:
+ p = "Unsupported Media Type";
+ break;
+ case 500:
+ p = "Internal Server Error";
+ break;
+ case 501:
+ p = "Not Implemented";
+ break;
+ case 502:
+ p = "Bad Gateway";
+ break;
+ case 503:
+ p = "Service Unavailable";
+ break;
+ case 504:
+ p = "Gateway Time-out";
+ break;
+ case 505:
+ p = "HTTP Version not supported";
+ break;
+ default:
+ p = "Unknown";
+ debug(11, 0) ("Unknown HTTP status code: %d\n", status);
+ break;
+ }
+ return p;
+}
diff --git a/src/Makefile.in b/src/Makefile.in
index 2dfce42d22..4aa8b56eba 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
#
# Makefile for the Squid Object Cache server
#
-# $Id: Makefile.in,v 1.122 1998/02/19 23:09:46 wessels Exp $
+# $Id: Makefile.in,v 1.123 1998/02/21 00:56:46 rousskov Exp $
#
# Uncomment and customize the following to suit your needs:
#
@@ -89,6 +89,10 @@ OBJS = \
hash.o \
http.o \
http-anon.o \
+ HttpStatusLine.o \
+ HttpHeader.o \
+ HttpBody.o \
+ HttpReply.o \
icmp.o \
icp_v2.o \
icp_v3.o \
@@ -97,11 +101,13 @@ OBJS = \
ipcache.o \
main.o \
mem.o \
+ MemBuf.o \
mime.o \
multicast.o \
neighbors.o \
net_db.o \
cache_manager.o \
+ Packer.o \
pass.o \
pconn.o \
peer_select.o \
diff --git a/src/MemBuf.cc b/src/MemBuf.cc
new file mode 100644
index 0000000000..23c39374af
--- /dev/null
+++ b/src/MemBuf.cc
@@ -0,0 +1,186 @@
+/*
+ * $Id: MemBuf.cc,v 1.2 1998/02/21 00:56:47 rousskov Exp $
+ *
+ * DEBUG: section ?? Memory Buffer with printf
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* see MemBuf.h for documentation */
+
+/*
+ * To-Do: uses memory pools for .buf recycling @?@
+ */
+
+
+#include "squid.h"
+
+/* local routines */
+static void memBufGrow(MemBuf *mb, mb_size_t min_cap);
+
+
+
+void
+memBufInit(MemBuf *mb, mb_size_t szInit, mb_size_t szMax)
+{
+ assert(mb);
+ assert(szInit > 0 && szMax > 0);
+
+ mb->buf = NULL;
+ mb->size = 0;
+ mb->max_capacity = szMax;
+ mb->capacity = 0;
+ mb->freefunc = NULL;
+
+ memBufGrow(mb, szInit);
+}
+
+void
+memBufClean(MemBuf *mb)
+{
+ assert(mb);
+ assert(mb->buf);
+ assert(mb->freefunc); /* not frozen */
+
+ (*mb->freefunc)(mb->buf); /* freeze */
+ mb->buf = NULL;
+ mb->size = mb->capacity = 0;
+}
+
+void
+memBufAppend(MemBuf *mb, const char *buf, mb_size_t sz)
+{
+ assert(mb && buf && sz >= 0);
+ assert(mb->buf);
+ assert(mb->freefunc); /* not frozen */
+
+ if (sz > 0) {
+ if (mb->size + sz > mb->capacity)
+ memBufGrow(mb, mb->size + sz);
+ assert(mb->size + sz <= mb->capacity); /* paranoid */
+ xmemcpy(mb->buf + mb->size, buf, sz);
+ mb->size += sz;
+ }
+}
+
+#ifdef __STDC__
+void
+memBufPrintf(MemBuf *mb, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+void
+memBufPrintf(va_alist)
+ va_dcl
+{
+ va_list args;
+ MemBuf *mb = NULL;
+ const char *fmt = NULL;
+ mb_size_t sz = 0;
+ va_start(args);
+ mb = va_arg(args, MemBuf *);
+ fmt = va_arg(args, char *);
+#endif
+ memBufVPrintf(mb, fmt, args);
+ va_end(args);
+}
+
+
+void
+memBufVPrintf(MemBuf *mb, const char *fmt, va_list vargs)
+{
+ mb_size_t sz = 0;
+ assert(mb && fmt);
+ assert(mb->buf);
+ assert(mb->freefunc); /* not frozen */
+ /* @?@ we do not init buf with '\0', do we have to for vsnprintf?? @?@ */
+ /* assert in Grow should quit first, but we do not want to have a scare (1) loop */
+ while (mb->capacity <= mb->max_capacity) {
+ mb_size_t free_space = mb->capacity - mb->size;
+ /* put as much as we can */
+ sz = vsnprintf(mb->buf + mb->size, free_space, fmt, vargs) + 1;
+ /* check for possible overflow @?@ can vsnprintf cut more than needed off? */
+ if (sz + 32 >= free_space) /* magic constant 32, ARGH! @?@ */
+ memBufGrow(mb, mb->capacity+1);
+ else
+ break;
+ }
+ mb->size += sz-1; /* note that we cut 0-terminator as store does @?@ @?@ */
+}
+
+FREE *
+memBufFreeFunc(MemBuf *mb)
+{
+ FREE *ff;
+ assert(mb);
+ assert(mb->buf);
+ assert(mb->freefunc); /* not frozen */
+
+ ff = mb->freefunc;
+ mb->freefunc = NULL; /* freeze */
+ return ff;
+}
+
+/* grows (doubles) internal buffer to satisfy required minimal capacity */
+static void
+memBufGrow(MemBuf *mb, mb_size_t min_cap)
+{
+ mb_size_t new_cap;
+ assert(mb);
+ assert(mb->capacity < min_cap);
+
+ /* determine next capacity */
+ new_cap = mb->capacity;
+ if (new_cap > 0)
+ while (new_cap < min_cap) new_cap *= 2; /* double */
+ else
+ new_cap = min_cap;
+
+ /* last chance to fit before we assert(!overflow) */
+ if (new_cap > mb->max_capacity)
+ new_cap = mb->max_capacity;
+
+ assert(new_cap <= mb->max_capacity); /* no overflow */
+ assert(new_cap > mb->capacity); /* progress */
+
+ /* finally [re]allocate memory */
+ if (!mb->buf) {
+ mb->buf = xmalloc(new_cap);
+ mb->freefunc = &xfree;
+ } else {
+ assert(mb->freefunc);
+ mb->buf = realloc(mb->buf, new_cap);
+ }
+ memset(mb->buf+mb->size, 0, new_cap-mb->size); /* just in case */
+ mb->capacity = new_cap;
+}
+
+void
+memBufReport(MemBuf *mb)
+{
+ assert(mb);
+ memBufPrintf(mb, "memBufReport is not yet implemented @?@\n");
+}
diff --git a/src/Packer.cc b/src/Packer.cc
new file mode 100644
index 0000000000..47d02282b0
--- /dev/null
+++ b/src/Packer.cc
@@ -0,0 +1,127 @@
+/*
+ * $Id: Packer.cc,v 1.2 1998/02/21 00:56:48 rousskov Exp $
+ *
+ * DEBUG: section ?? Packer: Uniform interface to "Storing" modules
+ * AUTHOR: Alex Rousskov
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by
+ * the National Science Foundation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* see Packer.h for documentation */
+
+/*
+ * To-Do:
+ */
+
+
+#include "squid.h"
+
+/* local types */
+
+/* local routines */
+
+/* local constants and vars */
+
+/*
+ * We do have one potential problem here. Both append_f and vprintf_f types
+ * cannot match real functions precisely (at least because of the difference in
+ * the type of the first parameter). Thus, we have to use type cast. If somebody
+ * changes the prototypes of real functions, Packer will not notice that because
+ * of the type cast.
+ *
+ * Solution: we use the constants below to *hard code* current prototypes of
+ * real functions. If real prototypes change, these constants will produce a
+ * warning (e.g., "warning: assignment from incompatible pointer type").
+ */
+
+/* append()'s */
+static void (*const store_append)(StoreEntry *, const char *, int) = &storeAppend;
+static void (*const memBuf_append)(MemBuf *, const char *, mb_size_t) = &memBufAppend;
+
+/* vprintf()'s */
+static void (*const store_vprintf)(StoreEntry *, const char *, va_list ap) = &storeAppendVPrintf;
+static void (*const memBuf_vprintf)(MemBuf *, const char *, va_list ap) = &memBufVPrintf;
+
+
+void
+packerToStoreInit(Packer *p, StoreEntry *e)
+{
+ assert(p && e);
+ p->append = (append_f)store_append;
+ p->vprintf = (vprintf_f)storeAppendVPrintf;
+ p->real_handler = e;
+}
+
+void
+packerToMemInit(Packer *p, MemBuf *mb)
+{
+ assert(p && mb);
+ p->append = (append_f)memBuf_append;
+ p->vprintf = (vprintf_f)memBuf_vprintf;
+ p->real_handler = mb;
+}
+
+void
+packerClean(Packer *p)
+{
+ assert(p);
+ /* it is not really necessary to do this, but, just in case... */
+ p->append = NULL;
+ p->vprintf = NULL;
+ p->real_handler = NULL;
+}
+
+void
+packerAppend(Packer *p, const char *buf, int sz)
+{
+ assert(p);
+ assert(p->real_handler && p->append);
+ p->append(p->real_handler, buf, sz);
+}
+
+#ifdef __STDC__
+void
+packerPrintf(Packer *p, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+void
+packerPrintf(va_alist)
+ va_dcl
+{
+ va_list args;
+ Packer *p = NULL;
+ const char *fmt = NULL;
+ int sz = 0;
+ va_start(args);
+ p = va_arg(args, Packer *);
+ fmt = va_arg(args, char *);
+#endif
+ assert(p);
+ assert(p->real_handler && p->vprintf);
+ tmp_debug(here) ("printf: fmt: '%s'\n", fmt);
+ p->vprintf(p->real_handler, fmt, args);
+ va_end(args);
+}
diff --git a/src/cache_manager.cc b/src/cache_manager.cc
index b67222de80..9f9c3e48cb 100644
--- a/src/cache_manager.cc
+++ b/src/cache_manager.cc
@@ -1,6 +1,6 @@
/*
- * $Id: cache_manager.cc,v 1.2 1998/02/19 23:11:48 wessels Exp $
+ * $Id: cache_manager.cc,v 1.3 1998/02/21 00:56:50 rousskov Exp $
*
* DEBUG: section 16 Cache Manager Objects
* AUTHOR: Duane Wessels
@@ -140,7 +140,9 @@ cachemgrStart(int fd, StoreEntry * entry)
{
cachemgrStateData *mgr = NULL;
ErrorState *err = NULL;
+#if 0
char *hdr;
+#endif
action_table *a;
debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry));
if ((mgr = cachemgrParse(storeUrl(entry))) == NULL) {
@@ -168,6 +170,14 @@ cachemgrStart(int fd, StoreEntry * entry)
a = cachemgrFindAction(mgr->action);
assert(a != NULL);
storeBuffer(entry);
+ {
+ HttpReply *rep = httpReplyCreate();
+ httpReplySetHeaders(rep, (double) 1.0, HTTP_OK, NULL,
+ "text/plain", -1 /* C-Len */, squid_curtime /* LMT */, squid_curtime);
+ httpReplySwapOut(rep, entry);
+ httpReplyDestroy(rep);
+ }
+#if 0
hdr = httpReplyHeader((double) 1.0,
HTTP_OK,
"text/plain",
@@ -176,6 +186,7 @@ cachemgrStart(int fd, StoreEntry * entry)
squid_curtime);
storeAppend(entry, hdr, strlen(hdr));
storeAppend(entry, "\r\n", 2);
+#endif
a->handler(entry);
storeBufferFlush(entry);
storeComplete(entry);
diff --git a/src/client_side.cc b/src/client_side.cc
index feec850bea..d15f211f86 100644
--- a/src/client_side.cc
+++ b/src/client_side.cc
@@ -1,6 +1,6 @@
/*
- * $Id: client_side.cc,v 1.211 1998/02/19 23:07:36 wessels Exp $
+ * $Id: client_side.cc,v 1.212 1998/02/21 00:56:50 rousskov Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
@@ -32,8 +32,8 @@
#include "squid.h"
static const char *const crlf = "\r\n";
-static const char *const proxy_auth_line =
-"Proxy-Authenticate: Basic realm=\"Squid proxy-caching web server\"\r\n";
+static const char *const proxy_auth_challenge =
+ "Basic realm=\"Squid proxy-caching web server\"";
#define REQUEST_BUF_SIZE 4096
#define FAILURE_MODE_TIME 300
@@ -46,7 +46,9 @@ static PF clientReadRequest;
static PF connStateFree;
static PF requestTimeout;
static STCB clientGetHeadersForIMS;
+#if 0
static char *clientConstruct304reply(struct _http_reply *);
+#endif
static int CheckQuickAbort2(const clientHttpRequest *);
static int clientCheckTransferDone(clientHttpRequest *);
static void CheckQuickAbort(clientHttpRequest *);
@@ -64,7 +66,11 @@ static STCB clientCacheHit;
static void clientParseRequestHeaders(clientHttpRequest *);
static void clientProcessRequest(clientHttpRequest *);
static void clientProcessExpired(void *data);
+#if 0
static char *clientConstructProxyAuthReply(clientHttpRequest * http);
+#else
+static HttpReply *clientConstructProxyAuthReply(clientHttpRequest * http);
+#endif
static int clientCachable(clientHttpRequest * http);
static int clientHierarchical(clientHttpRequest * http);
static int isTcpHit(log_type code);
@@ -108,6 +114,7 @@ clientAccessCheck(void *data)
aclNBCheck(http->acl_checklist, clientAccessCheckDone, http);
}
+#if 0 /* reimplemented using new interfaces */
static char *
clientConstructProxyAuthReply(clientHttpRequest * http)
{
@@ -156,6 +163,20 @@ clientConstructProxyAuthReply(clientHttpRequest * http)
content);
return buf;
}
+#endif
+
+static HttpReply *
+clientConstructProxyAuthReply(clientHttpRequest *http)
+{
+ ErrorState *err = errorCon(ERR_CACHE_ACCESS_DENIED, HTTP_PROXY_AUTHENTICATION_REQUIRED);
+ HttpReply *rep;
+ err->request = requestLink(http->request);
+ rep = errorBuildReply(err);
+ errorStateFree(err);
+ /* add Authenticate header */
+ httpHeaderSetStr(&rep->hdr, HDR_PROXY_AUTHENTICATE, proxy_auth_challenge);
+ return rep;
+}
StoreEntry *
clientCreateStoreEntry(clientHttpRequest * h, method_t m, int flags)
@@ -184,7 +205,6 @@ clientAccessCheckDone(int answer, void *data)
{
clientHttpRequest *http = data;
char *redirectUrl = NULL;
- char *buf;
ErrorState *err = NULL;
debug(33, 5) ("clientAccessCheckDone: '%s' answer=%d\n", http->uri, answer);
http->acl_checklist = NULL;
@@ -196,9 +216,19 @@ clientAccessCheckDone(int answer, void *data)
} else if (answer == ACCESS_REQ_PROXY_AUTH) {
http->al.http.code = HTTP_PROXY_AUTHENTICATION_REQUIRED;
http->log_type = LOG_TCP_DENIED;
- buf = clientConstructProxyAuthReply(http);
http->entry = clientCreateStoreEntry(http, http->request->method, 0);
+#if 0
+ const char *buf = clientConstructProxyAuthReply(http);
storeAppend(http->entry, buf, strlen(buf));
+#else
+ {
+ /* create appropreate response */
+ HttpReply *rep = clientConstructProxyAuthReply(http);
+ httpReplySwapOut(rep, http->entry);
+ /* do not need it anymore */
+ httpReplyDestroy(rep);
+ }
+#endif
} else {
debug(33, 5) ("Access Denied: %s\n", http->uri);
http->log_type = LOG_TCP_DENIED;
@@ -299,8 +329,9 @@ clientGetsOldEntry(StoreEntry * new_entry, StoreEntry * old_entry, request_t * r
{
/* If the reply is anything but "Not Modified" then
* we must forward it to the client */
- if (new_entry->mem_obj->reply->code != 304) {
- debug(33, 5) ("clientGetsOldEntry: NO, reply=%d\n", new_entry->mem_obj->reply->code);
+ const http_status status = new_entry->mem_obj->reply->sline.status;
+ if (status != 304) {
+ debug(33, 5) ("clientGetsOldEntry: NO, reply=%d\n", status);
return 0;
}
/* If the client did not send IMS in the request, then it
@@ -342,7 +373,7 @@ clientHandleIMSReply(void *data, char *buf, ssize_t size)
storeUnlockObject(entry);
entry = http->entry = http->old_entry;
entry->refcount++;
- } else if (mem->reply->code == 0) {
+ } else if (mem->reply->sline.status == 0) {
debug(33, 3) ("clientHandleIMSReply: Incomplete headers for '%s'\n", url);
if (entry->store_status == STORE_ABORTED)
debug(33, 0) ("clientHandleIMSReply: entry->swap_status == STORE_ABORTED\n");
@@ -368,7 +399,7 @@ clientHandleIMSReply(void *data, char *buf, ssize_t size)
* www.thegist.com (Netscape/1.13) returns a content-length for
* 304's which seems to be the length of the 304 HEADERS!!! and
* not the body they refer to. */
- storeCopyNotModifiedReplyHeaders(entry->mem_obj, oldentry->mem_obj);
+ httpReplyUpdateOnNotModified(entry->mem_obj->reply, oldentry->mem_obj->reply);
storeTimestampsSet(oldentry);
storeUnregister(entry, http);
storeUnlockObject(entry);
@@ -381,7 +412,7 @@ clientHandleIMSReply(void *data, char *buf, ssize_t size)
} else {
/* the client can handle this reply, whatever it is */
http->log_type = LOG_TCP_REFRESH_MISS;
- if (mem->reply->code == 304) {
+ if (mem->reply->sline.status == 304) {
http->old_entry->timestamp = squid_curtime;
http->old_entry->refcount++;
http->log_type = LOG_TCP_REFRESH_HIT;
@@ -417,9 +448,8 @@ modifiedSince(StoreEntry * entry, request_t * request)
if (entry->lastmod < 0)
return 1;
/* Find size of the object */
- if (mem->reply->content_length >= 0)
- object_length = mem->reply->content_length;
- else
+ object_length = httpReplyContentLen(mem->reply);
+ if (object_length < 0)
object_length = contentLen(entry);
if (entry->lastmod > request->ims) {
debug(33, 3) ("--> YES: entry newer than client\n");
@@ -472,10 +502,18 @@ void
clientPurgeRequest(clientHttpRequest * http)
{
int fd = http->conn->fd;
+#if 0
char *msg;
+#endif
StoreEntry *entry;
ErrorState *err = NULL;
const cache_key *k;
+#if 0
+ int len;
+ FREE *freefunc;
+#endif
+ MemBuf mb;
+
debug(33, 3) ("Config.onoff.enable_purge = %d\n", Config.onoff.enable_purge);
if (!Config.onoff.enable_purge) {
http->log_type = LOG_TCP_DENIED;
@@ -494,10 +532,15 @@ clientPurgeRequest(clientHttpRequest * http)
storeRelease(entry);
http->http_code = HTTP_OK;
}
+#if 0 /* new interface */
msg = httpReplyHeader(1.0, http->http_code, NULL, 0, 0, -1);
if ((int) strlen(msg) < 8190)
strcat(msg, "\r\n");
comm_write(fd, xstrdup(msg), strlen(msg), clientWriteComplete, http, xfree);
+#else
+ mb = httpPackedReply(1.0, http->http_code, NULL, 0, 0, -1);
+ comm_write_mbuf(fd, mb, clientWriteComplete, http);
+#endif
}
int
@@ -554,8 +597,8 @@ httpRequestFree(void *data)
http->al.icp.opcode = 0;
http->al.url = http->uri;
if (mem) {
- http->al.http.code = mem->reply->code;
- http->al.http.content_type = mem->reply->content_type;
+ http->al.http.code = mem->reply->sline.status;
+ http->al.http.content_type = httpReplyContentType(mem->reply);
}
http->al.cache.caddr = conn->log_addr;
http->al.cache.size = http->out.size;
@@ -1013,7 +1056,11 @@ clientWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *da
} else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) {
debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd);
/* We're finished case */
+#if 0
if (http->entry->mem_obj->reply->content_length < 0 || !done ||
+#else
+ if (httpReplyContentLen(http->entry->mem_obj->reply) < 0 || !done ||
+#endif
EBIT_TEST(entry->flag, ENTRY_BAD_LENGTH)) {
/*
* Client connection closed due to unknown or invalid
@@ -1075,7 +1122,10 @@ clientGetHeadersForIMS(void *data, char *buf, ssize_t size)
clientHttpRequest *http = data;
StoreEntry *entry = http->entry;
MemObject *mem;
+#if 0
+ MemObject *mem;
char *reply = NULL;
+#endif
debug(33, 3) ("clientGetHeadersForIMS: %s, %d bytes\n",
http->uri, (int) size);
assert(size <= SM_PAGE_SIZE);
@@ -1096,7 +1146,7 @@ clientGetHeadersForIMS(void *data, char *buf, ssize_t size)
return;
}
mem = entry->mem_obj;
- if (mem->reply->code == 0) {
+ if (mem->reply->sline.status == 0) {
if (entry->mem_status == IN_MEMORY) {
clientProcessMiss(http);
return;
@@ -1124,7 +1174,7 @@ clientGetHeadersForIMS(void *data, char *buf, ssize_t size)
}
/* All headers are available, check if object is modified or not */
/* ---------------------------------------------------------------
- * Removed check for reply->code != 200 because of a potential
+ * Removed check for reply->sline.status != 200 because of a potential
* problem with ICP. We will return a HIT for any public, cached
* object. This includes other responses like 301, 410, as coded in
* http.c. It is Bad(tm) to return UDP_HIT and then, if the reply
@@ -1137,9 +1187,9 @@ clientGetHeadersForIMS(void *data, char *buf, ssize_t size)
* ---------------------------------------------------------------- */
#ifdef CHECK_REPLY_CODE_NOTEQUAL_200
/* Only objects with statuscode==200 can be "Not modified" */
- if (mem->reply->code != 200) {
+ if (mem->reply->sline.status != 200) {
debug(33, 4) ("clientGetHeadersForIMS: Reply code %d!=200\n",
- mem->reply->code);
+ mem->reply->sline.status);
clientProcessMiss(http);
return;
}
@@ -1159,6 +1209,7 @@ clientGetHeadersForIMS(void *data, char *buf, ssize_t size)
return;
}
debug(33, 4) ("clientGetHeadersForIMS: Not modified '%s'\n", storeUrl(entry));
+#if 0 /* use new interfaces */
reply = clientConstruct304reply(mem->reply);
comm_write(http->conn->fd,
xstrdup(reply),
@@ -1166,6 +1217,10 @@ clientGetHeadersForIMS(void *data, char *buf, ssize_t size)
clientHandleIMSComplete,
http,
xfree);
+#else
+ comm_write_mbuf(http->conn->fd, httpPacked304Reply(mem->reply),
+ clientHandleIMSComplete, http);
+#endif
}
static void
@@ -1244,7 +1299,9 @@ clientProcessRequest(clientHttpRequest * http)
StoreEntry *entry = NULL;
request_t *r = http->request;
int fd = http->conn->fd;
+#if 0
char *hdr;
+#endif
debug(33, 4) ("clientProcessRequest: %s '%s'\n",
RequestMethodStr[r->method],
url);
@@ -1260,6 +1317,7 @@ clientProcessRequest(clientHttpRequest * http)
http->entry = clientCreateStoreEntry(http, r->method, 0);
storeReleaseRequest(http->entry);
storeBuffer(http->entry);
+#if 0 /* use new interface */
hdr = httpReplyHeader(1.0,
HTTP_OK,
"text/plain",
@@ -1268,6 +1326,14 @@ clientProcessRequest(clientHttpRequest * http)
squid_curtime);
storeAppend(http->entry, hdr, strlen(hdr));
storeAppend(http->entry, "\r\n", 2);
+#else
+ {
+ HttpReply *rep = httpReplyCreate();
+ httpReplySetHeaders(rep, 1.0, HTTP_OK, NULL, "text/plain", r->headers_sz, 0, squid_curtime);
+ httpReplySwapOut(rep, http->entry);
+ httpReplyDestroy(rep);
+ }
+#endif
storeAppend(http->entry, r->headers, r->headers_sz);
storeComplete(http->entry);
return;
@@ -1874,7 +1940,11 @@ CheckQuickAbort2(const clientHttpRequest * http)
return 1;
if (http->entry->mem_obj == NULL)
return 1;
+#if 0
expectlen = http->entry->mem_obj->reply->content_length;
+#else
+ expectlen = httpReplyContentLen(http->entry->mem_obj->reply);
+#endif
curlen = http->entry->mem_obj->inmem_hi;
minlen = Config.quickAbort.min;
if (minlen < 0)
@@ -1924,6 +1994,7 @@ clientCheckTransferDone(clientHttpRequest * http)
MemObject *mem;
http_reply *reply;
int sendlen;
+ int clen;
if (entry == NULL)
return 0;
/*
@@ -1945,13 +2016,13 @@ clientCheckTransferDone(clientHttpRequest * http)
reply = mem->reply;
if (reply->hdr_sz == 0)
return 0; /* haven't found end of headers yet */
- else if (reply->code == HTTP_OK)
+ else if (reply->sline.status == HTTP_OK)
sending = SENDING_BODY;
- else if (reply->code == HTTP_NO_CONTENT)
+ else if (reply->sline.status == HTTP_NO_CONTENT)
sending = SENDING_HDRSONLY;
- else if (reply->code == HTTP_NOT_MODIFIED)
+ else if (reply->sline.status == HTTP_NOT_MODIFIED)
sending = SENDING_HDRSONLY;
- else if (reply->code < HTTP_OK)
+ else if (reply->sline.status < HTTP_OK)
sending = SENDING_HDRSONLY;
else if (http->request->method == METHOD_HEAD)
sending = SENDING_HDRSONLY;
@@ -1963,12 +2034,13 @@ clientCheckTransferDone(clientHttpRequest * http)
* then we must wait for the object to become STORE_OK or
* STORE_ABORTED.
*/
+ clen = httpReplyContentLen(reply);
if (sending == SENDING_HDRSONLY)
sendlen = reply->hdr_sz;
- else if (reply->content_length < 0)
+ else if (clen < 0)
return 0;
else
- sendlen = reply->content_length + reply->hdr_sz;
+ sendlen = clen + reply->hdr_sz;
/*
* Now that we have the expected length, did we send it all?
*/
@@ -1978,8 +2050,9 @@ clientCheckTransferDone(clientHttpRequest * http)
return 1;
}
+#if 0 /* moved to HttpReply */
static char *
-clientConstruct304reply(struct _http_reply *source)
+clientConstruct304reply(http_reply *source)
{
LOCAL_ARRAY(char, line, 256);
LOCAL_ARRAY(char, reply, 8192);
@@ -2009,6 +2082,7 @@ clientConstruct304reply(struct _http_reply *source)
strcat(reply, "\r\n");
return reply;
}
+#endif
/*
* This function is designed to serve a fairly specific purpose.
diff --git a/src/comm.cc b/src/comm.cc
index 8bf055ff93..eb45cd9652 100644
--- a/src/comm.cc
+++ b/src/comm.cc
@@ -1,6 +1,6 @@
/*
- * $Id: comm.cc,v 1.229 1998/02/18 00:38:53 wessels Exp $
+ * $Id: comm.cc,v 1.230 1998/02/21 00:56:52 rousskov Exp $
*
* DEBUG: section 5 Socket Functions
* AUTHOR: Harvest Derived
@@ -1446,6 +1446,13 @@ comm_write(int fd, char *buf, int size, CWCB * handler, void *handler_data, FREE
0);
}
+/* a wrapper around comm_write to allow for MemBuf to comm_written in a snap */
+void
+comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
+{
+ comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
+}
+
int
ignoreErrno(int ierrno)
{
diff --git a/src/defines.h b/src/defines.h
index d37484543a..0d373d8c7f 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -49,6 +49,16 @@
#define debug(SECTION, LEVEL) \
((LEVEL) > debugLevels[SECTION]) ? (void) 0 : _db_print
#endif
+
+/* useful for temporary debuging messages, delete it later @?@ */
+#define here __FILE__,__LINE__
+#define dev_null 1 ? ((void)0) :
+#ifdef HAVE_SYSLOG
+#define tmp_debug(fl) _db_level = 0, dev_null _db_print("%s:%d: ",fl), dev_null _db_print
+#else
+#define tmp_debug(fl) _dev_null db_print("%s[%d]: ",fl), dev_null _db_print
+#endif
+
#define safe_free(x) if (x) { xxfree(x); x = NULL; }
#define DISK_OK (0)
diff --git a/src/enums.h b/src/enums.h
index 6b02b40b3c..88128f3012 100644
--- a/src/enums.h
+++ b/src/enums.h
@@ -43,6 +43,7 @@ typedef enum {
ERR_FTP_FAILURE,
ERR_URN_RESOLVE,
ERR_ACCESS_DENIED,
+ ERR_CACHE_ACCESS_DENIED,
ERR_MAX
} err_type;
@@ -141,7 +142,9 @@ typedef enum {
MGR_REDIRECTORS,
MGR_REFRESH,
MGR_REMOVE,
+ MGR_REQUEST_HDRS,
MGR_REPLY_HDRS,
+ MGR_MSG_HDRS,
MGR_SERVER_LIST,
MGR_NON_PEERS,
MGR_SHUTDOWN,
@@ -296,7 +299,8 @@ typedef enum {
HTTP_BAD_GATEWAY = 502,
HTTP_SERVICE_UNAVAILABLE = 503,
HTTP_GATEWAY_TIMEOUT = 504,
- HTTP_HTTP_VERSION_NOT_SUPPORTED = 505
+ HTTP_HTTP_VERSION_NOT_SUPPORTED = 505,
+ HTTP_INVALID_HEADER = 600 /* Squid header parsing error */
} http_status;
/* These are for StoreEntry->flag, which is defined as a SHORT */
@@ -410,7 +414,12 @@ typedef enum {
MEM_FQDNCACHE_ENTRY,
MEM_HASH_LINK,
MEM_HASH_TABLE,
+#if 0 /* renamed to detect all old uses */
MEM_HTTP_REPLY,
+#else
+ MEM_HTTPREPLY,
+#endif
+ MEM_HTTP_SCC,
MEM_HTTPSTATEDATA,
MEM_ICPUDPDATA,
MEM_CLIENTHTTPREQUEST,
diff --git a/src/errorpage.cc b/src/errorpage.cc
index 9cecf03ce2..71d9fd1409 100644
--- a/src/errorpage.cc
+++ b/src/errorpage.cc
@@ -1,6 +1,6 @@
/*
- * $Id: errorpage.cc,v 1.116 1998/02/02 21:15:00 wessels Exp $
+ * $Id: errorpage.cc,v 1.117 1998/02/21 00:56:54 rousskov Exp $
*
* DEBUG: section 4 Error Generation
* AUTHOR: Duane Wessels
@@ -40,9 +40,8 @@
static char *error_text[ERR_MAX];
-static void errorStateFree(ErrorState * err);
+static const char *errorBuildContent(ErrorState * err, int *len);
static const char *errorConvert(char token, ErrorState * err);
-static const char *errorBuildBuf(ErrorState * err, int *len);
static CWCB errorSendComplete;
/*
@@ -118,15 +117,25 @@ errorCon(err_type type, http_status status)
void
errorAppendEntry(StoreEntry * entry, ErrorState * err)
{
+#if 0
const char *buf;
- MemObject *mem = entry->mem_obj;
int len;
+#else
+ HttpReply *rep;
+#endif
+ MemObject *mem = entry->mem_obj;
assert(entry->store_status == STORE_PENDING);
assert(mem != NULL);
assert(mem->inmem_hi == 0);
+#if 0
buf = errorBuildBuf(err, &len);
storeAppend(entry, buf, len);
- mem->reply->code = err->http_status;
+#else
+ rep = errorBuildReply(err);
+ httpReplySwapOut(rep, entry);
+ httpReplyDestroy(rep);
+#endif
+ mem->reply->sline.status = err->http_status;
storeComplete(entry);
storeNegativeCache(entry);
storeReleaseRequest(entry);
@@ -155,8 +164,12 @@ errorAppendEntry(StoreEntry * entry, ErrorState * err)
void
errorSend(int fd, ErrorState * err)
{
- const char *buf;
+ HttpReply *rep;
+#if 0
+ FREE *freefunc;
+ char *buf;
int len;
+#endif
debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err);
assert(fd >= 0);
/*
@@ -165,10 +178,17 @@ errorSend(int fd, ErrorState * err)
*/
if (err->request)
err->request->err_type = err->type;
- buf = errorBuildBuf(err, &len);
+ /* moved in front of errorBuildBuf @?@ */
EBIT_SET(err->flags, ERR_FLAG_CBDATA);
cbdataAdd(err, MEM_NONE);
+#if 0
+ buf = errorBuildBuf(err, &len);
comm_write(fd, xstrdup(buf), len, errorSendComplete, err, xfree);
+#else
+ rep = errorBuildReply(err);
+ comm_write_mbuf(fd, httpReplyPack(rep), errorSendComplete, err);
+ httpReplyDestroy(rep);
+#endif
}
/*
@@ -194,7 +214,7 @@ errorSendComplete(int fd, char *bufnotused, size_t size, int errflag, void *data
errorStateFree(err);
}
-static void
+void
errorStateFree(ErrorState * err)
{
requestUnlink(err->request);
@@ -339,7 +359,63 @@ errorConvert(char token, ErrorState * err)
return p;
}
+/* allocates and initializes an error response */
+HttpReply *
+errorBuildReply(ErrorState *err)
+{
+ int clen;
+ HttpReply *rep = httpReplyCreate();
+ const char *content = errorBuildContent(err, &clen);
+ /* no LMT for error pages; error pages expire immediately */
+ httpReplySetHeaders(rep, 1.0, err->http_status, NULL, "text/html", clen, 0, squid_curtime);
+ httpBodySet(&rep->body, content, clen+1, NULL);
+ return rep;
+}
+
static const char *
+errorBuildContent(ErrorState * err, int *len)
+{
+ LOCAL_ARRAY(char, content, ERROR_BUF_SZ);
+ int clen;
+ char *m;
+ char *mx;
+ char *p;
+ const char *t;
+ assert(err != NULL);
+ assert(err->type > ERR_NONE && err->type < ERR_MAX);
+ mx = m = xstrdup(error_text[err->type]);
+ clen = 0;
+ while ((p = strchr(m, '%'))) {
+ *p = '\0'; /* terminate */
+ xstrncpy(content + clen, m, ERROR_BUF_SZ - clen); /* copy */
+ clen += (p - m); /* advance */
+ if (clen >= ERROR_BUF_SZ)
+ break;
+ p++;
+ m = p + 1;
+ t = errorConvert(*p, err); /* convert */
+ xstrncpy(content + clen, t, ERROR_BUF_SZ - clen); /* copy */
+ clen += strlen(t); /* advance */
+ if (clen >= ERROR_BUF_SZ)
+ break;
+ }
+ if (clen < ERROR_BUF_SZ && m != NULL) {
+ xstrncpy(content + clen, m, ERROR_BUF_SZ - clen);
+ clen += strlen(m);
+ }
+ if (clen >= ERROR_BUF_SZ) {
+ clen = ERROR_BUF_SZ - 1;
+ *(content + clen) = '\0';
+ }
+ assert(clen == strlen(content));
+ if (len)
+ *len = clen;
+ xfree(mx);
+ return content;
+}
+
+#if 0 /* we use httpReply instead of a buffer now */
+const char *
errorBuildBuf(ErrorState * err, int *len)
{
LOCAL_ARRAY(char, buf, ERROR_BUF_SZ);
@@ -390,3 +466,4 @@ errorBuildBuf(ErrorState * err, int *len)
xfree(mx);
return buf;
}
+#endif
diff --git a/src/ftp.cc b/src/ftp.cc
index 443448059c..bac074a529 100644
--- a/src/ftp.cc
+++ b/src/ftp.cc
@@ -1,6 +1,6 @@
/*
- * $Id: ftp.cc,v 1.194 1998/02/18 00:38:54 wessels Exp $
+ * $Id: ftp.cc,v 1.195 1998/02/21 00:56:55 rousskov Exp $
*
* DEBUG: section 9 File Transfer Protocol (FTP)
* AUTHOR: Harvest Derived
@@ -139,7 +139,11 @@ static char *ftpGetBasicAuth(const char *);
static void ftpLoginParser(const char *, FtpStateData *);
static wordlist *ftpParseControlReply(char *buf, size_t len, int *code);
static void ftpAppendSuccessHeader(FtpStateData * ftpState);
+#if 0
static char *ftpAuthRequired(const request_t *, const char *);
+#else
+static void ftpAuthRequired(HttpReply *reply, request_t *request, const char *realm);
+#endif
static STABH ftpAbort;
static void ftpHackShortcut(FtpStateData * ftpState, FTPSM * nextState);
@@ -919,7 +923,9 @@ ftpStart(request_t * request, StoreEntry * entry)
LOCAL_ARRAY(char, realm, 8192);
const char *url = storeUrl(entry);
FtpStateData *ftpState = xcalloc(1, sizeof(FtpStateData));
+#if 0
char *response;
+#endif
int fd;
ErrorState *err;
cbdataAdd(ftpState, MEM_NONE);
@@ -939,9 +945,19 @@ ftpStart(request_t * request, StoreEntry * entry)
snprintf(realm, 8192, "ftp %s port %d",
ftpState->user, request->port);
}
+#if 0
response = ftpAuthRequired(request, realm);
storeAppend(entry, response, strlen(response));
httpParseReplyHeaders(response, entry->mem_obj->reply);
+#else
+ {
+ HttpReply *reply = entry->mem_obj->reply;
+ assert(reply);
+ /* create appropreate reply */
+ ftpAuthRequired(reply, request, realm);
+ httpReplySwapOut(reply, entry);
+ }
+#endif
storeComplete(entry);
ftpStateFree(-1, ftpState);
return;
@@ -1944,6 +1960,7 @@ ftpAppendSuccessHeader(FtpStateData * ftpState)
}
}
storeBuffer(e);
+#if 0 /* old code */
storeAppendPrintf(e, "HTTP/1.0 200 Gatewaying\r\n");
reply->code = 200;
reply->version = 1.0;
@@ -1966,6 +1983,16 @@ ftpAppendSuccessHeader(FtpStateData * ftpState)
reply->last_modified = ftpState->mdtm;
}
storeAppendPrintf(e, "\r\n");
+#else
+ httpReplyReset(reply);
+ /* set standard stuff */
+ httpReplySetHeaders(reply, 1.0, HTTP_OK, "Gatewaying",
+ mime_type, ftpState->size, ftpState->mdtm, -2);
+ /* additional info */
+ if (mime_enc)
+ httpHeaderSetStr(&reply->hdr, HDR_CONTENT_ENCODING, mime_enc);
+ httpReplySwapOut(reply, e);
+#endif
storeBufferFlush(e);
reply->hdr_sz = e->mem_obj->inmem_hi;
storeTimestampsSet(e);
@@ -1984,6 +2011,7 @@ ftpAbort(void *data)
comm_close(ftpState->ctrl.fd);
}
+#if 0 /* use new interfaces instead */
static char *
ftpAuthRequired(const request_t * request, const char *realm)
{
@@ -2032,6 +2060,22 @@ ftpAuthRequired(const request_t * request, const char *realm)
l += snprintf(buf + l, s - l, "\r\n%s", content);
return buf;
}
+#endif
+
+static void
+ftpAuthRequired(HttpReply *reply, request_t *request, const char *realm)
+{
+ ErrorState *err = errorCon(ERR_ACCESS_DENIED, HTTP_UNAUTHORIZED);
+ HttpReply *rep;
+ err->request = requestLink(request);
+ rep = errorBuildReply(err);
+ /* add Authenticate header */
+ httpHeaderSetStr(&rep->hdr, HDR_WWW_AUTHENTICATE, realm);
+ errorStateFree(err);
+ /* substitute, should be OK because we clean it @?@ */
+ httpReplyClean(reply);
+ *reply = *rep; /* @?@ warning is generated due to hdr_sz being constant */
+}
char *
ftpUrlWith2f(const request_t * request)
diff --git a/src/globals.h b/src/globals.h
index 654800827c..15badfad18 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1,6 +1,6 @@
/*
- * $Id: globals.h,v 1.38 1998/02/20 21:03:44 wessels Exp $
+ * $Id: globals.h,v 1.39 1998/02/21 00:56:56 rousskov Exp $
*/
extern FILE *debug_log; /* NULL */
@@ -26,6 +26,7 @@ extern const char *const dash_str; /* "-" */
extern const char *const localhost; /* "127.0.0.1" */
extern const char *const null_string; /* "" */
extern const char *const version_string; /* SQUID_VERSION */
+extern const char *const full_appname_string; /* "Squid/" SQUID_VERSION */
extern const char *const w_space; /* " \t\n\r" */
extern const char *fdTypeStr[];
extern const char *hier_strings[];
diff --git a/src/http.cc b/src/http.cc
index 25e276684e..3b2ded92e0 100644
--- a/src/http.cc
+++ b/src/http.cc
@@ -1,6 +1,6 @@
/*
- * $Id: http.cc,v 1.238 1998/02/19 23:09:52 wessels Exp $
+ * $Id: http.cc,v 1.239 1998/02/21 00:56:56 rousskov Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
@@ -113,6 +113,7 @@
static const char *const crlf = "\r\n";
+#if 0 /* moved to HttpHeader */
typedef enum {
SCC_PUBLIC,
SCC_PRIVATE,
@@ -124,6 +125,7 @@ typedef enum {
SCC_MAXAGE,
SCC_ENUM_END
} http_server_cc_t;
+#endif
enum {
CCC_NOCACHE,
@@ -135,6 +137,7 @@ enum {
CCC_ENUM_END
};
+#if 0 /* moved to HttpHeader.h */
typedef enum {
HDR_ACCEPT,
HDR_AGE,
@@ -197,6 +200,7 @@ static struct {
int misc[HDR_MISC_END];
int cc[SCC_ENUM_END];
} ReplyHeaderStats;
+#endif /* if 0 */
static CNCB httpConnectDone;
static CWCB httpSendComplete;
@@ -208,7 +212,9 @@ static void httpAppendRequestHeader(char *hdr, const char *line, size_t * sz, si
static void httpCacheNegatively(StoreEntry *);
static void httpMakePrivate(StoreEntry *);
static void httpMakePublic(StoreEntry *);
+#if 0 /* moved to HttpResponse */
static char *httpStatusString(int status);
+#endif
static STABH httpAbort;
static HttpStateData *httpBuildState(int, StoreEntry *, request_t *, peer *);
static int httpSocketOpen(StoreEntry *, request_t *);
@@ -290,6 +296,7 @@ httpCacheNegatively(StoreEntry * entry)
}
+#if 0
/* Build a reply structure from HTTP reply headers */
void
httpParseReplyHeaders(const char *buf, struct _http_reply *reply)
@@ -420,17 +427,20 @@ httpParseReplyHeaders(const char *buf, struct _http_reply *reply)
memFree(MEM_4K_BUF, headers);
memFree(MEM_4K_BUF, line);
}
+#endif /* 0 */
static int
httpCachableReply(HttpStateData * httpState)
{
- struct _http_reply *reply = httpState->entry->mem_obj->reply;
- if (EBIT_TEST(reply->cache_control, SCC_PRIVATE))
+ HttpHeader *hdr = &httpState->entry->mem_obj->reply->hdr;
+ const HttpScc *scc = httpHeaderGetScc(hdr);
+ const int scc_mask = (scc) ? scc->mask : 0;
+ if (EBIT_TEST(scc_mask, SCC_PRIVATE))
return 0;
- if (EBIT_TEST(reply->cache_control, SCC_NOCACHE))
+ if (EBIT_TEST(scc_mask, SCC_NO_CACHE))
return 0;
if (EBIT_TEST(httpState->request->flags, REQ_AUTH))
- if (!EBIT_TEST(reply->cache_control, SCC_PROXYREVALIDATE))
+ if (!EBIT_TEST(scc_mask, SCC_PROXY_REVALIDATE))
return 0;
/*
* Dealing with cookies is quite a bit more complicated
@@ -438,9 +448,10 @@ httpCachableReply(HttpStateData * httpState)
* header from the reply but still cache the reply body.
* More confusion at draft-ietf-http-state-mgmt-05.txt.
*/
- if (EBIT_TEST(reply->misc_headers, HDR_SET_COOKIE))
+ /* With new headers the above stripping should be easy to do? @?@ */
+ if (httpHeaderHas(hdr, HDR_SET_COOKIE))
return 0;
- switch (reply->code) {
+ switch (httpState->entry->mem_obj->reply->sline.status) {
/* Responses that are cacheable */
case 200: /* OK */
case 203: /* Non-Authoritative Information */
@@ -448,13 +459,14 @@ httpCachableReply(HttpStateData * httpState)
case 301: /* Moved Permanently */
case 410: /* Gone */
/* don't cache objects from peers w/o LMT, Date, or Expires */
- if (reply->date > -1)
+ /* check that is it enough to check headers @?@ */
+ if (httpHeaderHas(hdr, HDR_DATE))
return 1;
- else if (reply->last_modified > -1)
+ else if (httpHeaderHas(hdr, HDR_LAST_MODIFIED))
return 1;
else if (!httpState->peer)
return 1;
- else if (reply->expires > -1)
+ else if (httpHeaderHas(hdr, HDR_EXPIRES))
return 1;
else
return 0;
@@ -462,12 +474,13 @@ httpCachableReply(HttpStateData * httpState)
break;
/* Responses that only are cacheable if the server says so */
case 302: /* Moved temporarily */
- if (reply->expires > -1)
+ if (httpHeaderHas(hdr, HDR_EXPIRES))
return 1;
else
return 0;
/* NOTREACHED */
break;
+/* @?@ should we replace these magic numbers with http_status enums? */
/* Errors can be negatively cached */
case 204: /* No Content */
case 305: /* Use Proxy (proxy redirect) */
@@ -499,6 +512,7 @@ httpCachableReply(HttpStateData * httpState)
/* NOTREACHED */
}
+/* rewrite this later using new interfaces @?@ */
void
httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
{
@@ -506,7 +520,7 @@ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
StoreEntry *entry = httpState->entry;
int room;
int hdr_len;
- struct _http_reply *reply = entry->mem_obj->reply;
+ HttpReply *reply = entry->mem_obj->reply;
debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
storeKeyText(entry->key));
if (httpState->reply_hdr == NULL)
@@ -519,7 +533,7 @@ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) {
debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr);
httpState->reply_hdr_state += 2;
- reply->code = 555;
+ reply->sline.status = 555;
return;
}
t = httpState->reply_hdr + hdr_len;
@@ -535,10 +549,12 @@ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
httpState->reply_hdr);
/* Parse headers into reply structure */
- httpParseReplyHeaders(httpState->reply_hdr, reply);
+ /* Old code never parsed headers if mime_headers_end failed, was it intentional ? @?@ @?@ */
+ /* what happens if we fail to parse here? @?@ @?@ */
+ httpReplyParse(reply, httpState->reply_hdr); /* httpState->eof); */
storeTimestampsSet(entry);
/* Check if object is cacheable or not based on reply code */
- debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->code);
+ debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status);
switch (httpCachableReply(httpState)) {
case 1:
httpMakePublic(entry);
@@ -553,12 +569,12 @@ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
assert(0);
break;
}
- if (EBIT_TEST(reply->cache_control, SCC_PROXYREVALIDATE))
+ if (httpReplyHasScc(reply, SCC_PROXY_REVALIDATE))
EBIT_SET(entry->flag, ENTRY_REVALIDATE);
if (EBIT_TEST(httpState->flags, HTTP_KEEPALIVE))
if (httpState->peer)
httpState->peer->stats.n_keepalives_sent++;
- if (EBIT_TEST(reply->misc_headers, HDR_PROXY_KEEPALIVE))
+ if (httpHeaderHas(&reply->hdr, HDR_PROXY_KEEPALIVE))
if (httpState->peer)
httpState->peer->stats.n_keepalives_recv++;
}
@@ -569,7 +585,7 @@ httpPconnTransferDone(HttpStateData * httpState)
{
/* return 1 if we got the last of the data on a persistent connection */
MemObject *mem = httpState->entry->mem_obj;
- struct _http_reply *reply = mem->reply;
+ HttpReply *reply = mem->reply;
debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
/*
* If we didn't send a Keepalive request header, then this
@@ -578,7 +594,7 @@ httpPconnTransferDone(HttpStateData * httpState)
if (!EBIT_TEST(httpState->flags, HTTP_KEEPALIVE))
return 0;
debug(11, 5) ("httpPconnTransferDone: content_length=%d\n",
- reply->content_length);
+ httpReplyContentLen(reply));
/*
* Deal with gross HTTP stuff
* - If we haven't seen the end of the reply headers, we can't
@@ -592,13 +608,13 @@ httpPconnTransferDone(HttpStateData * httpState)
*/
if (httpState->reply_hdr_state < 2)
return 0;
- else if (reply->code == HTTP_OK)
+ else if (reply->sline.status == HTTP_OK)
(void) 0; /* common case, continue */
- else if (reply->code == HTTP_NO_CONTENT)
+ else if (reply->sline.status == HTTP_NO_CONTENT)
return 1;
- else if (reply->code == HTTP_NOT_MODIFIED)
+ else if (reply->sline.status == HTTP_NOT_MODIFIED)
return 1;
- else if (reply->code < HTTP_OK)
+ else if (reply->sline.status < HTTP_OK)
return 1;
else if (httpState->request->method == METHOD_HEAD)
return 1;
@@ -607,9 +623,9 @@ httpPconnTransferDone(HttpStateData * httpState)
* persistent. If there is a content length, then we must
* wait until we've seen the end of the body.
*/
- if (reply->content_length < 0)
+ if (httpReplyContentLen(reply) < 0)
return 0;
- else if (mem->inmem_hi < reply->content_length + reply->hdr_sz)
+ else if (mem->inmem_hi < httpReplyContentLen(reply) + reply->hdr_sz)
return 0;
else
return 1;
@@ -1117,6 +1133,7 @@ httpConnectDone(int fd, int status, void *data)
}
}
+#if 0 /* moved to httpHeader */
void
httpReplyHeaderStats(StoreEntry * entry)
{
@@ -1134,13 +1151,14 @@ httpReplyHeaderStats(StoreEntry * entry)
HttpServerCCStr[i],
ReplyHeaderStats.cc[i]);
}
+#endif
void
httpInit(void)
{
cachemgrRegister("reply_headers",
"HTTP Reply Header Histograms",
- httpReplyHeaderStats, 0);
+ httpHeaderStoreRepReport, 0);
}
static void
@@ -1151,6 +1169,7 @@ httpAbort(void *data)
comm_close(httpState->fd);
}
+#if 0 /* moved to httpResponse.c */
static char *
httpStatusString(int status)
{
@@ -1274,7 +1293,9 @@ httpStatusString(int status)
}
return p;
}
+#endif
+#if 0 /* moved to HttpResponse.c */
char *
httpReplyHeader(double ver,
http_status status,
@@ -1302,3 +1323,4 @@ httpReplyHeader(double ver,
l += snprintf(buf + l, s - l, "Content-Type: %s\r\n", ctype);
return buf;
}
+#endif
diff --git a/src/main.cc b/src/main.cc
index f7cc870935..63660ed5f1 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1,6 +1,6 @@
/*
- * $Id: main.cc,v 1.224 1998/02/20 21:02:42 wessels Exp $
+ * $Id: main.cc,v 1.225 1998/02/21 00:56:57 rousskov Exp $
*
* DEBUG: section 1 Startup and Main Loop
* AUTHOR: Harvest Derived
@@ -441,6 +441,7 @@ mainInitialize(void)
dnsOpenServers();
redirectOpenServers();
useragentOpenLog();
+ httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
errorInitialize();
accessLogInit();
diff --git a/src/mem.cc b/src/mem.cc
index b4cffd2d41..812aa1bcec 100644
--- a/src/mem.cc
+++ b/src/mem.cc
@@ -1,6 +1,6 @@
/*
- * $Id: mem.cc,v 1.5 1998/02/19 23:28:39 wessels Exp $
+ * $Id: mem.cc,v 1.6 1998/02/21 00:56:58 rousskov Exp $
*
* DEBUG: section 13 Memory Pool Management
* AUTHOR: Harvest Derived
@@ -187,7 +187,8 @@ memInit(void)
memDataInit(MEM_HIERARCHYLOGENTRY, "HierarchyLogEntry",
sizeof(HierarchyLogEntry), 0);
memDataInit(MEM_HTTPSTATEDATA, "HttpStateData", sizeof(HttpStateData), 0);
- memDataInit(MEM_HTTP_REPLY, "http_reply", sizeof(http_reply), 0);
+ memDataInit(MEM_HTTPREPLY, "http_reply", sizeof(http_reply), 0);
+ memDataInit(MEM_HTTP_SCC, "HttpScc", sizeof(HttpScc), 0);
memDataInit(MEM_ICPUDPDATA, "icpUdpData", sizeof(icpUdpData), 0);
memDataInit(MEM_ICP_COMMON_T, "icp_common_t", sizeof(icp_common_t), 0);
memDataInit(MEM_ICP_PING_DATA, "icp_ping_data", sizeof(icp_ping_data), 0);
diff --git a/src/mime.cc b/src/mime.cc
index 9ba779a9c5..6079ff804d 100644
--- a/src/mime.cc
+++ b/src/mime.cc
@@ -1,6 +1,6 @@
/*
- * $Id: mime.cc,v 1.49 1998/02/13 19:59:01 wessels Exp $
+ * $Id: mime.cc,v 1.50 1998/02/21 00:56:59 rousskov Exp $
*
* DEBUG: section 25 MIME Parsing
* AUTHOR: Harvest Derived
@@ -396,7 +396,9 @@ mimeLoadIconFile(const char *icon)
{
int fd;
int n;
+#if 0
int l;
+#endif
int flags;
struct stat sb;
StoreEntry *e;
@@ -429,6 +431,7 @@ mimeLoadIconFile(const char *icon)
METHOD_GET);
assert(e != NULL);
e->mem_obj->request = requestLink(urlParse(METHOD_GET, url));
+#if 0 /* use new interface */
buf = memAllocate(MEM_4K_BUF, 1);
l = 0;
l += snprintf(buf + l, SM_PAGE_SIZE - l, "HTTP/1.0 200 OK\r\n");
@@ -441,7 +444,15 @@ mimeLoadIconFile(const char *icon)
l += snprintf(buf + l, SM_PAGE_SIZE - l, "\r\n");
httpParseReplyHeaders(buf, e->mem_obj->reply);
storeAppend(e, buf, l);
- while ((n = read(fd, buf, SM_PAGE_SIZE)) > 0)
+#else
+ httpReplyReset(e->mem_obj->reply);
+ httpReplySetHeaders(e->mem_obj->reply, 1.0, 200, NULL,
+ type, (int) sb.st_size, sb.st_mtime, squid_curtime + 86400);
+ httpReplySwapOut(e->mem_obj->reply, e);
+ /* read the file into the buffer and append it to store */
+ buf = memAllocate(MEM_4K_BUF, 1);
+#endif
+ while ((n = read(fd, buf, 4096)) > 0)
storeAppend(e, buf, n);
file_close(fd);
storeSetPublicKey(e);
diff --git a/src/protos.h b/src/protos.h
index d9a58c2009..f98081fbef 100644
--- a/src/protos.h
+++ b/src/protos.h
@@ -108,6 +108,7 @@ extern void comm_write(int fd,
CWCB * handler,
void *handler_data,
FREE *);
+extern void comm_write_mbuf(int fd, MemBuf mb, CWCB *handler, void *handler_data);
extern void commCallCloseHandlers(int fd);
extern int commSetTimeout(int fd, int, PF *, void *);
extern void commSetDefer(int fd, DEFER * func, void *);
@@ -199,9 +200,11 @@ extern HASHHASH hash4;
extern int httpCachable(method_t);
extern void httpStart(request_t *, StoreEntry *, peer *);
-extern void httpParseReplyHeaders(const char *, struct _http_reply *);
+extern void httpParseReplyHeaders(const char *, http_reply *);
extern void httpProcessReplyHeader(HttpStateData *, const char *, int);
+#if 0
extern void httpReplyHeaderStats(StoreEntry *);
+#endif
extern size_t httpBuildRequestHeader(request_t * request,
request_t * orig_request,
StoreEntry * entry,
@@ -212,12 +215,14 @@ extern size_t httpBuildRequestHeader(request_t * request,
int flags);
extern int httpAnonAllowed(const char *line);
extern int httpAnonDenied(const char *line);
+#if 0
extern char *httpReplyHeader(double ver,
http_status status,
char *ctype,
int clen,
time_t lmt,
time_t expires);
+#endif
extern void httpInit(void);
@@ -449,6 +454,7 @@ extern void storeAppendPrintf(StoreEntry *, const char *,...);
#else
extern void storeAppendPrintf();
#endif
+extern void storeAppendVPrintf(StoreEntry *, const char *, va_list ap);
extern int storeCheckCachable(StoreEntry * e);
extern void storeUnlinkFileno(int fileno);
extern void storeSetPrivateKey(StoreEntry *);
@@ -616,8 +622,10 @@ extern void useragentRotateLog(void);
extern void logUserAgent(const char *, const char *);
extern peer_t parseNeighborType(const char *s);
+extern HttpReply *errorBuildReply(ErrorState * err);
extern void errorSend(int fd, ErrorState *);
extern void errorAppendEntry(StoreEntry *, ErrorState *);
+void errorStateFree(ErrorState * err);
extern void errorInitialize(void);
extern void errorFree(void);
extern ErrorState *errorCon(err_type, http_status);
diff --git a/src/store.cc b/src/store.cc
index 71eb00962d..53e2f4d0d8 100644
--- a/src/store.cc
+++ b/src/store.cc
@@ -1,6 +1,6 @@
/*
- * $Id: store.cc,v 1.383 1998/02/20 16:03:20 wessels Exp $
+ * $Id: store.cc,v 1.384 1998/02/21 00:57:02 rousskov Exp $
*
* DEBUG: section 20 Storeage Manager
* AUTHOR: Harvest Derived
@@ -176,11 +176,7 @@ static MemObject *
new_MemObject(const char *url, const char *log_url)
{
MemObject *mem = memAllocate(MEM_MEMOBJECT, 1);
- mem->reply = memAllocate(MEM_HTTP_REPLY, 1);
- mem->reply->date = -2;
- mem->reply->expires = -2;
- mem->reply->last_modified = -2;
- mem->reply->content_length = -1;
+ mem->reply = httpReplyCreate();
mem->url = xstrdup(url);
mem->log_url = xstrdup(log_url);
mem->swapout.fd = -1;
@@ -214,7 +210,7 @@ destroy_MemObject(StoreEntry * e)
storeUnregister(e, mem->clients->callback_data);
#endif
assert(mem->clients == NULL);
- memFree(MEM_HTTP_REPLY, mem->reply);
+ httpReplyDestroy(mem->reply);
safe_free(mem->url);
safe_free(mem->log_url);
requestUnlink(mem->request);
@@ -458,6 +454,7 @@ storeAppend(StoreEntry * e, const char *buf, int len)
debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
len,
storeKeyText(e->key));
+ tmp_debug(here) ("bytes: '%.20s'\n", buf); /* @?@ @?@ */
storeGetMemSpace(len);
stmemAppend(mem->data, buf, len);
mem->inmem_hi += len;
@@ -473,7 +470,6 @@ void
storeAppendPrintf(StoreEntry * e, const char *fmt,...)
{
va_list args;
- LOCAL_ARRAY(char, buf, 4096);
va_start(args, fmt);
#else
void
@@ -483,15 +479,22 @@ storeAppendPrintf(va_alist)
va_list args;
StoreEntry *e = NULL;
const char *fmt = NULL;
- LOCAL_ARRAY(char, buf, 4096);
va_start(args);
e = va_arg(args, StoreEntry *);
fmt = va_arg(args, char *);
#endif
+ storeAppendVPrintf(e, fmt, args);
+ va_end(args);
+}
+
+/* used be storeAppendPrintf and Packer */
+void
+storeAppendVPrintf(StoreEntry * e, const char *fmt, va_list vargs)
+{
+ LOCAL_ARRAY(char, buf, 4096);
buf[0] = '\0';
- vsnprintf(buf, 4096, fmt, args);
+ vsnprintf(buf, 4096, fmt, vargs);
storeAppend(e, buf, strlen(buf));
- va_end(args);
}
int
@@ -746,16 +749,18 @@ storeEntryValidLength(const StoreEntry * e)
{
int diff;
http_reply *reply;
+ int clen;
assert(e->mem_obj != NULL);
reply = e->mem_obj->reply;
+ clen = httpReplyContentLen(reply);
debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", storeKeyText(e->key));
debug(20, 5) ("storeEntryValidLength: object_len = %d\n",
objectLen(e));
debug(20, 5) ("storeEntryValidLength: hdr_sz = %d\n",
reply->hdr_sz);
debug(20, 5) ("storeEntryValidLength: content_length = %d\n",
- reply->content_length);
- if (reply->content_length < 0) {
+ clen);
+ if (clen < 0) {
debug(20, 5) ("storeEntryValidLength: Unspecified content length: %s\n",
storeKeyText(e->key));
return 1;
@@ -770,11 +775,11 @@ storeEntryValidLength(const StoreEntry * e)
storeKeyText(e->key));
return 1;
}
- if (reply->code == HTTP_NOT_MODIFIED)
+ if (reply->sline.status == HTTP_NOT_MODIFIED)
return 1;
- if (reply->code == HTTP_NO_CONTENT)
+ if (reply->sline.status == HTTP_NO_CONTENT)
return 1;
- diff = reply->hdr_sz + reply->content_length - objectLen(e);
+ diff = reply->hdr_sz + clen - objectLen(e);
if (diff == 0)
return 1;
debug(20, 3) ("storeEntryValidLength: %d bytes too %s; '%s'\n",
@@ -966,14 +971,25 @@ void
storeTimestampsSet(StoreEntry * entry)
{
time_t served_date = -1;
- struct _http_reply *reply = entry->mem_obj->reply;
+ HttpReply *reply = entry->mem_obj->reply;
+#if 0 /* new interface */
served_date = reply->date > -1 ? reply->date : squid_curtime;
entry->expires = reply->expires;
if (reply->last_modified > -1)
entry->lastmod = reply->last_modified;
else
entry->lastmod = served_date;
+#else
+ served_date = httpHeaderGetTime(&reply->hdr, HDR_DATE);
+ if (served_date < 0)
+ served_date = squid_curtime;
+ entry->expires = httpReplyExpires(reply);
+ entry->lastmod = httpHeaderGetTime(&reply->hdr, HDR_LAST_MODIFIED);
+ if (entry->lastmod < 0)
+ entry->lastmod = served_date;
+#endif
entry->timestamp = served_date;
+
}
void
@@ -1080,6 +1096,7 @@ storeCreateMemObject(StoreEntry * e, const char *url, const char *log_url)
e->mem_obj = new_MemObject(url, log_url);
}
+#if 0 /* moved to HttpReply.c (has nothing to do with store.c) */
void
storeCopyNotModifiedReplyHeaders(MemObject * oldmem, MemObject * newmem)
{
@@ -1094,6 +1111,7 @@ storeCopyNotModifiedReplyHeaders(MemObject * oldmem, MemObject * newmem)
if (newreply->expires > -1)
oldreply->expires = newreply->expires;
}
+#endif
/* this just sets DELAY_SENDING */
void
diff --git a/src/store_client.cc b/src/store_client.cc
index b0842c60d4..725f80b64b 100644
--- a/src/store_client.cc
+++ b/src/store_client.cc
@@ -245,8 +245,8 @@ storeClientReadBody(int fd, const char *buf, int len, int flagnotused, void *dat
sc->disk_op_in_progress = 0;
assert(sc->callback != NULL);
debug(20, 3) ("storeClientReadBody: FD %d, len %d\n", fd, len);
- if (sc->copy_offset == 0 && len > 0 && mem->reply->code == 0)
- httpParseReplyHeaders(sc->copy_buf, mem->reply);
+ if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
+ httpReplyParse(mem->reply, sc->copy_buf);
sc->callback = NULL;
callback(sc->callback_data, sc->copy_buf, len);
}
@@ -305,8 +305,8 @@ storeClientReadHeader(int fd, const char *buf, int len, int flagnotused, void *d
copy_sz);
xmemcpy(sc->copy_buf, buf + swap_hdr_sz, copy_sz);
memFree(MEM_DISK_BUF, (void *) buf);
- if (sc->copy_offset == 0 && len > 0 && mem->reply->code == 0)
- httpParseReplyHeaders(sc->copy_buf, mem->reply);
+ if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
+ httpReplyParse(mem->reply, sc->copy_buf);
sc->callback = NULL;
callback(sc->callback_data, sc->copy_buf, copy_sz);
return;
diff --git a/src/store_log.cc b/src/store_log.cc
index f6bab8673f..9a9210e0da 100644
--- a/src/store_log.cc
+++ b/src/store_log.cc
@@ -16,7 +16,8 @@ storeLog(int tag, const StoreEntry * e)
{
LOCAL_ARRAY(char, logmsg, MAX_URL << 1);
MemObject *mem = e->mem_obj;
- struct _http_reply *reply;
+ HttpReply *reply;
+ const char *ctype;
if (storelog_fd < 0)
return;
if (mem == NULL)
@@ -27,17 +28,18 @@ storeLog(int tag, const StoreEntry * e)
mem->log_url = xstrdup(mem->url);
}
reply = mem->reply;
+ ctype = httpHeaderGetStr(&reply->hdr, HDR_CONTENT_TYPE);
snprintf(logmsg, MAX_URL << 1, "%9d.%03d %-7s %08X %4d %9d %9d %9d %s %d/%d %s %s\n",
(int) current_time.tv_sec,
(int) current_time.tv_usec / 1000,
storeLogTags[tag],
e->swap_file_number,
- reply->code,
- (int) reply->date,
- (int) reply->last_modified,
- (int) reply->expires,
- reply->content_type[0] ? reply->content_type : "unknown",
- reply->content_length,
+ reply->sline.status,
+ (int) httpHeaderGetTime(&reply->hdr, HDR_DATE),
+ (int) httpHeaderGetTime(&reply->hdr, HDR_LAST_MODIFIED),
+ (int) httpReplyExpires(reply),
+ ctype ? ctype : "unknown",
+ httpReplyContentLen(reply),
(int) (mem->inmem_hi - mem->reply->hdr_sz),
RequestMethodStr[mem->method],
mem->log_url);
diff --git a/src/structs.h b/src/structs.h
index 4249a67a09..417662ac5b 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1,7 +1,6 @@
-
struct _acl_ip_data {
struct in_addr addr1; /* if addr2 non-zero then its a range */
struct in_addr addr2;
@@ -398,6 +397,7 @@ struct _fde {
PF *timeout_handler;
time_t timeout;
void *timeout_data;
+ void *lifetime_data;
close_handler *close_handler; /* linked list */
DEFER *defer_check; /* check if we should defer read */
void *defer_data;
@@ -429,19 +429,34 @@ struct _hash_table {
hash_link *current_ptr;
};
+#if ! USE_ALEX_CODE
+#error must USE_ALEX_CODE
+#endif
+
+#include "MemBuf.h"
+#include "Packer.h"
+#include "HttpReply.h"
+
+# if 0 /* tmp moved to HttpReply.h */
+#define Const const
struct _http_reply {
double version;
int code;
int content_length;
- size_t hdr_sz;
- int cache_control;
- int misc_headers;
- time_t date;
- time_t expires;
- time_t last_modified;
- char content_type[HTTP_REPLY_FIELD_SZ];
- char user_agent[HTTP_REPLY_FIELD_SZ << 2];
+ int hdr_sz; /* includes _stored_ status-line, headers, and */
+ /* Note: fields below may not match info stored on disk */
+ Const int cache_control;
+ Const int misc_headers;
+ Const time_t date;
+ Const time_t expires;
+ Const time_t last_modified;
+ Const char content_type[HTTP_REPLY_FIELD_SZ];
+#if 0 /* unused 512 bytes? */
+ Const char user_agent[HTTP_REPLY_FIELD_SZ << 2];
+#endif
};
+#endif
+
struct _HttpStateData {
StoreEntry *entry;
@@ -736,11 +751,13 @@ struct _icp_common_t {
u_num32 shostid; /* sender host id */
};
+#if 0 /* this struct is not used */
struct _Stack {
void **base;
void **top;
int stack_size;
};
+#endif
struct _Meta_data {
int hot_vm;
@@ -804,7 +821,11 @@ struct _MemObject {
int fd;
void *ctrl;
} swapout;
+#if 0
struct _http_reply *reply;
+#else
+ HttpReply *reply;
+#endif
request_t *request;
struct timeval start_ping;
IRCB *icp_reply_callback;
diff --git a/src/typedefs.h b/src/typedefs.h
index ed02e80cdc..93dce7a4bd 100644
--- a/src/typedefs.h
+++ b/src/typedefs.h
@@ -41,7 +41,11 @@ typedef struct _fileMap fileMap;
typedef struct _fqdncache_entry fqdncache_entry;
typedef struct _hash_link hash_link;
typedef struct _hash_table hash_table;
+#if 0 /* use new interfaces */
typedef struct _http_reply http_reply;
+#else
+typedef struct _HttpReply http_reply;
+#endif
typedef struct _HttpStateData HttpStateData;
typedef struct _icpUdpData icpUdpData;
typedef struct _clientHttpRequest clientHttpRequest;
diff --git a/src/urn.cc b/src/urn.cc
index f13da37fa3..a6cd173799 100644
--- a/src/urn.cc
+++ b/src/urn.cc
@@ -152,7 +152,11 @@ urnHandleReply(void *data, char *buf, ssize_t size)
StoreEntry *e = urnState->entry;
StoreEntry *urlres_e = urnState->urlres_e;
char *s = NULL;
+#if 0
char *hdr;
+#else
+ HttpReply *rep;
+#endif
wordlist *w;
wordlist *urls;
wordlist *min_w;
@@ -192,10 +196,10 @@ urnHandleReply(void *data, char *buf, ssize_t size)
return;
}
assert(urlres_e->mem_obj->reply);
- httpParseReplyHeaders(buf, urlres_e->mem_obj->reply);
+ httpReplyParse(urlres_e->mem_obj->reply, buf);
debug(52, 3) ("mem->reply exists, code=%d.\n",
- urlres_e->mem_obj->reply->code);
- if (urlres_e->mem_obj->reply->code != HTTP_OK) {
+ urlres_e->mem_obj->reply->sline.status);
+ if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
debug(52, 3) ("urnHandleReply: failed.\n");
err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
err->request = requestLink(urnState->request);
@@ -241,7 +245,8 @@ urnHandleReply(void *data, char *buf, ssize_t size)
"\n",
appname, version_string, getMyHostname());
stringAppend(S, line, l);
- hdr = httpReplyHeader(1.0,
+#if 0 /* use new interface */
+ hdr = httpReplyHeader(1.0,
HTTP_MOVED_TEMPORARILY,
"text/html",
stringLength(S),
@@ -257,6 +262,20 @@ urnHandleReply(void *data, char *buf, ssize_t size)
}
storeAppend(e, "\r\n", 2);
storeAppend(e, S->buf, stringLength(S));
+#else
+ rep = e->mem_obj->reply;
+ httpReplyReset(rep);
+ httpReplySetHeaders(rep, 1.0, HTTP_MOVED_TEMPORARILY, NULL,
+ "text/html", stringLength(S), 0, squid_curtime);
+ if (EBIT_TEST(urnState->flags, URN_FORCE_MENU)) {
+ debug(51, 3) ("urnHandleReply: forcing menu\n");
+ } else
+ if (min_w) {
+ httpHeaderSetStr(&rep->hdr, HDR_LOCATION, min_w->key);
+ }
+ httpBodySet(&rep->body, S->buf, stringLength(S)+1, NULL);
+ httpReplySwapOut(rep, e);
+#endif
storeComplete(e);
memFree(MEM_4K_BUF, buf);
wordlistDestroy(&urls);
--
2.39.5