File SQUID_2016_2_port.patch of Package squid.1316
Index: squid-3.3.13/src/http.cc
===================================================================
--- squid-3.3.13.orig/src/http.cc
+++ squid-3.3.13/src/http.cc
@@ -173,6 +173,7 @@ void
HttpStateData::httpStateConnClosed(const CommCloseCbParams ¶ms)
{
debugs(11, 5, "httpStateFree: FD " << params.fd << ", httpState=" << params.data);
+ doneWithFwd = "httpStateConnClosed()"; // assume FwdState is monitoring too
mustStop("HttpStateData::httpStateConnClosed");
}
@@ -744,8 +745,7 @@ HttpStateData::processReplyHeader()
flags.headers_parsed = true;
newrep->sline.version = HttpVersion(1,1);
newrep->sline.status = error;
- HttpReply *vrep = setVirginReply(newrep);
- entry->replaceHttpReply(vrep);
+ setVirginReply(newrep);
ctx_exit(ctx);
return;
}
@@ -1769,7 +1769,8 @@ HttpStateData::httpBuildRequestHeader(Ht
String strFwd = hdr_in->getList(HDR_X_FORWARDED_FOR);
- if (strFwd.size() > 65536/2) {
+ // if we cannot double strFwd size, then it grew past 50% of the limit
+ if (!strFwd.canGrowBy(strFwd.size())) {
// There is probably a forwarding loop with Via detection disabled.
// If we do nothing, String will assert on overflow soon.
// TODO: Terminate all transactions with huge XFF?
@@ -2414,20 +2415,10 @@ HttpStateData::sentRequestBody(const Com
ServerStateData::sentRequestBody(io);
}
-// Quickly abort the transaction
-// TODO: destruction should be sufficient as the destructor should cleanup,
-// including canceling close handlers
void
HttpStateData::abortTransaction(const char *reason)
{
debugs(11,5, HERE << "aborting transaction for " << reason <<
"; " << serverConnection << ", this " << this);
-
- if (Comm::IsConnOpen(serverConnection)) {
- serverConnection->close();
- return;
- }
-
- fwd->handleUnregisteredServerEnd();
- mustStop("HttpStateData::abortTransaction");
+ mustStop(reason);
}
Index: squid-3.3.13/src/SquidString.h
===================================================================
--- squid-3.3.13.orig/src/SquidString.h
+++ squid-3.3.13/src/SquidString.h
@@ -146,6 +146,13 @@ public:
_SQUID_INLINE_ int caseCmp(char const *, size_type count) const;
_SQUID_INLINE_ int caseCmp(String const &) const;
+ /// Whether creating a totalLen-character string is safe (i.e., unlikely to assert).
+ /// Optional extras can be used for overflow-safe length addition.
+ /// Implementation has to add 1 because many String allocation methods do.
+ static bool CanGrowTo(size_type totalLen, const size_type extras = 0) { return SafeAdd(totalLen, extras) && SafeAdd(totalLen, 1); }
+ /// whether appending growthLen characters is safe (i.e., unlikely to assert)
+ bool canGrowBy(const size_type growthLen) const { return CanGrowTo(size(), growthLen); }
+
String substr(size_type from, size_type to) const;
_SQUID_INLINE_ void cut(size_type newLength);
@@ -162,10 +169,20 @@ private:
_SQUID_INLINE_ bool nilCmp(bool, bool, int &) const;
/* never reference these directly! */
- size_type size_; /* buffer size; 64K limit */
+ size_type size_; /* buffer size; limited by SizeMax_ */
size_type len_; /* current length */
+ static const size_type SizeMax_ = 65535; ///< 64K limit protects some fixed-size buffers
+ /// returns true after increasing the first argument by extra if the sum does not exceed SizeMax_
+ static bool SafeAdd(size_type &base, size_type extra) {
+ if (extra <= SizeMax_ && base <= SizeMax_ - extra) {
+ base += extra;
+ return true;
+ }
+ return false;
+ }
+
char *buf_;
_SQUID_INLINE_ void set(char const *loc, char const ch);
Index: squid-3.3.13/src/StrList.cc
===================================================================
--- squid-3.3.13.orig/src/StrList.cc
+++ squid-3.3.13/src/StrList.cc
@@ -33,20 +33,24 @@
#include "squid.h"
#include "SquidString.h"
#include "StrList.h"
+#include "base/TextException.h"
/** appends an item to the list */
void
strListAdd(String * str, const char *item, char del)
{
assert(str && item);
+ const String::size_type itemSize = strlen(item);
if (str->size()) {
char buf[3];
buf[0] = del;
buf[1] = ' ';
buf[2] = '\0';
+ Must(str->canGrowBy(2));
str->append(buf, 2);
}
- str->append(item, strlen(item));
+ Must(str->canGrowBy(itemSize));
+ str->append(item, itemSize);
}
/** returns true iff "m" is a member of the list */
Index: squid-3.3.13/src/String.cc
===================================================================
--- squid-3.3.13.orig/src/String.cc
+++ squid-3.3.13/src/String.cc
@@ -67,7 +67,7 @@ void
String::setBuffer(char *aBuf, String::size_type aSize)
{
assert(undefined());
- assert(aSize < 65536);
+ assert(aSize < SizeMax_);
buf_ = aBuf;
size_ = aSize;
}
@@ -198,7 +198,7 @@ String::append( char const *str, int len
} else {
// Create a temporary string and absorb it later.
String snew;
- assert(len_ + len < 65536); // otherwise snew.len_ overflows below
+ assert(canGrowBy(len)); // otherwise snew.len_ overflows below
snew.len_ = len_ + len;
snew.allocBuffer(snew.len_ + 1);
Index: squid-3.3.13/src/Server.cc
===================================================================
--- squid-3.3.13.orig/src/Server.cc
+++ squid-3.3.13/src/Server.cc
@@ -68,6 +68,7 @@ ServerStateData::ServerStateData(FwdStat
startedAdaptation(false),
#endif
receivedWholeRequestBody(false),
+ doneWithFwd(NULL),
theVirginReply(NULL),
theFinalReply(NULL)
{
@@ -94,8 +95,6 @@ ServerStateData::~ServerStateData()
HTTPMSGUNLOCK(theVirginReply);
HTTPMSGUNLOCK(theFinalReply);
- fwd = NULL; // refcounted
-
if (responseBodyBuffer != NULL) {
delete responseBodyBuffer;
responseBodyBuffer = NULL;
@@ -113,6 +112,14 @@ ServerStateData::swanSong()
cleanAdaptation();
#endif
+ if (!doneWithServer())
+ closeServer();
+
+ if (!doneWithFwd) {
+ doneWithFwd = "swanSong()";
+ fwd->handleUnregisteredServerEnd();
+ }
+
BodyConsumer::swanSong();
#if USE_ADAPTATION
Initiator::swanSong();
@@ -235,6 +242,7 @@ ServerStateData::completeForwarding()
{
debugs(11,5, HERE << "completing forwarding for " << fwd);
assert(fwd != NULL);
+ doneWithFwd = "completeForwarding()";
fwd->complete();
}
Index: squid-3.3.13/src/Server.h
===================================================================
--- squid-3.3.13.orig/src/Server.h
+++ squid-3.3.13/src/Server.h
@@ -192,6 +192,10 @@ protected:
#endif
bool receivedWholeRequestBody; ///< handleRequestBodyProductionEnded called
+ /// whether we should not be talking to FwdState; XXX: clear fwd instead
+ /// points to a string literal which is used only for debugging
+ const char *doneWithFwd;
+
private:
void sendBodyIsTooLargeError();
void maybePurgeOthers();
Index: squid-3.3.13/src/ftp.cc
===================================================================
--- squid-3.3.13.orig/src/ftp.cc
+++ squid-3.3.13/src/ftp.cc
@@ -466,6 +466,7 @@ FtpStateData::ctrlClosed(const CommClose
{
debugs(9, 4, HERE);
ctrl.clear();
+ doneWithFwd = "ctrlClosed()"; // assume FwdState is monitoring too
mustStop("FtpStateData::ctrlClosed");
}
@@ -3884,24 +3885,12 @@ FtpStateData::haveControlChannel(const c
return true;
}
-/**
- * Quickly abort the transaction
- *
- \todo destruction should be sufficient as the destructor should cleanup,
- * including canceling close handlers
- */
void
FtpStateData::abortTransaction(const char *reason)
{
debugs(9, 3, HERE << "aborting transaction for " << reason <<
"; FD " << (ctrl.conn!=NULL?ctrl.conn->fd:-1) << ", Data FD " << (data.conn!=NULL?data.conn->fd:-1) << ", this " << this);
- if (Comm::IsConnOpen(ctrl.conn)) {
- ctrl.conn->close();
- return;
- }
-
- fwd->handleUnregisteredServerEnd();
- mustStop("FtpStateData::abortTransaction");
+ mustStop(reason);
}
/// creates a data channel Comm close callback
Index: squid-3.3.13/src/esi/CustomParser.cc
===================================================================
--- squid-3.3.13.orig/src/esi/CustomParser.cc
+++ squid-3.3.13/src/esi/CustomParser.cc
@@ -110,9 +110,11 @@ ESICustomParser::parse(char const *dataT
}
size_t openESITags (0);
- //erring on the safe side. Probably rawBuf would be ok too
- char const *currentPos = content.termedBuf();
- size_t remainingCount = content.size();
+ // TODO: convert to Tokenizer parse
+ // erring on the safe side for now. Probably rawContent would be ok too
+ // note that operations below do *X='\0' ... altering the 'const' buffer content.
+ char const *currentPos = content.c_str();
+ SBuf::size_type remainingCount = content.length();
char const *tag = NULL;
while ((tag = findTag(currentPos, remainingCount))) {
Index: squid-3.3.13/src/esi/CustomParser.h
===================================================================
--- squid-3.3.13.orig/src/esi/CustomParser.h
+++ squid-3.3.13/src/esi/CustomParser.h
@@ -35,7 +35,7 @@ class Trie;
/* inherits from */
#include "esi/Parser.h"
-/* for String variables */
+#include "SBuf.h"
#include "SquidString.h"
/**
@@ -67,7 +67,7 @@ private:
ESIParserClient *theClient;
String error;
/* cheap n dirty - buffer it all */
- String content;
+ SBuf content;
/* TODO: make a class of this type code */
ESITAG_t lastTag;
};
Index: squid-3.3.13/src/SBuf.cc
===================================================================
--- /dev/null
+++ squid-3.3.13/src/SBuf.cc
@@ -0,0 +1,966 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/CharacterSet.h"
+#include "RefCount.h"
+#include "Debug.h"
+#include "OutOfBoundsException.h"
+#include "SBuf.h"
+#include "SBufDetailedStats.h"
+#include "SBufExceptions.h"
+#include "util.h"
+
+#include <cstring>
+#include <iostream>
+#include <sstream>
+
+#ifdef VA_COPY
+#undef VA_COPY
+#endif
+#if defined HAVE_VA_COPY
+#define VA_COPY va_copy
+#elif defined HAVE___VA_COPY
+#define VA_COPY __va_copy
+#endif
+
+InstanceIdDefinitions(SBuf, "SBuf");
+
+SBufStats SBuf::stats;
+const SBuf::size_type SBuf::npos;
+const SBuf::size_type SBuf::maxSize;
+
+SBufStats::SBufStats()
+ : alloc(0), allocCopy(0), allocFromString(0), allocFromCString(0),
+ assignFast(0), clear(0), append(0), toStream(0), setChar(0),
+ getChar(0), compareSlow(0), compareFast(0), copyOut(0),
+ rawAccess(0), nulTerminate(0), chop(0), trim(0), find(0), scanf(0),
+ caseChange(0), cowFast(0), cowSlow(0), live(0)
+{}
+
+SBufStats&
+SBufStats::operator +=(const SBufStats& ss)
+{
+ alloc += ss.alloc;
+ allocCopy += ss.allocCopy;
+ allocFromString += ss.allocFromString;
+ allocFromCString += ss.allocFromCString;
+ assignFast += ss.assignFast;
+ clear += ss.clear;
+ append += ss.append;
+ toStream += ss.toStream;
+ setChar += ss.setChar;
+ getChar += ss.getChar;
+ compareSlow += ss.compareSlow;
+ compareFast += ss.compareFast;
+ copyOut += ss.copyOut;
+ rawAccess += ss.rawAccess;
+ nulTerminate += ss.nulTerminate;
+ chop += ss.chop;
+ trim += ss.trim;
+ find += ss.find;
+ scanf += ss.scanf;
+ caseChange += ss.caseChange;
+ cowFast += ss.cowFast;
+ cowSlow += ss.cowSlow;
+ live += ss.live;
+
+ return *this;
+}
+
+SBuf::SBuf()
+ : store_(GetStorePrototype()), off_(0), len_(0)
+{
+ debugs(24, 8, id << " created");
+ ++stats.alloc;
+ ++stats.live;
+}
+
+SBuf::SBuf(const SBuf &S)
+ : store_(S.store_), off_(S.off_), len_(S.len_)
+{
+ debugs(24, 8, id << " created from id " << S.id);
+ ++stats.alloc;
+ ++stats.allocCopy;
+ ++stats.live;
+}
+
+SBuf::SBuf(const String &S)
+ : store_(GetStorePrototype()), off_(0), len_(0)
+{
+ debugs(24, 8, id << " created from string");
+ assign(S.rawBuf(), S.size());
+ ++stats.alloc;
+ ++stats.allocFromString;
+ ++stats.live;
+}
+
+SBuf::SBuf(const std::string &s)
+ : store_(GetStorePrototype()), off_(0), len_(0)
+{
+ debugs(24, 8, id << " created from std::string");
+ lowAppend(s.data(),s.length());
+ ++stats.alloc;
+ ++stats.allocFromString;
+ ++stats.live;
+}
+
+SBuf::SBuf(const char *S, size_type n)
+ : store_(GetStorePrototype()), off_(0), len_(0)
+{
+ append(S,n);
+ ++stats.alloc;
+ ++stats.allocFromCString;
+ ++stats.live;
+}
+
+SBuf::~SBuf()
+{
+ debugs(24, 8, id << " destructed");
+ --stats.live;
+ recordSBufSizeAtDestruct(len_);
+}
+
+MemBlob::Pointer
+SBuf::GetStorePrototype()
+{
+ static MemBlob::Pointer InitialStore = new MemBlob(0);
+ return InitialStore;
+}
+
+SBuf&
+SBuf::assign(const SBuf &S)
+{
+ debugs(24, 7, "assigning " << id << " from " << S.id);
+ if (&S == this) //assignment to self. Noop.
+ return *this;
+ ++stats.assignFast;
+ store_ = S.store_;
+ off_ = S.off_;
+ len_ = S.len_;
+ return *this;
+}
+
+SBuf&
+SBuf::assign(const char *S, size_type n)
+{
+ const Locker blobKeeper(this, S);
+ debugs(24, 6, id << " from c-string, n=" << n << ")");
+ clear();
+ return append(S, n); //bounds checked in append()
+}
+
+void
+SBuf::reserveCapacity(size_type minCapacity)
+{
+ Must(minCapacity <= maxSize);
+ 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)
+{
+ Must(length() <= maxSize - minSpace);
+ debugs(24, 7, "reserving " << minSpace << " for " << id);
+ ++stats.rawAccess;
+ // we're not concerned about RefCounts here,
+ // the store knows the last-used portion. If
+ // it's available, we're effectively claiming ownership
+ // of it. If it's not, we need to go away (realloc)
+ if (store_->canAppend(off_+len_, minSpace)) {
+ debugs(24, 7, id << " not growing");
+ return bufEnd();
+ }
+ // TODO: we may try to memmove before realloc'ing in order to avoid
+ // one allocation operation, if we're the sole owners of a MemBlob.
+ // Maybe some heuristic on off_ and length()?
+ cow(minSpace+length());
+ return bufEnd();
+}
+
+void
+SBuf::clear()
+{
+#if 0
+ //enabling this code path, the store will be freed and reinitialized
+ store_ = GetStorePrototype(); //uncomment to actually free storage upon clear()
+#else
+ //enabling this code path, we try to release the store without deallocating it.
+ // will be lazily reallocated if needed.
+ if (store_->LockCount() == 1)
+ store_->clear();
+#endif
+ len_ = 0;
+ off_ = 0;
+ ++stats.clear;
+}
+
+SBuf&
+SBuf::append(const SBuf &S)
+{
+ const Locker blobKeeper(this, S.buf());
+ return lowAppend(S.buf(), S.length());
+}
+
+SBuf &
+SBuf::append(const char * S, size_type Ssize)
+{
+ const Locker blobKeeper(this, S);
+ if (S == NULL)
+ return *this;
+ if (Ssize == SBuf::npos)
+ Ssize = strlen(S);
+ debugs(24, 7, "from c-string to id " << id);
+ // coverity[access_dbuff_in_call]
+ return lowAppend(S, Ssize);
+}
+
+SBuf &
+SBuf::append(const char c)
+{
+ return lowAppend(&c, 1);
+}
+
+SBuf&
+SBuf::Printf(const char *fmt, ...)
+{
+ // with printf() the fmt or an arg might be a dangerous char*
+ // NP: cant rely on vappendf() Locker because of clear()
+ const Locker blobKeeper(this, buf());
+
+ va_list args;
+ va_start(args, fmt);
+ clear();
+ vappendf(fmt, args);
+ va_end(args);
+ return *this;
+}
+
+SBuf&
+SBuf::appendf(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vappendf(fmt, args);
+ va_end(args);
+ return *this;
+}
+
+SBuf&
+SBuf::vappendf(const char *fmt, va_list vargs)
+{
+ // with (v)appendf() the fmt or an arg might be a dangerous char*
+ const Locker blobKeeper(this, buf());
+
+ Must(fmt != NULL);
+ int sz = 0;
+ //reserve twice the format-string size, it's a likely heuristic
+ size_type requiredSpaceEstimate = strlen(fmt)*2;
+
+ char *space = rawSpace(requiredSpaceEstimate);
+#ifdef VA_COPY
+ va_list ap;
+ VA_COPY(ap, vargs);
+ sz = vsnprintf(space, spaceSize(), fmt, ap);
+ va_end(ap);
+#else
+ sz = vsnprintf(space, spaceSize(), fmt, vargs);
+#endif
+
+ /* check for possible overflow */
+ /* snprintf on Linux returns -1 on output errors, or the size
+ * that would have been written if enough space had been available */
+ /* vsnprintf is standard in C99 */
+
+ if (sz >= static_cast<int>(spaceSize())) {
+ // not enough space on the first go, we now know how much we need
+ requiredSpaceEstimate = sz*2; // TODO: tune heuristics
+ space = rawSpace(requiredSpaceEstimate);
+ sz = vsnprintf(space, spaceSize(), fmt, vargs);
+ if (sz < 0) // output error in vsnprintf
+ throw TextException("output error in second-go vsnprintf",__FILE__,
+ __LINE__);
+ }
+
+ if (sz < 0) // output error in either vsnprintf
+ throw TextException("output error in vsnprintf",__FILE__, __LINE__);
+
+ // data was appended, update internal state
+ len_ += sz;
+
+ /* C99 specifies that the final '\0' is not counted in vsnprintf's
+ * return value. Older compilers/libraries might instead count it */
+ /* check whether '\0' was appended and counted */
+ static bool snPrintfTerminatorChecked = false;
+ static bool snPrintfTerminatorCounted = false;
+ if (!snPrintfTerminatorChecked) {
+ char testbuf[16];
+ snPrintfTerminatorCounted = snprintf(testbuf, sizeof(testbuf),
+ "%s", "1") == 2;
+ snPrintfTerminatorChecked = true;
+ }
+ if (snPrintfTerminatorCounted) {
+ --sz;
+ --len_;
+ }
+
+ store_->size += sz;
+ ++stats.append;
+
+ return *this;
+}
+
+std::ostream&
+SBuf::print(std::ostream &os) const
+{
+ os.write(buf(), length());
+ ++stats.toStream;
+ return os;
+}
+
+std::ostream&
+SBuf::dump(std::ostream &os) const
+{
+ os << id
+ << ": ";
+ store_->dump(os);
+ os << ", offset:" << off_
+ << ", len:" << len_
+ << ") : '";
+ print(os);
+ os << '\'' << std::endl;
+ return os;
+# if 0
+ // alternate implementation, based on Raw() API.
+ os << Raw("SBuf", buf(), length()) <<
+ ". id: " << id <<
+ ", offset:" << off_ <<
+ ", len:" << len_ <<
+ ", store: ";
+ store_->dump(os);
+ os << std::endl;
+ return os;
+#endif
+}
+
+void
+SBuf::setAt(size_type pos, char toset)
+{
+ checkAccessBounds(pos);
+ cow();
+ store_->mem[off_+pos] = toset;
+ ++stats.setChar;
+}
+
+static int
+memcasecmp(const char *b1, const char *b2, SBuf::size_type len)
+{
+ int rv=0;
+ while (len > 0) {
+ rv = tolower(*b1)-tolower(*b2);
+ if (rv != 0)
+ return rv;
+ ++b1;
+ ++b2;
+ --len;
+ }
+ return rv;
+}
+
+int
+SBuf::compare(const SBuf &S, const SBufCaseSensitive isCaseSensitive, const size_type n) const
+{
+ if (n != npos)
+ return substr(0,n).compare(S.substr(0,n),isCaseSensitive);
+
+ const size_type byteCompareLen = min(S.length(), length());
+ ++stats.compareSlow;
+ int rv = 0;
+ if (isCaseSensitive == caseSensitive) {
+ rv = memcmp(buf(), S.buf(), byteCompareLen);
+ } else {
+ rv = memcasecmp(buf(), S.buf(), byteCompareLen);
+ }
+ if (rv != 0)
+ return rv;
+ if (length() == S.length())
+ return 0;
+ if (length() > S.length())
+ return 1;
+ return -1;
+}
+
+int
+SBuf::compare(const char *s, const SBufCaseSensitive isCaseSensitive, const size_type n) const
+{
+ // 0-length comparison is always true regardless of buffer states
+ if (!n) {
+ ++stats.compareFast;
+ return 0;
+ }
+
+ // N-length compare MUST provide a non-NULL C-string pointer
+ assert(s);
+
+ // when this is a 0-length string, no need for any complexity.
+ if (!length()) {
+ ++stats.compareFast;
+ return '\0' - *s;
+ }
+
+ // brute-force scan in order to avoid ever needing strlen() on a c-string.
+ ++stats.compareSlow;
+ const char *left = buf();
+ const char *right = s;
+ int rv = 0;
+ // what area to scan.
+ // n may be npos, but we treat that as a huge positive value
+ size_type byteCount = min(length(), n);
+
+ // loop until we find a difference, a '\0', or reach the end of area to scan
+ if (isCaseSensitive == caseSensitive) {
+ while ((rv = *left - *right++) == 0) {
+ if (*left++ == '\0' || --byteCount == 0)
+ break;
+ }
+ } else {
+ while ((rv = tolower(*left) - tolower(*right++)) == 0) {
+ if (*left++ == '\0' || --byteCount == 0)
+ break;
+ }
+ }
+
+ // If we stopped scanning because we reached the end
+ // of buf() before we reached the end of s,
+ // pretend we have a 0-terminator there to compare.
+ // NP: the loop already incremented "right" ready for this comparison
+ if (!byteCount && length() < n)
+ return '\0' - *right;
+
+ // If we found a difference within the scan area,
+ // or we found a '\0',
+ // or all n characters were identical (and none was \0).
+ return rv;
+}
+
+bool
+SBuf::startsWith(const SBuf &S, const SBufCaseSensitive isCaseSensitive) const
+{
+ debugs(24, 8, id << " startsWith " << S.id << ", caseSensitive: " <<
+ isCaseSensitive);
+ if (length() < S.length()) {
+ debugs(24, 8, "no, too short");
+ ++stats.compareFast;
+ return false;
+ }
+ return (compare(S, isCaseSensitive, S.length()) == 0);
+}
+
+bool
+SBuf::operator ==(const SBuf & S) const
+{
+ debugs(24, 8, id << " == " << S.id);
+ if (length() != S.length()) {
+ debugs(24, 8, "no, different lengths");
+ ++stats.compareFast;
+ return false; //shortcut: must be equal length
+ }
+ if (store_ == S.store_ && off_ == S.off_) {
+ debugs(24, 8, "yes, same length and backing store");
+ ++stats.compareFast;
+ return true; //shortcut: same store, offset and length
+ }
+ ++stats.compareSlow;
+ const bool rv = (0 == memcmp(buf(), S.buf(), length()));
+ debugs(24, 8, "returning " << rv);
+ return rv;
+}
+
+bool
+SBuf::operator !=(const SBuf & S) const
+{
+ return !(*this == S);
+}
+
+SBuf
+SBuf::consume(size_type n)
+{
+ if (n == npos)
+ n = length();
+ else
+ n = min(n, length());
+ debugs(24, 8, id << " consume " << n);
+ SBuf rv(substr(0, n));
+ chop(n);
+ return rv;
+}
+
+const
+SBufStats& SBuf::GetStats()
+{
+ return stats;
+}
+
+SBuf::size_type
+SBuf::copy(char *dest, size_type n) const
+{
+ size_type toexport = min(n,length());
+ memcpy(dest, buf(), toexport);
+ ++stats.copyOut;
+ return toexport;
+}
+
+const char*
+SBuf::rawContent() const
+{
+ ++stats.rawAccess;
+ return buf();
+}
+
+void
+SBuf::forceSize(size_type newSize)
+{
+ debugs(24, 8, id << " force " << (newSize > length() ? "grow" : "shrink") << " to length=" << newSize);
+
+ Must(store_->LockCount() == 1);
+ if (newSize > min(maxSize,store_->capacity-off_))
+ throw SBufTooBigException(__FILE__,__LINE__);
+ len_ = newSize;
+ store_->size = newSize;
+}
+
+const char*
+SBuf::c_str()
+{
+ ++stats.rawAccess;
+ /* null-terminate the current buffer, by hand-appending a \0 at its tail but
+ * without increasing its length. May COW, the side-effect is to guarantee that
+ * the MemBlob's tail is availabe for us to use */
+ *rawSpace(1) = '\0';
+ ++store_->size;
+ ++stats.setChar;
+ ++stats.nulTerminate;
+ return buf();
+}
+
+SBuf&
+SBuf::chop(size_type pos, size_type n)
+{
+ if (pos == npos || pos > length())
+ pos = length();
+
+ if (n == npos || (pos+n) > length())
+ n = length() - pos;
+
+ // if there will be nothing left, reset the buffer while we can
+ if (pos == length() || n == 0) {
+ clear();
+ return *this;
+ }
+
+ ++stats.chop;
+ off_ += pos;
+ len_ = n;
+ return *this;
+}
+
+SBuf&
+SBuf::trim(const SBuf &toRemove, bool atBeginning, bool atEnd)
+{
+ ++stats.trim;
+ if (atEnd) {
+ const char *p = bufEnd()-1;
+ while (!isEmpty() && memchr(toRemove.buf(), *p, toRemove.length()) != NULL) {
+ //current end-of-buf is in the searched set
+ --len_;
+ --p;
+ }
+ }
+ if (atBeginning) {
+ const char *p = buf();
+ while (!isEmpty() && memchr(toRemove.buf(), *p, toRemove.length()) != NULL) {
+ --len_;
+ ++off_;
+ ++p;
+ }
+ }
+ if (isEmpty())
+ clear();
+ return *this;
+}
+
+SBuf
+SBuf::substr(size_type pos, size_type n) const
+{
+ SBuf rv(*this);
+ rv.chop(pos, n); //stats handled by callee
+ return rv;
+}
+
+SBuf::size_type
+SBuf::find(char c, size_type startPos) const
+{
+ ++stats.find;
+
+ if (startPos == npos) // can't find anything if we look past end of SBuf
+ return npos;
+
+ // std::string returns npos if needle is outside hay
+ if (startPos > length())
+ return npos;
+
+ const void *i = memchr(buf()+startPos, (int)c, (size_type)length()-startPos);
+
+ if (i == NULL)
+ return npos;
+
+ return (static_cast<const char *>(i)-buf());
+}
+
+SBuf::size_type
+SBuf::find(const SBuf &needle, size_type startPos) const
+{
+ if (startPos == npos) { // can't find anything if we look past end of SBuf
+ ++stats.find;
+ return npos;
+ }
+
+ // std::string allows needle to overhang hay but not start outside
+ if (startPos > length()) {
+ ++stats.find;
+ return npos;
+ }
+
+ // for empty needle std::string returns startPos
+ if (needle.length() == 0) {
+ ++stats.find;
+ return startPos;
+ }
+
+ // if needle length is 1 use the char search
+ if (needle.length() == 1)
+ return find(needle[0], startPos);
+
+ ++stats.find;
+
+ char *begin = buf()+startPos;
+ char *lastPossible = buf()+length()-needle.length()+1;
+ char needleBegin = needle[0];
+
+ debugs(24, 7, "looking for " << needle << "starting at " << startPos <<
+ " in id " << id);
+ while (begin < lastPossible) {
+ char *tmp;
+ debugs(24, 8, " begin=" << (void *) begin <<
+ ", lastPossible=" << (void*) lastPossible );
+ tmp = static_cast<char *>(memchr(begin, needleBegin, lastPossible-begin));
+ if (tmp == NULL) {
+ debugs(24, 8 , "First byte not found");
+ return npos;
+ }
+ // lastPossible guarrantees no out-of-bounds with memcmp()
+ if (0 == memcmp(needle.buf(), tmp, needle.length())) {
+ debugs(24, 8, "Found at " << (tmp-buf()));
+ return (tmp-buf());
+ }
+ begin = tmp+1;
+ }
+ debugs(24, 8, "not found");
+ return npos;
+}
+
+SBuf::size_type
+SBuf::rfind(const SBuf &needle, SBuf::size_type endPos) const
+{
+ // when the needle is 1 char, use the 1-char rfind()
+ if (needle.length() == 1)
+ return rfind(needle[0], endPos);
+
+ ++stats.find;
+
+ // needle is bigger than haystack, impossible find
+ if (length() < needle.length())
+ return npos;
+
+ // if startPos is npos, std::string scans from the end of hay
+ if (endPos == npos || endPos > length()-needle.length())
+ endPos = length()-needle.length();
+
+ // an empty needle found at the end of the haystack
+ if (needle.length() == 0)
+ return endPos;
+
+ char *bufBegin = buf();
+ char *cur = bufBegin+endPos;
+ const char needleBegin = needle[0];
+ while (cur >= bufBegin) {
+ if (*cur == needleBegin) {
+ if (0 == memcmp(needle.buf(), cur, needle.length())) {
+ // found
+ return (cur-buf());
+ }
+ }
+ --cur;
+ }
+ return npos;
+}
+
+SBuf::size_type
+SBuf::rfind(char c, SBuf::size_type endPos) const
+{
+ ++stats.find;
+
+ // shortcut: haystack is empty, can't find anything by definition
+ if (length() == 0)
+ return npos;
+
+ // on npos input std::string compares last octet of hay
+ if (endPos == npos || endPos >= length()) {
+ endPos = length();
+ } else {
+ // NP: off-by-one weirdness:
+ // endPos is an offset ... 0-based
+ // length() is a count ... 1-based
+ // memrhr() requires a 1-based count of space to scan.
+ ++endPos;
+ }
+
+ if (length() == 0)
+ return endPos;
+
+ const void *i = memrchr(buf(), (int)c, (size_type)endPos);
+
+ if (i == NULL)
+ return npos;
+
+ return (static_cast<const char *>(i)-buf());
+}
+
+SBuf::size_type
+SBuf::findFirstOf(const CharacterSet &set, size_type startPos) const
+{
+ ++stats.find;
+
+ if (startPos == npos)
+ return npos;
+
+ if (startPos >= length())
+ return npos;
+
+ debugs(24, 7, "first of characterset " << set.name << " in id " << id);
+ char *cur = buf()+startPos;
+ const char *end = bufEnd();
+ while (cur < end) {
+ if (set[*cur])
+ return cur-buf();
+ ++cur;
+ }
+ debugs(24, 7, "not found");
+ return npos;
+}
+
+SBuf::size_type
+SBuf::findFirstNotOf(const CharacterSet &set, size_type startPos) const
+{
+ ++stats.find;
+
+ if (startPos == npos)
+ return npos;
+
+ if (startPos >= length())
+ return npos;
+
+ debugs(24, 7, "first not of characterset " << set.name << " in id " << id);
+ char *cur = buf()+startPos;
+ const char *end = bufEnd();
+ while (cur < end) {
+ if (!set[*cur])
+ return cur-buf();
+ ++cur;
+ }
+ debugs(24, 7, "not found");
+ return npos;
+}
+
+/*
+ * TODO: borrow a sscanf implementation from Linux or similar?
+ * we'd really need a vsnscanf(3)... ? As an alternative, a
+ * light-regexp-like domain-specific syntax might be an idea.
+ */
+int
+SBuf::scanf(const char *format, ...)
+{
+ // with the format or an arg might be a dangerous char*
+ // that gets invalidated by c_str()
+ const Locker blobKeeper(this, buf());
+
+ va_list arg;
+ int rv;
+ ++stats.scanf;
+ va_start(arg, format);
+ rv = vsscanf(c_str(), format, arg);
+ va_end(arg);
+ return rv;
+}
+
+std::ostream &
+SBufStats::dump(std::ostream& os) const
+{
+ MemBlobStats ststats = MemBlob::GetStats();
+ os <<
+ "SBuf stats:\nnumber of allocations: " << alloc <<
+ "\ncopy-allocations: " << allocCopy <<
+ "\ncopy-allocations from SquidString: " << allocFromString <<
+ "\ncopy-allocations from C String: " << allocFromCString <<
+ "\nlive references: " << live <<
+ "\nno-copy assignments: " << assignFast <<
+ "\nclearing operations: " << clear <<
+ "\nappend operations: " << append <<
+ "\ndump-to-ostream: " << toStream <<
+ "\nset-char: " << setChar <<
+ "\nget-char: " << getChar <<
+ "\ncomparisons with data-scan: " << compareSlow <<
+ "\ncomparisons not requiring data-scan: " << compareFast <<
+ "\ncopy-out ops: " << copyOut <<
+ "\nraw access to memory: " << rawAccess <<
+ "\nNULL terminate C string: " << nulTerminate <<
+ "\nchop operations: " << chop <<
+ "\ntrim operations: " << trim <<
+ "\nfind: " << find <<
+ "\nscanf: " << scanf <<
+ "\ncase-change ops: " << caseChange <<
+ "\nCOW not actually requiring a copy: " << cowFast <<
+ "\nCOW: " << cowSlow <<
+ "\naverage store share factor: " <<
+ (ststats.live != 0 ? static_cast<float>(live)/ststats.live : 0) <<
+ std::endl;
+ return os;
+}
+
+void
+SBuf::toLower()
+{
+ debugs(24, 8, "\"" << *this << "\"");
+ for (size_type j = 0; j < length(); ++j) {
+ const int c = (*this)[j];
+ if (isupper(c))
+ setAt(j, tolower(c));
+ }
+ debugs(24, 8, "result: \"" << *this << "\"");
+ ++stats.caseChange;
+}
+
+void
+SBuf::toUpper()
+{
+ debugs(24, 8, "\"" << *this << "\"");
+ for (size_type j = 0; j < length(); ++j) {
+ const int c = (*this)[j];
+ if (islower(c))
+ setAt(j, toupper(c));
+ }
+ debugs(24, 8, "result: \"" << *this << "\"");
+ ++stats.caseChange;
+}
+
+/**
+ * checks whether the requested 'pos' is within the bounds of the SBuf
+ * \throw OutOfBoundsException if access is out of bounds
+ */
+void
+SBuf::checkAccessBounds(size_type pos) const
+{
+ if (pos >= length())
+ throw OutOfBoundsException(*this, pos, __FILE__, __LINE__);
+}
+
+String
+SBuf::toString() const
+{
+ String rv;
+ rv.limitInit(buf(), length());
+ ++stats.copyOut;
+ return rv;
+}
+
+/** re-allocate the backing store of the SBuf.
+ *
+ * If there are contents in the SBuf, they will be copied over.
+ * NO verifications are made on the size parameters, it's up to the caller to
+ * make sure that the new size is big enough to hold the copied contents.
+ * The re-allocated storage MAY be bigger than the requested size due to size-chunking
+ * algorithms in MemBlock, it is guarranteed NOT to be smaller.
+ */
+void
+SBuf::reAlloc(size_type newsize)
+{
+ debugs(24, 8, id << " new size: " << newsize);
+ if (newsize > maxSize)
+ throw SBufTooBigException(__FILE__, __LINE__);
+ MemBlob::Pointer newbuf = new MemBlob(newsize);
+ if (length() > 0)
+ newbuf->append(buf(), length());
+ store_ = newbuf;
+ off_ = 0;
+ ++stats.cowSlow;
+ debugs(24, 7, id << " new store capacity: " << store_->capacity);
+}
+
+SBuf&
+SBuf::lowAppend(const char * memArea, size_type areaSize)
+{
+ rawSpace(areaSize); //called method also checks n <= maxSize()
+ store_->append(memArea, areaSize);
+ len_ += areaSize;
+ ++stats.append;
+ return *this;
+}
+
+/**
+ * copy-on-write: make sure that we are the only holder of the backing store.
+ * If not, reallocate. If a new size is specified, and it is greater than the
+ * current length, the backing store will be extended as needed
+ */
+void
+SBuf::cow(SBuf::size_type newsize)
+{
+ debugs(24, 8, id << " new size:" << newsize);
+ if (newsize == npos || newsize < length())
+ newsize = length();
+
+ if (store_->LockCount() == 1 && newsize == length()) {
+ debugs(24, 8, id << " no cow needed");
+ ++stats.cowFast;
+ return;
+ }
+ reAlloc(newsize);
+}
+
Index: squid-3.3.13/src/SBuf.h
===================================================================
--- /dev/null
+++ squid-3.3.13/src/SBuf.h
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SBUF_H
+#define SQUID_SBUF_H
+
+#include "base/InstanceId.h"
+#include "MemBlob.h"
+#include "SBufExceptions.h"
+#include "SquidString.h"
+
+#include <climits>
+#include <cstdarg>
+#include <iosfwd>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* SBuf placeholder for printf */
+#ifndef SQUIDSBUFPH
+#define SQUIDSBUFPH "%.*s"
+#define SQUIDSBUFPRINT(s) (s).plength(),(s).rawContent()
+#endif /* SQUIDSBUFPH */
+
+// TODO: move within SBuf and rename
+typedef enum {
+ caseSensitive,
+ caseInsensitive
+} SBufCaseSensitive;
+
+/**
+ * Container for various SBuf class-wide statistics.
+ *
+ * The stats are not completely accurate; they're mostly meant to
+ * understand whether Squid is leaking resources
+ * and whether SBuf is paying off the expected gains.
+ */
+class SBufStats
+{
+public:
+ uint64_t alloc; ///<number of calls to SBuf constructors
+ uint64_t allocCopy; ///<number of calls to SBuf copy-constructor
+ uint64_t allocFromString; ///<number of copy-allocations from Strings
+ uint64_t allocFromCString; ///<number of copy-allocations from c-strings
+ uint64_t assignFast; ///<number of no-copy assignment operations
+ uint64_t clear; ///<number of clear operations
+ uint64_t append; ///<number of append operations
+ uint64_t toStream; ///<number of write operations to ostreams
+ uint64_t setChar; ///<number of calls to setAt
+ uint64_t getChar; ///<number of calls to at() and operator[]
+ uint64_t compareSlow; ///<number of comparison operations requiring data scan
+ uint64_t compareFast; ///<number of comparison operations not requiring data scan
+ uint64_t copyOut; ///<number of data-copies to other forms of buffers
+ uint64_t rawAccess; ///<number of accesses to raw contents
+ uint64_t nulTerminate; ///<number of c_str() terminations
+ uint64_t chop; ///<number of chop operations
+ uint64_t trim; ///<number of trim operations
+ uint64_t find; ///<number of find operations
+ uint64_t scanf; ///<number of scanf operations
+ uint64_t caseChange; ///<number of toUpper and toLower operations
+ uint64_t cowFast; ///<number of cow operations not actually requiring a copy
+ uint64_t cowSlow; ///<number of cow operations requiring a copy
+ uint64_t live; ///<number of currently-allocated SBuf
+
+ ///Dump statistics to an ostream.
+ std::ostream& dump(std::ostream &os) const;
+ SBufStats();
+
+ SBufStats& operator +=(const SBufStats&);
+};
+
+class CharacterSet;
+class SBufReservationRequirements;
+
+/**
+ * A String or Buffer.
+ * Features: refcounted backing store, cheap copy and sub-stringing
+ * operations, copy-on-write to isolate change operations to each instance.
+ * Where possible, we're trying to mimic std::string's interface.
+ */
+class SBuf
+{
+public:
+ typedef MemBlob::size_type size_type;
+ static const size_type npos = 0xffffffff; // max(uint32_t)
+
+ /// Maximum size of a SBuf. By design it MUST be < MAX(size_type)/2. Currently 256Mb.
+ static const size_type maxSize = 0xfffffff;
+
+ /// create an empty (zero-size) SBuf
+ SBuf();
+ SBuf(const SBuf &S);
+
+ /** Constructor: import c-style string
+ *
+ * Create a new SBuf containing a COPY of the contents of the
+ * c-string
+ * \param S the c string to be copied
+ * \param n how many bytes to import into the SBuf. If it is npos
+ * or unspecified, imports to end-of-cstring
+ * \note it is the caller's responsibility not to go out of bounds
+ * \note bounds is 0 <= pos < length(); caller must pay attention to signedness
+ */
+ explicit SBuf(const char *S, size_type n = npos);
+
+ /** Constructor: import SquidString, copying contents.
+ *
+ * This method will be removed once SquidString has gone.
+ */
+ explicit SBuf(const String &S);
+
+ /// Constructor: import std::string. Contents are copied.
+ explicit SBuf(const std::string &s);
+
+ ~SBuf();
+
+ /** Explicit assignment.
+ *
+ * Current SBuf will share backing store with the assigned one.
+ */
+ SBuf& assign(const SBuf &S);
+
+ /** Assignment operator.
+ *
+ * Current SBuf will share backing store with the assigned one.
+ */
+ SBuf& operator =(const SBuf & S) {return assign(S);}
+
+ /** Import a c-string into a SBuf, copying the data.
+ *
+ * It is the caller's duty to free the imported string, if needed.
+ * \param S the c string to be copied
+ * \param n how many bytes to import into the SBuf. If it is npos
+ * or unspecified, imports to end-of-cstring
+ * \note it is the caller's responsibility not to go out of bounds
+ * \note to assign a std::string use the pattern:
+ * assign(stdstr.data(), stdstd.length())
+ */
+ SBuf& assign(const char *S, size_type n = npos);
+
+ /** Assignment operator. Copy a NULL-terminated c-style string into a SBuf.
+ *
+ * Copy a c-style string into a SBuf. Shortcut for SBuf.assign(S)
+ * It is the caller's duty to free the imported string, if needed.
+ * \note not \0-clean
+ */
+ SBuf& operator =(const char *S) {return assign(S);}
+
+ /** reset the SBuf as if it was just created.
+ *
+ * Resets the SBuf to empty, memory is freed lazily.
+ */
+ void clear();
+
+ /** Append operation
+ *
+ * Append the supplied SBuf to the current one; extend storage as needed.
+ */
+ SBuf& append(const SBuf & S);
+
+ /// Append a single character. The character may be NUL (\0).
+ SBuf& append(const char c);
+
+ /** Append operation for C-style strings.
+ *
+ * Append the supplied c-string to the SBuf; extend storage
+ * as needed.
+ *
+ * \param S the c string to be copied. Can be NULL.
+ * \param Ssize how many bytes to import into the SBuf. If it is npos
+ * or unspecified, imports to end-of-cstring. If S is NULL,
+ * Ssize is ignored.
+ * \note to append a std::string use the pattern
+ * cstr_append(stdstr.data(), stdstd.length())
+ */
+ SBuf& append(const char * S, size_type Ssize = npos);
+
+ /** Assignment operation with printf(3)-style definition
+ * \note arguments may be evaluated more than once, be careful
+ * of side-effects
+ */
+ SBuf& Printf(const char *fmt, ...);
+
+ /** Append operation with printf-style arguments
+ * \note arguments may be evaluated more than once, be careful
+ * of side-effects
+ */
+ SBuf& appendf(const char *fmt, ...);
+
+ /** Append operation, with vsprintf(3)-style arguments.
+ * \note arguments may be evaluated more than once, be careful
+ * of side-effects
+ */
+ SBuf& vappendf(const char *fmt, va_list vargs);
+
+ /// print the SBuf contents to the supplied ostream
+ std::ostream& print(std::ostream &os) const;
+
+ /** print SBuf contents and debug information about the SBuf to an ostream
+ *
+ * Debug function, dumps to a stream informations on the current SBuf,
+ * including low-level details and statistics.
+ */
+ std::ostream& dump(std::ostream &os) const;
+
+ /** random-access read to any char within the SBuf
+ *
+ * does not check access bounds. If you need that, use at()
+ */
+ char operator [](size_type pos) const {++stats.getChar; return store_->mem[off_+pos];}
+
+ /** random-access read to any char within the SBuf.
+ *
+ * \throw OutOfBoundsException when access is out of bounds
+ * \note bounds is 0 <= pos < length(); caller must pay attention to signedness
+ */
+ char at(size_type pos) const {checkAccessBounds(pos); return operator[](pos);}
+
+ /** direct-access set a byte at a specified operation.
+ *
+ * \param pos the position to be overwritten
+ * \param toset the value to be written
+ * \throw OutOfBoundsException when pos is of bounds
+ * \note bounds is 0 <= pos < length(); caller must pay attention to signedness
+ * \note performs a copy-on-write if needed.
+ */
+ void setAt(size_type pos, char toset);
+
+ /** compare to other SBuf, str(case)cmp-style
+ *
+ * \param isCaseSensitive one of caseSensitive or caseInsensitive
+ * \param n compare up to this many bytes. if npos (default), compare whole SBufs
+ * \retval >0 argument of the call is greater than called SBuf
+ * \retval <0 argument of the call is smaller than called SBuf
+ * \retval 0 argument of the call has the same contents of called SBuf
+ */
+ int compare(const SBuf &S, const SBufCaseSensitive isCaseSensitive, const size_type n = npos) const;
+
+ /// shorthand version for compare()
+ inline int cmp(const SBuf &S, const size_type n = npos) const {
+ return compare(S,caseSensitive,n);
+ }
+
+ /// shorthand version for case-insensitive compare()
+ inline int caseCmp(const SBuf &S, const size_type n = npos) const {
+ return compare(S,caseInsensitive,n);
+ }
+
+ /// Comparison with a C-string.
+ int compare(const char *s, const SBufCaseSensitive isCaseSensitive, const size_type n = npos) const;
+
+ /// Shorthand version for C-string compare().
+ inline int cmp(const char *S, const size_type n = npos) const {
+ return compare(S,caseSensitive,n);
+ }
+
+ /// Shorthand version for case-insensitive C-string compare().
+ inline int caseCmp(const char *S, const size_type n = npos) const {
+ return compare(S,caseInsensitive,n);
+ }
+
+ /** check whether the entire supplied argument is a prefix of the SBuf.
+ * \param S the prefix to match against
+ * \param isCaseSensitive one of caseSensitive or caseInsensitive
+ * \retval true argument is a prefix of the SBuf
+ */
+ bool startsWith(const SBuf &S, const SBufCaseSensitive isCaseSensitive = caseSensitive) const;
+
+ bool operator ==(const SBuf & S) const;
+ bool operator !=(const SBuf & S) const;
+ bool operator <(const SBuf &S) const {return (cmp(S) < 0);}
+ bool operator >(const SBuf &S) const {return (cmp(S) > 0);}
+ bool operator <=(const SBuf &S) const {return (cmp(S) <= 0);}
+ bool operator >=(const SBuf &S) const {return (cmp(S) >= 0);}
+
+ /** Consume bytes at the head of the SBuf
+ *
+ * Consume N chars at SBuf head, or to SBuf's end,
+ * whichever is shorter. If more bytes are consumed than available,
+ * the SBuf is emptied
+ * \param n how many bytes to remove; could be zero.
+ * npos (or no argument) means 'to the end of SBuf'
+ * \return a new SBuf containing the consumed bytes.
+ */
+ SBuf consume(size_type n = npos);
+
+ /// gets global statistic informations
+ static const SBufStats& GetStats();
+
+ /** Copy SBuf contents into user-supplied C buffer.
+ *
+ * Export a copy of the SBuf's contents into the user-supplied
+ * buffer, up to the user-supplied-length. No zero-termination is performed
+ * \return num the number of actually-copied chars.
+ */
+ size_type copy(char *dest, size_type n) const;
+
+ /** exports a pointer to the SBuf internal storage.
+ * \warning ACCESSING RAW STORAGE IS DANGEROUS!
+ *
+ * Returns a ead-only pointer to SBuf's content. No terminating null
+ * character is appended (use c_str() for that).
+ * The returned value points to an internal location whose contents
+ * are guaranteed to remain unchanged only until the next call
+ * to a non-constant member function of the SBuf object. Such a
+ * call may be implicit (e.g., when SBuf is destroyed
+ * upon leaving the current context).
+ * This is a very UNSAFE way of accessing the data.
+ * This call never returns NULL.
+ * \see c_str
+ * \note the memory management system guarantees that the exported region
+ * of memory will remain valid if the caller keeps holding
+ * a valid reference to the SBuf object and does not write or append to
+ * it. For example:
+ * \code
+ * SBuf foo("some string");
+ * const char *bar = foo.rawContent();
+ * doSomething(bar); //safe
+ * foo.append(" other string");
+ * doSomething(bar); //unsafe
+ * \endcode
+ */
+ const char* rawContent() const;
+
+ /** Exports a writable pointer to the SBuf internal storage.
+ * \warning Use with EXTREME caution, this is a dangerous operation.
+ *
+ * Returns a pointer to the first unused byte in the SBuf's storage,
+ * which can be be used for appending. At least minSize bytes will
+ * be available for writing.
+ * The returned pointer must not be stored by the caller, as it will
+ * be invalidated by the first call to a non-const method call
+ * on the SBuf.
+ * This call guarantees to never return NULL.
+ * \see reserveSpace
+ * \note Unlike reserveSpace(), this method does not guarantee exclusive
+ * buffer ownership. It is instead optimized for a one writer
+ * (appender), many readers scenario by avoiding unnecessary
+ * copying and allocations.
+ * \throw SBufTooBigException if the user tries to allocate too big a SBuf
+ */
+ char *rawSpace(size_type minSize);
+
+ /** Obtain how much free space is available in the backing store.
+ *
+ * \note: unless the client just cow()ed, it is not guaranteed that
+ * the free space can be used.
+ */
+ size_type spaceSize() const { return store_->spaceSize(); }
+
+ /** Force a SBuf's size
+ * \warning use with EXTREME caution, this is a dangerous operation
+ *
+ * Adapt the SBuf internal state after external interference
+ * such as writing into it via rawSpace.
+ * \throw TextException if SBuf doesn't have exclusive ownership of store
+ * \throw SBufTooBigException if new size is bigger than available store space
+ */
+ void forceSize(size_type newSize);
+
+ /** exports a null-terminated reference to the SBuf internal storage.
+ * \warning ACCESSING RAW STORAGE IS DANGEROUS! DO NOT EVER USE
+ * THE RETURNED POINTER FOR WRITING
+ *
+ * The returned value points to an internal location whose contents
+ * are guaranteed to remain unchanged only until the next call
+ * to a non-constant member function of the SBuf object. Such a
+ * call may be implicit (e.g., when SBuf is destroyed
+ * upon leaving the current context).
+ * This is a very UNSAFE way of accessing the data.
+ * This call never returns NULL.
+ * \see rawContent
+ * \note the memory management system guarantees that the exported region
+ * of memory will remain valid will remain valid only if the
+ * caller keeps holding a valid reference to the SBuf object and
+ * does not write or append to it
+ */
+ const char* c_str();
+
+ /// Returns the number of bytes stored in SBuf.
+ size_type length() const {return len_;}
+
+ /** Get the length of the SBuf, as a signed integer
+ *
+ * Compatibility function for printf(3) which requires a signed int
+ * \throw SBufTooBigException if the SBuf is too big for a signed integer
+ */
+ int plength() const {
+ if (length()>INT_MAX)
+ throw SBufTooBigException(__FILE__, __LINE__);
+ return static_cast<int>(length());
+ }
+
+ /** Check whether the SBuf is empty
+ *
+ * \return true if length() == 0
+ */
+ bool isEmpty() const {return (len_==0);}
+
+ /** Request to guarantee the SBuf's free store space.
+ *
+ * After the reserveSpace request, the SBuf is guaranteed to have at
+ * least minSpace bytes of unused backing store following the currently
+ * used portion and single ownership of the backing store.
+ * \throw SBufTooBigException if the user tries to allocate too big a SBuf
+ */
+ void reserveSpace(size_type minSpace) {
+ Must(minSpace <= maxSize);
+ Must(length() <= maxSize - minSpace);
+ reserveCapacity(length()+minSpace);
+ }
+
+ /** Request to guarantee the SBuf's store capacity
+ *
+ * After this method is called, the SBuf is guaranteed to have at least
+ * minCapacity bytes of total buffer size, including the currently-used
+ * portion; it is also guaranteed that after this call this SBuf
+ * has unique ownership of the underlying memory store.
+ * \throw SBufTooBigException if the user tries to allocate too big a SBuf
+ */
+ 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'
+ * bytes starting from position 'pos', first byte is at pos 0.
+ * It is an in-place-modifying version of substr.
+ * \param pos start sub-stringing from this byte. If it is
+ * npos or it is greater than the SBuf length, the SBuf is cleared and
+ * an empty SBuf is returned.
+ * \param n maximum number of bytes of the resulting SBuf.
+ * npos means "to end of SBuf".
+ * if it is 0, the SBuf is cleared and an empty SBuf is returned.
+ * if it overflows the end of the SBuf, it is capped to the end of SBuf
+ * \see substr, trim
+ */
+ SBuf& chop(size_type pos, size_type n = npos);
+
+ /** Remove characters in the toremove set at the beginning, end or both
+ *
+ * \param toremove characters to be removed. Stops chomping at the first
+ * found char not in the set
+ * \param atBeginning if true (default), strips at the beginning of the SBuf
+ * \param atEnd if true (default), strips at the end of the SBuf
+ */
+ SBuf& trim(const SBuf &toRemove, bool atBeginning = true, bool atEnd = true);
+
+ /** Extract a part of the current SBuf.
+ *
+ * Return a fresh a fresh copy of a portion the current SBuf, which is
+ * left untouched. The same parameter convetions apply as for chop.
+ * \see trim, chop
+ */
+ SBuf substr(size_type pos, size_type n = npos) const;
+
+ /** Find first occurrence of character in SBuf
+ *
+ * Returns the index in the SBuf of the first occurrence of char c.
+ * \return npos if the char was not found
+ * \param startPos if specified, ignore any occurrences before that position
+ * if startPos is npos or greater than length() npos is always returned
+ * if startPos is less than zero, it is ignored
+ */
+ size_type find(char c, size_type startPos = 0) const;
+
+ /** Find first occurrence of SBuf in SBuf.
+ *
+ * Returns the index in the SBuf of the first occurrence of the
+ * sequence contained in the str argument.
+ * \param startPos if specified, ignore any occurrences before that position
+ * if startPos is npos or greater than length() npos is always returned
+ * \return npos if the SBuf was not found
+ */
+ size_type find(const SBuf & str, size_type startPos = 0) const;
+
+ /** Find last occurrence of character in SBuf
+ *
+ * Returns the index in the SBuf of the last occurrence of char c.
+ * \return npos if the char was not found
+ * \param endPos if specified, ignore any occurrences after that position.
+ * if npos or greater than length(), the whole SBuf is considered
+ */
+ size_type rfind(char c, size_type endPos = npos) const;
+
+ /** Find last occurrence of SBuf in SBuf
+ *
+ * Returns the index in the SBuf of the last occurrence of the
+ * sequence contained in the str argument.
+ * \return npos if the sequence was not found
+ * \param endPos if specified, ignore any occurrences after that position
+ * if npos or greater than length(), the whole SBuf is considered
+ */
+ size_type rfind(const SBuf &str, size_type endPos = npos) const;
+
+ /** Find first occurrence of character of set in SBuf
+ *
+ * Finds the first occurrence of ANY of the characters in the supplied set in
+ * the SBuf.
+ * \return npos if no character in the set could be found
+ * \param startPos if specified, ignore any occurrences before that position
+ * if npos, then npos is always returned
+ *
+ * TODO: rename to camelCase
+ */
+ size_type findFirstOf(const CharacterSet &set, size_type startPos = 0) const;
+
+ /** Find first occurrence character NOT in character set
+ *
+ * \return npos if all characters in the SBuf are from set
+ * \param startPos if specified, ignore any occurrences before that position
+ * if npos, then npos is always returned
+ *
+ * TODO: rename to camelCase
+ */
+ size_type findFirstNotOf(const CharacterSet &set, size_type startPos = 0) const;
+
+ /** sscanf-alike
+ *
+ * sscanf re-implementation. Non-const, and not \0-clean.
+ * \return same as sscanf
+ * \see man sscanf(3)
+ */
+ int scanf(const char *format, ...);
+
+ /// converts all characters to lower case; \see man tolower(3)
+ void toLower();
+
+ /// converts all characters to upper case; \see man toupper(3)
+ void toUpper();
+
+ /** String export function
+ * converts the SBuf to a legacy String, by copy.
+ * \deprecated
+ */
+ String toString() const;
+
+ /// std::string export function
+ std::string toStdString() const { return std::string(buf(),length()); }
+
+ // TODO: possibly implement erase() similar to std::string's erase
+ // TODO: possibly implement a replace() call
+private:
+
+ /**
+ * Keeps SBuf's MemBlob alive in a blob-destroying context where
+ * a seemingly unrelated memory pointer may belong to the same blob.
+ * For [an extreme] example, consider: a.append(a).
+ * Compared to an SBuf temporary, this class is optimized to
+ * preserve blobs only if needed and to reduce debugging noise.
+ */
+ class Locker
+ {
+ public:
+ Locker(SBuf *parent, const char *otherBuffer) {
+ // lock if otherBuffer intersects the parents buffer area
+ const MemBlob *blob = parent->store_.getRaw();
+ if (blob->mem <= otherBuffer && otherBuffer < (blob->mem + blob->capacity))
+ locket = blob;
+ }
+ private:
+ MemBlob::Pointer locket;
+ };
+ friend class Locker;
+
+ MemBlob::Pointer store_; ///< memory block, possibly shared with other SBufs
+ size_type off_; ///< our content start offset from the beginning of shared store_
+ size_type len_; ///< number of our content bytes in shared store_
+ static SBufStats stats; ///< class-wide statistics
+
+ /// SBuf object identifier; does not change when contents do,
+ /// including during assignment
+ const InstanceId<SBuf> id;
+
+ /** obtain prototype store
+ *
+ * Just-created SBufs all share to the same MemBlob.
+ * This call instantiates and returns it.
+ */
+ static MemBlob::Pointer GetStorePrototype();
+
+ /**
+ * obtains a char* to the beginning of this SBuf in memory.
+ * \note the obtained string is NOT null-terminated.
+ */
+ char * buf() const {return (store_->mem+off_);}
+
+ /** returns the pointer to the first char after this SBuf end
+ *
+ * No checks are made that the space returned is safe, checking that is
+ * up to the caller.
+ */
+ char * bufEnd() const {return (store_->mem+off_+len_);}
+
+ /**
+ * Try to guesstimate how big a MemBlob to allocate.
+ * The result is guarranteed to be to be at least the desired size.
+ */
+ size_type estimateCapacity(size_type desired) const {return (2*desired);}
+
+ void reAlloc(size_type newsize);
+
+ void cow(size_type minsize = npos);
+
+ void checkAccessBounds(size_type pos) const;
+
+ /** Low-level append operation
+ *
+ * Takes as input a contiguous area of memory and appends its contents
+ * to the SBuf, taking care of memory management. Does no bounds checking
+ * on the supplied memory buffer, it is the duty of the caller to ensure
+ * that the supplied area is valid.
+ */
+ 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)
+{
+ return S.print(os);
+}
+
+/// Returns a lower-cased copy of its parameter.
+inline SBuf
+ToUpper(SBuf buf)
+{
+ buf.toUpper();
+ return buf;
+}
+
+/// Returns an upper-cased copy of its parameter.
+inline SBuf
+ToLower(SBuf buf)
+{
+ buf.toLower();
+ return buf;
+}
+
+#endif /* SQUID_SBUF_H */
+
Index: squid-3.3.13/src/SBufDetailedStats.cc
===================================================================
--- /dev/null
+++ squid-3.3.13/src/SBufDetailedStats.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "SBufDetailedStats.h"
+#include "StatHist.h"
+
+/*
+ * Implementation note: the purpose of this construct is to avoid adding
+ * external dependencies to the SBuf code
+ */
+
+static StatHist *
+newStatHist() {
+ StatHist *stats = new StatHist;
+ stats->logInit(100, 30.0, 128000.0);
+ return stats;
+}
+
+StatHist &
+collectSBufDestructTimeStats()
+{
+ static StatHist *stats = newStatHist();
+ return *stats;
+}
+
+StatHist &
+collectMemBlobDestructTimeStats()
+{
+ static StatHist *stats = newStatHist();
+ return *stats;
+}
+
+void
+recordSBufSizeAtDestruct(SBuf::size_type sz)
+{
+ collectSBufDestructTimeStats().count(static_cast<double>(sz));
+}
+
+void
+recordMemBlobSizeAtDestruct(SBuf::size_type sz)
+{
+ collectMemBlobDestructTimeStats().count(static_cast<double>(sz));
+}
+
Index: squid-3.3.13/src/SBufDetailedStats.h
===================================================================
--- /dev/null
+++ squid-3.3.13/src/SBufDetailedStats.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SBUFDETAILEDSTATS_H
+#define SQUID_SBUFDETAILEDSTATS_H
+
+#include "SBuf.h"
+
+class StatHist;
+
+/// Record the size a SBuf had when it was destructed
+void recordSBufSizeAtDestruct(SBuf::size_type sz);
+
+/// the SBuf size-at-destruct-time histogram
+StatHist &collectSBufDestructTimeStats();
+
+/// Record the size a MemBlob had when it was destructed
+void recordMemBlobSizeAtDestruct(MemBlob::size_type sz);
+
+/// the MemBlob size-at-destruct-time histogram
+StatHist &collectMemBlobDestructTimeStats();
+
+#endif /* SQUID_SBUFDETAILEDSTATS_H */
+
Index: squid-3.3.13/src/SBufExceptions.cc
===================================================================
--- /dev/null
+++ squid-3.3.13/src/SBufExceptions.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "OutOfBoundsException.h"
+#include "SBuf.h"
+#include "SBufExceptions.h"
+
+OutOfBoundsException::OutOfBoundsException(const SBuf &throwingBuf,
+ SBuf::size_type &pos,
+ const char *aFileName, int aLineNo)
+ : TextException(NULL, aFileName, aLineNo),
+ theThrowingBuf(throwingBuf),
+ accessedPosition(pos)
+{
+ SBuf explanatoryText("OutOfBoundsException");
+ if (aLineNo != -1)
+ explanatoryText.appendf(" at line %d", aLineNo);
+ if (aFileName != NULL)
+ explanatoryText.appendf(" in file %s", aFileName);
+ explanatoryText.appendf(" while accessing position %d in a SBuf long %d",
+ pos, throwingBuf.length());
+ // we can safely alias c_str as both are local to the object
+ // and will not further manipulated.
+ message = xstrndup(explanatoryText.c_str(),explanatoryText.length());
+}
+
+OutOfBoundsException::~OutOfBoundsException() throw()
+{ }
+
+InvalidParamException::InvalidParamException(const char *aFilename, int aLineNo)
+ : TextException("Invalid parameter", aFilename, aLineNo)
+{ }
+
+SBufTooBigException::SBufTooBigException(const char *aFilename, int aLineNo)
+ : TextException("Trying to create an oversize SBuf", aFilename, aLineNo)
+{ }
+
Index: squid-3.3.13/src/SBufExceptions.h
===================================================================
--- /dev/null
+++ squid-3.3.13/src/SBufExceptions.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SBUFEXCEPTIONS_H
+#define SQUID_SBUFEXCEPTIONS_H
+
+#include "base/TextException.h"
+
+/**
+ * Exception raised when call parameters are not valid
+ * \todo move to an Exceptions.h?
+ */
+class InvalidParamException : public TextException
+{
+public:
+ explicit InvalidParamException(const char *aFilename = 0, int aLineNo = -1);
+};
+
+/**
+ * Exception raised when an attempt to resize a SBuf would cause it to reserve too big
+ */
+class SBufTooBigException : public TextException
+{
+public:
+ explicit SBufTooBigException(const char *aFilename = 0, int aLineNo = -1);
+};
+
+#endif /* SQUID_SBUFEXCEPTIONS_H */
+
Index: squid-3.3.13/src/Makefile.am
===================================================================
--- squid-3.3.13.orig/src/Makefile.am
+++ squid-3.3.13/src/Makefile.am
@@ -22,9 +22,14 @@ DNSSOURCE += \
DnsLookupDetails.cc
SBUF_SOURCE= \
+ base/CharacterSet.h \
base/InstanceId.h \
MemBlob.h \
- MemBlob.cc
+ MemBlob.cc \
+ SBuf.h \
+ SBuf.cc \
+ SBufExceptions.h \
+ SBufExceptions.cc
LOADABLE_MODULES_SOURCES = \
LoadableModule.h \
@@ -468,6 +473,8 @@ squid_SOURCES = \
send-announce.h \
send-announce.cc \
$(SBUF_SOURCE) \
+ SBufDetailedStats.h \
+ SBufDetailedStats.cc \
$(SNMP_SOURCE) \
SquidMath.h \
SquidMath.cc \
Index: squid-3.3.13/src/base/CharacterSet.cc
===================================================================
--- /dev/null
+++ squid-3.3.13/src/base/CharacterSet.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "CharacterSet.h"
+
+#include <algorithm>
+#include <functional>
+
+CharacterSet &
+CharacterSet::operator +=(const CharacterSet &src)
+{
+ Storage::const_iterator s = src.chars_.begin();
+ const Storage::const_iterator e = src.chars_.end();
+ Storage::iterator d = chars_.begin();
+ while (s != e) {
+ if (*s)
+ *d = 1;
+ ++s;
+ ++d;
+ }
+ return *this;
+}
+
+CharacterSet
+CharacterSet::operator +(const CharacterSet &src) const
+{
+ CharacterSet rv(*this);
+ rv += src;
+ return rv;
+}
+
+CharacterSet &
+CharacterSet::add(const unsigned char c)
+{
+ chars_[static_cast<uint8_t>(c)] = 1;
+ return *this;
+}
+
+CharacterSet &
+CharacterSet::addRange(unsigned char low, unsigned char high)
+{
+ //manual loop splitting is needed to cover case where high is 255
+ // otherwise low will wrap, resulting in infinite loop
+ while (low < high) {
+ chars_[static_cast<uint8_t>(low)] = 1;
+ ++low;
+ }
+ chars_[static_cast<uint8_t>(high)] = 1;
+ return *this;
+}
+
+CharacterSet
+CharacterSet::complement(const char *label) const
+{
+ CharacterSet result((label ? label : "complement_of_some_other_set"), "");
+ // negate each of our elements and add them to the result storage
+ std::transform(chars_.begin(), chars_.end(), result.chars_.begin(),
+ std::logical_not<Storage::value_type>());
+ return result;
+}
+
+CharacterSet::CharacterSet(const char *label, const char * const c) :
+ name(label == NULL ? "anonymous" : label),
+ chars_(Storage(256,0))
+{
+ const size_t clen = strlen(c);
+ for (size_t i = 0; i < clen; ++i)
+ add(c[i]);
+}
+
+CharacterSet::CharacterSet(const char *label, unsigned char low, unsigned char high) :
+ name(label == NULL ? "anonymous" : label),
+ chars_(Storage(256,0))
+{
+ addRange(low,high);
+}
+
+const CharacterSet
+// RFC 5234
+CharacterSet::ALPHA("ALPHA", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ CharacterSet::BIT("BIT","01"),
+ CharacterSet::CR("CR","\r"),
+#if __cplusplus == 201103L
+//CharacterSet::CTL("CTL",{{0x01,0x1f},{0x7f,0x7f}}),
+#endif
+ CharacterSet::DIGIT("DIGIT","0123456789"),
+ CharacterSet::DQUOTE("DQUOTE","\""),
+ CharacterSet::HEXDIG("HEXDIG","0123456789aAbBcCdDeEfF"),
+ CharacterSet::HTAB("HTAB","\t"),
+ CharacterSet::LF("LF","\n"),
+ CharacterSet::SP("SP"," "),
+ CharacterSet::VCHAR("VCHAR", 0x21, 0x7e),
+// RFC 7230
+ CharacterSet::WSP("WSP"," \t"),
+#if __cplusplus == 201103L
+//CharacterSet::CTEXT("ctext",{{0x09,0x09},{0x20,0x20},{0x2a,0x5b},{0x5d,0x7e},{0x80,0xff}}),
+#endif
+ CharacterSet::TCHAR("TCHAR","!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ CharacterSet::SPECIAL("SPECIAL","()<>@,;:\\\"/[]?={}"),
+#if __cplusplus == 201103L
+//CharacterSet::QDTEXT("QDTEXT",{{0x09,0x09},{0x20,0x21},{0x23,0x5b},{0x5d,0x7e},{0x80,0xff}}),
+#endif
+ CharacterSet::OBSTEXT("OBSTEXT",0x80,0xff),
+// RFC 7232
+#if __cplusplus == 201103L
+//CharacterSet::ETAGC("ETAGC",{{0x21,0x21},{0x23,0x7e},{0x80,0xff}}),
+#endif
+// RFC 7235
+ CharacterSet::TOKEN68C("TOKEN68C","-._~+/0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
+ ;
+
Index: squid-3.3.13/src/base/CharacterSet.h
===================================================================
--- /dev/null
+++ squid-3.3.13/src/base/CharacterSet.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef _SQUID_SRC_PARSER_CHARACTERSET_H
+#define _SQUID_SRC_PARSER_CHARACTERSET_H
+
+#include <vector>
+
+/// optimized set of C chars, with quick membership test and merge support
+class CharacterSet
+{
+public:
+ typedef std::vector<uint8_t> Storage;
+
+ /// define a character set with the given label ("anonymous" if NULL)
+ /// with specified initial contents
+ CharacterSet(const char *label, const char * const initial);
+
+ /// define a character set with the given label ("anonymous" if NULL)
+ /// containing characters defined in the supplied ranges
+ /// \see addRange
+ CharacterSet(const char *label, unsigned char low, unsigned char high);
+
+ /// whether a given character exists in the set
+ bool operator[](unsigned char c) const {return chars_[static_cast<uint8_t>(c)] != 0;}
+
+ /// add a given character to the character set
+ CharacterSet & add(const unsigned char c);
+
+ /// add a list of character ranges, expressed as pairs [low,high], including both ends
+ CharacterSet & addRange(unsigned char low, unsigned char high);
+
+ /// add all characters from the given CharacterSet to this one
+ CharacterSet &operator +=(const CharacterSet &src);
+
+ /// return a new CharacterSet containing the union of two sets
+ CharacterSet operator +(const CharacterSet &src) const;
+
+ /// return a new CharacterSet containing characters not in this set
+ CharacterSet complement(const char *complementLabel = NULL) const;
+
+ /// change name; handy in const declarations that use operators
+ CharacterSet &rename(const char *label) { name = label; return *this; }
+
+ /// optional set label for debugging (default: "anonymous")
+ const char * name;
+
+ // common character sets, RFC 5234
+ // A-Za-z
+ static const CharacterSet ALPHA;
+ // 0-1
+ static const CharacterSet BIT;
+ // carriage return
+ static const CharacterSet CR;
+ // controls
+#if __cplusplus == 201103L
+ // ready but disabled as needs C++11 constructor
+ //static const CharacterSet CTL;
+#endif
+ // 0-9
+ static const CharacterSet DIGIT;
+ // double quote
+ static const CharacterSet DQUOTE;
+ // 0-9aAbBcCdDeEfF
+ static const CharacterSet HEXDIG;
+ // horizontal tab
+ static const CharacterSet HTAB;
+ // line feed
+ static const CharacterSet LF;
+ // white space
+ static const CharacterSet SP;
+ // visible (printable) characters
+ static const CharacterSet VCHAR;
+ // <space><tab>
+ static const CharacterSet WSP;
+
+ // HTTP character sets, RFC 7230
+ // ctext
+#if __cplusplus == 201103L
+ // ready but disabled as needs C++11 constructor
+ //static const CharacterSet CTEXT;
+#endif
+ // XXX: maybe field-vchar = VCHAR / obs-text
+ // any VCHAR except for SPECIAL
+ static const CharacterSet TCHAR;
+ // special VCHARs
+ static const CharacterSet SPECIAL;
+ // qdtext
+#if __cplusplus == 201103L
+ // ready but disabled as needs C++11 constructor
+ //static const CharacterSet QDTEXT;
+#endif
+ // obs-text
+ static const CharacterSet OBSTEXT;
+
+ // HTTP character sets, RFC 7232
+ // etagc
+#if __cplusplus == 201103L
+ // ready but disabled as needs C++11 constructor
+ //static const CharacterSet ETAGC;
+#endif
+
+ // HTTP character sets, RFC 7235
+ // token68 (internal charaters only, excludes '=' terminator)
+ static const CharacterSet TOKEN68C;
+
+private:
+ /** index of characters in this set
+ *
+ * \note guaranteed to be always 256 slots big, as forced in the
+ * constructor. This assumption is relied upon in operator[], add,
+ * operator+=
+ */
+ Storage chars_;
+};
+
+#endif /* _SQUID_SRC_PARSER_CHARACTERSET_H */
+
Index: squid-3.3.13/src/base/Makefile.am
===================================================================
--- squid-3.3.13.orig/src/base/Makefile.am
+++ squid-3.3.13/src/base/Makefile.am
@@ -14,6 +14,8 @@ libbase_la_SOURCES = \
AsyncCallQueue.cc \
AsyncCallQueue.h \
TidyPointer.h \
+ CharacterSet.h \
+ CharacterSet.cc \
CbcPointer.h \
InstanceId.h \
RunnersRegistry.cc \
Index: squid-3.3.13/src/OutOfBoundsException.h
===================================================================
--- /dev/null
+++ squid-3.3.13/src/OutOfBoundsException.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef _SQUID_SRC_OUTOFBOUNDSEXCEPTION_H
+#define _SQUID_SRC_OUTOFBOUNDSEXCEPTION_H
+
+#include "base/TextException.h"
+#include "SBuf.h"
+
+/**
+ * Exception raised when the user is going out of bounds when accessing
+ * a char within the SBuf
+ */
+class OutOfBoundsException : public TextException
+{
+public:
+ OutOfBoundsException(const SBuf &buf, SBuf::size_type &pos, const char *aFileName = 0, int aLineNo = -1);
+ virtual ~OutOfBoundsException() throw();
+
+protected:
+ SBuf theThrowingBuf;
+ SBuf::size_type accessedPosition;
+};
+
+#endif /* _SQUID_SRC_OUTOFBOUNDSEXCEPTION_H */
+
Index: squid-3.3.13/include/RefCount.h
===================================================================
--- squid-3.3.13.orig/include/RefCount.h
+++ squid-3.3.13/include/RefCount.h
@@ -117,7 +117,7 @@ struct RefCountable_ {
++count_;
}
- unsigned RefCountDereference() const {
+ uint32_t RefCountDereference() const {
#if REFCOUNT_DEBUG
old_debug(0,1)("Decrementing this %p from count %u\n",this,count_);
#endif
@@ -125,10 +125,11 @@ struct RefCountable_ {
return --count_;
}
- unsigned RefCountCount() const { return count_; } // for debugging only
+ uint32_t RefCountCount() const { return count_; } // for debugging only
+ uint32_t LockCount() const { return count_; }
private:
- mutable unsigned count_;
+ mutable uint32_t count_;
};
#define RefCountable virtual RefCountable_