]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Dirty and buggy alex_2.
authorrousskov <>
Sat, 21 Feb 1998 07:56:32 +0000 (07:56 +0000)
committerrousskov <>
Sat, 21 Feb 1998 07:56:32 +0000 (07:56 +0000)
38 files changed:
configure
configure.in
errors/English/ERR_CACHE_ACCESS_DENIED [new file with mode: 0644]
include/MemPool.h [new file with mode: 0644]
include/Stack.h [new file with mode: 0644]
include/autoconf.h.in
include/util.h
include/version.h
lib/Makefile.in
lib/MemPool.c [new file with mode: 0644]
lib/Stack.c [new file with mode: 0644]
lib/util.c
src/HttpBody.cc [new file with mode: 0644]
src/HttpHeader.cc [new file with mode: 0644]
src/HttpReply.cc [new file with mode: 0644]
src/HttpStatusLine.cc [new file with mode: 0644]
src/Makefile.in
src/MemBuf.cc [new file with mode: 0644]
src/Packer.cc [new file with mode: 0644]
src/cache_manager.cc
src/client_side.cc
src/comm.cc
src/defines.h
src/enums.h
src/errorpage.cc
src/ftp.cc
src/globals.h
src/http.cc
src/main.cc
src/mem.cc
src/mime.cc
src/protos.h
src/store.cc
src/store_client.cc
src/store_log.cc
src/structs.h
src/typedefs.h
src/urn.cc

index 35c9076bd1c5e30f71f1c648624b87de8a7adc8c..cf5a3e5d6c2381d404227ed34e3b83207cf68dfa 100755 (executable)
--- 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 <<EOF
-#line 729 "configure"
+#line 731 "configure"
 #include "confdefs.h"
 main(){return(0);}
 EOF
-if { (eval echo configure:733: \"$ac_link\") 1>&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 <<EOF
-#line 1158 "configure"
+#line 1176 "configure"
 #include "confdefs.h"
 #include <assert.h>
 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 <<EOF
-#line 1175 "configure"
+#line 1193 "configure"
 #include "confdefs.h"
 #include <assert.h>
 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 <<EOF
-#line 1659 "configure"
+#line 1677 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #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 <<EOF
-#line 1700 "configure"
+#line 1718 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1707,7 +1725,7 @@ int main() {
 opendir()
 ; return 0; }
 EOF
-if { (eval echo configure:1711: \"$ac_link\") 1>&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 <<EOF
-#line 1741 "configure"
+#line 1759 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1748,7 +1766,7 @@ int main() {
 opendir()
 ; return 0; }
 EOF
-if { (eval echo configure:1752: \"$ac_link\") 1>&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 <<EOF
-#line 1780 "configure"
+#line 1798 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1784,7 +1802,7 @@ else
 #include <float.h>
 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
-#line 1805 "configure"
+#line 1823 "configure"
 #include "confdefs.h"
 #include <string.h>
 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
-#line 1823 "configure"
+#line 1841 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1840,7 +1858,7 @@ if test "$cross_compiling" = yes; then
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 1844 "configure"
+#line 1862 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #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
-#line 1936 "configure"
+#line 1954 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 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 <<EOF
-#line 1974 "configure"
+#line 1992 "configure"
 #include "confdefs.h"
 
 int main() {
@@ -2019,7 +2037,7 @@ ccp = (char const *const *) p;
 
 ; return 0; }
 EOF
-if { (eval echo configure:2023: \"$ac_compile\") 1>&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 <<EOF
-#line 2051 "configure"
+#line 2069 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -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 <<EOF
-#line 2066 "configure"
+#line 2084 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -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 <<EOF
-#line 2097 "configure"
+#line 2115 "configure"
 #include "confdefs.h"
 main () {
   /* Are we little or big endian?  From Harbison&Steele.  */
@@ -2106,7 +2124,7 @@ main () {
   exit (u.c[sizeof (long) - 1] == 1);
 }
 EOF
-if { (eval echo configure:2110: \"$ac_link\") 1>&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 <<EOF
-#line 2141 "configure"
+#line 2159 "configure"
 #include "confdefs.h"
 int foo(char *); int foo (char *bar) {return 1;}
 int main() {
 foo("bar")
 ; return 0; }
 EOF
-if { (eval echo configure:2148: \"$ac_compile\") 1>&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 <<EOF
-#line 2176 "configure"
+#line 2194 "configure"
 #include "confdefs.h"
 #include <time.h>
 #include <sys/time.h>
@@ -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 <<EOF
-#line 2213 "configure"
+#line 2231 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <malloc.h>
@@ -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 <<EOF
-#line 2250 "configure"
+#line 2268 "configure"
 #include "confdefs.h"
 
 #if HAVE_SYS_TIME_H
@@ -2259,7 +2277,7 @@ int main() {
 struct rusage R;
 ; return 0; }
 EOF
-if { (eval echo configure:2263: \"$ac_compile\") 1>&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 <<EOF
-#line 2291 "configure"
+#line 2309 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <netinet/in.h>
@@ -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 <<EOF
-#line 2338 "configure"
+#line 2356 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 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 <<EOF
-#line 2377 "configure"
+#line 2395 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 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 <<EOF
-#line 2416 "configure"
+#line 2434 "configure"
 #include "confdefs.h"
 #include <alloca.h>
 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 <<EOF
-#line 2449 "configure"
+#line 2467 "configure"
 #include "confdefs.h"
 
 #ifdef __GNUC__
@@ -2468,7 +2486,7 @@ int main() {
 char *p = (char *) alloca(1);
 ; return 0; }
 EOF
-if { (eval echo configure:2472: \"$ac_link\") 1>&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 <<EOF
-#line 2509 "configure"
+#line 2527 "configure"
 #include "confdefs.h"
 #if defined(CRAY) && ! defined(CRAY2)
 webecray
@@ -2530,12 +2548,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&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 <<EOF
-#line 2539 "configure"
+#line 2557 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2558,7 +2576,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:2562: \"$ac_link\") 1>&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 <<EOF
-#line 2597 "configure"
+#line 2615 "configure"
 #include "confdefs.h"
 find_stack_direction ()
 {
@@ -2612,7 +2630,7 @@ main ()
   exit (find_stack_direction() < 0);
 }
 EOF
-if { (eval echo configure:2616: \"$ac_link\") 1>&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 <<EOF
-#line 2644 "configure"
+#line 2662 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #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 <<EOF
-#line 2677 "configure"
+#line 2695 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #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 <<EOF
-#line 2710 "configure"
+#line 2728 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #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 <<EOF
-#line 2743 "configure"
+#line 2761 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #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 <<EOF
-#line 2776 "configure"
+#line 2794 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #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 <<EOF
-#line 2813 "configure"
+#line 2831 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:2820: \"$ac_link\") 1>&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 <<EOF
-#line 2856 "configure"
+#line 2874 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:2863: \"$ac_link\") 1>&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 <<EOF
-#line 2899 "configure"
+#line 2917 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:2906: \"$ac_link\") 1>&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 <<EOF
-#line 2956 "configure"
+#line 2974 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:2963: \"$ac_link\") 1>&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 <<EOF
-#line 3002 "configure"
+#line 3020 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:3009: \"$ac_link\") 1>&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 <<EOF
-#line 3045 "configure"
+#line 3063 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:3052: \"$ac_link\") 1>&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 <<EOF
-#line 3086 "configure"
+#line 3104 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -3093,7 +3111,7 @@ int main() {
 inet_aton()
 ; return 0; }
 EOF
-if { (eval echo configure:3097: \"$ac_link\") 1>&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 <<EOF
-#line 3121 "configure"
+#line 3139 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -3128,7 +3146,7 @@ int main() {
 inet_aton()
 ; return 0; }
 EOF
-if { (eval echo configure:3132: \"$ac_link\") 1>&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 <<EOF
-#line 3172 "configure"
+#line 3190 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:3179: \"$ac_link\") 1>&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 <<EOF
-#line 3217 "configure"
+#line 3235 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:3224: \"$ac_link\") 1>&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 <<EOF
-#line 3261 "configure"
+#line 3279 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -3268,7 +3286,7 @@ int main() {
 crypt()
 ; return 0; }
 EOF
-if { (eval echo configure:3272: \"$ac_link\") 1>&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 <<EOF
-#line 3303 "configure"
+#line 3321 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:3310: \"$ac_link\") 1>&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 <<EOF
-#line 3418 "configure"
+#line 3436 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -3437,7 +3455,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:3441: \"$ac_link\") 1>&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 <<EOF
-#line 3484 "configure"
+#line 3502 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char poll(); below.  */
@@ -3503,7 +3521,7 @@ poll();
 
 ; return 0; }
 EOF
-if { (eval echo configure:3507: \"$ac_link\") 1>&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 <<EOF
-#line 3538 "configure"
+#line 3556 "configure"
 #include "confdefs.h"
 
 #include <stdlib.h>
@@ -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 <<EOF
-#line 3612 "configure"
+#line 3630 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -3631,7 +3649,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:3635: \"$ac_link\") 1>&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 <<EOF
-#line 3668 "configure"
+#line 3686 "configure"
 #include "confdefs.h"
 
 #if HAVE_STDIO_H
@@ -3688,7 +3706,7 @@ main() {
 }
 
 EOF
-if { (eval echo configure:3692: \"$ac_link\") 1>&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 <<EOF
-#line 3716 "configure"
+#line 3734 "configure"
 #include "confdefs.h"
 
 #include <stdio.h>
@@ -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 <<EOF
-#line 3792 "configure"
+#line 3810 "configure"
 #include "confdefs.h"
 
 #include <stdlib.h>
@@ -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 <<EOF
-#line 3835 "configure"
+#line 3853 "configure"
 #include "confdefs.h"
 
 #include <stdlib.h>
@@ -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 <<EOF
-#line 3878 "configure"
+#line 3896 "configure"
 #include "confdefs.h"
 
 #include <stdlib.h>
@@ -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 <<EOF
-#line 3921 "configure"
+#line 3939 "configure"
 #include "confdefs.h"
 
 #include <stdlib.h>
@@ -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 <<EOF
-#line 3964 "configure"
+#line 3982 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 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 <<EOF
-#line 3995 "configure"
+#line 4013 "configure"
 #include "confdefs.h"
 extern int _dns_ttl_;
 int main() {
 return _dns_ttl_;
 ; return 0; }
 EOF
-if { (eval echo configure:4002: \"$ac_link\") 1>&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
index e5978bd5ce1888ed9689acdfce6a559f7f680905..d3a33284c0e701e8ea6322754142f1ea425393c3 100644 (file)
@@ -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 (file)
index 0000000..0ae61b0
--- /dev/null
@@ -0,0 +1,32 @@
+<HTML><HEAD>
+<TITLE>ERROR: Cache Access Denied</TITLE>
+</HEAD>
+<BODY>
+<H1>ERROR</H1>
+<H2>Cache Access Denied</H2>
+<HR>
+<P>
+While trying to retrieve the URL:
+<A HREF="%U">%U</A>
+<P>
+The following error was encountered:
+<UL>
+<LI>
+<STRONG>
+Cache Access Denied.
+</STRONG>
+</UL>
+</P>
+
+<P>Sorry, you are not currently allowed to request:
+<PRE>    %U</PRE>
+from this cache until you have authenticated yourself.
+</P>
+
+<P>
+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 <A HREF="mailto:%w">cache administrator</a> if you have
+difficulties authenticating yourself or 
+<A HREF="http://%h/cgi-bin/chpasswd.cgi\">change</a> your default password.
+</P>
diff --git a/include/MemPool.h b/include/MemPool.h
new file mode 100644 (file)
index 0000000..a890cb0
--- /dev/null
@@ -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 (file)
index 0000000..042c201
--- /dev/null
@@ -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_ */
index a31c2fe47b7e47917f0b7b78fa253afbc92ee20f..2326734248ae54c1887efc987068af81f57e492e 100644 (file)
@@ -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
index 64cdc2f4a17d24021a758d201038c11cbfa8e09c..4a4b53aa24deb077490d02d8fc9ac7f657b15c31 100644 (file)
@@ -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);
index 0b0f13ba9ca51454a8568593ddfe01fe109c7d25..01baa8e2ae04c4a0c39e8cc441285c5777975bf0 100644 (file)
@@ -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
  */
index 55148d4f11ba94e87c65214640c430a2b98dca62..a6c216e653af3e6d8debb3e56b4fe2962a9fa162 100644 (file)
@@ -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 (file)
index 0000000..ae8d1a4
--- /dev/null
@@ -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 <assert.h>
+#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 (file)
index 0000000..cc55683
--- /dev/null
@@ -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 <assert.h>
+#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 */
+}
index bc962a0f3053de761a4e80688821979810b37fbd..083bca4903bce7315a738d929dd11a235a59253b 100644 (file)
@@ -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 (file)
index 0000000..ad3e827
--- /dev/null
@@ -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 (file)
index 0000000..b55fddd
--- /dev/null
@@ -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 "<name>:[ws]<value>" lines delimited by <CRLF> */
+    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 <CRLF> */
+       /*
+        * 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 <CRLF>!) 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 (file)
index 0000000..2f3bda5
--- /dev/null
@@ -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 (file)
index 0000000..f334318
--- /dev/null
@@ -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;
+}
index 2dfce42d225898a8138fcc3199bc8f30afe58c38..4aa8b56eba617617d6fb64db4adb050092e4f8b9 100644 (file)
@@ -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 (file)
index 0000000..23c3937
--- /dev/null
@@ -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 (file)
index 0000000..47d0228
--- /dev/null
@@ -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);
+}
index b67222de8089933c97308e3ea08b903b4a368f3c..9f9c3e48cbbc3e6b320cf1936da9d4bcd15965bb 100644 (file)
@@ -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);
index feec850bea800291f064b79e4380317cd052a19c..d15f211f867044695e3f12d84d119acae96ce926 100644 (file)
@@ -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.
index 8bf055ff9320ba09f0964f36dbe73cc540f7c673..eb45cd9652f5ecaa25264275d626629ee2ba4bb8 100644 (file)
@@ -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)
 {
index d37484543af9b23744cad10de0c3fdb6716326fa..0d373d8c7f02d306536f709cc558eff3f59fed78 100644 (file)
 #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)
index 6b02b40b3cefc5e7d56ae1a7b50aeb77a400add7..88128f30124db59a45040179e27bd1e557782e40 100644 (file)
@@ -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,
index 9cecf03ce2dedc1775447679dc5d4a561fe229b9..71d9fd140973b7a4da755173d7025b401164a392 100644 (file)
@@ -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
index 443448059c56da209bb5d3547fa5a425f54d0793..bac074a529a20b6daa7453c6ed785d02549a0b2e 100644 (file)
@@ -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)
index 654800827c491e5da76e21c135ac77ee3e4eb563..15badfad18bdceca377a59a4b11e99e28a608a08 100644 (file)
@@ -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[];
index 25e276684e4b73a23652295826089939f584f647..3b2ded92e0ad7c5eb7936de92882a3ce993604de 100644 (file)
@@ -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
 
 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
index f7cc870935df718348164734ff991ad208480a4e..63660ed5f18f62fdf94516538c9b0d596407989a 100644 (file)
@@ -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();
 
index b4cffd2d4101681ebe408ec932c19adad0959e09..812aa1bceca40e8426dee266b3ae67735fab8a7e 100644 (file)
@@ -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);
index 9ba779a9c5f818f27a0e3d714dcb7f3bef3115cd..6079ff804d5ac40ca0874976a748e92fa3f0d402 100644 (file)
@@ -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);
index d9a58c20094a0c528debb4661363fca8693b389d..f98081fbefb005cc719e31af410310ee25601258 100644 (file)
@@ -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);
index 71eb00962d7fdb5e18107202dcde9c475c0b4fac..53e2f4d0d81216978c9b5451a48093e1ded67d77 100644 (file)
@@ -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
index b0842c60d478066ff6ecbfa285dadded3a9133f1..725f80b64b579447f3d66be53ae6329f0da573f6 100644 (file)
@@ -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;
index f6bab8673fcfb1d18793c92fb867c219102b3e93..9a9210e0da84470d5c6ece73eb2b630fa0537a5e 100644 (file)
@@ -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);
index 4249a67a09728c09428745f8321abe6877ce79a0..417662ac5bf8a632bb11ba65af1eb08ff6058657 100644 (file)
@@ -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 <CRLF> */
+    /* 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;
index ed02e80cdc0e4eecc52ca713c87e38bcfd567082..93dce7a4bd4a5e39b3c0bd28f654a2f9f0a5c1b5 100644 (file)
@@ -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;
index f13da37fa3684eec215a8886e2fecfe3effe8205..a6cd173799caf37c11a9d308b3083f9dbf22815f 100644 (file)
@@ -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)
        "</ADDRESS>\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);