diff -u -r -N squid-3.1.0.11/ChangeLog squid-3.1.0.12/ChangeLog
--- squid-3.1.0.11/ChangeLog	2009-07-19 17:11:05.000000000 +1200
+++ squid-3.1.0.12/ChangeLog	2009-07-27 12:05:41.000000000 +1200
@@ -1,3 +1,12 @@
+Changes to squid-3.1.0.12 (27 Jul 2009):
+
+	- Bug 2716: Chunked request Signed/Unsigned build error
+	- Bug 2674: Remove limit on HTTP headers read.
+	- Bug 2620: Invalid HTTP response codes causes segfault
+	- Fix FTP EPSV negotiation parser.
+	- Fix Via string when leak checking is enabled (valgrind etc)
+	- ... and several documentation and testing additions
+
 Changes to squid-3.1.0.11 (19 Jul 2009):
 
 	- Bug 2087: Support adaptation sets and chains
@@ -198,6 +207,19 @@
 	- Bug #2223: Follow XFF extensions added
 	- ... and many code and documentation cleanups
 
+Changes to squid-3.0.STABLE17 (27 Jul 2009):
+
+	- Bug 2680 regression: Crash after rotate with no helpers running
+	- Bug 2710: squid_kerb_auth non-terminated string
+	- Bug 2679: strsep and strtoll detection failure
+	- Bug 2674: Remove limit on HTTP headers read.
+	- Bug 2659: String length overflows on append, leading to segfaults
+	- Bug 2620: Invalid HTTP response codes causes segfault
+	- Bug 2080: wbinfo_group.pl - false positive under certain conditions
+	- Bug 1087: ESI processor not quoting attributes correctly.
+	- Fix: issue with AUFS/UFS/DiskD writing objects to disk cache
+	- Several small build issues with previous release.
+
 Changes to squid-3.0.STABLE16 (15 Jun 2009):
 
 	- Bug 2672: cacheMemMaxSize 32-bit overflow during snmpwalk
diff -u -r -N squid-3.1.0.11/configure squid-3.1.0.12/configure
--- squid-3.1.0.11/configure	2009-07-19 17:11:50.000000000 +1200
+++ squid-3.1.0.12/configure	2009-07-27 12:06:31.000000000 +1200
@@ -1,7 +1,7 @@
 #! /bin/sh
-# From configure.in Revision: 1.497 .
+# From configure.in Revision.
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.62 for Squid Web Proxy 3.1.0.11.
+# Generated by GNU Autoconf 2.62 for Squid Web Proxy 3.1.0.12.
 #
 # Report bugs to <http://www.squid-cache.org/bugs/>.
 #
@@ -751,8 +751,8 @@
 # Identity of this package.
 PACKAGE_NAME='Squid Web Proxy'
 PACKAGE_TARNAME='squid'
-PACKAGE_VERSION='3.1.0.11'
-PACKAGE_STRING='Squid Web Proxy 3.1.0.11'
+PACKAGE_VERSION='3.1.0.12'
+PACKAGE_STRING='Squid Web Proxy 3.1.0.12'
 PACKAGE_BUGREPORT='http://www.squid-cache.org/bugs/'
 
 ac_unique_file="src/main.cc"
@@ -1678,7 +1678,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures Squid Web Proxy 3.1.0.11 to adapt to many kinds of systems.
+\`configure' configures Squid Web Proxy 3.1.0.12 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1748,7 +1748,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Squid Web Proxy 3.1.0.11:";;
+     short | recursive ) echo "Configuration of Squid Web Proxy 3.1.0.12:";;
    esac
   cat <<\_ACEOF
 
@@ -1939,10 +1939,6 @@
   --disable-translation   Prevent Squid generating localized error page
                           templates and manuals. Which is usually tried, but
                           may not be needed.
- if test "$enableval" = "no" ; then
-    use_translation=no
-  fi
-
   --disable-auto-locale   This prevents Squid providing localized error pages
                           based on the clients request headers. When disabled
                           Squid requires explicit language configuration.
@@ -2079,7 +2075,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Squid Web Proxy configure 3.1.0.11
+Squid Web Proxy configure 3.1.0.12
 generated by GNU Autoconf 2.62
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -2093,7 +2089,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Squid Web Proxy $as_me 3.1.0.11, which was
+It was created by Squid Web Proxy $as_me 3.1.0.12, which was
 generated by GNU Autoconf 2.62.  Invocation command line was
 
   $ $0 $@
@@ -2811,7 +2807,7 @@
 
 # Define the identity of the package.
  PACKAGE='squid'
- VERSION='3.1.0.11'
+ VERSION='3.1.0.12'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -5664,7 +5660,7 @@
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 5667 "configure"' > conftest.$ac_ext
+  echo '#line 5663 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -8286,11 +8282,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8289: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8285: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8293: \$? = $ac_status" >&5
+   echo "$as_me:8289: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8576,11 +8572,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8579: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8575: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8583: \$? = $ac_status" >&5
+   echo "$as_me:8579: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8680,11 +8676,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8683: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8679: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8687: \$? = $ac_status" >&5
+   echo "$as_me:8683: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -11080,7 +11076,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 11083 "configure"
+#line 11079 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11180,7 +11176,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 11183 "configure"
+#line 11179 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13589,11 +13585,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:13592: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:13588: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:13596: \$? = $ac_status" >&5
+   echo "$as_me:13592: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -13693,11 +13689,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:13696: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:13692: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:13700: \$? = $ac_status" >&5
+   echo "$as_me:13696: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -15276,11 +15272,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15279: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:15275: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:15283: \$? = $ac_status" >&5
+   echo "$as_me:15279: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -15380,11 +15376,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15383: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:15379: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:15387: \$? = $ac_status" >&5
+   echo "$as_me:15383: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -17595,11 +17591,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:17598: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:17594: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:17602: \$? = $ac_status" >&5
+   echo "$as_me:17598: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -17885,11 +17881,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:17888: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:17884: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:17892: \$? = $ac_status" >&5
+   echo "$as_me:17888: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -17989,11 +17985,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:17992: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:17988: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:17996: \$? = $ac_status" >&5
+   echo "$as_me:17992: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -48812,7 +48808,10 @@
 use_translation="yes"
 # Check whether --enable-translation was given.
 if test "${enable_translation+set}" = set; then
-  enableval=$enable_translation;
+  enableval=$enable_translation;  if test "$enableval" = "no" ; then
+    use_translation=no
+  fi
+
 fi
 
 if test "$use_translation" = "yes" ; then
@@ -49693,7 +49692,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Squid Web Proxy $as_me 3.1.0.11, which was
+This file was extended by Squid Web Proxy $as_me 3.1.0.12, which was
 generated by GNU Autoconf 2.62.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -49746,7 +49745,7 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-Squid Web Proxy config.status 3.1.0.11
+Squid Web Proxy config.status 3.1.0.12
 configured by $0, generated by GNU Autoconf 2.62,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
diff -u -r -N squid-3.1.0.11/configure.in squid-3.1.0.12/configure.in
--- squid-3.1.0.11/configure.in	2009-07-19 17:11:50.000000000 +1200
+++ squid-3.1.0.12/configure.in	2009-07-27 12:06:31.000000000 +1200
@@ -2,13 +2,13 @@
 dnl
 dnl  $Id$
 dnl
-AC_INIT(Squid Web Proxy, 3.1.0.11, http://www.squid-cache.org/bugs/, squid)
+AC_INIT(Squid Web Proxy, 3.1.0.12, http://www.squid-cache.org/bugs/, squid)
 AC_PREREQ(2.52)
 AM_CONFIG_HEADER(include/autoconf.h)
 AC_CONFIG_AUX_DIR(cfgaux)
 AC_CONFIG_SRCDIR([src/main.cc])
 AM_INIT_AUTOMAKE([tar-ustar nostdinc])
-AC_REVISION($Revision: 1.497 $)dnl
+AC_REVISION($Revision$)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AM_MAINTAINER_MODE
 
@@ -3781,7 +3781,7 @@
 AC_ARG_ENABLE(translation,
  AC_HELP_STRING([--disable-translation],
 		[Prevent Squid generating localized error page templates and manuals.
-		 Which is usually tried, but may not be needed.])
+		 Which is usually tried, but may not be needed.]),
 [ if test "$enableval" = "no" ; then
     use_translation=no
   fi
diff -u -r -N squid-3.1.0.11/helpers/basic_auth/NCSA/crypt_md5.c squid-3.1.0.12/helpers/basic_auth/NCSA/crypt_md5.c
--- squid-3.1.0.11/helpers/basic_auth/NCSA/crypt_md5.c	2009-07-19 17:11:07.000000000 +1200
+++ squid-3.1.0.12/helpers/basic_auth/NCSA/crypt_md5.c	2009-07-27 12:05:44.000000000 +1200
@@ -14,12 +14,16 @@
  * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp
  *
  */
+#include "config.h"
 
+#if HAVE_STRING_H
 #include <string.h>
+#endif
+#if HAVE_STDIO_H
 #include <stdio.h>
-#include "config.h"
-#include "md5.h"
+#endif
 
+#include "md5.h"
 #include "crypt_md5.h"
 
 static unsigned char itoa64[] =	/* 0 ... 63 => ascii - 64 */
diff -u -r -N squid-3.1.0.11/helpers/basic_auth/NCSA/ncsa_auth.c squid-3.1.0.12/helpers/basic_auth/NCSA/ncsa_auth.c
--- squid-3.1.0.11/helpers/basic_auth/NCSA/ncsa_auth.c	2009-07-19 17:11:07.000000000 +1200
+++ squid-3.1.0.12/helpers/basic_auth/NCSA/ncsa_auth.c	2009-07-27 12:05:44.000000000 +1200
@@ -18,6 +18,7 @@
  */
 
 #include "config.h"
+
 #if HAVE_STDIO_H
 #include <stdio.h>
 #endif
diff -u -r -N squid-3.1.0.11/include/version.h squid-3.1.0.12/include/version.h
--- squid-3.1.0.11/include/version.h	2009-07-19 17:11:50.000000000 +1200
+++ squid-3.1.0.12/include/version.h	2009-07-27 12:06:31.000000000 +1200
@@ -9,7 +9,7 @@
  */
 
 #ifndef SQUID_RELEASE_TIME
-#define SQUID_RELEASE_TIME 1247980265
+#define SQUID_RELEASE_TIME 1248653140
 #endif
 
 #ifndef APP_SHORTNAME
diff -u -r -N squid-3.1.0.11/src/adaptation/History.cc squid-3.1.0.12/src/adaptation/History.cc
--- squid-3.1.0.11/src/adaptation/History.cc	2009-07-19 17:11:12.000000000 +1200
+++ squid-3.1.0.12/src/adaptation/History.cc	2009-07-27 12:05:51.000000000 +1200
@@ -7,7 +7,7 @@
 #include "adaptation/History.h"
 
 /// impossible services value to identify unset theNextServices
-const static String TheNullServices(",null,");
+const static char *TheNullServices = ",null,";
 
 Adaptation::History::Entry::Entry(const String &sid, const timeval &when):
     service(sid), start(when), theRptm(-1), retried(false)
@@ -33,7 +33,7 @@
 }
 
 
-Adaptation::History::History(): theNextServices(TheNullServices) {
+Adaptation::History::History(): theNextServices(String(TheNullServices)) {
 }
 
 int Adaptation::History::recordXactStart(const String &sid, const timeval &when, bool retrying)
@@ -120,19 +120,19 @@
 
 void Adaptation::History::updateNextServices(const String &services)
 {
-    if (theNextServices != TheNullServices)
+    if (theNextServices != String(TheNullServices))
        debugs(93,3, HERE << "old services: " << theNextServices);
     debugs(93,3, HERE << "new services: " << services);
-    Must(services != TheNullServices);
+    Must(services != String(TheNullServices));
     theNextServices = services;
 }
 
 bool Adaptation::History::extractNextServices(String &value)
 {
-    if (theNextServices == TheNullServices)
+    if (theNextServices == String(TheNullServices))
        return false;
 
     value = theNextServices;
-    theNextServices = TheNullServices; // prevents resetting the plan twice
+    theNextServices = String(TheNullServices); // prevents resetting the plan twice
     return true;
 }
diff -u -r -N squid-3.1.0.11/src/client_side.cc squid-3.1.0.12/src/client_side.cc
--- squid-3.1.0.11/src/client_side.cc	2009-07-19 17:11:13.000000000 +1200
+++ squid-3.1.0.12/src/client_side.cc	2009-07-27 12:05:51.000000000 +1200
@@ -1360,7 +1360,7 @@
     /** Please don't do anything with the FD past here! */
 }
 
-void
+static void
 ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn)
 {
     debugs(33, 2, "ClientSocketContextPushDeferredIfNeeded: FD " << conn->fd << " Sending next");
@@ -1931,6 +1931,17 @@
     /* pre-set these values to make aborting simpler */
     *method_p = METHOD_NONE;
 
+    /* NP: don't be tempted to move this down or remove again.
+     * It's the only DDoS protection old-String has against long URL */
+    if ( hp->bufsiz <= 0) {
+        debugs(33, 5, "Incomplete request, waiting for end of request line");
+        return NULL;
+    }
+    else if ( (size_t)hp->bufsiz >= Config.maxRequestHeaderSize && headersEnd(hp->buf, Config.maxRequestHeaderSize) == 0) {
+        debugs(33, 5, "parseHttpRequest: Too large request");
+        return parseHttpRequestAbort(conn, "error:request-too-large");
+    }
+
     /* Attempt to parse the first line; this'll define the method, url, version and header begin */
     r = HttpParserParseReqLine(hp);
 
@@ -2222,7 +2233,7 @@
     // when we read chunked requests, the entire body is buffered
     // XXX: this check ignores header size and its limits.
     if (conn->in.dechunkingState == ConnStateData::chunkParsing)
-        return conn->in.notYetUsed < Config.maxChunkedRequestBodySize;
+        return ((int64_t)conn->in.notYetUsed) < Config.maxChunkedRequestBodySize;
 
     return conn->in.notYetUsed >= Config.maxRequestHeaderSize ? 0 : 1;
 }
diff -u -r -N squid-3.1.0.11/src/client_side_reply.cc squid-3.1.0.12/src/client_side_reply.cc
--- squid-3.1.0.11/src/client_side_reply.cc	2009-07-19 17:11:13.000000000 +1200
+++ squid-3.1.0.12/src/client_side_reply.cc	2009-07-27 12:05:51.000000000 +1200
@@ -1403,7 +1403,7 @@
         LOCAL_ARRAY(char, bbuf, MAX_URL + 32);
         String strVia;
         hdr->getList(HDR_VIA, &strVia);
-        snprintf(bbuf, sizeof(bbuf), "%d.%d %s",
+        snprintf(bbuf, MAX_URL + 32, "%d.%d %s",
                  reply->sline.version.major,
                  reply->sline.version.minor,
                  ThisCache);
diff -u -r -N squid-3.1.0.11/src/fs/ufs/store_io_ufs.cc squid-3.1.0.12/src/fs/ufs/store_io_ufs.cc
--- squid-3.1.0.11/src/fs/ufs/store_io_ufs.cc	2009-07-19 17:11:14.000000000 +1200
+++ squid-3.1.0.12/src/fs/ufs/store_io_ufs.cc	2009-07-27 12:05:52.000000000 +1200
@@ -363,17 +363,10 @@
     }
 
     /*
-     * DPW 2007-04-12
-     * I'm seeing disk files remain open under vanilla UFS storage
-     * because storeClose() gets called before the last write is
-     * complete.  I guess we have to check for the try_closing
-     * flag here.
+     * HNO 2009-07-24
+     * Kick any pending write/close operations alive
      */
-    if (flags.try_closing) {
-        debugs(72, 2, HERE << "UFSStoreState::writeCompleted" <<
-               " flags.try_closing is set");
-        tryClosing();
-    }
+    drainWriteQueue();
 }
 
 void
diff -u -r -N squid-3.1.0.11/src/ftp.cc squid-3.1.0.12/src/ftp.cc
--- squid-3.1.0.11/src/ftp.cc	2009-07-19 17:11:14.000000000 +1200
+++ squid-3.1.0.12/src/ftp.cc	2009-07-27 12:05:52.000000000 +1200
@@ -2447,9 +2447,13 @@
         /* server response with list of supported methods   */
         /*   522 Network protocol not supported, use (1)    */
         /*   522 Network protocol not supported, use (1,2)  */
+        /* TODO: handle the (1,2) case. We might get it back after EPSV ALL 
+         * which means close data + control without self-destructing and re-open from scratch. */
         debugs(9, 5, HERE << "scanning: " << ftpState->ctrl.last_reply);
+        buf = ftpState->ctrl.last_reply;
+        while (buf != NULL && *buf != '\0' && *buf != '\n' && *buf != '(') ++buf;
+        if (buf != NULL && *buf == '\n') ++buf;
 
-        buf = ftpState->ctrl.last_reply + strcspn(ftpState->ctrl.last_reply, "(1,2)");
         if (buf == NULL || *buf == '\0') {
             /* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
             debugs(9, DBG_IMPORTANT, "Broken FTP Server at " << fd_table[ftpState->ctrl.fd].ipaddr << ". 522 error missing protocol negotiation hints");
@@ -2473,6 +2477,11 @@
             ftpSendPassive(ftpState);
 #endif
         }
+        else {
+            /* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
+            debugs(9, DBG_IMPORTANT, "WARNING: Server at " << fd_table[ftpState->ctrl.fd].ipaddr << " sent unknown protocol negotiation hint: " << buf);
+            ftpSendPassive(ftpState);
+        }
         return;
     }
 
diff -u -r -N squid-3.1.0.11/src/http.cc squid-3.1.0.12/src/http.cc
--- squid-3.1.0.11/src/http.cc	2009-07-19 17:11:14.000000000 +1200
+++ squid-3.1.0.12/src/http.cc	2009-07-27 12:05:52.000000000 +1200
@@ -84,7 +84,7 @@
     surrogateNoStore = false;
     fd = fwd->server_fd;
     readBuf = new MemBuf;
-    readBuf->init(4096, SQUID_TCP_SO_RCVBUF);
+    readBuf->init();
     orig_request = HTTPMSGLOCK(fwd->request);
 
     // reset peer response time stats for %<pt
diff -u -r -N squid-3.1.0.11/src/HttpHeader.cc squid-3.1.0.12/src/HttpHeader.cc
--- squid-3.1.0.11/src/HttpHeader.cc	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/HttpHeader.cc	2009-07-27 12:05:47.000000000 +1200
@@ -320,6 +320,8 @@
 
     httpHeaderCalcMask(&RequestHeadersMask, EntityHeadersArr, countof(EntityHeadersArr));
 
+    httpHeaderMaskInit(&HopByHopHeadersMask, 0);
+    
     httpHeaderCalcMask(&HopByHopHeadersMask, HopByHopHeadersArr, countof(HopByHopHeadersArr));
 
     /* init header stats */
diff -u -r -N squid-3.1.0.11/src/HttpMsg.cc squid-3.1.0.12/src/HttpMsg.cc
--- squid-3.1.0.11/src/HttpMsg.cc	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/HttpMsg.cc	2009-07-27 12:05:47.000000000 +1200
@@ -150,20 +150,24 @@
     buf->terminate(); // does not affect content size
 
     // find the end of headers
-    // TODO: Remove? httpReplyParseStep() should do similar checks
     const size_t hdr_len = headersEnd(buf->content(), buf->contentSize());
 
+    // sanity check the start line to see if this is in fact an HTTP message
+    if (!sanityCheckStartLine(buf, hdr_len, error)) {
+        debugs(58,1, HERE << "first line of HTTP message is invalid");
+        // NP: sanityCheck sets *error
+        return false;
+    }
+
     // TODO: move to httpReplyParseStep()
     if (hdr_len > Config.maxReplyHeaderSize || (hdr_len <= 0 && (size_t)buf->contentSize() > Config.maxReplyHeaderSize)) {
-        debugs(58, 1, "HttpMsg::parse: Too large reply header (" <<
-               hdr_len << " > " << Config.maxReplyHeaderSize);
+        debugs(58, 1, "HttpMsg::parse: Too large reply header (" << hdr_len << " > " << Config.maxReplyHeaderSize);
         *error = HTTP_HEADER_TOO_LARGE;
         return false;
     }
 
     if (hdr_len <= 0) {
-        debugs(58, 3, "HttpMsg::parse: failed to find end of headers " <<
-               "(eof: " << eof << ") in '" << buf->content() << "'");
+        debugs(58, 3, "HttpMsg::parse: failed to find end of headers (eof: " << eof << ") in '" << buf->content() << "'");
 
         if (eof) // iff we have seen the end, this is an error
             *error = HTTP_INVALID_HEADER;
@@ -171,30 +175,22 @@
         return false;
     }
 
-    if (!sanityCheckStartLine(buf, error)) {
-        debugs(58,1, HERE << "first line of HTTP message is invalid");
-        *error = HTTP_INVALID_HEADER;
-        return false;
-    }
-
     const int res = httpMsgParseStep(buf->content(), buf->contentSize(), eof);
 
     if (res < 0) { // error
-        debugs(58, 3, "HttpMsg::parse: cannot parse isolated headers " <<
-               "in '" << buf->content() << "'");
+        debugs(58, 3, "HttpMsg::parse: cannot parse isolated headers in '" << buf->content() << "'");
         *error = HTTP_INVALID_HEADER;
         return false;
     }
 
     if (res == 0) {
-        debugs(58, 2, "HttpMsg::parse: strange, need more data near '" <<
-               buf->content() << "'");
+        debugs(58, 2, "HttpMsg::parse: strange, need more data near '" << buf->content() << "'");
+        *error = HTTP_INVALID_HEADER;
         return false; // but this should not happen due to headersEnd() above
     }
 
     assert(res > 0);
-    debugs(58, 9, "HttpMsg::parse success (" << hdr_len << " bytes) " <<
-           "near '" << buf->content() << "'");
+    debugs(58, 9, "HttpMsg::parse success (" << hdr_len << " bytes) near '" << buf->content() << "'");
 
     if (hdr_sz != (int)hdr_len) {
         debugs(58, 1, "internal HttpMsg::parse vs. headersEnd error: " <<
@@ -379,9 +375,8 @@
     packerClean(&p);
 }
 
-HttpMsg *
-
 // use HTTPMSGLOCK() instead of calling this directly
+HttpMsg *
 HttpMsg::_lock()
 {
     lock_count++;
diff -u -r -N squid-3.1.0.11/src/HttpMsg.h squid-3.1.0.12/src/HttpMsg.h
--- squid-3.1.0.11/src/HttpMsg.h	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/HttpMsg.h	2009-07-27 12:05:47.000000000 +1200
@@ -99,7 +99,14 @@
     virtual bool inheritProperties(const HttpMsg *aMsg) = 0;
 
 protected:
-    virtual bool sanityCheckStartLine(MemBuf *buf, http_status *error) = 0;
+     /**
+      * Validate the message start line is syntactically correct.
+      * Set HTTP error status according to problems found.
+      *
+      * \retval true   Status line has no serious problems.
+      * \retval false  Status line has a serious problem. Correct response is indicated by error.
+      */
+    virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error) = 0;
 
     virtual void packFirstLineInto(Packer * p, bool full_uri) const = 0;
 
diff -u -r -N squid-3.1.0.11/src/HttpReply.cc squid-3.1.0.12/src/HttpReply.cc
--- squid-3.1.0.11/src/HttpReply.cc	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/HttpReply.cc	2009-07-27 12:05:47.000000000 +1200
@@ -437,15 +437,54 @@
     return content_length;
 }
 
-bool HttpReply::sanityCheckStartLine(MemBuf *buf, http_status *error)
+/**
+ * Checks the first line of an HTTP Reply is valid.
+ * currently only checks "HTTP/" exists.
+ *
+ * NP: not all error cases are detected yet. Some are left for detection later in parse.
+ */
+bool
+HttpReply::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error)
 {
-    //hack warning: using psize instead of size here due to type mismatches with MemBuf.
-    if (buf->contentSize() >= protoPrefix.psize() && protoPrefix.cmp(buf->content(), protoPrefix.size()) != 0) {
+    // hack warning: using psize instead of size here due to type mismatches with MemBuf.
+
+    // content is long enough to possibly hold a reply
+    // 4 being magic size of a 3-digit number plus space delimiter
+    if ( buf->contentSize() < (protoPrefix.psize() + 4) ) {
+        if (hdr_len > 0)
+            *error = HTTP_INVALID_HEADER;
+        return false;
+    }
+
+    // catch missing or mismatched protocol identifier
+    if (protoPrefix.cmp(buf->content(), protoPrefix.size()) != 0) {
         debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol prefix (" << protoPrefix << ") in '" << buf->content() << "'");
         *error = HTTP_INVALID_HEADER;
         return false;
     }
 
+    // catch missing or negative status value (negative '-' is not a digit)
+    int pos = protoPrefix.psize();
+
+    // skip arbitrary number of digits and a dot in the verion portion
+    while ( pos <= buf->contentSize() && (*(buf->content()+pos) == '.' || xisdigit(*(buf->content()+pos)) ) ) ++pos;
+
+    // catch missing version info
+    if (pos == protoPrefix.psize()) {
+        debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol version numbers (ie. " << protoPrefix << "/1.0) in '" << buf->content() << "'");
+        *error = HTTP_INVALID_HEADER;
+        return false;
+    }
+
+    // skip arbitrary number of spaces...
+    while (pos <= buf->contentSize() && (char)*(buf->content()+pos) == ' ') ++pos;
+
+    if (!xisdigit(*(buf->content()+pos))) {
+        debugs(58, 3, "HttpReply::sanityCheckStartLine: missing or invalid status number in '" << buf->content() << "'");
+        *error = HTTP_INVALID_HEADER;
+        return false;
+    }
+
     return true;
 }
 
diff -u -r -N squid-3.1.0.11/src/HttpReply.h squid-3.1.0.12/src/HttpReply.h
--- squid-3.1.0.11/src/HttpReply.h	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/HttpReply.h	2009-07-27 12:05:47.000000000 +1200
@@ -68,7 +68,7 @@
      \retval false and sets *error to zero when needs more data
      \retval false and sets *error to a positive http_status code on error
      */
-    virtual bool sanityCheckStartLine(MemBuf *buf, http_status *error);
+    virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error);
 
     /** \par public, readable; never update these or their .hdr equivalents directly */
     time_t date;
diff -u -r -N squid-3.1.0.11/src/HttpRequest.cc squid-3.1.0.12/src/HttpRequest.cc
--- squid-3.1.0.11/src/HttpRequest.cc	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/HttpRequest.cc	2009-07-27 12:05:47.000000000 +1200
@@ -208,18 +208,29 @@
     return copy;
 }
 
+/**
+ * Checks the first line of an HTTP request is valid
+ * currently just checks the request method is present.
+ *
+ * NP: Other errors are left for detection later in the parse.
+ */
 bool
-HttpRequest::sanityCheckStartLine(MemBuf *buf, http_status *error)
+HttpRequest::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error)
 {
-    /**
-     * Just see if the request buffer starts with a known
-     * HTTP request method.  NOTE this whole function is somewhat
-     * superfluous and could just go away.
-     \todo AYJ: Check for safely removing this function. We now accept 'unknown' request methods in HTTP.
-     */
+    // content is long enough to possibly hold a reply
+    // 2 being magic size of a 1-byte request method plus space delimiter
+    if ( buf->contentSize() < 2 ) {
+        // this is ony a real error if the headers apparently complete.
+        if (hdr_len > 0) {
+            *error = HTTP_INVALID_HEADER;
+        }
+        return false;
+    }
 
+    /* See if the request buffer starts with a known HTTP request method. */
     if (HttpRequestMethod(buf->content(),NULL) == METHOD_NONE) {
         debugs(73, 3, "HttpRequest::sanityCheckStartLine: did not find HTTP request method");
+        *error = HTTP_INVALID_HEADER;
         return false;
     }
 
diff -u -r -N squid-3.1.0.11/src/HttpRequest.h squid-3.1.0.12/src/HttpRequest.h
--- squid-3.1.0.11/src/HttpRequest.h	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/HttpRequest.h	2009-07-27 12:05:47.000000000 +1200
@@ -234,7 +234,7 @@
 protected:
     virtual void packFirstLineInto(Packer * p, bool full_uri) const;
 
-    virtual bool sanityCheckStartLine(MemBuf *buf, http_status *error);
+    virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error);
 
     virtual void hdrCacheInit();
 
diff -u -r -N squid-3.1.0.11/src/Makefile.am squid-3.1.0.12/src/Makefile.am
--- squid-3.1.0.11/src/Makefile.am	2009-07-19 17:11:09.000000000 +1200
+++ squid-3.1.0.12/src/Makefile.am	2009-07-27 12:05:47.000000000 +1200
@@ -402,6 +402,7 @@
 	MemObject.cc \
 	MemObject.h \
 	mime.cc \
+	mime_header.cc \
 	multicast.cc \
 	neighbors.cc \
 	Packer.cc \
@@ -835,12 +836,16 @@
 	tests/testEvent \
 	tests/testEventLoop \
 	tests/test_http_range \
+	tests/testHttpReply \
 	tests/testHttpRequest \
 	tests/testStore \
 	tests/testString \
 	tests/testURL \
 	@STORE_TESTS@
 
+## NP: required to run the above list. check_PROGRAMS only builds the binaries...
+TESTS += $(check_PROGRAMS)
+
 ### Template for new Unit Test Program
 ## - add tests/testX to check_PROGRAMS above.
 ## - copy template below and substitue X for class name
@@ -864,6 +869,61 @@
 #tests_testX_DEPENDENCIES= @SQUID_CPPUNIT_LA@ \
 #	$(top_builddir)/lib/libmiscutil.a
 
+
+# - add other component .(h|cc) files needed to link and run tests
+tests_testHttpReply_SOURCES=\
+	tests/testHttpReply.h \
+	tests/testHttpReply.cc \
+	tests/testMain.cc \
+	cbdata.h \
+	cbdata.cc \
+	ETag.cc \
+	HttpBody.cc \
+	HttpHdrCc.cc \
+	HttpHdrContRange.h \
+	HttpHdrContRange.cc \
+	HttpHdrRange.cc \
+	HttpHdrSc.h \
+	HttpHdrSc.cc \
+	HttpHdrScTarget.h \
+	HttpHdrScTarget.cc \
+	HttpHeader.h \
+	HttpHeader.cc \
+	HttpHeaderMask.h \
+	HttpHeaderTools.cc \
+	HttpMsg.h \
+	HttpMsg.cc \
+	HttpReply.h \
+	HttpReply.cc \
+	HttpStatusLine.h \
+	HttpStatusLine.cc \
+	mem.cc \
+	MemBuf.h \
+	MemBuf.cc \
+	mime_header.cc \
+	Packer.h \
+	Packer.cc \
+	tests/stub_cache_manager.cc \
+	tests/stub_StatHist.cc \
+	tests/stub_store.cc \
+	SquidString.h \
+	String.cc \
+	SquidTime.h \
+	time.cc
+nodist_tests_testHttpReply_SOURCES=\
+	$(TESTSOURCES)
+tests_testHttpReply_LDFLAGS = $(LIBADD_DL)
+tests_testHttpReply_LDADD=\
+	acl/libapi.la \
+	acl/libstate.la \
+	auth/libauth.la \
+	ip/libip.la \
+	@SQUID_CPPUNIT_LIBS@ \
+	@SQUID_CPPUNIT_LA@ \
+	-L../lib -lmiscutil
+tests_testHttpReply_DEPENDENCIES= @SQUID_CPPUNIT_LA@ \
+	$(top_builddir)/lib/libmiscutil.a
+
 tests_testAuth_SOURCES = \
 	tests/testAuth.cc tests/testMain.cc  tests/testAuth.h \
 	ConfigParser.cc \
@@ -1055,6 +1115,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -1224,6 +1285,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -1371,6 +1433,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -1508,6 +1571,7 @@
 	mem_node.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	multicast.cc \
 	neighbors.cc \
 	Parsing.cc \
@@ -1659,6 +1723,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -2010,6 +2075,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
diff -u -r -N squid-3.1.0.11/src/Makefile.in squid-3.1.0.12/src/Makefile.in
--- squid-3.1.0.11/src/Makefile.in	2009-07-19 17:11:33.000000000 +1200
+++ squid-3.1.0.12/src/Makefile.in	2009-07-27 12:06:14.000000000 +1200
@@ -48,9 +48,9 @@
 	tests/testACLMaxUserIP$(EXEEXT) tests/testBoilerplate$(EXEEXT) \
 	tests/testCacheManager$(EXEEXT) tests/testDiskIO$(EXEEXT) \
 	tests/testEvent$(EXEEXT) tests/testEventLoop$(EXEEXT) \
-	tests/test_http_range$(EXEEXT) tests/testHttpRequest$(EXEEXT) \
-	tests/testStore$(EXEEXT) tests/testString$(EXEEXT) \
-	tests/testURL$(EXEEXT) @STORE_TESTS@
+	tests/test_http_range$(EXEEXT) tests/testHttpReply$(EXEEXT) \
+	tests/testHttpRequest$(EXEEXT) tests/testStore$(EXEEXT) \
+	tests/testString$(EXEEXT) tests/testURL$(EXEEXT) @STORE_TESTS@
 @USE_ADAPTATION_TRUE@am__append_1 = adaptation
 @USE_ESI_TRUE@am__append_2 = esi
 EXTRA_PROGRAMS = DiskIO/DiskDaemon/diskd$(EXEEXT) unlinkd$(EXEEXT) \
@@ -196,15 +196,15 @@
 	icp_v2.cc icp_v3.cc int.cc internal.cc ipc.cc ipc_win32.cc \
 	ipcache.cc LeakFinder.cc list.cc logfile.cc main.cc mem.cc \
 	mem_node.cc mem_node.h Mem.h MemBuf.cc MemObject.cc \
-	MemObject.h mime.cc multicast.cc neighbors.cc Packer.cc \
-	Packer.h Parsing.cc Parsing.h ProfStats.cc pconn.cc pconn.h \
-	PeerDigest.h peer_digest.cc peer_select.cc peer_sourcehash.cc \
-	peer_userhash.cc PeerSelectState.h PingData.h protos.h \
-	redirect.cc referer.cc refresh.cc RemovalPolicy.cc \
-	RemovalPolicy.h send-announce.cc snmp_core.cc snmp_agent.cc \
-	squid.h SquidNew.cc ssl_support.cc ssl_support.h stat.cc \
-	StatHist.cc String.cc stmem.cc stmem.h store.cc Store.h \
-	StoreFileSystem.cc StoreFileSystem.h StoreHashIndex.h \
+	MemObject.h mime.cc mime_header.cc multicast.cc neighbors.cc \
+	Packer.cc Packer.h Parsing.cc Parsing.h ProfStats.cc pconn.cc \
+	pconn.h PeerDigest.h peer_digest.cc peer_select.cc \
+	peer_sourcehash.cc peer_userhash.cc PeerSelectState.h \
+	PingData.h protos.h redirect.cc referer.cc refresh.cc \
+	RemovalPolicy.cc RemovalPolicy.h send-announce.cc snmp_core.cc \
+	snmp_agent.cc squid.h SquidNew.cc ssl_support.cc ssl_support.h \
+	stat.cc StatHist.cc String.cc stmem.cc stmem.h store.cc \
+	Store.h StoreFileSystem.cc StoreFileSystem.h StoreHashIndex.h \
 	store_io.cc StoreIOBuffer.h StoreIOState.cc StoreIOState.h \
 	store_client.cc StoreClient.h store_digest.cc store_dir.cc \
 	store_key_md5.cc store_log.cc store_rebuild.cc store_swapin.cc \
@@ -275,9 +275,9 @@
 	$(am__objects_12) list.$(OBJEXT) logfile.$(OBJEXT) \
 	main.$(OBJEXT) mem.$(OBJEXT) mem_node.$(OBJEXT) \
 	MemBuf.$(OBJEXT) MemObject.$(OBJEXT) mime.$(OBJEXT) \
-	multicast.$(OBJEXT) neighbors.$(OBJEXT) Packer.$(OBJEXT) \
-	Parsing.$(OBJEXT) $(am__objects_13) pconn.$(OBJEXT) \
-	peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
+	mime_header.$(OBJEXT) multicast.$(OBJEXT) neighbors.$(OBJEXT) \
+	Packer.$(OBJEXT) Parsing.$(OBJEXT) $(am__objects_13) \
+	pconn.$(OBJEXT) peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
 	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
 	redirect.$(OBJEXT) referer.$(OBJEXT) refresh.$(OBJEXT) \
 	RemovalPolicy.$(OBJEXT) send-announce.$(OBJEXT) \
@@ -404,11 +404,12 @@
 	HttpReply.cc HttpStatusLine.cc icp_v2.cc icp_v3.cc ipc.cc \
 	ipc_win32.cc ipcache.cc int.cc internal.cc list.cc logfile.cc \
 	multicast.cc mem_node.cc MemBuf.cc MemObject.cc mime.cc \
-	neighbors.cc Packer.cc Parsing.cc pconn.cc peer_digest.cc \
-	peer_select.cc peer_sourcehash.cc peer_userhash.cc redirect.cc \
-	referer.cc refresh.cc RemovalPolicy.cc Server.cc snmp_core.cc \
-	snmp_agent.cc ssl_support.cc ssl_support.h stat.cc StatHist.cc \
-	stmem.cc store.cc store_client.cc store_digest.cc store_dir.cc \
+	mime_header.cc neighbors.cc Packer.cc Parsing.cc pconn.cc \
+	peer_digest.cc peer_select.cc peer_sourcehash.cc \
+	peer_userhash.cc redirect.cc referer.cc refresh.cc \
+	RemovalPolicy.cc Server.cc snmp_core.cc snmp_agent.cc \
+	ssl_support.cc ssl_support.h stat.cc StatHist.cc stmem.cc \
+	store.cc store_client.cc store_digest.cc store_dir.cc \
 	store_io.cc store_key_md5.cc store_log.cc store_rebuild.cc \
 	store_swapin.cc store_swapmeta.cc store_swapout.cc \
 	StoreFileSystem.cc StoreIOState.cc StoreMeta.cc \
@@ -443,26 +444,27 @@
 	int.$(OBJEXT) internal.$(OBJEXT) list.$(OBJEXT) \
 	logfile.$(OBJEXT) multicast.$(OBJEXT) mem_node.$(OBJEXT) \
 	MemBuf.$(OBJEXT) MemObject.$(OBJEXT) mime.$(OBJEXT) \
-	neighbors.$(OBJEXT) Packer.$(OBJEXT) Parsing.$(OBJEXT) \
-	pconn.$(OBJEXT) peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
-	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
-	redirect.$(OBJEXT) referer.$(OBJEXT) refresh.$(OBJEXT) \
-	RemovalPolicy.$(OBJEXT) Server.$(OBJEXT) $(am__objects_15) \
-	$(am__objects_17) stat.$(OBJEXT) StatHist.$(OBJEXT) \
-	stmem.$(OBJEXT) store.$(OBJEXT) store_client.$(OBJEXT) \
-	store_digest.$(OBJEXT) store_dir.$(OBJEXT) store_io.$(OBJEXT) \
-	store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
-	store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
-	store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
-	StoreFileSystem.$(OBJEXT) StoreIOState.$(OBJEXT) \
-	StoreMeta.$(OBJEXT) StoreMetaMD5.$(OBJEXT) \
-	StoreMetaSTD.$(OBJEXT) StoreMetaSTDLFS.$(OBJEXT) \
-	StoreMetaUnpacker.$(OBJEXT) StoreMetaURL.$(OBJEXT) \
-	StoreMetaVary.$(OBJEXT) StoreSwapLogData.$(OBJEXT) \
-	$(am__objects_24) tools.$(OBJEXT) tunnel.$(OBJEXT) \
-	SwapDir.$(OBJEXT) url.$(OBJEXT) URLScheme.$(OBJEXT) \
-	urn.$(OBJEXT) useragent.$(OBJEXT) wccp2.$(OBJEXT) \
-	whois.$(OBJEXT) $(am__objects_19) wordlist.$(OBJEXT)
+	mime_header.$(OBJEXT) neighbors.$(OBJEXT) Packer.$(OBJEXT) \
+	Parsing.$(OBJEXT) pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
+	peer_select.$(OBJEXT) peer_sourcehash.$(OBJEXT) \
+	peer_userhash.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
+	refresh.$(OBJEXT) RemovalPolicy.$(OBJEXT) Server.$(OBJEXT) \
+	$(am__objects_15) $(am__objects_17) stat.$(OBJEXT) \
+	StatHist.$(OBJEXT) stmem.$(OBJEXT) store.$(OBJEXT) \
+	store_client.$(OBJEXT) store_digest.$(OBJEXT) \
+	store_dir.$(OBJEXT) store_io.$(OBJEXT) store_key_md5.$(OBJEXT) \
+	store_log.$(OBJEXT) store_rebuild.$(OBJEXT) \
+	store_swapin.$(OBJEXT) store_swapmeta.$(OBJEXT) \
+	store_swapout.$(OBJEXT) StoreFileSystem.$(OBJEXT) \
+	StoreIOState.$(OBJEXT) StoreMeta.$(OBJEXT) \
+	StoreMetaMD5.$(OBJEXT) StoreMetaSTD.$(OBJEXT) \
+	StoreMetaSTDLFS.$(OBJEXT) StoreMetaUnpacker.$(OBJEXT) \
+	StoreMetaURL.$(OBJEXT) StoreMetaVary.$(OBJEXT) \
+	StoreSwapLogData.$(OBJEXT) $(am__objects_24) tools.$(OBJEXT) \
+	tunnel.$(OBJEXT) SwapDir.$(OBJEXT) url.$(OBJEXT) \
+	URLScheme.$(OBJEXT) urn.$(OBJEXT) useragent.$(OBJEXT) \
+	wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_19) \
+	wordlist.$(OBJEXT)
 nodist_tests_testCacheManager_OBJECTS = globals.$(OBJEXT) \
 	repl_modules.$(OBJEXT) string_arrays.$(OBJEXT)
 tests_testCacheManager_OBJECTS = $(am_tests_testCacheManager_OBJECTS) \
@@ -622,8 +624,8 @@
 	HttpHdrScTarget.cc HttpMsg.cc HttpReply.cc HttpStatusLine.cc \
 	icp_v2.cc icp_v3.cc ipc.cc ipc_win32.cc ipcache.cc int.cc \
 	internal.cc list.cc logfile.cc multicast.cc mem_node.cc \
-	MemBuf.cc MemObject.cc mime.cc neighbors.cc Packer.cc \
-	Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
+	MemBuf.cc MemObject.cc mime.cc mime_header.cc neighbors.cc \
+	Packer.cc Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
 	peer_sourcehash.cc peer_userhash.cc redirect.cc referer.cc \
 	refresh.cc Server.cc snmp_core.cc snmp_agent.cc ssl_support.cc \
 	ssl_support.h stat.cc StatHist.cc stmem.cc store.cc \
@@ -661,26 +663,26 @@
 	int.$(OBJEXT) internal.$(OBJEXT) list.$(OBJEXT) \
 	logfile.$(OBJEXT) multicast.$(OBJEXT) mem_node.$(OBJEXT) \
 	MemBuf.$(OBJEXT) MemObject.$(OBJEXT) mime.$(OBJEXT) \
-	neighbors.$(OBJEXT) Packer.$(OBJEXT) Parsing.$(OBJEXT) \
-	pconn.$(OBJEXT) peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
-	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
-	redirect.$(OBJEXT) referer.$(OBJEXT) refresh.$(OBJEXT) \
-	Server.$(OBJEXT) $(am__objects_15) $(am__objects_17) \
-	stat.$(OBJEXT) StatHist.$(OBJEXT) stmem.$(OBJEXT) \
-	store.$(OBJEXT) store_client.$(OBJEXT) store_digest.$(OBJEXT) \
-	store_dir.$(OBJEXT) store_io.$(OBJEXT) store_key_md5.$(OBJEXT) \
-	store_log.$(OBJEXT) store_rebuild.$(OBJEXT) \
-	store_swapin.$(OBJEXT) store_swapmeta.$(OBJEXT) \
-	store_swapout.$(OBJEXT) StoreFileSystem.$(OBJEXT) \
-	StoreIOState.$(OBJEXT) StoreMeta.$(OBJEXT) \
-	StoreMetaMD5.$(OBJEXT) StoreMetaSTD.$(OBJEXT) \
-	StoreMetaSTDLFS.$(OBJEXT) StoreMetaUnpacker.$(OBJEXT) \
-	StoreMetaURL.$(OBJEXT) StoreMetaVary.$(OBJEXT) \
-	StoreSwapLogData.$(OBJEXT) $(am__objects_24) tools.$(OBJEXT) \
-	tunnel.$(OBJEXT) SwapDir.$(OBJEXT) url.$(OBJEXT) \
-	URLScheme.$(OBJEXT) urn.$(OBJEXT) useragent.$(OBJEXT) \
-	wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_19) \
-	wordlist.$(OBJEXT)
+	mime_header.$(OBJEXT) neighbors.$(OBJEXT) Packer.$(OBJEXT) \
+	Parsing.$(OBJEXT) pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
+	peer_select.$(OBJEXT) peer_sourcehash.$(OBJEXT) \
+	peer_userhash.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
+	refresh.$(OBJEXT) Server.$(OBJEXT) $(am__objects_15) \
+	$(am__objects_17) stat.$(OBJEXT) StatHist.$(OBJEXT) \
+	stmem.$(OBJEXT) store.$(OBJEXT) store_client.$(OBJEXT) \
+	store_digest.$(OBJEXT) store_dir.$(OBJEXT) store_io.$(OBJEXT) \
+	store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
+	store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
+	store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
+	StoreFileSystem.$(OBJEXT) StoreIOState.$(OBJEXT) \
+	StoreMeta.$(OBJEXT) StoreMetaMD5.$(OBJEXT) \
+	StoreMetaSTD.$(OBJEXT) StoreMetaSTDLFS.$(OBJEXT) \
+	StoreMetaUnpacker.$(OBJEXT) StoreMetaURL.$(OBJEXT) \
+	StoreMetaVary.$(OBJEXT) StoreSwapLogData.$(OBJEXT) \
+	$(am__objects_24) tools.$(OBJEXT) tunnel.$(OBJEXT) \
+	SwapDir.$(OBJEXT) url.$(OBJEXT) URLScheme.$(OBJEXT) \
+	urn.$(OBJEXT) useragent.$(OBJEXT) wccp2.$(OBJEXT) \
+	whois.$(OBJEXT) $(am__objects_19) wordlist.$(OBJEXT)
 nodist_tests_testEvent_OBJECTS = globals.$(OBJEXT) \
 	repl_modules.$(OBJEXT) string_arrays.$(OBJEXT)
 tests_testEvent_OBJECTS = $(am_tests_testEvent_OBJECTS) \
@@ -714,8 +716,8 @@
 	HttpHdrScTarget.cc HttpMsg.cc HttpReply.cc HttpStatusLine.cc \
 	icp_v2.cc icp_v3.cc ipc.cc ipc_win32.cc ipcache.cc int.cc \
 	internal.cc list.cc logfile.cc multicast.cc mem_node.cc \
-	MemBuf.cc MemObject.cc mime.cc neighbors.cc Packer.cc \
-	Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
+	MemBuf.cc MemObject.cc mime.cc mime_header.cc neighbors.cc \
+	Packer.cc Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
 	peer_sourcehash.cc peer_userhash.cc redirect.cc referer.cc \
 	refresh.cc Server.cc snmp_core.cc snmp_agent.cc ssl_support.cc \
 	ssl_support.h stat.cc StatHist.cc stmem.cc store.cc \
@@ -753,26 +755,26 @@
 	int.$(OBJEXT) internal.$(OBJEXT) list.$(OBJEXT) \
 	logfile.$(OBJEXT) multicast.$(OBJEXT) mem_node.$(OBJEXT) \
 	MemBuf.$(OBJEXT) MemObject.$(OBJEXT) mime.$(OBJEXT) \
-	neighbors.$(OBJEXT) Packer.$(OBJEXT) Parsing.$(OBJEXT) \
-	pconn.$(OBJEXT) peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
-	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
-	redirect.$(OBJEXT) referer.$(OBJEXT) refresh.$(OBJEXT) \
-	Server.$(OBJEXT) $(am__objects_15) $(am__objects_17) \
-	stat.$(OBJEXT) StatHist.$(OBJEXT) stmem.$(OBJEXT) \
-	store.$(OBJEXT) store_client.$(OBJEXT) store_digest.$(OBJEXT) \
-	store_dir.$(OBJEXT) store_io.$(OBJEXT) store_key_md5.$(OBJEXT) \
-	store_log.$(OBJEXT) store_rebuild.$(OBJEXT) \
-	store_swapin.$(OBJEXT) store_swapmeta.$(OBJEXT) \
-	store_swapout.$(OBJEXT) StoreFileSystem.$(OBJEXT) \
-	StoreIOState.$(OBJEXT) StoreMeta.$(OBJEXT) \
-	StoreMetaMD5.$(OBJEXT) StoreMetaSTD.$(OBJEXT) \
-	StoreMetaSTDLFS.$(OBJEXT) StoreMetaUnpacker.$(OBJEXT) \
-	StoreMetaURL.$(OBJEXT) StoreMetaVary.$(OBJEXT) \
-	StoreSwapLogData.$(OBJEXT) $(am__objects_24) tools.$(OBJEXT) \
-	tunnel.$(OBJEXT) SwapDir.$(OBJEXT) url.$(OBJEXT) \
-	URLScheme.$(OBJEXT) urn.$(OBJEXT) useragent.$(OBJEXT) \
-	wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_19) \
-	wordlist.$(OBJEXT)
+	mime_header.$(OBJEXT) neighbors.$(OBJEXT) Packer.$(OBJEXT) \
+	Parsing.$(OBJEXT) pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
+	peer_select.$(OBJEXT) peer_sourcehash.$(OBJEXT) \
+	peer_userhash.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
+	refresh.$(OBJEXT) Server.$(OBJEXT) $(am__objects_15) \
+	$(am__objects_17) stat.$(OBJEXT) StatHist.$(OBJEXT) \
+	stmem.$(OBJEXT) store.$(OBJEXT) store_client.$(OBJEXT) \
+	store_digest.$(OBJEXT) store_dir.$(OBJEXT) store_io.$(OBJEXT) \
+	store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
+	store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
+	store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
+	StoreFileSystem.$(OBJEXT) StoreIOState.$(OBJEXT) \
+	StoreMeta.$(OBJEXT) StoreMetaMD5.$(OBJEXT) \
+	StoreMetaSTD.$(OBJEXT) StoreMetaSTDLFS.$(OBJEXT) \
+	StoreMetaUnpacker.$(OBJEXT) StoreMetaURL.$(OBJEXT) \
+	StoreMetaVary.$(OBJEXT) StoreSwapLogData.$(OBJEXT) \
+	$(am__objects_24) tools.$(OBJEXT) tunnel.$(OBJEXT) \
+	SwapDir.$(OBJEXT) url.$(OBJEXT) URLScheme.$(OBJEXT) \
+	urn.$(OBJEXT) useragent.$(OBJEXT) wccp2.$(OBJEXT) \
+	whois.$(OBJEXT) $(am__objects_19) wordlist.$(OBJEXT)
 nodist_tests_testEventLoop_OBJECTS = globals.$(OBJEXT) \
 	repl_modules.$(OBJEXT) string_arrays.$(OBJEXT)
 tests_testEventLoop_OBJECTS = $(am_tests_testEventLoop_OBJECTS) \
@@ -780,6 +782,23 @@
 tests_testEventLoop_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
 	$(CXXFLAGS) $(tests_testEventLoop_LDFLAGS) $(LDFLAGS) -o $@
+am_tests_testHttpReply_OBJECTS = tests/testHttpReply.$(OBJEXT) \
+	tests/testMain.$(OBJEXT) cbdata.$(OBJEXT) ETag.$(OBJEXT) \
+	HttpBody.$(OBJEXT) HttpHdrCc.$(OBJEXT) \
+	HttpHdrContRange.$(OBJEXT) HttpHdrRange.$(OBJEXT) \
+	HttpHdrSc.$(OBJEXT) HttpHdrScTarget.$(OBJEXT) \
+	HttpHeader.$(OBJEXT) HttpHeaderTools.$(OBJEXT) \
+	HttpMsg.$(OBJEXT) HttpReply.$(OBJEXT) HttpStatusLine.$(OBJEXT) \
+	mem.$(OBJEXT) MemBuf.$(OBJEXT) mime_header.$(OBJEXT) \
+	Packer.$(OBJEXT) tests/stub_cache_manager.$(OBJEXT) \
+	tests/stub_StatHist.$(OBJEXT) tests/stub_store.$(OBJEXT) \
+	String.$(OBJEXT) time.$(OBJEXT)
+nodist_tests_testHttpReply_OBJECTS = $(am__objects_25)
+tests_testHttpReply_OBJECTS = $(am_tests_testHttpReply_OBJECTS) \
+	$(nodist_tests_testHttpReply_OBJECTS)
+tests_testHttpReply_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(tests_testHttpReply_LDFLAGS) $(LDFLAGS) -o $@
 am__tests_testHttpRequest_SOURCES_DIST = debug.cc HttpRequest.cc \
 	HttpRequestMethod.cc mem.cc String.cc tests/testHttpRequest.h \
 	tests/testHttpRequest.cc tests/testHttpRequestMethod.h \
@@ -806,8 +825,8 @@
 	HttpHdrScTarget.cc HttpMsg.cc HttpReply.cc HttpStatusLine.cc \
 	icp_v2.cc icp_v3.cc ipc.cc ipc_win32.cc ipcache.cc int.cc \
 	internal.cc list.cc logfile.cc multicast.cc mem_node.cc \
-	MemBuf.cc MemObject.cc mime.cc neighbors.cc Packer.cc \
-	Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
+	MemBuf.cc MemObject.cc mime.cc mime_header.cc neighbors.cc \
+	Packer.cc Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
 	peer_sourcehash.cc peer_userhash.cc redirect.cc referer.cc \
 	refresh.cc RemovalPolicy.cc Server.cc snmp_core.cc \
 	snmp_agent.cc ssl_support.cc ssl_support.h stat.cc StatHist.cc \
@@ -846,26 +865,27 @@
 	int.$(OBJEXT) internal.$(OBJEXT) list.$(OBJEXT) \
 	logfile.$(OBJEXT) multicast.$(OBJEXT) mem_node.$(OBJEXT) \
 	MemBuf.$(OBJEXT) MemObject.$(OBJEXT) mime.$(OBJEXT) \
-	neighbors.$(OBJEXT) Packer.$(OBJEXT) Parsing.$(OBJEXT) \
-	pconn.$(OBJEXT) peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
-	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
-	redirect.$(OBJEXT) referer.$(OBJEXT) refresh.$(OBJEXT) \
-	RemovalPolicy.$(OBJEXT) Server.$(OBJEXT) $(am__objects_15) \
-	$(am__objects_17) stat.$(OBJEXT) StatHist.$(OBJEXT) \
-	stmem.$(OBJEXT) store.$(OBJEXT) store_client.$(OBJEXT) \
-	store_digest.$(OBJEXT) store_dir.$(OBJEXT) store_io.$(OBJEXT) \
-	store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
-	store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
-	store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
-	StoreFileSystem.$(OBJEXT) StoreIOState.$(OBJEXT) \
-	StoreMeta.$(OBJEXT) StoreMetaMD5.$(OBJEXT) \
-	StoreMetaSTD.$(OBJEXT) StoreMetaSTDLFS.$(OBJEXT) \
-	StoreMetaUnpacker.$(OBJEXT) StoreMetaURL.$(OBJEXT) \
-	StoreMetaVary.$(OBJEXT) StoreSwapLogData.$(OBJEXT) \
-	$(am__objects_24) tools.$(OBJEXT) tunnel.$(OBJEXT) \
-	SwapDir.$(OBJEXT) url.$(OBJEXT) URLScheme.$(OBJEXT) \
-	urn.$(OBJEXT) useragent.$(OBJEXT) wccp2.$(OBJEXT) \
-	whois.$(OBJEXT) $(am__objects_19) wordlist.$(OBJEXT)
+	mime_header.$(OBJEXT) neighbors.$(OBJEXT) Packer.$(OBJEXT) \
+	Parsing.$(OBJEXT) pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
+	peer_select.$(OBJEXT) peer_sourcehash.$(OBJEXT) \
+	peer_userhash.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
+	refresh.$(OBJEXT) RemovalPolicy.$(OBJEXT) Server.$(OBJEXT) \
+	$(am__objects_15) $(am__objects_17) stat.$(OBJEXT) \
+	StatHist.$(OBJEXT) stmem.$(OBJEXT) store.$(OBJEXT) \
+	store_client.$(OBJEXT) store_digest.$(OBJEXT) \
+	store_dir.$(OBJEXT) store_io.$(OBJEXT) store_key_md5.$(OBJEXT) \
+	store_log.$(OBJEXT) store_rebuild.$(OBJEXT) \
+	store_swapin.$(OBJEXT) store_swapmeta.$(OBJEXT) \
+	store_swapout.$(OBJEXT) StoreFileSystem.$(OBJEXT) \
+	StoreIOState.$(OBJEXT) StoreMeta.$(OBJEXT) \
+	StoreMetaMD5.$(OBJEXT) StoreMetaSTD.$(OBJEXT) \
+	StoreMetaSTDLFS.$(OBJEXT) StoreMetaUnpacker.$(OBJEXT) \
+	StoreMetaURL.$(OBJEXT) StoreMetaVary.$(OBJEXT) \
+	StoreSwapLogData.$(OBJEXT) $(am__objects_24) tools.$(OBJEXT) \
+	tunnel.$(OBJEXT) SwapDir.$(OBJEXT) url.$(OBJEXT) \
+	URLScheme.$(OBJEXT) urn.$(OBJEXT) useragent.$(OBJEXT) \
+	wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_19) \
+	wordlist.$(OBJEXT)
 nodist_tests_testHttpRequest_OBJECTS = globals.$(OBJEXT) \
 	repl_modules.$(OBJEXT) string_arrays.$(OBJEXT)
 tests_testHttpRequest_OBJECTS = $(am_tests_testHttpRequest_OBJECTS) \
@@ -989,8 +1009,8 @@
 	HttpHdrScTarget.cc HttpMsg.cc HttpReply.cc HttpStatusLine.cc \
 	icp_v2.cc icp_v3.cc ipc.cc ipc_win32.cc ipcache.cc int.cc \
 	internal.cc list.cc logfile.cc multicast.cc mem_node.cc \
-	MemBuf.cc MemObject.cc mime.cc neighbors.cc Packer.cc \
-	Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
+	MemBuf.cc MemObject.cc mime.cc mime_header.cc neighbors.cc \
+	Packer.cc Parsing.cc pconn.cc peer_digest.cc peer_select.cc \
 	peer_sourcehash.cc peer_userhash.cc redirect.cc referer.cc \
 	refresh.cc Server.cc snmp_core.cc snmp_agent.cc ssl_support.cc \
 	ssl_support.h stat.cc StatHist.cc stmem.cc store.cc \
@@ -1029,26 +1049,26 @@
 	ipcache.$(OBJEXT) int.$(OBJEXT) internal.$(OBJEXT) \
 	list.$(OBJEXT) logfile.$(OBJEXT) multicast.$(OBJEXT) \
 	mem_node.$(OBJEXT) MemBuf.$(OBJEXT) MemObject.$(OBJEXT) \
-	mime.$(OBJEXT) neighbors.$(OBJEXT) Packer.$(OBJEXT) \
-	Parsing.$(OBJEXT) pconn.$(OBJEXT) peer_digest.$(OBJEXT) \
-	peer_select.$(OBJEXT) peer_sourcehash.$(OBJEXT) \
-	peer_userhash.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
-	refresh.$(OBJEXT) Server.$(OBJEXT) $(am__objects_15) \
-	$(am__objects_17) stat.$(OBJEXT) StatHist.$(OBJEXT) \
-	stmem.$(OBJEXT) store.$(OBJEXT) store_client.$(OBJEXT) \
-	store_digest.$(OBJEXT) store_dir.$(OBJEXT) store_io.$(OBJEXT) \
-	store_key_md5.$(OBJEXT) store_log.$(OBJEXT) \
-	store_rebuild.$(OBJEXT) store_swapin.$(OBJEXT) \
-	store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
-	StoreFileSystem.$(OBJEXT) StoreIOState.$(OBJEXT) \
-	StoreMeta.$(OBJEXT) StoreMetaMD5.$(OBJEXT) \
-	StoreMetaSTD.$(OBJEXT) StoreMetaSTDLFS.$(OBJEXT) \
-	StoreMetaUnpacker.$(OBJEXT) StoreMetaURL.$(OBJEXT) \
-	StoreMetaVary.$(OBJEXT) StoreSwapLogData.$(OBJEXT) \
-	$(am__objects_24) tools.$(OBJEXT) tunnel.$(OBJEXT) \
-	SwapDir.$(OBJEXT) urn.$(OBJEXT) useragent.$(OBJEXT) \
-	wccp2.$(OBJEXT) whois.$(OBJEXT) $(am__objects_19) \
-	wordlist.$(OBJEXT)
+	mime.$(OBJEXT) mime_header.$(OBJEXT) neighbors.$(OBJEXT) \
+	Packer.$(OBJEXT) Parsing.$(OBJEXT) pconn.$(OBJEXT) \
+	peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
+	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
+	redirect.$(OBJEXT) referer.$(OBJEXT) refresh.$(OBJEXT) \
+	Server.$(OBJEXT) $(am__objects_15) $(am__objects_17) \
+	stat.$(OBJEXT) StatHist.$(OBJEXT) stmem.$(OBJEXT) \
+	store.$(OBJEXT) store_client.$(OBJEXT) store_digest.$(OBJEXT) \
+	store_dir.$(OBJEXT) store_io.$(OBJEXT) store_key_md5.$(OBJEXT) \
+	store_log.$(OBJEXT) store_rebuild.$(OBJEXT) \
+	store_swapin.$(OBJEXT) store_swapmeta.$(OBJEXT) \
+	store_swapout.$(OBJEXT) StoreFileSystem.$(OBJEXT) \
+	StoreIOState.$(OBJEXT) StoreMeta.$(OBJEXT) \
+	StoreMetaMD5.$(OBJEXT) StoreMetaSTD.$(OBJEXT) \
+	StoreMetaSTDLFS.$(OBJEXT) StoreMetaUnpacker.$(OBJEXT) \
+	StoreMetaURL.$(OBJEXT) StoreMetaVary.$(OBJEXT) \
+	StoreSwapLogData.$(OBJEXT) $(am__objects_24) tools.$(OBJEXT) \
+	tunnel.$(OBJEXT) SwapDir.$(OBJEXT) urn.$(OBJEXT) \
+	useragent.$(OBJEXT) wccp2.$(OBJEXT) whois.$(OBJEXT) \
+	$(am__objects_19) wordlist.$(OBJEXT)
 nodist_tests_testURL_OBJECTS = globals.$(OBJEXT) \
 	repl_modules.$(OBJEXT) string_arrays.$(OBJEXT)
 tests_testURL_OBJECTS = $(am_tests_testURL_OBJECTS) \
@@ -1123,20 +1143,20 @@
 	HttpRequestMethod.cc HttpStatusLine.cc icp_v2.cc icp_v3.cc \
 	int.cc internal.cc ipc.cc ipc_win32.cc ipcache.cc list.cc \
 	logfile.cc mem.cc mem_node.cc MemObject.cc mime.cc \
-	multicast.cc neighbors.cc Parsing.cc peer_digest.cc \
-	peer_select.cc peer_sourcehash.cc peer_userhash.cc pconn.cc \
-	redirect.cc referer.cc refresh.cc RemovalPolicy.cc Server.cc \
-	snmp_core.cc snmp_agent.cc ssl_support.cc ssl_support.h \
-	stat.cc StatHist.cc stmem.cc store.cc store_client.cc \
-	store_digest.cc store_dir.cc store_key_md5.cc store_io.cc \
-	store_log.cc store_rebuild.cc store_swapin.cc \
-	store_swapmeta.cc store_swapout.cc StoreFileSystem.cc \
-	StoreIOState.cc StoreMeta.cc StoreMetaMD5.cc StoreMetaSTD.cc \
-	StoreMetaSTDLFS.cc StoreMetaUnpacker.cc StoreMetaURL.cc \
-	StoreMetaVary.cc StoreSwapLogData.cc String.cc SwapDir.cc \
-	event.cc time.cc tools.cc tunnel.cc url.cc URLScheme.cc urn.cc \
-	useragent.cc wccp2.cc whois.cc win32.cc wordlist.cc Packer.cc \
-	MemBuf.cc
+	mime_header.cc multicast.cc neighbors.cc Parsing.cc \
+	peer_digest.cc peer_select.cc peer_sourcehash.cc \
+	peer_userhash.cc pconn.cc redirect.cc referer.cc refresh.cc \
+	RemovalPolicy.cc Server.cc snmp_core.cc snmp_agent.cc \
+	ssl_support.cc ssl_support.h stat.cc StatHist.cc stmem.cc \
+	store.cc store_client.cc store_digest.cc store_dir.cc \
+	store_key_md5.cc store_io.cc store_log.cc store_rebuild.cc \
+	store_swapin.cc store_swapmeta.cc store_swapout.cc \
+	StoreFileSystem.cc StoreIOState.cc StoreMeta.cc \
+	StoreMetaMD5.cc StoreMetaSTD.cc StoreMetaSTDLFS.cc \
+	StoreMetaUnpacker.cc StoreMetaURL.cc StoreMetaVary.cc \
+	StoreSwapLogData.cc String.cc SwapDir.cc event.cc time.cc \
+	tools.cc tunnel.cc url.cc URLScheme.cc urn.cc useragent.cc \
+	wccp2.cc whois.cc win32.cc wordlist.cc Packer.cc MemBuf.cc
 am_tests_test_http_range_OBJECTS = tests/test_http_range.$(OBJEXT) \
 	access_log.$(OBJEXT) BodyPipe.$(OBJEXT) cache_cf.$(OBJEXT) \
 	ProtoPort.$(OBJEXT) cache_manager.$(OBJEXT) \
@@ -1161,8 +1181,8 @@
 	internal.$(OBJEXT) $(am__objects_11) ipcache.$(OBJEXT) \
 	list.$(OBJEXT) logfile.$(OBJEXT) mem.$(OBJEXT) \
 	mem_node.$(OBJEXT) MemObject.$(OBJEXT) mime.$(OBJEXT) \
-	multicast.$(OBJEXT) neighbors.$(OBJEXT) Parsing.$(OBJEXT) \
-	peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
+	mime_header.$(OBJEXT) multicast.$(OBJEXT) neighbors.$(OBJEXT) \
+	Parsing.$(OBJEXT) peer_digest.$(OBJEXT) peer_select.$(OBJEXT) \
 	peer_sourcehash.$(OBJEXT) peer_userhash.$(OBJEXT) \
 	pconn.$(OBJEXT) redirect.$(OBJEXT) referer.$(OBJEXT) \
 	refresh.$(OBJEXT) RemovalPolicy.$(OBJEXT) Server.$(OBJEXT) \
@@ -1251,6 +1271,8 @@
 	$(tests_testEvent_SOURCES) $(nodist_tests_testEvent_SOURCES) \
 	$(tests_testEventLoop_SOURCES) \
 	$(nodist_tests_testEventLoop_SOURCES) \
+	$(tests_testHttpReply_SOURCES) \
+	$(nodist_tests_testHttpReply_SOURCES) \
 	$(tests_testHttpRequest_SOURCES) \
 	$(nodist_tests_testHttpRequest_SOURCES) \
 	$(tests_testNull_SOURCES) $(nodist_tests_testNull_SOURCES) \
@@ -1274,6 +1296,7 @@
 	$(am__tests_testDiskIO_SOURCES_DIST) \
 	$(am__tests_testEvent_SOURCES_DIST) \
 	$(am__tests_testEventLoop_SOURCES_DIST) \
+	$(tests_testHttpReply_SOURCES) \
 	$(am__tests_testHttpRequest_SOURCES_DIST) \
 	$(am__tests_testNull_SOURCES_DIST) \
 	$(am__tests_testStore_SOURCES_DIST) \
@@ -1487,7 +1510,7 @@
 	squid.conf.documented globals.cc string_arrays.c \
 	repl_modules.cc DiskIO/DiskIOModules_gen.cc test_tools.cc *.a \
 	testHeaders
-TESTS = testHeaders
+TESTS = $(check_PROGRAMS) testHeaders
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/src \
 	-I$(top_builddir)/include @SQUID_CPPUNIT_INC@ \
 	-I$(top_srcdir)/lib -I$(top_builddir)/src
@@ -1700,9 +1723,9 @@
 	icp_v2.cc icp_v3.cc int.cc internal.cc $(IPC_SOURCE) \
 	ipcache.cc $(LEAKFINDERSOURCE) list.cc logfile.cc main.cc \
 	mem.cc mem_node.cc mem_node.h Mem.h MemBuf.cc MemObject.cc \
-	MemObject.h mime.cc multicast.cc neighbors.cc Packer.cc \
-	Packer.h Parsing.cc Parsing.h $(XPROF_STATS_SOURCE) pconn.cc \
-	pconn.h PeerDigest.h peer_digest.cc peer_select.cc \
+	MemObject.h mime.cc mime_header.cc multicast.cc neighbors.cc \
+	Packer.cc Packer.h Parsing.cc Parsing.h $(XPROF_STATS_SOURCE) \
+	pconn.cc pconn.h PeerDigest.h peer_digest.cc peer_select.cc \
 	peer_sourcehash.cc peer_userhash.cc PeerSelectState.h \
 	PingData.h protos.h redirect.cc referer.cc refresh.cc \
 	RemovalPolicy.cc RemovalPolicy.h send-announce.cc \
@@ -1936,6 +1959,64 @@
 #	-L../lib -lmiscutil
 #tests_testX_DEPENDENCIES= @SQUID_CPPUNIT_LA@ \
 #	$(top_builddir)/lib/libmiscutil.a
+
+# - add other component .(h|cc) files needed to link and run tests
+tests_testHttpReply_SOURCES = \
+	tests/testHttpReply.h \
+	tests/testHttpReply.cc \
+	tests/testMain.cc \
+	cbdata.h \
+	cbdata.cc \
+	ETag.cc \
+	HttpBody.cc \
+	HttpHdrCc.cc \
+	HttpHdrContRange.h \
+	HttpHdrContRange.cc \
+	HttpHdrRange.cc \
+	HttpHdrSc.h \
+	HttpHdrSc.cc \
+	HttpHdrScTarget.h \
+	HttpHdrScTarget.cc \
+	HttpHeader.h \
+	HttpHeader.cc \
+	HttpHeaderMask.h \
+	HttpHeaderTools.cc \
+	HttpMsg.h \
+	HttpMsg.cc \
+	HttpReply.h \
+	HttpReply.cc \
+	HttpStatusLine.h \
+	HttpStatusLine.cc \
+	mem.cc \
+	MemBuf.h \
+	MemBuf.cc \
+	mime_header.cc \
+	Packer.h \
+	Packer.cc \
+	tests/stub_cache_manager.cc \
+	tests/stub_StatHist.cc \
+	tests/stub_store.cc \
+	SquidString.h \
+	String.cc \
+	SquidTime.h \
+	time.cc
+
+nodist_tests_testHttpReply_SOURCES = \
+	$(TESTSOURCES)
+
+tests_testHttpReply_LDFLAGS = $(LIBADD_DL)
+tests_testHttpReply_LDADD = \
+	acl/libapi.la \
+	acl/libstate.la \
+	auth/libauth.la \
+	ip/libip.la \
+	@SQUID_CPPUNIT_LIBS@ \
+	@SQUID_CPPUNIT_LA@ \
+	-L../lib -lmiscutil
+
+tests_testHttpReply_DEPENDENCIES = @SQUID_CPPUNIT_LA@ \
+	$(top_builddir)/lib/libmiscutil.a
+
 tests_testAuth_SOURCES = \
 	tests/testAuth.cc tests/testMain.cc  tests/testAuth.h \
 	ConfigParser.cc \
@@ -2110,6 +2191,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -2283,6 +2365,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -2432,6 +2515,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -2572,6 +2656,7 @@
 	mem_node.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	multicast.cc \
 	neighbors.cc \
 	Parsing.cc \
@@ -2724,6 +2809,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -3086,6 +3172,7 @@
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
+	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
@@ -3508,6 +3595,13 @@
 tests/testEventLoop$(EXEEXT): $(tests_testEventLoop_OBJECTS) $(tests_testEventLoop_DEPENDENCIES) tests/$(am__dirstamp)
 	@rm -f tests/testEventLoop$(EXEEXT)
 	$(tests_testEventLoop_LINK) $(tests_testEventLoop_OBJECTS) $(tests_testEventLoop_LDADD) $(LIBS)
+tests/testHttpReply.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
+tests/stub_StatHist.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
+tests/testHttpReply$(EXEEXT): $(tests_testHttpReply_OBJECTS) $(tests_testHttpReply_DEPENDENCIES) tests/$(am__dirstamp)
+	@rm -f tests/testHttpReply$(EXEEXT)
+	$(tests_testHttpReply_LINK) $(tests_testHttpReply_OBJECTS) $(tests_testHttpReply_LDADD) $(LIBS)
 tests/testHttpRequest.$(OBJEXT): tests/$(am__dirstamp) \
 	tests/$(DEPDIR)/$(am__dirstamp)
 tests/testHttpRequestMethod.$(OBJEXT): tests/$(am__dirstamp) \
@@ -3597,6 +3691,7 @@
 	-rm -f tests/stub_HttpReply.$(OBJEXT)
 	-rm -f tests/stub_HttpRequest.$(OBJEXT)
 	-rm -f tests/stub_MemObject.$(OBJEXT)
+	-rm -f tests/stub_StatHist.$(OBJEXT)
 	-rm -f tests/stub_access_log.$(OBJEXT)
 	-rm -f tests/stub_acl.$(OBJEXT)
 	-rm -f tests/stub_cache_cf.$(OBJEXT)
@@ -3622,6 +3717,7 @@
 	-rm -f tests/testDiskIO.$(OBJEXT)
 	-rm -f tests/testEvent.$(OBJEXT)
 	-rm -f tests/testEventLoop.$(OBJEXT)
+	-rm -f tests/testHttpReply.$(OBJEXT)
 	-rm -f tests/testHttpRequest.$(OBJEXT)
 	-rm -f tests/testHttpRequestMethod.$(OBJEXT)
 	-rm -f tests/testMain.$(OBJEXT)
@@ -3757,6 +3853,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_node.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mime_header.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/multicast.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/neighbors.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pconn.Po@am__quote@
@@ -3829,6 +3926,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/stub_HttpReply.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/stub_HttpRequest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/stub_MemObject.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/stub_StatHist.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/stub_access_log.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/stub_acl.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/stub_cache_cf.Po@am__quote@
@@ -3854,6 +3952,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/testDiskIO.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/testEvent.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/testEventLoop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/testHttpReply.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/testHttpRequest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/testHttpRequestMethod.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/testMain.Po@am__quote@
diff -u -r -N squid-3.1.0.11/src/mime.cc squid-3.1.0.12/src/mime.cc
--- squid-3.1.0.11/src/mime.cc	2009-07-19 17:11:14.000000000 +1200
+++ squid-3.1.0.12/src/mime.cc	2009-07-27 12:05:52.000000000 +1200
@@ -2,7 +2,7 @@
 /*
  * $Id$
  *
- * DEBUG: section 25    MIME Parsing
+ * DEBUG: section 25    MIME Parsing and Internal Icons
  * AUTHOR: Harvest Derived
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -96,132 +96,6 @@
     safe_free (address);
 }
 
-/* returns a pointer to a field-value of the first matching field-name */
-char *
-mime_get_header(const char *mime, const char *name)
-{
-    return mime_get_header_field(mime, name, NULL);
-}
-
-/*
- * returns a pointer to a field-value of the first matching field-name where
- * field-value matches prefix if any
- */
-char *
-mime_get_header_field(const char *mime, const char *name, const char *prefix)
-{
-    LOCAL_ARRAY(char, header, GET_HDR_SZ);
-    const char *p = NULL;
-    char *q = NULL;
-    char got = 0;
-    const int namelen = name ? strlen(name) : 0;
-    const int preflen = prefix ? strlen(prefix) : 0;
-    int l;
-
-    if (NULL == mime)
-        return NULL;
-
-    assert(NULL != name);
-
-    debugs(25, 5, "mime_get_header: looking for '" << name << "'");
-
-    for (p = mime; *p; p += strcspn(p, "\n\r")) {
-        if (strcmp(p, "\r\n\r\n") == 0 || strcmp(p, "\n\n") == 0)
-            return NULL;
-
-        while (xisspace(*p))
-            p++;
-
-        if (strncasecmp(p, name, namelen))
-            continue;
-
-        if (!xisspace(p[namelen]) && p[namelen] != ':')
-            continue;
-
-        l = strcspn(p, "\n\r") + 1;
-
-        if (l > GET_HDR_SZ)
-            l = GET_HDR_SZ;
-
-        xstrncpy(header, p, l);
-
-        debugs(25, 5, "mime_get_header: checking '" << header << "'");
-
-        q = header;
-
-        q += namelen;
-
-        if (*q == ':')
-            q++, got = 1;
-
-        while (xisspace(*q))
-            q++, got = 1;
-
-        if (got && prefix) {
-            /* we could process list entries here if we had strcasestr(). */
-            /* make sure we did not match a part of another field-value */
-            got = !strncasecmp(q, prefix, preflen) && !xisalpha(q[preflen]);
-        }
-
-        if (got) {
-            debugs(25, 5, "mime_get_header: returning '" << q << "'");
-            return q;
-        }
-    }
-
-    return NULL;
-}
-
-size_t
-headersEnd(const char *mime, size_t l)
-{
-    size_t e = 0;
-    int state = 1;
-
-    PROF_start(headersEnd);
-
-    while (e < l && state < 3) {
-        switch (state) {
-
-        case 0:
-
-            if ('\n' == mime[e])
-                state = 1;
-
-            break;
-
-        case 1:
-            if ('\r' == mime[e])
-                state = 2;
-            else if ('\n' == mime[e])
-                state = 3;
-            else
-                state = 0;
-
-            break;
-
-        case 2:
-            if ('\n' == mime[e])
-                state = 3;
-            else
-                state = 0;
-
-            break;
-
-        default:
-            break;
-        }
-
-        e++;
-    }
-    PROF_stop(headersEnd);
-
-    if (3 == state)
-        return e;
-
-    return 0;
-}
-
 static mimeEntry *
 mimeGetEntry(const char *fn, int skip_encodings)
 {
diff -u -r -N squid-3.1.0.11/src/mime_header.cc squid-3.1.0.12/src/mime_header.cc
--- squid-3.1.0.11/src/mime_header.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-3.1.0.12/src/mime_header.cc	2009-07-27 12:05:52.000000000 +1200
@@ -0,0 +1,164 @@
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 25    MiME Header Parsing
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "squid.h"
+
+#define GET_HDR_SZ 1024
+
+/* returns a pointer to a field-value of the first matching field-name */
+char *
+mime_get_header(const char *mime, const char *name)
+{
+    return mime_get_header_field(mime, name, NULL);
+}
+
+/*
+ * returns a pointer to a field-value of the first matching field-name where
+ * field-value matches prefix if any
+ */
+char *
+mime_get_header_field(const char *mime, const char *name, const char *prefix)
+{
+    LOCAL_ARRAY(char, header, GET_HDR_SZ);
+    const char *p = NULL;
+    char *q = NULL;
+    char got = 0;
+    const int namelen = name ? strlen(name) : 0;
+    const int preflen = prefix ? strlen(prefix) : 0;
+    int l;
+
+    if (NULL == mime)
+        return NULL;
+
+    assert(NULL != name);
+
+    debugs(25, 5, "mime_get_header: looking for '" << name << "'");
+
+    for (p = mime; *p; p += strcspn(p, "\n\r")) {
+        if (strcmp(p, "\r\n\r\n") == 0 || strcmp(p, "\n\n") == 0)
+            return NULL;
+
+        while (xisspace(*p))
+            p++;
+
+        if (strncasecmp(p, name, namelen))
+            continue;
+
+        if (!xisspace(p[namelen]) && p[namelen] != ':')
+            continue;
+
+        l = strcspn(p, "\n\r") + 1;
+
+        if (l > GET_HDR_SZ)
+            l = GET_HDR_SZ;
+
+        xstrncpy(header, p, l);
+
+        debugs(25, 5, "mime_get_header: checking '" << header << "'");
+
+        q = header;
+
+        q += namelen;
+
+        if (*q == ':')
+            q++, got = 1;
+
+        while (xisspace(*q))
+            q++, got = 1;
+
+        if (got && prefix) {
+            /* we could process list entries here if we had strcasestr(). */
+            /* make sure we did not match a part of another field-value */
+            got = !strncasecmp(q, prefix, preflen) && !xisalpha(q[preflen]);
+        }
+
+        if (got) {
+            debugs(25, 5, "mime_get_header: returning '" << q << "'");
+            return q;
+        }
+    }
+
+    return NULL;
+}
+
+size_t
+headersEnd(const char *mime, size_t l)
+{
+    size_t e = 0;
+    int state = 1;
+
+    PROF_start(headersEnd);
+
+    while (e < l && state < 3) {
+        switch (state) {
+
+        case 0:
+
+            if ('\n' == mime[e])
+                state = 1;
+
+            break;
+
+        case 1:
+            if ('\r' == mime[e])
+                state = 2;
+            else if ('\n' == mime[e])
+                state = 3;
+            else
+                state = 0;
+
+            break;
+
+        case 2:
+            if ('\n' == mime[e])
+                state = 3;
+            else
+                state = 0;
+
+            break;
+
+        default:
+            break;
+        }
+
+        e++;
+    }
+    PROF_stop(headersEnd);
+
+    if (3 == state)
+        return e;
+
+    return 0;
+}
diff -u -r -N squid-3.1.0.11/src/String.cc squid-3.1.0.12/src/String.cc
--- squid-3.1.0.11/src/String.cc	2009-07-19 17:11:12.000000000 +1200
+++ squid-3.1.0.12/src/String.cc	2009-07-27 12:05:50.000000000 +1200
@@ -150,6 +150,7 @@
     PROF_start(StringClean);
     assert(this);
 
+    /* TODO if mempools has already closed this will FAIL!! */
     if (defined())
         memFreeString(size_, buf_);
 
diff -u -r -N squid-3.1.0.11/src/tests/stub_HttpReply.cc squid-3.1.0.12/src/tests/stub_HttpReply.cc
--- squid-3.1.0.11/src/tests/stub_HttpReply.cc	2009-07-19 17:11:15.000000000 +1200
+++ squid-3.1.0.12/src/tests/stub_HttpReply.cc	2009-07-27 12:05:53.000000000 +1200
@@ -70,7 +70,7 @@
 }
 
 bool
-HttpReply::sanityCheckStartLine(MemBuf *buf, http_status *error)
+HttpReply::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error)
 {
     fatal ("Not implemented");
     return false;
diff -u -r -N squid-3.1.0.11/src/tests/stub_HttpRequest.cc squid-3.1.0.12/src/tests/stub_HttpRequest.cc
--- squid-3.1.0.11/src/tests/stub_HttpRequest.cc	2009-07-19 17:11:15.000000000 +1200
+++ squid-3.1.0.12/src/tests/stub_HttpRequest.cc	2009-07-27 12:05:53.000000000 +1200
@@ -56,7 +56,7 @@
 }
 
 bool
-HttpRequest::sanityCheckStartLine(MemBuf *buf, http_status *error)
+HttpRequest::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error)
 {
     fatal("Not implemented");
     return false;
diff -u -r -N squid-3.1.0.11/src/tests/stub_StatHist.cc squid-3.1.0.12/src/tests/stub_StatHist.cc
--- squid-3.1.0.11/src/tests/stub_StatHist.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-3.1.0.12/src/tests/stub_StatHist.cc	2009-07-27 12:05:53.000000000 +1200
@@ -0,0 +1,22 @@
+#include "squid.h"
+
+// for StatHist definitions
+#include "protos.h"
+
+void
+statHistDump(const StatHist * H, StoreEntry * sentry, StatHistBinDumper * bd)
+{
+    fatal("statHistDump: Not implemented");
+}
+
+void
+statHistCount(StatHist * H, double val)
+{
+    fatal("statHistCount: Not implemented");
+}
+
+void
+statHistEnumInit(StatHist * H, int last_enum)
+{
+//NO-OP    fatal("statHistEnumInit: Not implemented");
+}
diff -u -r -N squid-3.1.0.11/src/tests/stub_store.cc squid-3.1.0.12/src/tests/stub_store.cc
--- squid-3.1.0.11/src/tests/stub_store.cc	2009-07-19 17:11:15.000000000 +1200
+++ squid-3.1.0.12/src/tests/stub_store.cc	2009-07-27 12:05:53.000000000 +1200
@@ -40,13 +40,13 @@
 extern "C" void
     storeAppendPrintf(StoreEntry * e, const char *fmt,...)
 {
-    fatal("Not implemented");
+    fatal("storeAppendPrintf: Not implemented");
 }
 
 extern "C" void
     storeAppendVPrintf(StoreEntry * e, const char *fmt, va_list vargs)
 {
-    fatal("Not implemented");
+    fatal("storeAppendVPrintf: Not implemented");
 }
 
 #ifndef _USE_INLINE_
diff -u -r -N squid-3.1.0.11/src/tests/testHttpReply.cc squid-3.1.0.12/src/tests/testHttpReply.cc
--- squid-3.1.0.11/src/tests/testHttpReply.cc	1970-01-01 12:00:00.000000000 +1200
+++ squid-3.1.0.12/src/tests/testHttpReply.cc	2009-07-27 12:05:53.000000000 +1200
@@ -0,0 +1,183 @@
+#include "config.h"
+#include <cppunit/TestAssert.h>
+
+#include "testHttpReply.h"
+#include "HttpReply.h"
+#include "Mem.h"
+
+/* to avoid libsquid.la and its comm stuff */
+#include "TextException.cc"
+
+CPPUNIT_TEST_SUITE_REGISTRATION( testHttpReply );
+
+struct SquidConfig Config;
+
+/* stub functions to link successfully */
+
+#include "Store.h"
+void
+StoreEntry::timestampsSet()
+{
+    fatal("StoreEntry::timestampsSet. Not implemented.");
+}
+
+void
+StoreEntry::setPublicKey()
+{
+    fatal("StoreEntry::setPulicKey. Not implemented.");
+}
+
+#include "MemObject.h"
+int64_t
+MemObject::endOffset() const
+{
+    return 0;
+}
+
+#include "ConfigParser.h"
+void
+ConfigParser::destruct()
+{
+// CALLED as shutdown no-op
+//    fatal("ConfigParser::destruct. Not implemented.");
+}
+
+void
+eventAdd(const char *name, EVH * func, void *arg, double when, int, bool cbdata)
+{
+// CALLED as setUp no-op
+//    fatal("eventAdd. Not implemented.");
+}
+
+/* end */
+
+void
+testHttpReply::setUp()
+{
+    Mem::Init();
+    httpHeaderInitModule();
+}
+
+void
+testHttpReply::testSanityCheckFirstLine()
+{
+    MemBuf input;
+    HttpReply engine;
+    http_status error = HTTP_STATUS_NONE;
+    size_t hdr_len;
+    input.init();
+
+    // a valid status line
+    input.append("HTTP/1.1 200 Okay\n\n", 19);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT( 1 && engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("HTTP/1.1    200  Okay     \n\n", 28);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT( 2 && engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+#if TODO // these cases are only checked after parse...
+    // invalid status line
+    input.append("HTTP/1.1 999 Okay\n\n", 19);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT( 3 && !engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("HTTP/1.1    2000  Okay     \n\n", 29);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT( 4 && engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+#endif
+
+    // empty status line
+    input.append("\n\n", 2);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT( 5 && !engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("      \n\n", 8);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT( 6 && !engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    // status line with no message
+    input.append("HTTP/1.1 200\n\n", 14); /* real case seen */
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT(engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("HTTP/1.1 200 \n\n", 15); /* real case seen */
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT(engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+#if FUTURE
+
+    // status line with no status
+    input.append("HTTP/1.1 \n\n", 11);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("HTTP/1.1     \n\n", 15);
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("HTTP/1.1  Okay\n\n", 16); /* real case seen */
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    // status line with nul-byte
+    input.append("HTTP/1.1\0200 Okay\n\n", 19); /* real case seen */
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    // status line with negative status
+    input.append("HTTP/1.1 -000\n\n", 15); /* real case seen */
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    // status line with non-HTTP protocol
+    input.append("ICY/1.1 200 Okay\n\n", 18); /* real case seen */
+    hdr_len = headersEnd(input.content(),input.contentSize());
+    /* NP: for nw ICY is handled as a pass-thru */
+    /*     Squid-3 will ignore it (and mangle the headers as per HTTP). */
+    CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+#endif
+
+}
diff -u -r -N squid-3.1.0.11/src/tests/testHttpReply.h squid-3.1.0.12/src/tests/testHttpReply.h
--- squid-3.1.0.11/src/tests/testHttpReply.h	1970-01-01 12:00:00.000000000 +1200
+++ squid-3.1.0.12/src/tests/testHttpReply.h	2009-07-27 12:05:53.000000000 +1200
@@ -0,0 +1,25 @@
+
+#ifndef SQUID_SRC_TEST_HTTP_REPLY_H
+#define SQUID_SRC_TEST_HTTP_REPLY_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+/*
+ * test HttpReply
+ */
+
+class testHttpReply : public CPPUNIT_NS::TestFixture
+{
+    CPPUNIT_TEST_SUITE( testHttpReply );
+    CPPUNIT_TEST( testSanityCheckFirstLine );
+    CPPUNIT_TEST_SUITE_END();
+
+public:
+    void setUp();
+
+protected:
+    void testSanityCheckFirstLine();
+};
+
+#endif
+
diff -u -r -N squid-3.1.0.11/src/tests/testHttpRequest.cc squid-3.1.0.12/src/tests/testHttpRequest.cc
--- squid-3.1.0.11/src/tests/testHttpRequest.cc	2009-07-19 17:11:15.000000000 +1200
+++ squid-3.1.0.12/src/tests/testHttpRequest.cc	2009-07-27 12:05:53.000000000 +1200
@@ -9,6 +9,13 @@
 
 CPPUNIT_TEST_SUITE_REGISTRATION( testHttpRequest );
 
+/** wrapper for testing HttpRequest object private and protected functions */
+class PrivateHttpRequest : public HttpRequest
+{
+public:
+    bool doSanityCheckStartLine(MemBuf *b, const size_t h, http_status *e) { return sanityCheckStartLine(b,h,e); };
+};
+
 /* stub functions to link successfully */
 void
 shut_down(int)
@@ -26,6 +33,7 @@
 testHttpRequest::setUp()
 {
     Mem::Init();
+    httpHeaderInitModule();
 }
 
 /*
@@ -150,3 +158,60 @@
     CPPUNIT_ASSERT_EQUAL(String("http://2000:800::45/foo"), String(url));
     xfree(url);
 }
+
+void
+testHttpRequest::testSanityCheckStartLine()
+{
+    MemBuf input;
+    PrivateHttpRequest engine;
+    http_status error = HTTP_STATUS_NONE;
+    size_t hdr_len;
+    input.init();
+
+    // a valid request line
+    input.append("GET / HTTP/1.1\n\n", 16);
+    hdr_len = headersEnd(input.content(), input.contentSize());
+    CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("GET  /  HTTP/1.1\n\n", 18);
+    hdr_len = headersEnd(input.content(), input.contentSize());
+    CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    // strange but valid methods
+    input.append(". / HTTP/1.1\n\n", 14);
+    hdr_len = headersEnd(input.content(), input.contentSize());
+    CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+    input.append("OPTIONS * HTTP/1.1\n\n", 20);
+    hdr_len = headersEnd(input.content(), input.contentSize());
+    CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_STATUS_NONE);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+
+// TODO no method
+
+// TODO binary code in method
+
+// TODO no URL
+
+// TODO no status (okay)
+
+// TODO non-HTTP protocol
+
+    input.append("      \n\n", 8);
+    hdr_len = headersEnd(input.content(), input.contentSize());
+    CPPUNIT_ASSERT(!engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+    CPPUNIT_ASSERT_EQUAL(error, HTTP_INVALID_HEADER);
+    input.reset();
+    error = HTTP_STATUS_NONE;
+}
diff -u -r -N squid-3.1.0.11/src/tests/testHttpRequest.h squid-3.1.0.12/src/tests/testHttpRequest.h
--- squid-3.1.0.11/src/tests/testHttpRequest.h	2009-07-19 17:11:15.000000000 +1200
+++ squid-3.1.0.12/src/tests/testHttpRequest.h	2009-07-27 12:05:53.000000000 +1200
@@ -14,6 +14,7 @@
     CPPUNIT_TEST( testCreateFromUrlAndMethod );
     CPPUNIT_TEST( testCreateFromUrl );
     CPPUNIT_TEST( testIPv6HostColonBug );
+    CPPUNIT_TEST( testSanityCheckStartLine );
     CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -23,6 +24,7 @@
     void testCreateFromUrlAndMethod();
     void testCreateFromUrl();
     void testIPv6HostColonBug();
+    void testSanityCheckStartLine();
 };
 
 #endif
diff -u -r -N squid-3.1.0.11/tools/squidclient.1 squid-3.1.0.12/tools/squidclient.1
--- squid-3.1.0.11/tools/squidclient.1	2009-07-19 17:11:15.000000000 +1200
+++ squid-3.1.0.12/tools/squidclient.1	2009-07-27 12:05:53.000000000 +1200
@@ -43,7 +43,7 @@
 .B squidclient
 is a tool providing a command line interface for retrieving URLs.
 Designed for testing any HTTP 0.9, 1.0, or 1.1 web server or proxy.
-This tool can be combined scripts to perform any basic HTTP operation.
+This tool can be combined with scripts to perform any basic HTTP operation.
 Some additional features for access to the 
 .B Squid
 proxy object cache and management information are provided.
