[PATCH] squid 3.5.19: latest patches from upstream

Matthias Fischer matthias.fischer at ipfire.org
Tue Jun 21 20:22:13 CEST 2016


For details see:
http://www.squid-cache.org/Versions/v3/3.5/changesets/

Signed-off-by: Matthias Fischer <matthias.fischer at ipfire.org>
---
 lfs/squid                               |   5 +
 src/patches/squid/squid-3.5-14057.patch | 132 ++++++
 src/patches/squid/squid-3.5-14058.patch | 732 ++++++++++++++++++++++++++++++++
 src/patches/squid/squid-3.5-14059.patch |  49 +++
 src/patches/squid/squid-3.5-14060.patch | 117 +++++
 src/patches/squid/squid-3.5-14061.patch | 237 +++++++++++
 6 files changed, 1272 insertions(+)
 create mode 100644 src/patches/squid/squid-3.5-14057.patch
 create mode 100644 src/patches/squid/squid-3.5-14058.patch
 create mode 100644 src/patches/squid/squid-3.5-14059.patch
 create mode 100644 src/patches/squid/squid-3.5-14060.patch
 create mode 100644 src/patches/squid/squid-3.5-14061.patch

diff --git a/lfs/squid b/lfs/squid
index edaf943..c2b899e 100644
--- a/lfs/squid
+++ b/lfs/squid
@@ -76,6 +76,11 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
 	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14054.patch
 	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14055.patch
 	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14056.patch
+	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14057.patch
+	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14058.patch
+	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14059.patch
+	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14060.patch
+	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid/squid-3.5-14061.patch
 	cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/squid-3.5.17-fix-max-file-descriptors.patch
 
 	cd $(DIR_APP) && autoreconf -vfi
diff --git a/src/patches/squid/squid-3.5-14057.patch b/src/patches/squid/squid-3.5-14057.patch
new file mode 100644
index 0000000..fd4ddc3
--- /dev/null
+++ b/src/patches/squid/squid-3.5-14057.patch
@@ -0,0 +1,132 @@
+------------------------------------------------------------
+revno: 14057
+revision-id: squid3 at treenet.co.nz-20160524200503-1nn3hijw86ti726r
+parent: squid3 at treenet.co.nz-20160521172919-du6cbdirqcxdjbtr
+fixes bug: http://bugs.squid-cache.org/show_bug.cgi?id=4485
+author: Eduard Bagdasaryan <eduard.bagdasaryan at measurement-factory.com>
+committer: Amos Jeffries <squid3 at treenet.co.nz>
+branch nick: 3.5
+timestamp: Wed 2016-05-25 08:05:03 +1200
+message:
+  Bug 4485: off-by-one out-of-bounds Parser::Tokenizer::int64() read errors
+------------------------------------------------------------
+# Bazaar merge directive format 2 (Bazaar 0.90)
+# revision_id: squid3 at treenet.co.nz-20160524200503-1nn3hijw86ti726r
+# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# testament_sha1: a7a643f09c2d39665e013fc7a6bc87577f0890e0
+# timestamp: 2016-05-24 20:51:02 +0000
+# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# base_revision_id: squid3 at treenet.co.nz-20160521172919-\
+#   du6cbdirqcxdjbtr
+# 
+# Begin patch
+=== modified file 'src/parser/Tokenizer.cc'
+--- src/parser/Tokenizer.cc	2016-01-01 00:14:27 +0000
++++ src/parser/Tokenizer.cc	2016-05-24 20:05:03 +0000
+@@ -111,8 +111,9 @@
+     } else if (*s == '+') {
+         ++s;
+     }
++
+     if (s >= end) return false;
+-    if (( base == 0 || base == 16) && *s == '0' && (s+1 <= end ) &&
++    if (( base == 0 || base == 16) && *s == '0' && (s+1 < end ) &&
+             tolower(*(s+1)) == 'x') {
+         s += 2;
+         base = 16;
+@@ -135,7 +136,8 @@
+ 
+     int any = 0, c;
+     int64_t acc = 0;
+-    for (c = *s++; s <= end; c = *s++) {
++    do {
++        c = *s;
+         if (xisdigit(c)) {
+             c -= '0';
+         } else if (xisalpha(c)) {
+@@ -152,7 +154,7 @@
+             acc *= base;
+             acc += c;
+         }
+-    }
++    } while (++s < end);
+ 
+     if (any == 0) // nothing was parsed
+         return false;
+@@ -164,6 +166,6 @@
+         acc = -acc;
+ 
+     result = acc;
+-    return success(s - buf_.rawContent() - 1);
++    return success(s - buf_.rawContent());
+ }
+ 
+
+=== modified file 'src/tests/testTokenizer.cc'
+--- src/tests/testTokenizer.cc	2016-01-01 00:14:27 +0000
++++ src/tests/testTokenizer.cc	2016-05-24 20:05:03 +0000
+@@ -144,6 +144,7 @@
+         const int64_t benchmark = 1234;
+         CPPUNIT_ASSERT(t.int64(rv, 10));
+         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
++        CPPUNIT_ASSERT(t.buf().isEmpty());
+     }
+ 
+     // successful parse, autodetect base
+@@ -153,6 +154,7 @@
+         const int64_t benchmark = 1234;
+         CPPUNIT_ASSERT(t.int64(rv));
+         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
++        CPPUNIT_ASSERT(t.buf().isEmpty());
+     }
+ 
+     // successful parse, autodetect base
+@@ -162,6 +164,7 @@
+         const int64_t benchmark = 01234;
+         CPPUNIT_ASSERT(t.int64(rv));
+         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
++        CPPUNIT_ASSERT(t.buf().isEmpty());
+     }
+ 
+     // successful parse, autodetect base
+@@ -171,6 +174,7 @@
+         const int64_t benchmark = 0x12f4;
+         CPPUNIT_ASSERT(t.int64(rv));
+         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
++        CPPUNIT_ASSERT(t.buf().isEmpty());
+     }
+ 
+     // API mismatch: don't eat leading space
+@@ -178,6 +182,7 @@
+         int64_t rv;
+         Parser::Tokenizer t(SBuf(" 1234"));
+         CPPUNIT_ASSERT(!t.int64(rv));
++        CPPUNIT_ASSERT_EQUAL(SBuf(" 1234"), t.buf());
+     }
+ 
+     // API mismatch: don't eat multiple leading spaces
+@@ -185,6 +190,7 @@
+         int64_t rv;
+         Parser::Tokenizer t(SBuf("  1234"));
+         CPPUNIT_ASSERT(!t.int64(rv));
++        CPPUNIT_ASSERT_EQUAL(SBuf("  1234"), t.buf());
+     }
+ 
+     // trailing spaces
+@@ -222,6 +228,7 @@
+         int64_t rv;
+         Parser::Tokenizer t(SBuf("1029397752385698678762234"));
+         CPPUNIT_ASSERT(!t.int64(rv));
++        CPPUNIT_ASSERT_EQUAL(SBuf("1029397752385698678762234"), t.buf());
+     }
+ 
+     // buffered sub-string parsing
+@@ -233,6 +240,7 @@
+         CPPUNIT_ASSERT_EQUAL(SBuf("22"),t.buf());
+         CPPUNIT_ASSERT(t.int64(rv));
+         CPPUNIT_ASSERT_EQUAL(benchmark,rv);
++        CPPUNIT_ASSERT(t.buf().isEmpty());
+     }
+ 
+     // base-16, prefix
+
diff --git a/src/patches/squid/squid-3.5-14058.patch b/src/patches/squid/squid-3.5-14058.patch
new file mode 100644
index 0000000..451b964
--- /dev/null
+++ b/src/patches/squid/squid-3.5-14058.patch
@@ -0,0 +1,732 @@
+------------------------------------------------------------
+revno: 14058
+revision-id: squid3 at treenet.co.nz-20160615220816-yqh6bmry6ijvfwi1
+parent: squid3 at treenet.co.nz-20160524200503-1nn3hijw86ti726r
+author: Alex Rousskov <rousskov at measurement-factory.com>
+committer: Amos Jeffries <squid3 at treenet.co.nz>
+branch nick: 3.5
+timestamp: Thu 2016-06-16 10:08:16 +1200
+message:
+  Do not allow low-level debugging to hide important/critical messages.
+  
+  Removed debugs() side effects that inadvertently resulted in some
+  important/critical messages logged at the wrong debugging level and,
+  hence, becoming invisible to the admin. The removed side effects set the
+  "current" debugging level when a debugs() parameter called a function
+  that also called debugs(). The last nested debugs() called affected the
+  level of all debugs() still in progress!
+  
+  Related changes:
+  
+  * Reentrant debugging messages no longer clobber parent messages. Each
+    debugging message is logged separately, in the natural order of
+    debugs() calls that would have happened if debugs() were a function
+    (that gets already evaluated arguments) and not a macro (that
+    evaluates its arguments in the middle of the call). This order is
+    "natural" because good macros work like functions from the caller
+    point of view.
+  
+  * Assertions hit while evaluating debugs() parameters are now logged
+    instead of being lost with the being-built debugs() log line.
+  
+  * 10-20% faster debugs() performance because we no longer allocate a new
+    std::ostringstream buffer for the vast majority of debugs() calls.
+    Only reentrant calls get a new buffer.
+  
+  * Removed old_debug(), addressing an old "needs to die" to-do.
+  
+  * Removed do_debug() that changed debugging level while testing whether
+    debugging is needed. Use side-effect-free Debug::Enabled() instead.
+  
+  Also removed the OutStream wrapper class. The wrapper was added in trunk
+  revision 13767 that promised to (but did not?) MemPool the debug output
+  buffers. We no longer "new" the buffer stream so a custom new() method
+  would be unused. Besides, the r13767 explanation implied that providing
+  a Child::new() method would somehow overwrite Parent::allocator_type,
+  which did not compute for me. Finally, Squid "new"s other allocator-
+  enabled STL objects without overriding their new methods so either the
+  same problem is still there or it did not exist (or was different?).
+  
+  Also removed Debug::xassert() because the debugs() assertions now work
+  OK without that hack.
+------------------------------------------------------------
+# Bazaar merge directive format 2 (Bazaar 0.90)
+# revision_id: squid3 at treenet.co.nz-20160615220816-yqh6bmry6ijvfwi1
+# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# testament_sha1: 1d7a703d3dfe6ebd05138880652ab78c3260a323
+# timestamp: 2016-06-15 22:51:04 +0000
+# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# base_revision_id: squid3 at treenet.co.nz-20160524200503-\
+#   1nn3hijw86ti726r
+# 
+# Begin patch
+=== modified file 'src/Debug.h'
+--- src/Debug.h	2016-01-01 00:14:27 +0000
++++ src/Debug.h	2016-06-15 22:08:16 +0000
+@@ -49,38 +49,51 @@
+ {
+ 
+ public:
++    /// meta-information for debugs() or a similar debugging call
++    class Context
++    {
++    public:
++        Context(const int aSectionLevel, const int aLevel);
++
++        int level; ///< minimum debugging level required by the debugs() call
++        int sectionLevel; ///< maximum debugging level allowed during the call
++
++    private:
++        friend class Debug;
++        void rewind(const int aSection, const int aLevel);
++        void formatStream();
++        Context *upper; ///< previous or parent record in nested debugging calls
++        std::ostringstream buf; ///< debugs() output sink
++    };
++
++    /// whether debugging the given section and the given level produces output
++    static bool Enabled(const int section, const int level)
++    {
++        return level <= Debug::Levels[section];
++    }
++
+     static char *debugOptions;
+     static char *cache_log;
+     static int rotateNumber;
+     static int Levels[MAX_DEBUG_SECTIONS];
+-    static int level; ///< minimum debugging level required by debugs() call
+-    static int sectionLevel; ///< maximum debugging level allowed now
+     static int override_X;
+     static int log_stderr;
+     static bool log_syslog;
+ 
+-    static std::ostream &getDebugOut();
+-    static void finishDebug();
+     static void parseOptions(char const *);
+ 
++    /// minimum level required by the current debugs() call
++    static int Level() { return Current ? Current->level : 1; }
++    /// maximum level currently allowed
++    static int SectionLevel() { return Current ? Current->sectionLevel : 1; }
++
++    /// opens debugging context and returns output buffer
++    static std::ostringstream &Start(const int section, const int level);
++    /// logs output buffer created in Start() and closes debugging context
++    static void Finish();
++
+ private:
+-    // Hack: replaces global ::xassert() to debug debugging assertions
+-    static void xassert(const char *msg, const char *file, int line);
+-
+-    /// Wrapper class to prevent SquidNew.h overrides getting confused
+-    /// with the libc++6 std::ostringstream definitions
+-    class OutStream : public std::ostringstream
+-    {
+-        // XXX: use MEMPROXY_CLASS() once that no longer pulls in typedefs.h and enums.h and globals.h
+-    public:
+-        void *operator new(size_t size) throw(std::bad_alloc) {return xmalloc(size);}
+-        void operator delete(void *address) throw() {xfree(address);}
+-        void *operator new[] (size_t size) throw(std::bad_alloc) ; //{return xmalloc(size);}
+-        void operator delete[] (void *address) throw() ; // {xfree(address);}
+-    };
+-
+-    static OutStream *CurrentDebug;
+-    static int TheDepth; // level of nested debugging calls
++    static Context *Current; ///< deepest active context; nil outside debugs()
+ };
+ 
+ extern FILE *debug_log;
+@@ -91,15 +104,15 @@
+ /* Debug stream */
+ #define debugs(SECTION, LEVEL, CONTENT) \
+    do { \
+-        if ((Debug::level = (LEVEL)) <= Debug::Levels[SECTION]) { \
+-            Debug::sectionLevel = Debug::Levels[SECTION]; \
+-            std::ostream &_dbo=Debug::getDebugOut(); \
+-            if (Debug::level > DBG_IMPORTANT) { \
+-                _dbo << (SECTION) << ',' << (LEVEL) << "| " \
++        const int _dbg_level = (LEVEL); \
++        if (Debug::Enabled((SECTION), _dbg_level)) { \
++            std::ostream &_dbo = Debug::Start((SECTION), _dbg_level); \
++            if (_dbg_level > DBG_IMPORTANT) { \
++                _dbo << (SECTION) << ',' << _dbg_level << "| " \
+                      << SkipBuildPrefix(__FILE__)<<"("<<__LINE__<<") "<<__FUNCTION__<<": "; \
+             } \
+             _dbo << CONTENT; \
+-            Debug::finishDebug(); \
++            Debug::Finish(); \
+         } \
+    } while (/*CONSTCOND*/ 0)
+ 
+@@ -135,10 +148,6 @@
+     return (os << (int)d);
+ }
+ 
+-/* Legacy debug style. Still used in some places. needs to die... */
+-#define do_debug(SECTION, LEVEL)   ((Debug::level = (LEVEL)) <= Debug::Levels[SECTION])
+-#define old_debug(SECTION, LEVEL)  if do_debug((SECTION), (LEVEL)) _db_print
+-
+ /* Legacy debug function definitions */
+ void _db_init(const char *logfile, const char *options);
+ void _db_print(const char *,...) PRINTF_FORMAT_ARG1;
+
+=== modified file 'src/adaptation/ecap/Host.cc'
+--- src/adaptation/ecap/Host.cc	2016-02-23 15:58:54 +0000
++++ src/adaptation/ecap/Host.cc	2016-06-15 22:08:16 +0000
+@@ -147,18 +147,16 @@
+ {
+     const int squidLevel = SquidLogLevel(lv);
+     const int squidSection = 93; // XXX: this should be a global constant
+-    // XXX: Debug.h should provide this to us
+-    if ((Debug::level = squidLevel) <= Debug::Levels[squidSection])
+-        return &Debug::getDebugOut();
+-    else
+-        return NULL;
++    return Debug::Enabled(squidSection, squidLevel) ?
++        &Debug::Start(squidSection, squidLevel) :
++        NULL;
+ }
+ 
+ void
+ Adaptation::Ecap::Host::closeDebug(std::ostream *debug)
+ {
+     if (debug)
+-        Debug::finishDebug();
++        Debug::Finish();
+ }
+ 
+ Adaptation::Ecap::Host::MessagePtr
+
+=== modified file 'src/base/Lock.h'
+--- src/base/Lock.h	2016-01-01 00:14:27 +0000
++++ src/base/Lock.h	2016-06-15 22:08:16 +0000
+@@ -33,7 +33,7 @@
+     /// All locks must be cleared before it may be destroyed.
+     void lock() const {
+ #if defined(LOCKCOUNT_DEBUG)
+-        old_debug(0,1)("Incrementing this %p from count %u\n",this,count_);
++        debugs(0,1, "Incrementing this " << static_cast<void*>(this) << " from count " << count_);
+ #endif
+         assert(count_ < UINT32_MAX);
+         ++count_;
+@@ -43,7 +43,7 @@
+     /// All locks must be cleared before it may be destroyed.
+     uint32_t unlock() const {
+ #if defined(LOCKCOUNT_DEBUG)
+-        old_debug(0,1)("Decrementing this %p from count %u\n",this,count_);
++        debugs(0,1, "Decrementing this " << static_cast<void*>(this) << " from count " << count_);
+ #endif
+         assert(count_ > 0);
+         return --count_;
+
+=== modified file 'src/client_side.cc'
+--- src/client_side.cc	2016-05-02 10:51:18 +0000
++++ src/client_side.cc	2016-06-15 22:08:16 +0000
+@@ -3778,7 +3778,7 @@
+         debugs(83, 2, "clientNegotiateSSL: Session " << SSL_get_session(ssl) <<
+                " reused on FD " << fd << " (" << fd_table[fd].ipaddr << ":" << (int)fd_table[fd].remote_port << ")");
+     } else {
+-        if (do_debug(83, 4)) {
++        if (Debug::Enabled(83, 4)) {
+             /* Write out the SSL session details.. actually the call below, but
+              * OpenSSL headers do strange typecasts confusing GCC.. */
+             /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
+
+=== modified file 'src/debug.cc'
+--- src/debug.cc	2016-03-23 14:46:37 +0000
++++ src/debug.cc	2016-06-15 22:08:16 +0000
+@@ -22,8 +22,6 @@
+ int Debug::log_stderr = -1;
+ bool Debug::log_syslog = false;
+ int Debug::Levels[MAX_DEBUG_SECTIONS];
+-int Debug::level;
+-int Debug::sectionLevel;
+ char *Debug::cache_log = NULL;
+ int Debug::rotateNumber = -1;
+ FILE *debug_log = NULL;
+@@ -134,7 +132,7 @@
+ static void
+ _db_print_stderr(const char *format, va_list args)
+ {
+-    if (Debug::log_stderr < Debug::level)
++    if (Debug::log_stderr < Debug::Level())
+         return;
+ 
+     if (debug_log == stderr)
+@@ -149,7 +147,7 @@
+ {
+     /* level 0,1 go to syslog */
+ 
+-    if (Debug::level > 1)
++    if (Debug::Level() > 1)
+         return;
+ 
+     if (!Debug::log_syslog)
+@@ -162,7 +160,7 @@
+ 
+     tmpbuf[BUFSIZ - 1] = '\0';
+ 
+-    syslog(Debug::level == 0 ? LOG_WARNING : LOG_NOTICE, "%s", tmpbuf);
++    syslog(Debug::Level() == 0 ? LOG_WARNING : LOG_NOTICE, "%s", tmpbuf);
+ }
+ #endif /* HAVE_SYSLOG */
+ 
+@@ -512,7 +510,7 @@
+     static char buf[128];
+     static time_t last_t = 0;
+ 
+-    if (Debug::level > 1) {
++    if (Debug::Level() > 1) {
+         char buf2[128];
+         tm = localtime(&t);
+         strftime(buf2, 127, "%Y/%m/%d %H:%M:%S", tm);
+@@ -714,55 +712,75 @@
+     return Ctx_Descrs[ctx] ? Ctx_Descrs[ctx] : "<null>";
+ }
+ 
+-int Debug::TheDepth = 0;
+-
+-Debug::OutStream *Debug::CurrentDebug(NULL);
+-
+-std::ostream &
+-Debug::getDebugOut()
+-{
+-    assert(TheDepth >= 0);
+-    ++TheDepth;
+-    if (TheDepth > 1) {
+-        assert(CurrentDebug);
+-        *CurrentDebug << std::endl << "reentrant debuging " << TheDepth << "-{";
+-    } else {
+-        assert(!CurrentDebug);
+-        CurrentDebug = new Debug::OutStream;
+-        // set default formatting flags
+-        CurrentDebug->setf(std::ios::fixed);
+-        CurrentDebug->precision(2);
+-    }
+-    return *CurrentDebug;
+-}
+-
+-void
+-Debug::finishDebug()
+-{
+-    assert(TheDepth >= 0);
+-    assert(CurrentDebug);
+-    if (TheDepth > 1) {
+-        *CurrentDebug << "}-" << TheDepth << std::endl;
+-    } else {
+-        assert(TheDepth == 1);
+-        _db_print("%s\n", CurrentDebug->str().c_str());
+-        delete CurrentDebug;
+-        CurrentDebug = NULL;
+-    }
+-    --TheDepth;
+-}
+-
+-// Hack: replaces global ::xassert() to debug debugging assertions
+-// Relies on assert macro calling xassert() without a specific scope.
+-void
+-Debug::xassert(const char *msg, const char *file, int line)
+-{
+-
+-    if (CurrentDebug) {
+-        *CurrentDebug << "assertion failed: " << file << ":" << line <<
+-                      ": \"" << msg << "\"";
+-    }
+-    abort();
++Debug::Context *Debug::Current = NULL;
++
++Debug::Context::Context(const int aSection, const int aLevel):
++    level(aLevel),
++    sectionLevel(Levels[aSection]),
++    upper(Current)
++{
++    formatStream();
++}
++
++/// Optimization: avoids new Context creation for every debugs().
++void
++Debug::Context::rewind(const int aSection, const int aLevel)
++{
++    level = aLevel;
++    sectionLevel = Levels[aSection];
++    assert(upper == Current);
++    
++    buf.str(std::string());
++    buf.clear();
++    // debugs() users are supposed to preserve format, but
++    // some do not, so we have to waste cycles resetting it for all.
++    formatStream();
++}
++
++/// configures default formatting for the debugging stream
++void
++Debug::Context::formatStream()
++{
++    const static std::ostringstream cleanStream;
++    buf.flags(cleanStream.flags() | std::ios::fixed);
++    buf.width(cleanStream.width());
++    buf.precision(2);
++    buf.fill(' ');
++    // If this is not enough, use copyfmt(cleanStream) which is ~10% slower.
++}
++
++std::ostringstream &
++Debug::Start(const int section, const int level)
++{
++    Context *future = NULL;
++
++    // prepare future context
++    if (Current) {
++        // all reentrant debugs() calls get here; create a dedicated context
++        future = new Context(section, level);
++    } else {
++        // Optimization: Nearly all debugs() calls get here; avoid allocations
++        static Context *topContext = new Context(1, 1);
++        topContext->rewind(section, level);
++        future = topContext;
++    }
++
++    Current = future;
++
++    return future->buf;
++}
++
++void
++Debug::Finish()
++{
++    // TODO: Optimize to remove at least one extra copy.
++    _db_print("%s\n", Current->buf.str().c_str());
++
++    Context *past = Current;
++    Current = past->upper;
++    if (Current)
++        delete past;
++    // else it was a static topContext from Debug::Start()
+ }
+ 
+ size_t
+@@ -799,8 +817,8 @@
+ 
+     // finalize debugging level if no level was set explicitly via minLevel()
+     const int finalLevel = (level >= 0) ? level :
+-                           (size_ > 40 ? DBG_DATA : Debug::sectionLevel);
+-    if (finalLevel <= Debug::sectionLevel) {
++                           (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
++    if (finalLevel <= Debug::SectionLevel()) {
+         os << (label_ ? '=' : ' ');
+         if (data_)
+             os.write(data_, size_);
+
+=== modified file 'src/esi/Expression.cc'
+--- src/esi/Expression.cc	2016-01-01 00:14:27 +0000
++++ src/esi/Expression.cc	2016-06-15 22:08:16 +0000
+@@ -116,8 +116,6 @@
+ static int membercompare(stackmember a, stackmember b);
+ static char const *trim(char const *s);
+ static stackmember getsymbol(const char *s, char const **endptr);
+-static void printliteral(stackmember s);
+-static void printmember(stackmember s);
+ 
+ /* -2 = failed to compate
+  * -1 = a less than b
+@@ -846,105 +844,106 @@
+     return rv;
+ }
+ 
+-void
+-printliteral(stackmember s)
++static void
++printLiteral(std::ostream &os, const stackmember &s)
+ {
+     switch (s.valuestored) {
+ 
+     case ESI_LITERAL_INVALID:
+-        old_debug(86, 1)( " Invalid " );
++        os << " Invalid ";
+         break;
+ 
+     case ESI_LITERAL_FLOAT:
+-        old_debug(86,1)("%f", s.value.floating);
++        os << s.value.floating;
+         break;
+ 
+     case ESI_LITERAL_STRING:
+-        old_debug(86,1)("'%s'", s.value.string);
++        os << '\'' << s.value.string << '\'';
+         break;
+ 
+     case ESI_LITERAL_INT:
+-        old_debug(86,1)("%d", s.value.integral);
++        os << s.value.integral;
+         break;
+ 
+     case ESI_LITERAL_BOOL:
+-        old_debug(86,1)("%s",s.value.integral ? "true" : "false");
++        os << (s.value.integral ? "true" : "false");
+     }
+ }
+ 
+-void
+-printmember(stackmember s)
++static std::ostream &
++operator <<(std::ostream &os, const stackmember &s)
+ {
+     switch (s.valuetype) {
+ 
+     case ESI_EXPR_INVALID:
+-        old_debug(86,1)(" Invalid ");
++        os << " Invalid ";
+         break;
+ 
+     case ESI_EXPR_LITERAL:
+-        printliteral(s);
++        printLiteral(os, s);
+         break;
+ 
+     case ESI_EXPR_EXPR:
+-        old_debug(86,1)("%s", s.value.integral ? "true" : "false");
++        os << (s.value.integral ? "true" : "false");
+         break;
+ 
+     case ESI_EXPR_OR:
+-        old_debug(86,1)("|");
++        os << "|";
+         break;
+ 
+     case ESI_EXPR_AND:
+-        old_debug(86,1)("&");
++        os << "&";
+         break;
+ 
+     case ESI_EXPR_NOT:
+-        old_debug(86,1)("!");
++        os << "!";
+         break;
+ 
+     case ESI_EXPR_START:
+-        old_debug(86,1)("(");
++        os << "(";
+         break;
+ 
+     case ESI_EXPR_END:
+-        old_debug(86,1)(")");
++        os << ")";
+         break;
+ 
+     case ESI_EXPR_EQ:
+-        old_debug(86,1)("==");
++        os << "==";
+         break;
+ 
+     case ESI_EXPR_NOTEQ:
+-        old_debug(86,1)("!=");
++        os << "!=";
+         break;
+ 
+     case ESI_EXPR_LESS:
+-        old_debug(86,1)("<");
++        os << "<";
+         break;
+ 
+     case ESI_EXPR_LESSEQ:
+-        old_debug(86,1)("<=");
++        os << "<=";
+         break;
+ 
+     case ESI_EXPR_MORE:
+-        old_debug(86,1)(">");
++        os << ">";
+         break;
+ 
+     case ESI_EXPR_MOREEQ:
+-        old_debug(86,1)(">=");
++        os << ">=";
+         break;
+     }
++
++    return os;
+ }
+ 
+ void
+ dumpstack(stackmember * stack, int depth)
+ {
+-    int i;
+-
+-    for (i = 0; i < depth; ++i)
+-        printmember(stack[i]);
+-
+-    if (depth)
+-        old_debug(86,1)("\n");
++    if (depth) {
++        std::ostringstream buf;
++        for (int i = 0; i < depth; ++i)
++            buf << stack[i];
++        debugs(86,1, buf.str());
++    }
+ }
+ 
+ int
+
+=== modified file 'src/servers/FtpServer.cc'
+--- src/servers/FtpServer.cc	2016-03-23 15:43:55 +0000
++++ src/servers/FtpServer.cc	2016-06-15 22:08:16 +0000
+@@ -1303,7 +1303,7 @@
+     Must(header.has(HDR_FTP_ARGUMENTS));
+     String &params = header.findEntry(HDR_FTP_ARGUMENTS)->value;
+ 
+-    if (do_debug(9, 2)) {
++    if (Debug::Enabled(9, 2)) {
+         MemBuf mb;
+         Packer p;
+         mb.init();
+
+=== modified file 'src/ssl/support.cc'
+--- src/ssl/support.cc	2016-04-19 15:04:09 +0000
++++ src/ssl/support.cc	2016-06-15 22:08:16 +0000
+@@ -135,7 +135,7 @@
+     }
+ 
+     if (newkey) {
+-        if (do_debug(83, 5))
++        if (Debug::Enabled(83, 5))
+             PEM_write_RSAPrivateKey(debug_log, rsa, NULL, NULL, 0, NULL, NULL);
+ 
+         debugs(83, DBG_IMPORTANT, "Generated ephemeral RSA key of length " << keylen);
+
+=== modified file 'src/tests/stub_debug.cc'
+--- src/tests/stub_debug.cc	2016-01-01 00:14:27 +0000
++++ src/tests/stub_debug.cc	2016-06-15 22:08:16 +0000
+@@ -17,14 +17,11 @@
+ #include "Debug.h"
+ 
+ FILE *debug_log = NULL;
+-int Debug::TheDepth = 0;
+ 
+ char *Debug::debugOptions;
+ char *Debug::cache_log= NULL;
+ int Debug::rotateNumber = 0;
+ int Debug::Levels[MAX_DEBUG_SECTIONS];
+-int Debug::level;
+-int Debug::sectionLevel;
+ int Debug::override_X = 0;
+ int Debug::log_stderr = 1;
+ bool Debug::log_syslog = false;
+@@ -81,71 +78,52 @@
+ static void
+ _db_print_stderr(const char *format, va_list args)
+ {
+-    if (1 < Debug::level)
++    if (1 < Debug::Level())
+         return;
+ 
+     vfprintf(stderr, format, args);
+ }
+ 
+-Debug::OutStream *Debug::CurrentDebug(NULL);
+-
+-std::ostream &
+-Debug::getDebugOut()
+-{
+-    assert(TheDepth >= 0);
+-    ++TheDepth;
+-    if (TheDepth > 1) {
+-        assert(CurrentDebug);
+-        *CurrentDebug << std::endl << "reentrant debuging " << TheDepth << "-{";
+-    } else {
+-        assert(!CurrentDebug);
+-        CurrentDebug = new Debug::OutStream;
+-        // set default formatting flags
+-        CurrentDebug->setf(std::ios::fixed);
+-        CurrentDebug->precision(2);
+-    }
+-    return *CurrentDebug;
+-}
+-
+ void
+ Debug::parseOptions(char const *)
+ {
+     return;
+ }
+ 
+-void
+-Debug::finishDebug()
+-{
+-    assert(TheDepth >= 0);
+-    assert(CurrentDebug);
+-    if (TheDepth > 1) {
+-        *CurrentDebug << "}-" << TheDepth << std::endl;
+-    } else {
+-        assert(TheDepth == 1);
+-        _db_print("%s\n", CurrentDebug->str().c_str());
+-        delete CurrentDebug;
+-        CurrentDebug = NULL;
+-    }
+-    --TheDepth;
+-}
+-
+-void
+-Debug::xassert(const char *msg, const char *file, int line)
+-{
+-
+-    if (CurrentDebug) {
+-        *CurrentDebug << "assertion failed: " << file << ":" << line <<
+-                      ": \"" << msg << "\"";
+-    }
+-    abort();
+-}
+-
+ const char*
+ SkipBuildPrefix(const char* path)
+ {
+     return path;
+ }
+ 
++Debug::Context *Debug::Current = NULL;
++
++Debug::Context::Context(const int aSection, const int aLevel):
++    level(aLevel),
++    sectionLevel(Levels[aSection]),
++    upper(Current)
++{
++    buf.setf(std::ios::fixed);
++    buf.precision(2);
++}
++
++std::ostringstream &
++Debug::Start(const int section, const int level)
++{
++    Current = new Context(section, level);
++    return Current->buf;
++}
++
++void
++Debug::Finish()
++{
++    if (Current) {
++        _db_print("%s\n", Current->buf.str().c_str());
++        delete Current;
++        Current = NULL;
++    }
++}
++
+ std::ostream &
+ Raw::print(std::ostream &os) const
+ {
+@@ -157,10 +135,13 @@
+ 
+     // finalize debugging level if no level was set explicitly via minLevel()
+     const int finalLevel = (level >= 0) ? level :
+-                           (size_ > 40 ? DBG_DATA : Debug::sectionLevel);
+-    if (finalLevel <= Debug::sectionLevel) {
++                           (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
++    if (finalLevel <= Debug::SectionLevel()) {
+         os << (label_ ? '=' : ' ');
+-        os.write(data_, size_);
++        if (data_)
++            os.write(data_, size_);
++        else
++            os << "[null]";
+     }
+ 
+     return os;
+
diff --git a/src/patches/squid/squid-3.5-14059.patch b/src/patches/squid/squid-3.5-14059.patch
new file mode 100644
index 0000000..5fbd503
--- /dev/null
+++ b/src/patches/squid/squid-3.5-14059.patch
@@ -0,0 +1,49 @@
+------------------------------------------------------------
+revno: 14059
+revision-id: squidadm at squid-cache.org-20160616001416-jb7a6qq30tm5gpoc
+parent: squid3 at treenet.co.nz-20160615220816-yqh6bmry6ijvfwi1
+committer: Source Maintenance <squidadm at squid-cache.org>
+branch nick: 3.5
+timestamp: Thu 2016-06-16 00:14:16 +0000
+message:
+  SourceFormat Enforcement
+------------------------------------------------------------
+# Bazaar merge directive format 2 (Bazaar 0.90)
+# revision_id: squidadm at squid-cache.org-20160616001416-\
+#   jb7a6qq30tm5gpoc
+# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# testament_sha1: 222d2b2638e1aae18afd737bbdf56623ee8ecab3
+# timestamp: 2016-06-16 00:51:03 +0000
+# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# base_revision_id: squid3 at treenet.co.nz-20160615220816-\
+#   yqh6bmry6ijvfwi1
+# 
+# Begin patch
+=== modified file 'src/adaptation/ecap/Host.cc'
+--- src/adaptation/ecap/Host.cc	2016-06-15 22:08:16 +0000
++++ src/adaptation/ecap/Host.cc	2016-06-16 00:14:16 +0000
+@@ -148,8 +148,8 @@
+     const int squidLevel = SquidLogLevel(lv);
+     const int squidSection = 93; // XXX: this should be a global constant
+     return Debug::Enabled(squidSection, squidLevel) ?
+-        &Debug::Start(squidSection, squidLevel) :
+-        NULL;
++           &Debug::Start(squidSection, squidLevel) :
++           NULL;
+ }
+ 
+ void
+
+=== modified file 'src/debug.cc'
+--- src/debug.cc	2016-06-15 22:08:16 +0000
++++ src/debug.cc	2016-06-16 00:14:16 +0000
+@@ -729,7 +729,7 @@
+     level = aLevel;
+     sectionLevel = Levels[aSection];
+     assert(upper == Current);
+-    
++
+     buf.str(std::string());
+     buf.clear();
+     // debugs() users are supposed to preserve format, but
+
diff --git a/src/patches/squid/squid-3.5-14060.patch b/src/patches/squid/squid-3.5-14060.patch
new file mode 100644
index 0000000..02e8675
--- /dev/null
+++ b/src/patches/squid/squid-3.5-14060.patch
@@ -0,0 +1,117 @@
+------------------------------------------------------------
+revno: 14060
+revision-id: squid3 at treenet.co.nz-20160618114803-m7riuy90mrdlxw1f
+parent: squidadm at squid-cache.org-20160616001416-jb7a6qq30tm5gpoc
+fixes bug: http://bugs.squid-cache.org/show_bug.cgi?id=3579
+committer: Amos Jeffries <squid3 at treenet.co.nz>
+branch nick: 3.5
+timestamp: Sat 2016-06-18 23:48:03 +1200
+message:
+  Bug 3579: assertion failed 'MemPools[type]' from dst_as ACL
+------------------------------------------------------------
+# Bazaar merge directive format 2 (Bazaar 0.90)
+# revision_id: squid3 at treenet.co.nz-20160618114803-m7riuy90mrdlxw1f
+# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# testament_sha1: cc798e8d0b4767544c21f3614ce995d435bca867
+# timestamp: 2016-06-18 11:50:56 +0000
+# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# base_revision_id: squidadm at squid-cache.org-20160616001416-\
+#   jb7a6qq30tm5gpoc
+# 
+# Begin patch
+=== modified file 'src/PeerSelectState.h'
+--- src/PeerSelectState.h	2016-01-01 00:14:27 +0000
++++ src/PeerSelectState.h	2016-06-18 11:48:03 +0000
+@@ -38,11 +38,17 @@
+ class FwdServer
+ {
+ public:
++    MEMPROXY_CLASS(FwdServer);
++    FwdServer(CachePeer *p, hier_code c) : _peer(cbdataReference(p)), code(c), next(NULL) {}
++    ~FwdServer() {cbdataReferenceDone(_peer);}
++
+     CachePeer *_peer;                /* NULL --> origin server */
+     hier_code code;
+     FwdServer *next;
+ };
+ 
++MEMPROXY_CLASS_INLINE(FwdServer);
++
+ class ps_state
+ {
+ 
+
+=== modified file 'src/enums.h'
+--- src/enums.h	2016-01-01 00:14:27 +0000
++++ src/enums.h	2016-06-18 11:48:03 +0000
+@@ -170,7 +170,6 @@
+     MEM_DONTFREE,
+     // following pools are initialized late by their component if needed (or never)
+     MEM_FQDNCACHE_ENTRY,
+-    MEM_FWD_SERVER,
+     MEM_IDNS_QUERY,
+     MEM_IPCACHE_ENTRY,
+     MEM_MAX
+
+=== modified file 'src/peer_select.cc'
+--- src/peer_select.cc	2016-01-01 00:14:27 +0000
++++ src/peer_select.cc	2016-06-18 11:48:03 +0000
+@@ -71,7 +71,7 @@
+     while (servers) {
+         FwdServer *next = servers->next;
+         cbdataReferenceDone(servers->_peer);
+-        memFree(servers, MEM_FWD_SERVER);
++        delete servers;
+         servers = next;
+     }
+ 
+@@ -246,7 +246,7 @@
+         // clear the used fs and continue
+         psstate->servers = fs->next;
+         cbdataReferenceDone(fs->_peer);
+-        memFree(fs, MEM_FWD_SERVER);
++        delete fs;
+         peerSelectDnsPaths(psstate);
+         return;
+     }
+@@ -268,7 +268,7 @@
+         while (fs) {
+             psstate->servers = fs->next;
+             cbdataReferenceDone(fs->_peer);
+-            memFree(fs, MEM_FWD_SERVER);
++            delete fs;
+             fs = psstate->servers;
+         }
+     }
+@@ -377,7 +377,7 @@
+ 
+     psstate->servers = fs->next;
+     cbdataReferenceDone(fs->_peer);
+-    memFree(fs, MEM_FWD_SERVER);
++    delete fs;
+ 
+     // see if more paths can be found
+     peerSelectDnsPaths(psstate);
+@@ -772,7 +772,6 @@
+ peerSelectInit(void)
+ {
+     memset(&PeerStats, '\0', sizeof(PeerStats));
+-    memDataInit(MEM_FWD_SERVER, "FwdServer", sizeof(FwdServer), 0);
+ }
+ 
+ static void
+@@ -934,12 +933,10 @@
+ static void
+ peerAddFwdServer(FwdServer ** FSVR, CachePeer * p, hier_code code)
+ {
+-    FwdServer *fs = (FwdServer *)memAllocate(MEM_FWD_SERVER);
+     debugs(44, 5, "peerAddFwdServer: adding " <<
+            (p ? p->host : "DIRECT")  << " " <<
+            hier_code_str[code]  );
+-    fs->_peer = cbdataReference(p);
+-    fs->code = code;
++    FwdServer *fs = new FwdServer(p, code);
+ 
+     while (*FSVR)
+         FSVR = &(*FSVR)->next;
+
diff --git a/src/patches/squid/squid-3.5-14061.patch b/src/patches/squid/squid-3.5-14061.patch
new file mode 100644
index 0000000..0985db5
--- /dev/null
+++ b/src/patches/squid/squid-3.5-14061.patch
@@ -0,0 +1,237 @@
+------------------------------------------------------------
+revno: 14061
+revision-id: squid3 at treenet.co.nz-20160618133607-yt9vr8gjdrctcqd1
+parent: squid3 at treenet.co.nz-20160618114803-m7riuy90mrdlxw1f
+author: Alex Rousskov <rousskov at measurement-factory.com>
+committer: Amos Jeffries <squid3 at treenet.co.nz>
+branch nick: 3.5
+timestamp: Sun 2016-06-19 01:36:07 +1200
+message:
+  Fixed ConnStateData::In::maybeMakeSpaceAvailable() logic.
+  
+  This change fixes logic bugs that mostly affect performance: In micro-
+  tests, this change gives 10% performance improvement.
+  
+  maybeMakeSpaceAvailable() is called with an essentially random in.buf.
+  The method must prepare in.buf for the next network read. The old code
+  was not doing that [well enough], leading to performance problems.
+  
+  In some environments, in.buf often ends up having tiny space exceeding 2
+  bytes (e.g., 6 bytes). This happens, for example, when Squid creates and
+  parses a fake CONNECT request. The old code often left such tiny in.bufs
+  "as is" because we tried to ensure that we have at least 2 bytes to read
+  instead of trying to provide a reasonable number of buffer space for the
+  next network read. Tiny buffers naturally result in tiny network reads,
+  which are very inefficient, especially for non-incremental parsers.
+  
+  I have removed the explicit "2 byte" space checks: Both the new and the
+  old code do not _guarantee_ that at least 2 bytes of buffer space are
+  always available, and the caller does not check that condition either.
+  If some other code relies on it, more fixes will be needed (but this
+  change is not breaking that guarantee -- either it was broken earlier or
+  was never fully enforced). In practice, only buffers approaching
+  Config.maxRequestBufferSize limit may violate this guarantee AFAICT, and
+  those buffers ought to be rare, so the bug, if any, remains unnoticed.
+  
+  Another subtle maybeMakeSpaceAvailable() problem was that the code
+  contained its own buffer capacity increase algorithm (n^2 growth).
+  However, increasing buffer capacity exponentially does not make much
+  sense because network read sizes are not going to increase
+  exponentially. Also, memAllocStringmemAllocate() overwrites n^2 growth
+  with its own logic. Besides, it is buffer _space_, not the total
+  capacity that should be increased. More work is needed to better match
+  Squid buffer size for from-user network reads with the TCP stack buffers
+  and traffic patterns.
+  
+  Both the old and the new code reallocate in.buf MemBlobs. However, the
+  new code leaves "reallocate or memmove" decision to the new
+  SBuf::reserve(), opening the possibility for future memmove
+  optimizations that SBuf/MemBlob do not currently support.
+  
+  It is probably wrong that in.buf points to an essentially random MemBlob
+  outside ConnStateData control but this change does not attempt to fix that.
+------------------------------------------------------------
+# Bazaar merge directive format 2 (Bazaar 0.90)
+# revision_id: squid3 at treenet.co.nz-20160618133607-yt9vr8gjdrctcqd1
+# target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# testament_sha1: 86f65c860a5470008ab241b44a72d4cd35418e73
+# timestamp: 2016-06-18 13:50:58 +0000
+# source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
+# base_revision_id: squid3 at treenet.co.nz-20160618114803-\
+#   m7riuy90mrdlxw1f
+# 
+# Begin patch
+=== modified file 'src/SBuf.cc'
+--- src/SBuf.cc	2016-01-01 00:14:27 +0000
++++ src/SBuf.cc	2016-06-18 13:36:07 +0000
+@@ -162,6 +162,29 @@
+     cow(minCapacity);
+ }
+ 
++SBuf::size_type
++SBuf::reserve(const SBufReservationRequirements &req)
++{
++    debugs(24, 8, id << " was: " << off_ << '+' << len_ << '+' << spaceSize() <<
++           '=' << store_->capacity);
++
++    const bool mustRealloc = !req.allowShared && store_->LockCount() > 1;
++
++    if (!mustRealloc && spaceSize() >= req.minSpace)
++        return spaceSize(); // the caller is content with what we have
++
++    /* only reallocation can make the caller happy */
++
++    if (!mustRealloc && len_ >= req.maxCapacity)
++        return spaceSize(); // but we cannot reallocate
++
++    const size_type newSpace = std::min(req.idealSpace, maxSize - len_);
++    reserveCapacity(std::min(len_ + newSpace, req.maxCapacity));
++    debugs(24, 7, id << " now: " << off_ << '+' << len_ << '+' << spaceSize() <<
++           '=' << store_->capacity);
++    return spaceSize(); // reallocated and probably reserved enough space
++}
++
+ char *
+ SBuf::rawSpace(size_type minSpace)
+ {
+
+=== modified file 'src/SBuf.h'
+--- src/SBuf.h	2016-01-01 00:14:27 +0000
++++ src/SBuf.h	2016-06-18 13:36:07 +0000
+@@ -75,6 +75,7 @@
+ };
+ 
+ class CharacterSet;
++class SBufReservationRequirements;
+ 
+ /**
+  * A String or Buffer.
+@@ -424,6 +425,12 @@
+      */
+     void reserveCapacity(size_type minCapacity);
+ 
++    /** Accommodate caller's requirements regarding SBuf's storage if possible.
++     *
++     * \return spaceSize(), which may be zero
++     */
++    size_type reserve(const SBufReservationRequirements &requirements);
++
+     /** slicing method
+      *
+      * Removes SBuf prefix and suffix, leaving a sequence of 'n'
+@@ -617,6 +624,24 @@
+     SBuf& lowAppend(const char * memArea, size_type areaSize);
+ };
+ 
++/// Named SBuf::reserve() parameters. Defaults ask for and restrict nothing.
++class SBufReservationRequirements
++{
++public:
++    typedef SBuf::size_type size_type;
++
++    SBufReservationRequirements() : idealSpace(0), minSpace(0), maxCapacity(SBuf::maxSize), allowShared(true) {}
++
++    /*
++     * Parameters are listed in the reverse order of importance: Satisfaction of
++     * the lower-listed requirements may violate the higher-listed requirements.
++     */
++    size_type idealSpace; ///< if allocating anyway, provide this much space
++    size_type minSpace; ///< allocate if spaceSize() is smaller
++    size_type maxCapacity; ///< do not allocate more than this
++    bool allowShared; ///< whether sharing our storage with others is OK
++};
++
+ /// ostream output operator
+ inline std::ostream &
+ operator <<(std::ostream& os, const SBuf& S)
+
+=== modified file 'src/client_side.cc'
+--- src/client_side.cc	2016-06-15 22:08:16 +0000
++++ src/client_side.cc	2016-06-18 13:36:07 +0000
+@@ -2351,26 +2351,24 @@
+     return result;
+ }
+ 
+-bool
++/// Prepare inBuf for I/O. This method balances several conflicting desires:
++/// 1. Do not read too few bytes at a time.
++/// 2. Do not waste too much buffer space.
++/// 3. Do not [re]allocate or memmove the buffer too much.
++/// 4. Obey Config.maxRequestBufferSize limit.
++void
+ ConnStateData::In::maybeMakeSpaceAvailable()
+ {
+-    if (buf.spaceSize() < 2) {
+-        const SBuf::size_type haveCapacity = buf.length() + buf.spaceSize();
+-        if (haveCapacity >= Config.maxRequestBufferSize) {
+-            debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
+-            return false;
+-        }
+-        if (haveCapacity == 0) {
+-            // haveCapacity is based on the SBuf visible window of the MemBlob buffer, which may fill up.
+-            // at which point bump the buffer back to default. This allocates a new MemBlob with any un-parsed bytes.
+-            buf.reserveCapacity(CLIENT_REQ_BUF_SZ);
+-        } else {
+-            const SBuf::size_type wantCapacity = min(static_cast<SBuf::size_type>(Config.maxRequestBufferSize), haveCapacity*2);
+-            buf.reserveCapacity(wantCapacity);
+-        }
+-        debugs(33, 2, "growing request buffer: available=" << buf.spaceSize() << " used=" << buf.length());
+-    }
+-    return (buf.spaceSize() >= 2);
++    // The hard-coded parameters are arbitrary but seem reasonable.
++    // A careful study of Squid I/O and parsing patterns is needed to tune them.
++    SBufReservationRequirements requirements;
++    requirements.minSpace = 1024; // smaller I/Os are not worth their overhead
++    requirements.idealSpace = CLIENT_REQ_BUF_SZ; // we expect few larger I/Os
++    requirements.maxCapacity = Config.maxRequestBufferSize;
++    requirements.allowShared = true; // allow because inBuf is used immediately
++    buf.reserve(requirements);
++    if (!buf.spaceSize())
++        debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
+ }
+ 
+ void
+
+=== modified file 'src/client_side.h'
+--- src/client_side.h	2016-01-01 00:14:27 +0000
++++ src/client_side.h	2016-06-18 13:36:07 +0000
+@@ -195,10 +195,11 @@
+     // Client TCP connection details from comm layer.
+     Comm::ConnectionPointer clientConnection;
+ 
+-    struct In {
++    class In {
++    public:
+         In();
+         ~In();
+-        bool maybeMakeSpaceAvailable();
++        void maybeMakeSpaceAvailable();
+ 
+         ChunkedCodingParser *bodyParser; ///< parses chunked request body
+         SBuf buf;
+
+=== modified file 'src/tests/stub_SBuf.cc'
+--- src/tests/stub_SBuf.cc	2016-01-01 00:14:27 +0000
++++ src/tests/stub_SBuf.cc	2016-06-18 13:36:07 +0000
+@@ -53,6 +53,7 @@
+ void SBuf::forceSize(size_type newSize) STUB
+ const char* SBuf::c_str() STUB_RETVAL("")
+ void SBuf::reserveCapacity(size_type minCapacity) STUB
++SBuf::size_type SBuf::reserve(const SBufReservationRequirements &) STUB_RETVAL(0)
+ SBuf& SBuf::chop(size_type pos, size_type n) STUB_RETVAL(*this)
+ SBuf& SBuf::trim(const SBuf &toRemove, bool atBeginning, bool atEnd) STUB_RETVAL(*this)
+ SBuf SBuf::substr(size_type pos, size_type n) const STUB_RETVAL(*this)
+
+=== modified file 'src/tests/stub_client_side.cc'
+--- src/tests/stub_client_side.cc	2016-01-01 00:14:27 +0000
++++ src/tests/stub_client_side.cc	2016-06-18 13:36:07 +0000
+@@ -80,7 +80,7 @@
+ bool ConnStateData::serveDelayedError(ClientSocketContext *context) STUB_RETVAL(false)
+ #endif
+ 
+-bool ConnStateData::In::maybeMakeSpaceAvailable() STUB_RETVAL(false)
++void ConnStateData::In::maybeMakeSpaceAvailable() STUB
+ 
+ void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl) STUB
+ const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end) STUB_RETVAL(NULL)
+
-- 
2.9.0



More information about the Development mailing list