=== modified file 'src/AccessLogEntry.h'
--- src/AccessLogEntry.h	2014-03-30 12:00:34 +0000
+++ src/AccessLogEntry.h	2014-04-10 07:40:21 +0000
@@ -206,42 +206,41 @@
 
         char *reply;
     } headers;
 
 #if USE_ADAPTATION
     /** \brief This subclass holds general adaptation log info.
      * \todo Inner class declarations should be moved outside.
      */
     class AdaptationDetails
     {
 
     public:
         AdaptationDetails(): last_meta(NULL) {}
 
         /// image of the last ICAP response header or eCAP meta received
         char *last_meta;
     } adapt;
 #endif
 
     // Why is this a sub-class and not a set of real "private:" fields?
-    // It looks like its duplicating HTTPRequestMethod anyway!
-    // TODO: shuffle this to the relevant protocol section OR replace with request->method
+    // TODO: shuffle this to the relevant ICP/HTCP protocol section
     class Private
     {
 
     public:
         Private() : method_str(NULL) {}
 
         const char *method_str;
     } _private;
     HierarchyLogEntry hier;
     HttpReply *reply;
     HttpRequest *request; //< virgin HTTP request
     HttpRequest *adapted_request; //< HTTP request after adaptation and redirection
 
     /// key:value pairs set by squid.conf note directive and
     /// key=value pairs returned from URL rewrite/redirect helper
     NotePairs::Pointer notes;
 
 #if ICAP_CLIENT
     /** \brief This subclass holds log info for ICAP part of request
      *  \todo Inner class declarations should be moved outside

=== modified file 'src/FwdState.cc'
--- src/FwdState.cc	2014-03-31 06:57:27 +0000
+++ src/FwdState.cc	2014-04-11 02:51:52 +0000
@@ -1197,41 +1197,41 @@
     }
 #if SO_MARK && USE_LIBCAP
     serverDestinations[0]->nfmark = GetNfmarkToServer(request);
     debugs(17, 3, "fwdConnectStart: got outgoing addr " << serverDestinations[0]->local << ", tos " << int(serverDestinations[0]->tos)
            << ", netfilter mark " << serverDestinations[0]->nfmark);
 #else
     serverDestinations[0]->nfmark = 0;
     debugs(17, 3, "fwdConnectStart: got outgoing addr " << serverDestinations[0]->local << ", tos " << int(serverDestinations[0]->tos));
 #endif
 
     calls.connector = commCbCall(17,3, "fwdConnectDoneWrapper", CommConnectCbPtrFun(fwdConnectDoneWrapper, this));
     Comm::ConnOpener *cs = new Comm::ConnOpener(serverDestinations[0], calls.connector, ctimeout);
     if (host)
         cs->setHost(host);
     AsyncJob::Start(cs);
 }
 
 void
 FwdState::dispatch()
 {
-    debugs(17, 3, HERE << clientConn << ": Fetching '" << RequestMethodStr(request->method) << " " << entry->url() << "'");
+    debugs(17, 3, clientConn << ": Fetching " << request->method << ' ' << entry->url());
     /*
      * Assert that server_fd is set.  This is to guarantee that fwdState
      * is attached to something and will be deallocated when server_fd
      * is closed.
      */
     assert(Comm::IsConnOpen(serverConn));
 
     fd_note(serverConnection()->fd, entry->url());
 
     fd_table[serverConnection()->fd].noteUse(fwdPconnPool);
 
     /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
     assert(entry->ping_status != PING_WAITING);
 
     assert(entry->locked());
 
     EBIT_SET(entry->flags, ENTRY_DISPATCHED);
 
     netdbPingSite(request->GetHost());
 

=== modified file 'src/HttpRequest.cc'
--- src/HttpRequest.cc	2014-03-15 02:50:12 +0000
+++ src/HttpRequest.cc	2014-04-08 13:57:34 +0000
@@ -374,64 +374,64 @@
     return result;
 }
 
 /* swaps out request using httpRequestPack */
 void
 HttpRequest::swapOut(StoreEntry * e)
 {
     Packer p;
     assert(e);
     packerToStoreInit(&p, e);
     pack(&p);
     packerClean(&p);
 }
 
 /* packs request-line and headers, appends <crlf> terminator */
 void
 HttpRequest::pack(Packer * p)
 {
     assert(p);
     /* pack request-line */
-    packerPrintf(p, "%s " SQUIDSTRINGPH " HTTP/%d.%d\r\n",
-                 RequestMethodStr(method), SQUIDSTRINGPRINT(urlpath),
+    packerPrintf(p, SQUIDSBUFPH " " SQUIDSTRINGPH " HTTP/%d.%d\r\n",
+                 SQUIDSBUFPRINT(method.image()), SQUIDSTRINGPRINT(urlpath),
                  http_ver.major, http_ver.minor);
     /* headers */
     header.packInto(p);
     /* trailer */
     packerAppend(p, "\r\n", 2);
 }
 
 /*
  * A wrapper for debugObj()
  */
 void
 httpRequestPack(void *obj, Packer *p)
 {
     HttpRequest *request = static_cast<HttpRequest*>(obj);
     request->pack(p);
 }
 
 /* returns the length of request line + headers + crlf */
 int
 HttpRequest::prefixLen()
 {
-    return strlen(RequestMethodStr(method)) + 1 +
+    return method.image().length() + 1 +
            urlpath.size() + 1 +
            4 + 1 + 3 + 2 +
            header.len + 2;
 }
 
 /* sync this routine when you update HttpRequest struct */
 void
 HttpRequest::hdrCacheInit()
 {
     HttpMsg::hdrCacheInit();
 
     assert(!range);
     range = header.getRange();
 }
 
 #if ICAP_CLIENT
 Adaptation::Icap::History::Pointer
 HttpRequest::icapHistory() const
 {
     if (!icapHistory_) {
@@ -507,42 +507,42 @@
 {
     debugs(11, 7, HERE << "old error details: " << errType << '/' << errDetail);
     errType = ERR_NONE;
     errDetail = ERR_DETAIL_NONE;
 }
 
 const char *HttpRequest::packableURI(bool full_uri) const
 {
     if (full_uri)
         return urlCanonical((HttpRequest*)this);
 
     if (urlpath.size())
         return urlpath.termedBuf();
 
     return "/";
 }
 
 void HttpRequest::packFirstLineInto(Packer * p, bool full_uri) const
 {
     // form HTTP request-line
-    packerPrintf(p, "%s %s HTTP/%d.%d\r\n",
-                 RequestMethodStr(method),
+    packerPrintf(p, SQUIDSBUFPH " %s HTTP/%d.%d\r\n",
+                 SQUIDSBUFPRINT(method.image()),
                  packableURI(full_uri),
                  http_ver.major, http_ver.minor);
 }
 
 /*
  * Indicate whether or not we would expect an entity-body
  * along with this request
  */
 bool
 HttpRequest::expectingBody(const HttpRequestMethod& unused, int64_t& theSize) const
 {
     bool expectBody = false;
 
     /*
      * Note: Checks for message validity is in clientIsContentLengthValid().
      * this just checks if a entity-body is expected based on HTTP message syntax
      */
     if (header.chunked()) {
         expectBody = true;
         theSize = -1;

=== modified file 'src/HttpRequestMethod.cc'
--- src/HttpRequestMethod.cc	2013-12-18 00:48:33 +0000
+++ src/HttpRequestMethod.cc	2014-04-11 02:44:18 +0000
@@ -3,96 +3,87 @@
  */
 
 #include "squid.h"
 #include "HttpRequestMethod.h"
 #include "SquidConfig.h"
 #include "wordlist.h"
 
 static Http::MethodType &
 operator++ (Http::MethodType &aMethod)
 {
     int tmp = (int)aMethod;
     aMethod = (Http::MethodType)(++tmp);
     return aMethod;
 }
 
 /**
  * Construct a HttpRequestMethod from a NULL terminated string such as "GET"
  * or from a range of chars, * such as "GET" from "GETFOOBARBAZ"
  * (pass in pointer to G and pointer to F.)
  */
-HttpRequestMethod::HttpRequestMethod(char const *begin, char const *end) : theMethod (Http::METHOD_NONE)
+HttpRequestMethod::HttpRequestMethod(char const *begin, char const *end) : theMethod(Http::METHOD_NONE)
 {
     if (begin == NULL)
         return;
 
     /*
-     * This check for '%' makes sure that we don't
-     * match one of the extension method placeholders,
-     * which have the form %EXT[0-9][0-9]
-     */
-
-    if (*begin == '%')
-        return;
-
-    /*
      * if e is NULL, b must be NULL terminated and we
      * make e point to the first whitespace character
      * after b.
      */
     if (NULL == end)
         end = begin + strcspn(begin, w_space);
 
-    if (end == begin) {
-        theMethod = Http::METHOD_NONE;
+    if (end == begin)
         return;
-    }
 
+    // TODO: Optimize this linear search.
     for (++theMethod; theMethod < Http::METHOD_ENUM_END; ++theMethod) {
         // RFC 2616 section 5.1.1 - Method names are case-sensitive
         // NP: this is not a HTTP_VIOLATIONS case since there is no MUST/SHOULD involved.
-        if (0 == strncasecmp(begin, Http::MethodType_str[theMethod], end-begin)) {
+        if (0 == image().caseCmp(begin, end-begin)) {
 
             // relaxed parser allows mixed-case and corrects them on output
             if (Config.onoff.relaxed_header_parser)
                 return;
 
-            if (0 == strncmp(begin, Http::MethodType_str[theMethod], end-begin))
+            if (0 == image().cmp(begin, end-begin))
                 return;
         }
     }
 
     // if method not found and method string is not null then it is other method
     theMethod = Http::METHOD_OTHER;
-    theImage.limitInit(begin,end-begin);
+    theImage.assign(begin, end-begin);
 }
 
-char const*
+const SBuf &
 HttpRequestMethod::image() const
 {
+    static const SBuf methodOther("METHOD_OTHER");
     if (Http::METHOD_OTHER != theMethod) {
-        return Http::MethodType_str[theMethod];
+        return Http::MethodType_sb[theMethod];
     } else {
-        if (theImage.size()>0) {
-            return theImage.termedBuf();
+        if (!theImage.isEmpty()) {
+            return theImage;
         } else {
-            return "METHOD_OTHER";
+            return methodOther;
         }
     }
 }
 
 bool
 HttpRequestMethod::isHttpSafe() const
 {
     // Only a few methods are defined as safe. All others are "unsafe"
 
     // NOTE:
     // All known RFCs which register methods are listed in comments.
     // if there is one not listed which defines methods, it needs
     // checking and adding. If only to say it is known to define none.
 
     switch (theMethod) {
         // RFC 2068 - none
 
         // RFC 2616 section 9.1.1
     case Http::METHOD_GET:
     case Http::METHOD_HEAD:

=== modified file 'src/HttpRequestMethod.h'
--- src/HttpRequestMethod.h	2012-10-26 11:36:45 +0000
+++ src/HttpRequestMethod.h	2014-04-10 10:39:44 +0000
@@ -1,140 +1,125 @@
 #ifndef SQUID_HTTPREQUESTMETHOD_H
 #define SQUID_HTTPREQUESTMETHOD_H
 
 #include "http/MethodType.h"
-#include "SquidString.h"
-#include "SquidString.h"
+#include "SBuf.h"
 
 class SquidConfig;
 
 #include <iosfwd>
 
 /**
  * This class represents an HTTP Request METHOD
  * - i.e. PUT, POST, GET etc.
  * It has a runtime extension facility to allow it to
  * efficiently support new methods
  */
 class HttpRequestMethod
 {
 
 public:
 //    static void Configure(SquidConfig &Config);
 
     HttpRequestMethod() : theMethod(Http::METHOD_NONE), theImage() {}
 
     HttpRequestMethod(Http::MethodType const aMethod) : theMethod(aMethod), theImage() {}
 
     /**
      \param begin    string to convert to request method.
      \param end      end of the method string (relative to begin). Use NULL if this is unknown.
      *
      \note DO NOT give end a default (ie NULL). That will cause silent char* conversion clashes.
      */
     HttpRequestMethod(char const * begin, char const * end);
 
     HttpRequestMethod & operator = (const HttpRequestMethod& aMethod) {
         theMethod = aMethod.theMethod;
         theImage = aMethod.theImage;
         return *this;
     }
 
     HttpRequestMethod & operator = (Http::MethodType const aMethod) {
         theMethod = aMethod;
-        theImage.clean();
+        theImage.clear();
         return *this;
     }
 
     bool operator == (Http::MethodType const & aMethod) const { return theMethod == aMethod; }
     bool operator == (HttpRequestMethod const & aMethod) const {
         return theMethod == aMethod.theMethod &&
                (theMethod != Http::METHOD_OTHER || theImage == aMethod.theImage);
     }
 
     bool operator != (Http::MethodType const & aMethod) const { return theMethod != aMethod; }
     bool operator != (HttpRequestMethod const & aMethod) const {
         return !operator==(aMethod);
     }
 
     /** Iterate through all HTTP method IDs. */
     HttpRequestMethod& operator++() {
         // TODO: when this operator is used in more than one place,
         // replace it with HttpRequestMethods::Iterator API
         // XXX: this interface can create Http::METHOD_OTHER without an image
         assert(theMethod < Http::METHOD_ENUM_END);
         theMethod = (Http::MethodType)(1 + (int)theMethod);
         return *this;
     }
 
     /** Get an ID representation of the method.
      * \retval Http::METHOD_NONE   the method is unset
      * \retval Http::METHOD_OTHER  the method is not recognized and has no unique ID
      * \retval *                   the method is on of the recognized HTTP methods.
      */
     Http::MethodType id() const { return theMethod; }
 
-    /** Get a char string representation of the method. */
-    char const * image() const;
+    /** Get a string representation of the method. */
+    const SBuf &image() const;
 
     /// Whether this method is defined as a "safe" in HTTP/1.1
     /// see RFC 2616 section 9.1.1
     bool isHttpSafe() const;
 
     /// Whether this method is defined as "idempotent" in HTTP/1.1
     /// see RFC 2616 section 9.1.2
     bool isIdempotent() const;
 
     /** Whether responses to this method MAY be cached.
      * \retval false  Not cacheable.
      * \retval true   Possibly cacheable. Other details will determine.
      */
     bool respMaybeCacheable() const;
 
     /** Whether this method SHOULD (or MUST) invalidate existing cached entries.
      * Invalidation is always determined by the response
      *
      * RFC 2616 defines invalidate as either immediate purge
      * or delayed explicit revalidate all stored copies on next use.
      *
      * \retval true   SHOULD invalidate. Response details can raise this to a MUST.
      * \retval false  Other details will determine. Method is not a factor.
      */
     bool shouldInvalidate() const;
 
     /* Whether this method invalidates existing cached entries.
      * Kept for backward-compatibility. This is the old 2.x-3.2 invalidation behaviour.
      *
      * NOTE:
      *    purgesOthers differs from shouldInvalidate() in that purgesOthers() returns
      *    true on any methods the MAY invalidate (Squid opts to do so).
      *    shouldInvalidate() only returns true on methods which SHOULD invalidate.
      */
     bool purgesOthers() const;
 
 private:
-    static const char *RequestMethodStr[];
-
     Http::MethodType theMethod; ///< Method type
-    String theImage;     ///< Used for storing the Http::METHOD_OTHER only. A copy of the parsed method text.
+    SBuf theImage;     ///< Used for storing the Http::METHOD_OTHER only. A copy of the parsed method text.
 };
 
 inline std::ostream &
 operator << (std::ostream &os, HttpRequestMethod const &method)
 {
     os << method.image();
     return os;
 }
 
-inline const char*
-RequestMethodStr(const Http::MethodType m)
-{
-    return HttpRequestMethod(m).image();
-}
-
-inline const char*
-RequestMethodStr(const HttpRequestMethod& m)
-{
-    return m.image();
-}
-
 #endif /* SQUID_HTTPREQUESTMETHOD_H */

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2014-04-08 15:52:58 +0000
+++ src/Makefile.am	2014-04-09 02:40:25 +0000
@@ -807,40 +807,41 @@
 	base/libbase.la \
 	libsquid.la \
 	ip/libip.la \
 	fs/libfs.la \
 	ipc/libipc.la \
 	mgr/libmgr.la \
 	$(EPOLL_LIBS) \
 	$(MINGW_LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 
 include $(srcdir)/tests/Stub.list
 
 EXTRA_DIST = \
 	cf_gen_defines \
 	cf.data.pre \
 	cf.data.depend \
 	DiskIO/modules.sh \
 	mk-globals-c.pl \
 	mk-globals-c.awk \
+	mk-sbuf-arrays.awk \
 	mk-string-arrays.pl \
 	mk-string-arrays.awk \
 	repl_modules.sh \
 	$(STUB_SOURCE) \
 	mib.txt \
 	mime.conf.default
 
 libAIO_a_SOURCES = \
 		$(AIO_WIN32_SOURCES) \
 		DiskIO/AIO/async_io.h \
 		DiskIO/AIO/AIODiskFile.cc \
 		DiskIO/AIO/AIODiskFile.h \
 		DiskIO/AIO/AIODiskIOStrategy.cc \
 		DiskIO/AIO/AIODiskIOStrategy.h \
 		DiskIO/AIO/AIODiskIOModule.cc \
 		DiskIO/AIO/AIODiskIOModule.h
 
 libBlocking_a_SOURCES = \
 		DiskIO/Blocking/BlockingFile.cc \
 		DiskIO/Blocking/BlockingFile.h \
@@ -3787,58 +3788,62 @@
 	$(TESTSOURCES)
 tests_testConfigParser_LDADD = \
 	base/libbase.la \
 	libsquid.la \
 	ip/libip.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(REGEXLIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SSLLIB) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_testConfigParser_LDFLAGS = $(LIBADD_DL)
 tests_testConfigParser_DEPENDENCIES = \
 	$(SQUID_CPPUNIT_LA)
 	
 tests_testStatHist_SOURCES = \
 	tests/stub_cbdata.cc \
 	fatal.h \
 	tests/stub_fatal.cc \
 	tests/stub_MemBuf.cc \
+	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	StatHist.cc \
 	StatHist.h \
 	String.cc \
 	tests/stub_cache_manager.cc \
 	tests/stub_comm.cc \
 	tests/stub_debug.cc \
 	tests/stub_DelayId.cc \
 	tests/stub_HelperChildConfig.cc \
 	Mem.h \
 	tests/stub_mem.cc \
 	tests/stub_MemObject.cc \
 	mime.h \
 	tests/stub_mime.cc \
 	tests/stub_pconn.cc \
 	tests/stub_stmem.cc \
 	repl_modules.h \
 	tests/stub_store.cc \
 	tests/stub_store_stats.cc \
+	time.cc \
 	tools.h \
 	tests/stub_tools.cc \
 	tests/testMain.cc \
 	tests/testStatHist.cc \
 	tests/testStatHist.h
 nodist_tests_testStatHist_SOURCES = \
 	$(TESTSOURCES)
 tests_testStatHist_LDFLAGS = $(LIBADD_DL)
 tests_testStatHist_LDADD = \
 	base/libbase.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(COMPAT_LIB)
 tests_testStatHist_DEPENDENCIES = $(SQUID_CPPUNIT_LA)
 
 TESTS += testHeaders
 
 ## Special Universal .h dependency test script

=== modified file 'src/MemObject.cc'
--- src/MemObject.cc	2013-12-31 18:49:41 +0000
+++ src/MemObject.cc	2014-04-08 13:49:58 +0000
@@ -226,42 +226,41 @@
     }
 
     int64_t current;
 };
 
 struct StoreClientStats : public unary_function<store_client, void> {
     StoreClientStats(MemBuf *anEntry):where(anEntry),index(0) {}
 
     void operator()(store_client const &x) {
         x.dumpStats(where, index);
         ++index;
     }
 
     MemBuf *where;
     size_t index;
 };
 
 void
 MemObject::stat(MemBuf * mb) const
 {
-    mb->Printf("\t%s %s\n",
-               RequestMethodStr(method), logUri());
+    mb->Printf("\t" SQUIDSBUFPH " %s\n", SQUIDSBUFPRINT(method.image()), logUri());
     if (vary_headers)
         mb->Printf("\tvary_headers: %s\n", vary_headers);
     mb->Printf("\tinmem_lo: %" PRId64 "\n", inmem_lo);
     mb->Printf("\tinmem_hi: %" PRId64 "\n", data_hdr.endOffset());
     mb->Printf("\tswapout: %" PRId64 " bytes queued\n",
                swapout.queue_offset);
 
     if (swapout.sio.getRaw())
         mb->Printf("\tswapout: %" PRId64 " bytes written\n",
                    (int64_t) swapout.sio->offset());
 
     if (xitTable.index >= 0)
         mb->Printf("\ttransient index: %d state: %d\n",
                    xitTable.index, xitTable.io);
     if (memCache.index >= 0)
         mb->Printf("\tmem-cache index: %d state: %d offset: %" PRId64 "\n",
                    memCache.index, memCache.io, memCache.offset);
     if (object_sz >= 0)
         mb->Printf("\tobject_sz: %" PRId64 "\n", object_sz);
     if (smpCollapsed)

=== modified file 'src/SBuf.cc'
--- src/SBuf.cc	2014-04-06 07:08:04 +0000
+++ src/SBuf.cc	2014-04-14 16:53:12 +0000
@@ -360,64 +360,98 @@
     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, SBufCaseSensitive isCaseSensitive, size_type n) const
+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);
 
-    size_type byteCompareLen = min(S.length(), length());
+    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);
+
+    // recurse after finding length if unknown (including terminator byte)
+    if (n == npos)
+        return compare(s, isCaseSensitive, strlen(s)+1);
+
+    // if this SBuf is bigger than N truncate it.
+    // guaranteeing length() <= n for the following comparison
+    if (length() > n)
+        return substr(0,n).compare(s, isCaseSensitive, n);
+
+    const size_type byteCompareLen = min(n, length());
+    ++stats.compareSlow;
+    int rv = 0;
+    if (isCaseSensitive == caseSensitive) {
+        rv = strncmp(buf(), s, byteCompareLen);
+    } else {
+        rv = strncasecmp(buf(), s, byteCompareLen);
+    }
+    // BUG 1: when length() < n - buffer overruns on buf().
+    // BUG 2: when length() == strlen(s) < n, no terminator to match against in buf()
+    return rv;
+}
+
 bool
-SBuf::startsWith(const SBuf &S, SBufCaseSensitive isCaseSensitive) const
+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
     }

=== modified file 'src/SBuf.h'
--- src/SBuf.h	2014-04-06 07:08:04 +0000
+++ src/SBuf.h	2014-04-13 04:05:25 +0000
@@ -238,58 +238,71 @@
     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, SBufCaseSensitive isCaseSensitive, size_type n = npos) const;
+    int compare(const SBuf &S, const SBufCaseSensitive isCaseSensitive, const size_type n = npos) const;
 
-    /// shorthand version for compare
-    inline int cmp(const SBuf &S, 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 comparison
-    inline int caseCmp(const SBuf &S, size_type n = npos) const {
+    /// 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) 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, SBufCaseSensitive isCaseSensitive = caseSensitive) const;
+    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

=== modified file 'src/Server.cc'
--- src/Server.cc	2014-01-01 19:20:49 +0000
+++ src/Server.cc	2014-04-05 05:29:06 +0000
@@ -500,41 +500,41 @@
 
     if (absUrl != NULL) {
         safe_free(absUrl);
     }
 }
 
 // some HTTP methods should purge matching cache entries
 void
 ServerStateData::maybePurgeOthers()
 {
     // only some HTTP methods should purge matching cache entries
     if (!request->method.purgesOthers())
         return;
 
     // and probably only if the response was successful
     if (theFinalReply->sline.status() >= 400)
         return;
 
     // XXX: should we use originalRequest() here?
     const char *reqUrl = urlCanonical(request);
-    debugs(88, 5, "maybe purging due to " << RequestMethodStr(request->method) << ' ' << reqUrl);
+    debugs(88, 5, "maybe purging due to " << request->method << ' ' << reqUrl);
     purgeEntriesByUrl(request, reqUrl);
     purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_LOCATION);
     purgeEntriesByHeader(request, reqUrl, theFinalReply, HDR_CONTENT_LOCATION);
 }
 
 /// called when we have final (possibly adapted) reply headers; kids extend
 void
 ServerStateData::haveParsedReplyHeaders()
 {
     Must(theFinalReply);
     maybePurgeOthers();
 
     // adaptation may overwrite old offset computed using the virgin response
     const bool partial = theFinalReply->content_range &&
                          theFinalReply->sline.status() == Http::scPartialContent;
     currentOffset = partial ? theFinalReply->content_range->spec.offset : 0;
 }
 
 /// whether to prevent caching of an otherwise cachable response
 bool

=== modified file 'src/acl/MethodData.cc'
--- src/acl/MethodData.cc	2014-04-12 13:29:42 +0000
+++ src/acl/MethodData.cc	2014-04-14 05:10:19 +0000
@@ -57,41 +57,41 @@
 /// todo make this a pass-by-reference now that HTTPRequestMethods a full class?
 bool
 ACLMethodData::match(HttpRequestMethod toFind)
 {
     return values->findAndTune(toFind);
 }
 
 /* explicit instantiation required for some systems */
 
 /// \cond AUTODOCS_IGNORE
 template cbdata_type CbDataList<HttpRequestMethod>::CBDATA_CbDataList;
 /// \endcond
 
 SBufList
 ACLMethodData::dump() const
 {
     SBufList sl;
     CbDataList<HttpRequestMethod> *data = values;
 
     while (data != NULL) {
-        sl.push_back(SBuf(RequestMethodStr(data->element)));
+        sl.push_back(data->element.image());
         data = data->next;
     }
 
     return sl;
 }
 
 void
 ACLMethodData::parse()
 {
     CbDataList<HttpRequestMethod> **Tail;
     char *t = NULL;
 
     for (Tail = &values; *Tail; Tail = &((*Tail)->next));
     while ((t = strtokFile())) {
         if (strcmp(t, "PURGE") == 0)
             ++ThePurgeCount; // configuration code wants to know
         CbDataList<HttpRequestMethod> *q = new CbDataList<HttpRequestMethod> (HttpRequestMethod(t, NULL));
         *(Tail) = q;
         Tail = &q->next;
     }

=== modified file 'src/auth/digest/UserRequest.cc'
--- src/auth/digest/UserRequest.cc	2014-02-21 02:19:52 +0000
+++ src/auth/digest/UserRequest.cc	2014-04-10 08:10:53 +0000
@@ -85,64 +85,66 @@
     assert(digest_user != NULL);
 
     Auth::Digest::UserRequest *digest_request = this;
 
     /* do we have the HA1 */
     if (!digest_user->HA1created) {
         auth_user->credentials(Auth::Pending);
         return;
     }
 
     if (digest_request->nonce == NULL) {
         /* this isn't a nonce we issued */
         auth_user->credentials(Auth::Failed);
         return;
     }
 
     DigestCalcHA1(digest_request->algorithm, NULL, NULL, NULL,
                   authenticateDigestNonceNonceb64(digest_request->nonce),
                   digest_request->cnonce,
                   digest_user->HA1, SESSIONKEY);
+    SBuf sTmp = request->method.image();
     DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
                        digest_request->nc, digest_request->cnonce, digest_request->qop,
-                       RequestMethodStr(request->method), digest_request->uri, HA2, Response);
+                       sTmp.c_str(), digest_request->uri, HA2, Response);
 
     debugs(29, 9, "\nResponse = '" << digest_request->response << "'\nsquid is = '" << Response << "'");
 
     if (strcasecmp(digest_request->response, Response) != 0) {
         if (!digest_request->flags.helper_queried) {
             /* Query the helper in case the password has changed */
             digest_request->flags.helper_queried = true;
             auth_user->credentials(Auth::Pending);
             return;
         }
 
         if (static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->PostWorkaround && request->method != Http::METHOD_GET) {
             /* Ugly workaround for certain very broken browsers using the
              * wrong method to calculate the request-digest on POST request.
              * This should be deleted once Digest authentication becomes more
              * widespread and such broken browsers no longer are commonly
              * used.
              */
+            sTmp = HttpRequestMethod(Http::METHOD_GET).image();
             DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
                                digest_request->nc, digest_request->cnonce, digest_request->qop,
-                               RequestMethodStr(Http::METHOD_GET), digest_request->uri, HA2, Response);
+                               sTmp.c_str(), digest_request->uri, HA2, Response);
 
             if (strcasecmp(digest_request->response, Response)) {
                 auth_user->credentials(Auth::Failed);
                 digest_request->flags.invalid_password = true;
                 digest_request->setDenyMessage("Incorrect password");
                 return;
             } else {
                 const char *useragent = request->header.getStr(HDR_USER_AGENT);
 
                 static Ip::Address last_broken_addr;
                 static int seen_broken_client = 0;
 
                 if (!seen_broken_client) {
                     last_broken_addr.setNoAddr();
                     seen_broken_client = 1;
                 }
 
                 if (last_broken_addr != request->client_addr) {
                     debugs(29, DBG_IMPORTANT, "Digest POST bug detected from " <<
                            request->client_addr << " using '" <<

=== modified file 'src/cache_diff.cc'
--- src/cache_diff.cc	2012-09-01 14:38:36 +0000
+++ src/cache_diff.cc	2014-04-06 08:01:34 +0000
@@ -42,52 +42,40 @@
 #include <errno.h>
 #endif
 
 typedef struct {
     const char *name;
     hash_table *hash;
     int count;			/* #currently cached entries */
     int scanned_count;		/* #scanned entries */
     int bad_add_count;		/* #duplicate adds */
     int bad_del_count;		/* #dels with no prior add */
 } CacheIndex;
 
 typedef struct _CacheEntry {
     const cache_key *key;
 
     struct _CacheEntry *next;
     /* StoreSwapLogData s; */
     unsigned char key_arr[SQUID_MD5_DIGEST_LENGTH];
 } CacheEntry;
 
-/* copied from url.c */
-const char *RequestMethodStr[] = {
-    "NONE",
-    "GET",
-    "POST",
-    "PUT",
-    "HEAD",
-    "CONNECT",
-    "TRACE",
-    "PURGE"
-};
-
 static int cacheIndexScan(CacheIndex * idx, const char *fname, FILE * file);
 
 static CacheEntry *
 cacheEntryCreate(const StoreSwapLogData * s)
 {
     CacheEntry *e = xcalloc(1, sizeof(CacheEntry));
     assert(s);
     /* e->s = *s; */
     memcpy(e->key_arr, s->key, SQUID_MD5_DIGEST_LENGTH);
     e->key = &e->key_arr[0];
     return e;
 }
 
 static void
 cacheEntryDestroy(CacheEntry * e)
 {
     assert(e);
     xfree(e);
 }
 

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2014-03-31 06:57:27 +0000
+++ src/client_side.cc	2014-04-11 02:56:47 +0000
@@ -881,44 +881,42 @@
 
     if (bodyPipe != NULL)
         stopProducingFor(bodyPipe, false);
 
 #if USE_OPENSSL
     delete sslServerBump;
 #endif
 }
 
 /**
  * clientSetKeepaliveFlag() sets request->flags.proxyKeepalive.
  * This is the client-side persistent connection flag.  We need
  * to set this relatively early in the request processing
  * to handle hacks for broken servers and clients.
  */
 static void
 clientSetKeepaliveFlag(ClientHttpRequest * http)
 {
     HttpRequest *request = http->request;
 
-    debugs(33, 3, "clientSetKeepaliveFlag: http_ver = " <<
-           request->http_ver.major << "." << request->http_ver.minor);
-    debugs(33, 3, "clientSetKeepaliveFlag: method = " <<
-           RequestMethodStr(request->method));
+    debugs(33, 3, "http_ver = " << request->http_ver);
+    debugs(33, 3, "method = " << request->method);
 
     // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
     request->flags.proxyKeepalive = request->persistent();
 }
 
 static int
 clientIsContentLengthValid(HttpRequest * r)
 {
     switch (r->method.id()) {
 
     case Http::METHOD_GET:
 
     case Http::METHOD_HEAD:
         /* We do not want to see a request entity on GET/HEAD requests */
         return (r->content_length <= 0 || Config.onoff.request_entities);
 
     default:
         /* For other types of requests we don't care */
         return 1;
     }

=== modified file 'src/client_side_reply.cc'
--- src/client_side_reply.cc	2014-03-31 06:57:27 +0000
+++ src/client_side_reply.cc	2014-04-11 02:53:10 +0000
@@ -614,41 +614,41 @@
         else
 #endif
             if (e->mem_status == IN_MEMORY)
                 http->logType = LOG_TCP_MEM_HIT;
             else if (Config.onoff.offline)
                 http->logType = LOG_TCP_OFFLINE_HIT;
 
         sendMoreData(result);
     }
 }
 
 /**
  * Prepare to fetch the object as it's a cache miss of some kind.
  */
 void
 clientReplyContext::processMiss()
 {
     char *url = http->uri;
     HttpRequest *r = http->request;
     ErrorState *err = NULL;
-    debugs(88, 4, "clientProcessMiss: '" << RequestMethodStr(r->method) << " " << url << "'");
+    debugs(88, 4, r->method << ' ' << url);
 
     /**
      * We might have a left-over StoreEntry from a failed cache hit
      * or IMS request.
      */
     if (http->storeEntry()) {
         if (EBIT_TEST(http->storeEntry()->flags, ENTRY_SPECIAL)) {
             debugs(88, DBG_CRITICAL, "clientProcessMiss: miss on a special object (" << url << ").");
             debugs(88, DBG_CRITICAL, "\tlog_type = " << LogTags_str[http->logType]);
             http->storeEntry()->dump(1);
         }
 
         removeClientStoreReference(&sc, http);
     }
 
     /** Check if its a PURGE request to be actioned. */
     if (r->method == Http::METHOD_PURGE) {
         purgeRequest();
         return;
     }
@@ -691,42 +691,41 @@
         if (http->flags.internal)
             r->protocol = AnyP::PROTO_INTERNAL;
 
         assert(r->clientConnectionManager == http->getConn());
 
         /** Start forwarding to get the new object from network */
         Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL;
         FwdState::Start(conn, http->storeEntry(), r, http->al);
     }
 }
 
 /**
  * client issued a request with an only-if-cached cache-control directive;
  * we did not find a cached object that can be returned without
  *     contacting other servers;
  * respond with a 504 (Gateway Timeout) as suggested in [RFC 2068]
  */
 void
 clientReplyContext::processOnlyIfCachedMiss()
 {
-    debugs(88, 4, "clientProcessOnlyIfCachedMiss: '" <<
-           RequestMethodStr(http->request->method) << " " << http->uri << "'");
+    debugs(88, 4, http->request->method << ' ' << http->uri);
     http->al->http.code = Http::scGatewayTimeout;
     ErrorState *err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, Http::scGatewayTimeout, NULL,
                                        http->getConn()->clientConnection->remote, http->request);
     removeClientStoreReference(&sc, http);
     startError(err);
 }
 
 /// process conditional request from client
 void
 clientReplyContext::processConditional(StoreIOBuffer &result)
 {
     StoreEntry *const e = http->storeEntry();
 
     if (e->getReply()->sline.status() != Http::scOkay) {
         debugs(88, 4, "clientReplyContext::processConditional: Reply code " <<
                e->getReply()->sline.status() << " != 200");
         http->logType = LOG_TCP_MISS;
         processMiss();
         return;
     }
@@ -818,41 +817,41 @@
     // getPublicByRequestMethod() dance?
     StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_GET);
 }
 
 // Purges all entries with a given url
 // TODO: move to SideAgent parent, when we have one
 /*
  * We probably cannot purge Vary-affected responses because their MD5
  * keys depend on vary headers.
  */
 void
 purgeEntriesByUrl(HttpRequest * req, const char *url)
 {
 #if USE_HTCP
     bool get_or_head_sent = false;
 #endif
 
     for (HttpRequestMethod m(Http::METHOD_NONE); m != Http::METHOD_ENUM_END; ++m) {
         if (m.respMaybeCacheable()) {
             if (StoreEntry *entry = storeGetPublic(url, m)) {
-                debugs(88, 5, "purging " << *entry << ' ' << RequestMethodStr(m) << ' ' << url);
+                debugs(88, 5, "purging " << *entry << ' ' << m << ' ' << url);
 #if USE_HTCP
                 neighborsHtcpClear(entry, url, req, m, HTCP_CLR_INVALIDATION);
                 if (m == Http::METHOD_GET || m == Http::METHOD_HEAD) {
                     get_or_head_sent = true;
                 }
 #endif
                 entry->release();
             }
         }
     }
 
 #if USE_HTCP
     if (!get_or_head_sent) {
         neighborsHtcpClear(NULL, url, req, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_INVALIDATION);
     }
 #endif
 }
 
 void
 clientReplyContext::purgeAllCached()
@@ -1978,43 +1977,43 @@
     }
 
     /** Process http_reply_access lists */
     ACLFilledChecklist *replyChecklist =
         clientAclChecklistCreate(Config.accessList.reply, http);
     replyChecklist->reply = reply;
     HTTPMSGLOCK(replyChecklist->reply);
     replyChecklist->nonBlockingCheck(ProcessReplyAccessResult, this);
 }
 
 void
 clientReplyContext::ProcessReplyAccessResult(allow_t rv, void *voidMe)
 {
     clientReplyContext *me = static_cast<clientReplyContext *>(voidMe);
     me->processReplyAccessResult(rv);
 }
 
 void
 clientReplyContext::processReplyAccessResult(const allow_t &accessAllowed)
 {
-    debugs(88, 2, "The reply for " << RequestMethodStr(http->request->method)
-           << " " << http->uri << " is " << accessAllowed << ", because it matched '"
-           << (AclMatchedName ? AclMatchedName : "NO ACL's") << "'" );
+    debugs(88, 2, "The reply for " << http->request->method
+           << ' ' << http->uri << " is " << accessAllowed << ", because it matched "
+           << (AclMatchedName ? AclMatchedName : "NO ACL's"));
 
     if (accessAllowed != ACCESS_ALLOWED) {
         ErrorState *err;
         err_type page_id;
         page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName, 1);
 
         http->logType = LOG_TCP_DENIED_REPLY;
 
         if (page_id == ERR_NONE)
             page_id = ERR_ACCESS_DENIED;
 
         Ip::Address tmp_noaddr;
         tmp_noaddr.setNoAddr();
         err = clientBuildError(page_id, Http::scForbidden, NULL,
                                http->getConn() != NULL ? http->getConn()->clientConnection->remote : tmp_noaddr,
                                http->request);
 
         removeClientStoreReference(&sc, http);
 
         HTTPMSGUNLOCK(reply);

=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2014-03-31 06:57:27 +0000
+++ src/client_side_request.cc	2014-04-11 02:54:14 +0000
@@ -741,42 +741,41 @@
     }
 }
 
 void
 clientAccessCheckDoneWrapper(allow_t answer, void *data)
 {
     ClientRequestContext *calloutContext = (ClientRequestContext *) data;
 
     if (!calloutContext->httpStateIsValid())
         return;
 
     calloutContext->clientAccessCheckDone(answer);
 }
 
 void
 ClientRequestContext::clientAccessCheckDone(const allow_t &answer)
 {
     acl_checklist = NULL;
     err_type page_id;
     Http::StatusCode status;
-    debugs(85, 2, "The request " <<
-           RequestMethodStr(http->request->method) << " " <<
+    debugs(85, 2, "The request " << http->request->method << ' ' <<
            http->uri << " is " << answer <<
            "; last ACL checked: " << (AclMatchedName ? AclMatchedName : "[none]"));
 
 #if USE_AUTH
     char const *proxy_auth_msg = "<null>";
     if (http->getConn() != NULL && http->getConn()->getAuth() != NULL)
         proxy_auth_msg = http->getConn()->getAuth()->denyMessage("<null>");
     else if (http->request->auth_user_request != NULL)
         proxy_auth_msg = http->request->auth_user_request->denyMessage("<null>");
 #endif
 
     if (answer != ACCESS_ALLOWED) {
         // auth has a grace period where credentials can be expired but okay not to challenge.
 
         /* Send an auth challenge or error */
         // XXX: do we still need aclIsProxyAuth() ?
         bool auth_challenge = (answer == ACCESS_AUTH_REQUIRED || aclIsProxyAuth(AclMatchedName));
         debugs(85, 5, "Access Denied: " << http->uri);
         debugs(85, 5, "AclMatchedName = " << (AclMatchedName ? AclMatchedName : "<null>"));
 #if USE_AUTH
@@ -1499,41 +1498,41 @@
     if (!httpStateIsValid())
         return;
 
     const Ssl::BumpMode bumpMode = answer == ACCESS_ALLOWED ?
                                    static_cast<Ssl::BumpMode>(answer.kind) : Ssl::bumpNone;
     http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed
     http->al->ssl.bumpMode = bumpMode; // for logging
 
     http->doCallouts();
 }
 #endif
 
 /*
  * Identify requests that do not go through the store and client side stream
  * and forward them to the appropriate location. All other requests, request
  * them.
  */
 void
 ClientHttpRequest::processRequest()
 {
-    debugs(85, 4, "clientProcessRequest: " << RequestMethodStr(request->method) << " '" << uri << "'");
+    debugs(85, 4, request->method << ' ' << uri);
 
     if (request->method == Http::METHOD_CONNECT && !redirect.status) {
 #if USE_OPENSSL
         if (sslBumpNeeded()) {
             sslBumpStart();
             return;
         }
 #endif
         logType = LOG_TCP_MISS;
         getConn()->stopReading(); // tunnels read for themselves
         tunnelStart(this, &out.size, &al->http.code, al);
         return;
     }
 
     httpStart();
 }
 
 void
 ClientHttpRequest::httpStart()
 {

=== modified file 'src/errorpage.cc'
--- src/errorpage.cc	2014-03-31 06:57:27 +0000
+++ src/errorpage.cc	2014-04-10 07:08:08 +0000
@@ -747,42 +747,42 @@
     /* - IP stuff */
     str.Printf("ClientIP: %s\r\n", src_addr.toStr(ntoabuf,MAX_IPSTRLEN));
 
     if (request && request->hier.host[0] != '\0') {
         str.Printf("ServerIP: %s\r\n", request->hier.host);
     }
 
     str.Printf("\r\n");
     /* - HTTP stuff */
     str.Printf("HTTP Request:\r\n");
 
     if (NULL != request) {
         Packer pck;
         String urlpath_or_slash;
 
         if (request->urlpath.size() != 0)
             urlpath_or_slash = request->urlpath;
         else
             urlpath_or_slash = "/";
 
-        str.Printf("%s " SQUIDSTRINGPH " %s/%d.%d\n",
-                   RequestMethodStr(request->method),
+        str.Printf(SQUIDSBUFPH " " SQUIDSTRINGPH " %s/%d.%d\n",
+                   SQUIDSBUFPRINT(request->method.image()),
                    SQUIDSTRINGPRINT(urlpath_or_slash),
                    AnyP::ProtocolType_str[request->http_ver.protocol],
                    request->http_ver.major, request->http_ver.minor);
         packerToMemInit(&pck, &str);
         request->header.packInto(&pck);
         packerClean(&pck);
     }
 
     str.Printf("\r\n");
     /* - FTP stuff */
 
     if (ftp.request) {
         str.Printf("FTP Request: %s\r\n", ftp.request);
         str.Printf("FTP Reply: %s\r\n", (ftp.reply? ftp.reply:"[none]"));
         str.Printf("FTP Msg: ");
         wordlistCat(ftp.server_msg, &str);
         str.Printf("\r\n");
     }
 
     str.Printf("\r\n");
@@ -923,85 +923,86 @@
 
     case 'L':
         if (building_deny_info_url) break;
         if (Config.errHtmlText) {
             mb.Printf("%s", Config.errHtmlText);
             do_quote = 0;
         } else
             p = "[not available]";
         break;
 
     case 'm':
         if (building_deny_info_url) break;
 #if USE_AUTH
         p = auth_user_request->denyMessage("[not available]");
 #else
         p = "-";
 #endif
         break;
 
     case 'M':
-        if (request)
-            p = RequestMethodStr(request->method);
-        else if (!building_deny_info_url)
-            p= "[unknown method]";
+        if (request) {
+           const SBuf &m = request->method.image();
+           mb.append(m.rawContent(), m.length());
+        } else if (!building_deny_info_url)
+            p = "[unknown method]";
         break;
 
     case 'o':
         p = request ? request->extacl_message.termedBuf() : external_acl_message;
         if (!p && !building_deny_info_url)
             p = "[not available]";
         break;
 
     case 'p':
         if (request) {
             mb.Printf("%d", (int) request->port);
         } else if (!building_deny_info_url) {
             p = "[unknown port]";
         }
         break;
 
     case 'P':
         if (request) {
             p = AnyP::ProtocolType_str[request->protocol];
         } else if (!building_deny_info_url) {
             p = "[unknown protocol]";
         }
         break;
 
     case 'R':
         if (building_deny_info_url) {
             p = (request->urlpath.size() != 0 ? request->urlpath.termedBuf() : "/");
             no_urlescape = 1;
             break;
         }
         if (NULL != request) {
             Packer pck;
             String urlpath_or_slash;
 
             if (request->urlpath.size() != 0)
                 urlpath_or_slash = request->urlpath;
             else
                 urlpath_or_slash = "/";
 
-            mb.Printf("%s " SQUIDSTRINGPH " %s/%d.%d\n",
-                      RequestMethodStr(request->method),
+            mb.Printf(SQUIDSBUFPH " " SQUIDSTRINGPH " %s/%d.%d\n",
+                      SQUIDSBUFPRINT(request->method.image()),
                       SQUIDSTRINGPRINT(urlpath_or_slash),
                       AnyP::ProtocolType_str[request->http_ver.protocol],
                       request->http_ver.major, request->http_ver.minor);
             packerToMemInit(&pck, &mb);
             request->header.packInto(&pck, true); //hide authorization data
             packerClean(&pck);
         } else if (request_hdrs) {
             p = request_hdrs;
         } else {
             p = "[no request]";
         }
         break;
 
     case 's':
         /* for backward compat we make %s show the full URL. Drop this in some future release. */
         if (building_deny_info_url) {
             p = request ? urlCanonical(request) : url;
             debugs(0, DBG_CRITICAL, "WARNING: deny_info now accepts coded tags. Use %u to get the full URL instead of %s");
         } else
             p = visible_appname_string;

=== modified file 'src/external_acl.cc'
--- src/external_acl.cc	2014-04-12 09:11:20 +0000
+++ src/external_acl.cc	2014-04-14 05:03:10 +0000
@@ -1041,41 +1041,45 @@
             break;
 
         case _external_acl_format::EXT_ACL_DST:
             str = request->GetHost();
             break;
 
         case _external_acl_format::EXT_ACL_PROTO:
             str = AnyP::ProtocolType_str[request->protocol];
             break;
 
         case _external_acl_format::EXT_ACL_PORT:
             snprintf(buf, sizeof(buf), "%d", request->port);
             str = buf;
             break;
 
         case _external_acl_format::EXT_ACL_PATH:
             str = request->urlpath.termedBuf();
             break;
 
         case _external_acl_format::EXT_ACL_METHOD:
-            str = RequestMethodStr(request->method);
+            {
+                const SBuf &s = request->method.image();
+                sb.append(s.rawContent(), s.length());
+            }
+            str = sb.termedBuf();
             break;
 
         case _external_acl_format::EXT_ACL_HEADER_REQUEST:
             sb = request->header.getByName(format->header);
             str = sb.termedBuf();
             break;
 
         case _external_acl_format::EXT_ACL_HEADER_REQUEST_ID:
             sb = request->header.getStrOrList(format->header_id);
             str = sb.termedBuf();
             break;
 
         case _external_acl_format::EXT_ACL_HEADER_REQUEST_MEMBER:
             sb = request->header.getByNameListMember(format->header, format->member, format->separator);
             str = sb.termedBuf();
             break;
 
         case _external_acl_format::EXT_ACL_HEADER_REQUEST_ID_MEMBER:
             sb = request->header.getListMember(format->header_id, format->member, format->separator);
             str = sb.termedBuf();

=== modified file 'src/format/Format.cc'
--- src/format/Format.cc	2014-03-30 12:00:34 +0000
+++ src/format/Format.cc	2014-04-10 08:00:37 +0000
@@ -899,92 +899,103 @@
                         out = tmp;
                     }
                 }
             break;
 
         case LFT_SQUID_HIERARCHY:
             if (al->hier.ping.timedout)
                 mb.append("TIMEOUT_", 8);
 
             out = hier_code_str[al->hier.code];
 
             break;
 
         case LFT_MIME_TYPE:
             out = al->http.content_type;
 
             break;
 
         case LFT_CLIENT_REQ_METHOD:
             if (al->request) {
-                out = al->request->method.image();
+                const SBuf &s = al->request->method.image();
+                sb.append(s.rawContent(), s.length());
+                out = sb.termedBuf();
                 quote = 1;
             }
             break;
 
         case LFT_CLIENT_REQ_URI:
             // original client URI
             if (al->request) {
                 out = urlCanonical(al->request);
                 quote = 1;
             }
             break;
 
         case LFT_CLIENT_REQ_URLDOMAIN:
             if (al->request) {
                 out = al->request->GetHost();
                 quote = 1;
             }
             break;
 
         case LFT_REQUEST_URLPATH_OLD_31:
         case LFT_CLIENT_REQ_URLPATH:
             if (al->request) {
                 out = al->request->urlpath.termedBuf();
                 quote = 1;
             }
             break;
 
         case LFT_CLIENT_REQ_VERSION:
             if (al->request) {
                 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor);
                 out = tmp;
             }
             break;
 
         case LFT_REQUEST_METHOD:
-            out = al->_private.method_str;
+            if (al->_private.method_str) // ICP, HTCP method code
+                out = al->_private.method_str;
+            else {
+                const SBuf &s = al->http.method.image();
+                sb.append(s.rawContent(), s.length());
+                out = sb.termedBuf();
+                quote = 1;
+            }
             break;
 
         case LFT_REQUEST_URI:
             out = al->url;
             break;
 
         case LFT_REQUEST_VERSION_OLD_2X:
         case LFT_REQUEST_VERSION:
             snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
             out = tmp;
             break;
 
         case LFT_SERVER_REQ_METHOD:
             if (al->adapted_request) {
-                out = al->adapted_request->method.image();
+                const SBuf &s = al->adapted_request->method.image();
+                sb.append(s.rawContent(), s.length());
+                out = sb.termedBuf();
                 quote = 1;
             }
             break;
 
         case LFT_SERVER_REQ_URI:
             // adapted request URI sent to server/peer
             if (al->adapted_request) {
                 out = urlCanonical(al->adapted_request);
                 quote = 1;
             }
             break;
 
         case LFT_SERVER_REQ_URLPATH:
             if (al->adapted_request) {
                 out = al->adapted_request->urlpath.termedBuf();
                 quote = 1;
             }
             break;
 
         case LFT_SERVER_REQ_VERSION:

=== modified file 'src/htcp.cc'
--- src/htcp.cc	2013-10-25 00:13:46 +0000
+++ src/htcp.cc	2014-04-10 10:15:59 +0000
@@ -151,41 +151,41 @@
 struct _htcpAuthHeader {
     uint16_t length;
     time_t sig_time;
     time_t sig_expire;
     Countstr key_name;
     Countstr signature;
 };
 
 class htcpSpecifier : public StoreClient
 {
 
 public:
     MEMPROXY_CLASS(htcpSpecifier);
 
     void created (StoreEntry *newEntry);
     void checkHit();
     void checkedHit(StoreEntry *e);
 
     void setFrom(Ip::Address &from);
     void setDataHeader(htcpDataHeader *);
-    char *method;
+    const char *method;
     char *uri;
     char *version;
     char *req_hdrs;
     HttpRequest *request;
 
 private:
     HttpRequest *checkHitRequest;
 
     Ip::Address from; // was a ptr. return to such IFF needed. otherwise copy should do.
     htcpDataHeader *dhdr;
 };
 
 MEMPROXY_CLASS_INLINE(htcpSpecifier);
 
 struct _htcpDetail {
     char *resp_hdrs;
     char *entity_hdrs;
     char *cache_hdrs;
 };
 
@@ -1560,41 +1560,42 @@
     ssize_t pktlen;
     char vbuf[32];
     htcpStuff stuff;
     HttpHeader hdr(hoRequest);
     Packer pa;
     MemBuf mb;
     HttpStateFlags flags;
 
     if (!Comm::IsConnOpen(htcpIncomingConn))
         return 0;
 
     old_squid_format = p->options.htcp_oldsquid;
     memset(&flags, '\0', sizeof(flags));
     snprintf(vbuf, sizeof(vbuf), "%d/%d",
              req->http_ver.major, req->http_ver.minor);
     stuff.op = HTCP_TST;
     stuff.rr = RR_REQUEST;
     stuff.f1 = 1;
     stuff.response = 0;
     stuff.msg_id = ++msg_id_counter;
-    stuff.S.method = (char *) RequestMethodStr(req->method);
+    SBuf sb = req->method.image();
+    stuff.S.method = sb.c_str();
     stuff.S.uri = (char *) e->url();
     stuff.S.version = vbuf;
     HttpStateData::httpBuildRequestHeader(req, e, NULL, &hdr, flags);
     mb.init();
     packerToMemInit(&pa, &mb);
     hdr.packInto(&pa);
     hdr.clean();
     packerClean(&pa);
     stuff.S.req_hdrs = mb.buf;
     pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
     mb.clean();
     if (!pktlen) {
         debugs(31, 3, "htcpQuery: htcpBuildPacket() failed");
         return -1;
     }
 
     htcpSend(pkt, (int) pktlen, p->in_addr);
 
     queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id;
     save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
@@ -1623,41 +1624,42 @@
     if (!Comm::IsConnOpen(htcpIncomingConn))
         return;
 
     old_squid_format = p->options.htcp_oldsquid;
     memset(&flags, '\0', sizeof(flags));
     snprintf(vbuf, sizeof(vbuf), "%d/%d",
              req->http_ver.major, req->http_ver.minor);
     stuff.op = HTCP_CLR;
     stuff.rr = RR_REQUEST;
     stuff.f1 = 0;
     stuff.response = 0;
     stuff.msg_id = ++msg_id_counter;
     switch (reason) {
     case HTCP_CLR_INVALIDATION:
         stuff.reason = 1;
         break;
     default:
         stuff.reason = 0;
         break;
     }
-    stuff.S.method = (char *) RequestMethodStr(req->method);
+    SBuf sb = req->method.image();
+    stuff.S.method = sb.c_str();
     if (e == NULL || e->mem_obj == NULL) {
         if (uri == NULL) {
             return;
         }
         stuff.S.uri = xstrdup(uri);
     } else {
         stuff.S.uri = (char *) e->url();
     }
     stuff.S.version = vbuf;
     if (reason != HTCP_CLR_INVALIDATION) {
         HttpStateData::httpBuildRequestHeader(req, e, NULL, &hdr, flags);
         mb.init();
         packerToMemInit(&pa, &mb);
         hdr.packInto(&pa);
         hdr.clean();
         packerClean(&pa);
         stuff.S.req_hdrs = mb.buf;
     } else {
         stuff.S.req_hdrs = NULL;
     }

=== modified file 'src/http.cc'
--- src/http.cc	2014-03-31 06:57:27 +0000
+++ src/http.cc	2014-04-09 16:10:02 +0000
@@ -1029,41 +1029,41 @@
 {
     const HttpReply *rep = virginReply();
     /** \par
      * If the reply wants to close the connection, it takes precedence */
 
     if (httpHeaderHasConnDir(&rep->header, "close"))
         return COMPLETE_NONPERSISTENT_MSG;
 
     /** \par
      * If we didn't send a keep-alive request header, then this
      * can not be a persistent connection.
      */
     if (!flags.keepalive)
         return COMPLETE_NONPERSISTENT_MSG;
 
     /** \par
      * If we haven't sent the whole request then this can not be a persistent
      * connection.
      */
     if (!flags.request_sent) {
-        debugs(11, 2, "statusIfComplete: Request not yet fully sent \"" << RequestMethodStr(request->method) << " " << entry->url() << "\"" );
+        debugs(11, 2, "Request not yet fully sent \"" << request->method << ' ' << entry->url() << '\"' );
         return COMPLETE_NONPERSISTENT_MSG;
     }
 
     /** \par
      * What does the reply have to say about keep-alive?
      */
     /**
      \bug XXX BUG?
      * If the origin server (HTTP/1.0) does not send a keep-alive
      * header, but keeps the connection open anyway, what happens?
      * We'll return here and http.c waits for an EOF before changing
      * store_status to STORE_OK.   Combine this with ENTRY_FWD_HDR_WAIT
      * and an error status code, and we might have to wait until
      * the server times out the socket.
      */
     if (!rep->keep_alive)
         return COMPLETE_NONPERSISTENT_MSG;
 
     return COMPLETE_PERSISTENT_MSG;
 }
@@ -2100,42 +2100,42 @@
 }
 
 /* build request prefix and append it to a given MemBuf;
  * return the length of the prefix */
 mb_size_t
 HttpStateData::buildRequestPrefix(MemBuf * mb)
 {
     const int offset = mb->size;
     /* Uses a local httpver variable to print the HTTP/1.1 label
      * since the HttpRequest may have an older version label.
      * XXX: This could create protocol bugs as the headers sent and
      * flow control should all be based on the HttpRequest version
      * not the one we are sending. Needs checking.
      */
     Http::ProtocolVersion httpver(1,1);
     const char * url;
     if (_peer && !_peer->options.originserver)
         url = urlCanonical(request);
     else
         url = request->urlpath.termedBuf();
-    mb->Printf("%s %s %s/%d.%d\r\n",
-               RequestMethodStr(request->method),
+    mb->Printf(SQUIDSBUFPH " %s %s/%d.%d\r\n",
+               SQUIDSBUFPRINT(request->method.image()),
                url && *url ? url : "/",
                AnyP::ProtocolType_str[httpver.protocol],
                httpver.major,httpver.minor);
     /* build and pack headers */
     {
         HttpHeader hdr(hoRequest);
         Packer p;
         httpBuildRequestHeader(request, entry, fwd->al, &hdr, flags);
 
         if (request->flags.pinned && request->flags.connectionAuth)
             request->flags.authSent = true;
         else if (hdr.has(HDR_AUTHORIZATION))
             request->flags.authSent = true;
 
         packerToMemInit(&p, mb);
         hdr.packInto(&p);
         hdr.clean();
         packerClean(&p);
     }
     /* append header terminator */
@@ -2252,41 +2252,41 @@
 
     buf.Printf("%x\r\n", static_cast<unsigned int>(rawDataSize));
     buf.append(raw.content(), rawDataSize);
     buf.Printf("\r\n");
 
     Must(rawDataSize > 0); // we did not accidently created last-chunk above
 
     // Do not send last-chunk unless we successfully received everything
     if (receivedWholeRequestBody) {
         Must(!flags.sentLastChunk);
         flags.sentLastChunk = true;
         buf.append("0\r\n\r\n", 5);
     }
 
     return true;
 }
 
 void
 httpStart(FwdState *fwd)
 {
-    debugs(11, 3, "httpStart: \"" << RequestMethodStr(fwd->request->method) << " " << fwd->entry->url() << "\"" );
+    debugs(11, 3, '\"' << fwd->request->method << ' ' << fwd->entry->url() << '\"');
     AsyncJob::Start(new HttpStateData(fwd));
 }
 
 void
 HttpStateData::start()
 {
     if (!sendRequest()) {
         debugs(11, 3, "httpStart: aborted");
         mustStop("HttpStateData::start failed");
         return;
     }
 
     ++ statCounter.server.all.requests;
     ++ statCounter.server.http.requests;
 
     /*
      * We used to set the read timeout here, but not any more.
      * Now its set in httpSendComplete() after the full request,
      * including request body, has been written to the server.
      */

=== modified file 'src/http/Makefile.am'
--- src/http/Makefile.am	2013-03-18 04:55:51 +0000
+++ src/http/Makefile.am	2014-04-09 16:39:45 +0000
@@ -1,19 +1,19 @@
 include $(top_srcdir)/src/Common.am
 include $(top_srcdir)/src/TestHeaders.am
 
 noinst_LTLIBRARIES = libsquid-http.la
 
 libsquid_http_la_SOURCES = \
 	MethodType.cc \
 	MethodType.h \
 	ProtocolVersion.h \
 	StatusCode.cc \
 	StatusCode.h \
 	StatusLine.cc \
 	StatusLine.h
 
 MethodType.cc: MethodType.h $(top_srcdir)/src/mk-string-arrays.awk
-	($(AWK) -f $(top_srcdir)/src/mk-string-arrays.awk < $(srcdir)/MethodType.h | \
+	($(AWK) -f $(top_srcdir)/src/mk-string-arrays.awk sbuf=1 < $(srcdir)/MethodType.h | \
 		sed -e 's%METHOD_%%' -e 's%_C%-C%' >$@) || ($(RM) -f $@ && exit 1)
 
 CLEANFILES += MethodType.cc

=== modified file 'src/http/MethodType.h'
--- src/http/MethodType.h	2014-03-31 10:28:35 +0000
+++ src/http/MethodType.h	2014-04-09 15:55:03 +0000
@@ -1,49 +1,51 @@
 #ifndef SQUID_SRC_HTTP_METHODTYPE_H
 #define SQUID_SRC_HTTP_METHODTYPE_H
 
+#include "SBuf.h"
+
 namespace Http
 {
 
 /*
  * The IANA registry for HTTP status codes can be found at:
  * http://www.iana.org/assignments/http-methods/http-methods.xhtml
  */
 typedef enum _method_t {
     METHOD_NONE = 0,
 
-#if NO_SPECIAL_HANDLING
-    // RFC 2068
-    METHOD_LINK,
-    METHOD_UNLINK,
-#endif
-
     // RFC 2616 (HTTP)
     METHOD_GET,
     METHOD_POST,
     METHOD_PUT,
     METHOD_HEAD,
     METHOD_CONNECT,
     METHOD_TRACE,
     METHOD_OPTIONS,
     METHOD_DELETE,
 
+#if NO_SPECIAL_HANDLING
+    // RFC 2068
+    METHOD_LINK,
+    METHOD_UNLINK,
+#endif
+
     // RFC 3253
     METHOD_CHECKOUT,
     METHOD_CHECKIN,
     METHOD_UNCHECKOUT,
     METHOD_MKWORKSPACE,
     METHOD_VERSION_CONTROL,
     METHOD_REPORT,
     METHOD_UPDATE,
     METHOD_LABEL,
     METHOD_MERGE,
     METHOD_BASELINE_CONTROL,
     METHOD_MKACTIVITY,
 
 #if NO_SPECIAL_HANDLING
     // RFC 3648
     METHOD_ORDERPATCH,
 
     // RFC 3744
     METHOD_ACL,
 
@@ -66,31 +68,31 @@
 
     // RFC 5323
     METHOD_SEARCH,
 
 #if NO_SPECIAL_HANDLING
     // RFC 5789
     METHOD_PATCH,
 
     // RFC 5842
     METHOD_BIND,
     METHOD_REBIND,
     METHOD_UNBIND,
 #endif
 
     // Squid extension methods
     METHOD_PURGE,
     METHOD_OTHER,
     METHOD_ENUM_END  // MUST be last, (yuck) this is used as an array-initialization index constant!
 } MethodType;
 
-extern const char *MethodType_str[];
+extern const SBuf MethodType_sb[];
 
-inline const char*
+inline const SBuf &
 MethodStr(const MethodType m)
 {
-    return MethodType_str[m];
+    return MethodType_sb[m];
 }
 
 }; // namespace Http
 
 #endif /* SQUID_SRC_HTTP_METHODTYPE_H */

=== modified file 'src/log/FormatHttpdCombined.cc'
--- src/log/FormatHttpdCombined.cc	2013-11-11 12:09:44 +0000
+++ src/log/FormatHttpdCombined.cc	2014-04-10 07:52:59 +0000
@@ -50,46 +50,52 @@
     const char *agent = NULL;
 
     if (al->request) {
 #if USE_AUTH
         if (al->request->auth_user_request != NULL)
             user_auth = ::Format::QuoteUrlEncodeUsername(al->request->auth_user_request->username());
 #endif
         referer = al->request->header.getStr(HDR_REFERER);
         agent = al->request->header.getStr(HDR_USER_AGENT);
     }
 
     if (!referer || *referer == '\0')
         referer = "-";
 
     if (!agent || *agent == '\0')
         agent = "-";
 
     char clientip[MAX_IPSTRLEN];
     al->getLogClientIp(clientip, MAX_IPSTRLEN);
 
-    logfilePrintf(logfile, "%s %s %s [%s] \"%s %s %s/%d.%d\" %d %" PRId64 " \"%s\" \"%s\" %s%s:%s%s",
+    static SBuf method;
+    if (al->_private.method_str)
+        method.assign(al->_private.method_str);
+    else
+        method = al->http.method.image();
+
+    logfilePrintf(logfile, "%s %s %s [%s] \"" SQUIDSBUFPH " %s %s/%d.%d\" %d %" PRId64 " \"%s\" \"%s\" %s%s:%s%s",
                   clientip,
                   user_ident ? user_ident : dash_str,
                   user_auth ? user_auth : dash_str,
                   Time::FormatHttpd(squid_curtime),
-                  al->_private.method_str,
+                  SQUIDSBUFPRINT(method),
                   al->url,
                   AnyP::ProtocolType_str[al->http.version.protocol],
                   al->http.version.major, al->http.version.minor,
                   al->http.code,
                   al->http.clientReplySz.messageTotal(),
                   referer,
                   agent,
                   LogTags_str[al->cache.code],
                   al->http.statusSfx(),
                   hier_code_str[al->hier.code],
                   (Config.onoff.log_mime_hdrs?"":"\n"));
 
     safe_free(user_ident);
     safe_free(user_auth);
 
     if (Config.onoff.log_mime_hdrs) {
         char *ereq = ::Format::QuoteMimeBlob(al->headers.request);
         char *erep = ::Format::QuoteMimeBlob(al->headers.reply);
         logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
         safe_free(ereq);

=== modified file 'src/log/FormatHttpdCommon.cc'
--- src/log/FormatHttpdCommon.cc	2013-11-11 12:09:44 +0000
+++ src/log/FormatHttpdCommon.cc	2014-04-10 07:53:06 +0000
@@ -37,46 +37,52 @@
 #include "globals.h"
 #include "HttpRequest.h"
 #include "log/File.h"
 #include "log/Formats.h"
 #include "SquidConfig.h"
 #include "SquidTime.h"
 
 void
 Log::Format::HttpdCommon(const AccessLogEntry::Pointer &al, Logfile * logfile)
 {
     const char *user_auth = NULL;
 #if USE_AUTH
     if (al->request && al->request->auth_user_request != NULL)
         user_auth = ::Format::QuoteUrlEncodeUsername(al->request->auth_user_request->username());
 #endif
     const char *user_ident = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931);
 
     char clientip[MAX_IPSTRLEN];
     al->getLogClientIp(clientip, MAX_IPSTRLEN);
 
-    logfilePrintf(logfile, "%s %s %s [%s] \"%s %s %s/%d.%d\" %d %" PRId64 " %s%s:%s%s",
+    static SBuf method;
+    if (al->_private.method_str)
+        method.assign(al->_private.method_str);
+    else
+        method = al->http.method.image();
+
+    logfilePrintf(logfile, "%s %s %s [%s] \"" SQUIDSBUFPH " %s %s/%d.%d\" %d %" PRId64 " %s%s:%s%s",
                   clientip,
                   user_ident ? user_ident : dash_str,
                   user_auth ? user_auth : dash_str,
                   Time::FormatHttpd(squid_curtime),
-                  al->_private.method_str,
+                  SQUIDSBUFPRINT(method),
                   al->url,
                   AnyP::ProtocolType_str[al->http.version.protocol],
                   al->http.version.major, al->http.version.minor,
                   al->http.code,
                   al->http.clientReplySz.messageTotal(),
                   LogTags_str[al->cache.code],
                   al->http.statusSfx(),
                   hier_code_str[al->hier.code],
                   (Config.onoff.log_mime_hdrs?"":"\n"));
 
     safe_free(user_auth);
     safe_free(user_ident);
 
     if (Config.onoff.log_mime_hdrs) {
         char *ereq = ::Format::QuoteMimeBlob(al->headers.request);
         char *erep = ::Format::QuoteMimeBlob(al->headers.reply);
         logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
         safe_free(ereq);
         safe_free(erep);
     }

=== modified file 'src/log/FormatSquidNative.cc'
--- src/log/FormatSquidNative.cc	2014-03-30 12:00:34 +0000
+++ src/log/FormatSquidNative.cc	2014-04-10 07:52:51 +0000
@@ -53,48 +53,54 @@
         user = ::Format::QuoteUrlEncodeUsername(al->request->auth_user_request->username());
 #endif
 
     if (!user)
         user = ::Format::QuoteUrlEncodeUsername(al->cache.extuser);
 
 #if USE_OPENSSL
     if (!user)
         user = ::Format::QuoteUrlEncodeUsername(al->cache.ssluser);
 #endif
 
     if (!user)
         user = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931);
 
     if (user && !*user)
         safe_free(user);
 
     char clientip[MAX_IPSTRLEN];
     al->getLogClientIp(clientip, MAX_IPSTRLEN);
 
-    logfilePrintf(logfile, "%9ld.%03d %6d %s %s%s/%03d %" PRId64 " %s %s %s %s%s/%s %s%s",
+    static SBuf method;
+    if (al->_private.method_str)
+        method.assign(al->_private.method_str);
+    else
+        method = al->http.method.image();
+
+    logfilePrintf(logfile, "%9ld.%03d %6d %s %s%s/%03d %" PRId64 " " SQUIDSBUFPH " %s %s %s%s/%s %s%s",
                   (long int) current_time.tv_sec,
                   (int) current_time.tv_usec / 1000,
                   al->cache.msec,
                   clientip,
                   LogTags_str[al->cache.code],
                   al->http.statusSfx(),
                   al->http.code,
                   al->http.clientReplySz.messageTotal(),
-                  al->_private.method_str,
+                  SQUIDSBUFPRINT(method),
                   al->url,
                   user ? user : dash_str,
                   al->hier.ping.timedout ? "TIMEOUT_" : "",
                   hier_code_str[al->hier.code],
                   al->hier.tcpServer != NULL ? al->hier.tcpServer->remote.toStr(hierHost, sizeof(hierHost)) : "-",
                   al->http.content_type,
                   (Config.onoff.log_mime_hdrs?"":"\n"));
 
     safe_free(user);
 
     if (Config.onoff.log_mime_hdrs) {
         char *ereq = ::Format::QuoteMimeBlob(al->headers.request);
         char *erep = ::Format::QuoteMimeBlob(al->headers.reply);
         logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
         safe_free(ereq);
         safe_free(erep);
     }
 }

=== modified file 'src/log/access_log.cc'
--- src/log/access_log.cc	2013-10-25 00:13:46 +0000
+++ src/log/access_log.cc	2014-04-10 07:46:30 +0000
@@ -92,41 +92,41 @@
 static void fvdbRegisterWithCacheManager();
 #endif
 
 int LogfileStatus = LOG_DISABLE;
 
 void
 accessLogLogTo(CustomLog* log, AccessLogEntry::Pointer &al, ACLChecklist * checklist)
 {
 
     if (al->url == NULL)
         al->url = dash_str;
 
     if (!al->http.content_type || *al->http.content_type == '\0')
         al->http.content_type = dash_str;
 
     if (al->icp.opcode)
         al->_private.method_str = icp_opcode_str[al->icp.opcode];
     else if (al->htcp.opcode)
         al->_private.method_str = al->htcp.opcode;
     else
-        al->_private.method_str = RequestMethodStr(al->http.method);
+        al->_private.method_str = NULL;
 
     if (al->hier.host[0] == '\0')
         xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
 
     for (; log; log = log->next) {
         if (log->aclList && checklist && checklist->fastCheck(log->aclList) != ACCESS_ALLOWED)
             continue;
 
         if (log->logfile) {
             logfileLineStart(log->logfile);
 
             switch (log->type) {
 
             case Log::Format::CLF_SQUID:
                 Log::Format::SquidNative(al, log->logfile);
                 break;
 
             case Log::Format::CLF_COMBINED:
                 Log::Format::HttpdCombined(al, log->logfile);
                 break;

=== modified file 'src/mgr/ActionParams.cc'
--- src/mgr/ActionParams.cc	2013-03-21 21:06:48 +0000
+++ src/mgr/ActionParams.cc	2014-04-04 12:44:54 +0000
@@ -16,30 +16,30 @@
 {
     msg.getString(httpUri);
 
     String method;
     msg.getString(method);
     httpMethod = HttpRequestMethod(method.termedBuf(), NULL);
 
     msg.getPod(httpFlags);
     msg.getString(httpOrigin);
 
     msg.getString(actionName);
     msg.getString(userName);
     msg.getString(password);
     queryParams.unpack(msg);
 }
 
 void
 Mgr::ActionParams::pack(Ipc::TypedMsgHdr &msg) const
 {
     msg.putString(httpUri);
-    String foo(httpMethod.image());
+    String foo(httpMethod.image().toString());
     msg.putString(foo);
     msg.putPod(httpFlags);
     msg.putString(httpOrigin);
 
     msg.putString(actionName);
     msg.putString(userName);
     msg.putString(password);
     queryParams.pack(msg);
 }

=== modified file 'src/mk-string-arrays.awk'
--- src/mk-string-arrays.awk	2012-01-20 18:55:04 +0000
+++ src/mk-string-arrays.awk	2014-04-09 16:37:06 +0000
@@ -4,64 +4,67 @@
 # invoke similarly: perl -f mk-string-arrays.pl	 enum.h
 #		-->  awk -f mk-string-arrays.awk enum.h
 #
 # 2006 by Christopher Kerr.
 #
 # 2009 modified by Amos Jeffries
 #   Adapted to convert individual enum headers
 #
 
 BEGIN {
 	print "/*"
 	print " * Auto-Generated File. Changes will be destroyed."
 	print " */"
 	print "#include \"squid.h\""
         codeSkip = 1
         e = 0
         nspath = ""
 }
 
 # when namespace is encountered store it
-/^namespace [a-zA-Z]+/	{
+/^namespace *[a-zA-Z]+/	{
 	nspath = tolower($2) "/"		# nested folder
 	namespace = $2				# code namespace reconstruct
 	next
 }
 
 # Skip all lines outside of typedef {}
 /^typedef/		{ codeSkip = 0; next }
 codeSkip == 1		{ next }
 
 /^[ \t]*[A-Z]/ {
 	split($1, t, ",")			# remove ,
-	Element[++e] = t[1]
+	if (sbuf) Element[++e] = "SBuf(\"" t[1] "\")"
+	else Element[++e] = "\"" t[1] "\""
 	next
 }
 
 /^#/ {
 	if (codeSkip) next
 
 	Wrapper[++e] = $0
 	next
 }
 
 /^} / {
 	split($2, t, ";")			# remove ;
 	type = t[1]
         codeSkip = 1
 
+	if (sbuf) print "#include \"SBuf.h\""
 	print "#include \"" nspath type ".h\""
 
 	# if namesapce is not empty ??
 	if (namespace) print "namespace " namespace
 	if (namespace) print "{"
 
-	print "\nconst char *" type "_str[] = {"
+	if (sbuf) print "\nconst SBuf " type "_sb[] = {"
+	else print "\nconst char * " type "_str[] = {"
 	for ( i = 1; i < e; ++i)
 		if (Wrapper[i]) print Wrapper[i]
-		else print "\t\"" Element[i] "\","
+		else print "\t" Element[i] ","
 
-	print "\t\"" Element[i] "\""
+	print "\t" Element[i]
 	print "};"
 	if (namespace) print "}; // namespace " namespace
 	next
 }

=== modified file 'src/peer_select.cc'
--- src/peer_select.cc	2014-04-03 10:22:52 +0000
+++ src/peer_select.cc	2014-04-09 16:14:21 +0000
@@ -139,43 +139,43 @@
             return 0;
 
     n = neighborsCount(request);
 
     debugs(44, 3, "peerSelectIcpPing: counted " << n << " neighbors");
 
     return n;
 }
 
 void
 peerSelect(Comm::ConnectionList * paths,
            HttpRequest * request,
            AccessLogEntry::Pointer const &al,
            StoreEntry * entry,
            PSC * callback,
            void *callback_data)
 {
     ps_state *psstate;
 
     if (entry)
-        debugs(44, 3, "peerSelect: " << entry->url()  );
+        debugs(44, 3, *entry << ' ' << entry->url());
     else
-        debugs(44, 3, "peerSelect: " << RequestMethodStr(request->method));
+        debugs(44, 3, request->method);
 
     psstate = new ps_state;
 
     psstate->request = request;
     HTTPMSGLOCK(psstate->request);
     psstate->al = al;
 
     psstate->entry = entry;
     psstate->paths = paths;
 
     psstate->callback = callback;
 
     psstate->callback_data = cbdataReference(callback_data);
 
 #if USE_CACHE_DIGESTS
 
     request->hier.peer_select_start = current_time;
 
 #endif
 
@@ -442,41 +442,41 @@
 
     if (myrtt && myrtt <= psstate->ping.p_rtt)
         return 1;
 
 #endif /* USE_ICMP */
 
     return 0;
 }
 
 static void
 peerSelectFoo(ps_state * ps)
 {
     if (!cbdataReferenceValid(ps->callback_data)) {
         debugs(44, 3, "Aborting peer selection. Parent Job went away.");
         delete ps;
         return;
     }
 
     StoreEntry *entry = ps->entry;
     HttpRequest *request = ps->request;
-    debugs(44, 3, "peerSelectFoo: '" << RequestMethodStr(request->method) << " " << request->GetHost() << "'");
+    debugs(44, 3, request->method << ' ' << request->GetHost());
 
     /** If we don't know whether DIRECT is permitted ... */
     if (ps->direct == DIRECT_UNKNOWN) {
         if (ps->always_direct == ACCESS_DUNNO) {
             debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (always_direct to be checked)");
             /** check always_direct; */
             ACLFilledChecklist *ch = new ACLFilledChecklist(Config.accessList.AlwaysDirect, request, NULL);
             ch->al = ps->al;
             ps->acl_checklist = ch;
             ps->acl_checklist->nonBlockingCheck(peerCheckAlwaysDirectDone, ps);
             return;
         } else if (ps->never_direct == ACCESS_DUNNO) {
             debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (never_direct to be checked)");
             /** check never_direct; */
             ACLFilledChecklist *ch = new ACLFilledChecklist(Config.accessList.NeverDirect, request, NULL);
             ch->al = ps->al;
             ps->acl_checklist = ch;
             ps->acl_checklist->nonBlockingCheck(peerCheckNeverDirectDone, ps);
             return;
         } else if (request->flags.noDirect) {
@@ -686,41 +686,41 @@
  */
 static void
 peerGetSomeDirect(ps_state * ps)
 {
     if (ps->direct == DIRECT_NO)
         return;
 
     /* WAIS is not implemented natively */
     if (ps->request->protocol == AnyP::PROTO_WAIS)
         return;
 
     peerAddFwdServer(&ps->servers, NULL, HIER_DIRECT);
 }
 
 static void
 peerGetSomeParent(ps_state * ps)
 {
     CachePeer *p;
     HttpRequest *request = ps->request;
     hier_code code = HIER_NONE;
-    debugs(44, 3, "peerGetSomeParent: " << RequestMethodStr(request->method) << " " << request->GetHost());
+    debugs(44, 3, request->method << ' ' << request->GetHost());
 
     if (ps->direct == DIRECT_YES)
         return;
 
     if ((p = peerSourceHashSelectParent(request))) {
         code = SOURCEHASH_PARENT;
 #if USE_AUTH
     } else if ((p = peerUserHashSelectParent(request))) {
         code = USERHASH_PARENT;
 #endif
     } else if ((p = carpSelectParent(request))) {
         code = CARP;
     } else if ((p = getRoundRobinParent(request))) {
         code = ROUNDROBIN_PARENT;
     } else if ((p = getWeightedRoundRobinParent(request))) {
         code = ROUNDROBIN_PARENT;
     } else if ((p = getFirstUpParent(request))) {
         code = FIRSTUP_PARENT;
     } else if ((p = getDefaultParent(request))) {
         code = DEFAULT_PARENT;

=== modified file 'src/store_log.cc'
--- src/store_log.cc	2013-12-06 23:52:26 +0000
+++ src/store_log.cc	2014-04-08 13:48:15 +0000
@@ -63,55 +63,55 @@
     HttpReply const *reply;
 
     if (str_unknown.size()==0)
         str_unknown="unknown"; //hack. Delay initialization as string doesn't support global variables..
 
     if (NULL == storelog)
         return;
 
     ++storeLogTagsCounts[tag];
     if (mem != NULL) {
         reply = e->getReply();
         /*
          * XXX Ok, where should we print the dir number here?
          * Because if we print it before the swap file number, it'll break
          * the existing log format.
          */
 
         String ctype=(reply->content_type.size() ? reply->content_type.termedBuf() : str_unknown);
 
         logfileLineStart(storelog);
-        logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %s %4d %9d %9d %9d " SQUIDSTRINGPH " %" PRId64 "/%" PRId64 " %s %s\n",
+        logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %s %4d %9d %9d %9d " SQUIDSTRINGPH " %" PRId64 "/%" PRId64 " " SQUIDSBUFPH " %s\n",
                       (int) current_time.tv_sec,
                       (int) current_time.tv_usec / 1000,
                       storeLogTags[tag],
                       e->swap_dirn,
                       e->swap_filen,
                       e->getMD5Text(),
                       reply->sline.status(),
                       (int) reply->date,
                       (int) reply->last_modified,
                       (int) reply->expires,
                       SQUIDSTRINGPRINT(ctype),
                       reply->content_length,
                       e->contentLen(),
-                      RequestMethodStr(mem->method),
+                      SQUIDSBUFPRINT(mem->method.image()),
                       mem->logUri());
         logfileLineEnd(storelog);
     } else {
         /* no mem object. Most RELEASE cases */
         logfileLineStart(storelog);
         logfilePrintf(storelog, "%9d.%03d %-7s %02d %08X %s   ?         ?         ?         ? ?/? ?/? ? ?\n",
                       (int) current_time.tv_sec,
                       (int) current_time.tv_usec / 1000,
                       storeLogTags[tag],
                       e->swap_dirn,
                       e->swap_filen,
                       e->getMD5Text());
         logfileLineEnd(storelog);
     }
 }
 
 void
 storeLogRotate(void)
 {
     if (NULL == storelog)

=== modified file 'src/test_cache_digest.cc'
--- src/test_cache_digest.cc	2012-09-01 14:38:36 +0000
+++ src/test_cache_digest.cc	2014-04-06 08:02:33 +0000
@@ -86,52 +86,40 @@
 
 typedef struct _FileIterator FileIterator;
 typedef fr_result(*FI_READER) (FileIterator * fi);
 
 struct _FileIterator {
     const char *fname;
     FILE *file;
     time_t inner_time;		/* timestamp of the current entry */
     time_t time_offset;		/* to adjust time set by reader */
     int line_count;		/* number of lines scanned */
     int bad_line_count;		/* number of parsing errors */
     int time_warp_count;	/* number of out-of-order entries in the file */
     FI_READER reader;		/* reads next entry and updates inner_time */
     void *entry;		/* buffer for the current entry, freed with xfree() */
 };
 
 /* globals */
 static time_t cur_time = -1;	/* timestamp of the current log entry */
 
 /* copied from url.c */
-const char *RequestMethodStr[] = {
-    "NONE",
-    "GET",
-    "POST",
-    "PUT",
-    "HEAD",
-    "CONNECT",
-    "TRACE",
-    "PURGE"
-};
-
-/* copied from url.c */
 static HttpRequestMethod
 methodStrToId(const char *s)
 {
     if (strcasecmp(s, "GET") == 0) {
         return METHOD_GET;
     } else if (strcasecmp(s, "POST") == 0) {
         return METHOD_POST;
     } else if (strcasecmp(s, "PUT") == 0) {
         return METHOD_PUT;
     } else if (strcasecmp(s, "HEAD") == 0) {
         return METHOD_HEAD;
     } else if (strcasecmp(s, "CONNECT") == 0) {
         return METHOD_CONNECT;
     } else if (strcasecmp(s, "TRACE") == 0) {
         return METHOD_TRACE;
     } else if (strcasecmp(s, "PURGE") == 0) {
         return METHOD_PURGE;
     }
 
     return METHOD_NONE;

=== modified file 'src/tests/testHttpRequestMethod.cc'
--- src/tests/testHttpRequestMethod.cc	2014-02-21 10:46:19 +0000
+++ src/tests/testHttpRequestMethod.cc	2014-04-05 09:27:56 +0000
@@ -67,49 +67,49 @@
 
 /*
  * we should be able to construct a HttpRequestMethod from a Http::MethodType
  */
 void
 testHttpRequestMethod::testConstructmethod_t()
 {
     CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), HttpRequestMethod(Http::METHOD_NONE));
     CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_POST), HttpRequestMethod(Http::METHOD_POST));
     CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_NONE) != HttpRequestMethod(Http::METHOD_POST));
 }
 
 /*
  * we should be able to get a char const * version of the method.
  */
 void
 testHttpRequestMethod::testImage()
 {
     // relaxed RFC-compliance parse HTTP methods are upgraded to correct case
     Config.onoff.relaxed_header_parser = 1;
-    CPPUNIT_ASSERT_EQUAL(String("POST"), String(HttpRequestMethod("POST",NULL).image()));
-    CPPUNIT_ASSERT_EQUAL(String("POST"), String(HttpRequestMethod("pOsT",NULL).image()));
-    CPPUNIT_ASSERT_EQUAL(String("POST"), String(HttpRequestMethod("post",NULL).image()));
+    CPPUNIT_ASSERT_EQUAL(SBuf("POST"), HttpRequestMethod("POST",NULL).image());
+    CPPUNIT_ASSERT_EQUAL(SBuf("POST"), HttpRequestMethod("pOsT",NULL).image());
+    CPPUNIT_ASSERT_EQUAL(SBuf("POST"), HttpRequestMethod("post",NULL).image());
 
     // strict RFC-compliance parse HTTP methods are case sensitive
     Config.onoff.relaxed_header_parser = 0;
-    CPPUNIT_ASSERT_EQUAL(String("POST"), String(HttpRequestMethod("POST",NULL).image()));
-    CPPUNIT_ASSERT_EQUAL(String("pOsT"), String(HttpRequestMethod("pOsT",NULL).image()));
-    CPPUNIT_ASSERT_EQUAL(String("post"), String(HttpRequestMethod("post",NULL).image()));
+    CPPUNIT_ASSERT_EQUAL(SBuf("POST"), HttpRequestMethod("POST",NULL).image());
+    CPPUNIT_ASSERT_EQUAL(SBuf("pOsT"), HttpRequestMethod("pOsT",NULL).image());
+    CPPUNIT_ASSERT_EQUAL(SBuf("post"), HttpRequestMethod("post",NULL).image());
 }
 
 /*
  * an HttpRequestMethod should be comparable to a Http::MethodType without false
  * matches
  */
 void
 testHttpRequestMethod::testEqualmethod_t()
 {
     CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_NONE) == Http::METHOD_NONE);
     CPPUNIT_ASSERT(not (HttpRequestMethod(Http::METHOD_POST) == Http::METHOD_GET));
     CPPUNIT_ASSERT(HttpRequestMethod(Http::METHOD_GET) == Http::METHOD_GET);
     CPPUNIT_ASSERT(not (HttpRequestMethod(Http::METHOD_TRACE) == Http::METHOD_SEARCH));
 }
 
 /*
  * an HttpRequestMethod should testable for inequality without fail maatches
  */
 void
 testHttpRequestMethod::testNotEqualmethod_t()

=== modified file 'src/tests/testSBuf.cc'
--- src/tests/testSBuf.cc	2014-02-08 13:36:42 +0000
+++ src/tests/testSBuf.cc	2014-04-14 16:30:24 +0000
@@ -227,74 +227,177 @@
 // note: can't use cppunit's CPPUNIT_TEST_EXCEPTION because TextException asserts, and
 // so the test can't be properly completed.
 void
 testSBuf::testSubscriptOpFail()
 {
     char c;
     c=literal.at(literal.length()); //out of bounds by 1
     //notreached
     std::cout << c << std::endl;
 }
 
 static int sign(int v)
 {
     if (v < 0)
         return -1;
     if (v>0)
         return 1;
     return 0;
 }
 
+static void
+testComparisonStdFull(const char *left, const char *right)
+{
+    if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(SBuf(right))))
+        std::cerr << std::endl << " cmp(SBuf) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(SBuf(right))));
+
+    if (sign(strcmp(left, right)) != sign(SBuf(left).cmp(right)))
+        std::cerr << std::endl << " cmp(char*) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcmp(left, right)), sign(SBuf(left).cmp(right)));
+
+    if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(SBuf(right))))
+        std::cerr << std::endl << " caseCmp(SBuf) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(SBuf(right))));
+
+    if (sign(strcasecmp(left, right)) != sign(SBuf(left).caseCmp(right)))
+        std::cerr << std::endl << " caseCmp(char*) npos " << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strcasecmp(left, right)), sign(SBuf(left).caseCmp(right)));
+}
+
+static void
+testComparisonStdN(const char *left, const char *right, const size_t n)
+{
+    if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(SBuf(right), n)))
+        std::cerr << std::endl << " cmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(SBuf(right), n)));
+
+    if (sign(strncmp(left, right, n)) != sign(SBuf(left).cmp(right, n)))
+        std::cerr << std::endl << " cmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncmp(left, right, n)), sign(SBuf(left).cmp(right, n)));
+
+    if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(SBuf(right), n)))
+        std::cerr << std::endl << " caseCmp(SBuf) " << n << ' ' << left << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(SBuf(right), n)));
+
+    if (sign(strncasecmp(left, right, n)) != sign(SBuf(left).caseCmp(right, n)))
+        std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << SBuf(left) << " ?= " << right << std::endl;
+    CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left, right, n)), sign(SBuf(left).caseCmp(right, n)));
+}
+
+static void
+testComparisonStdOneWay(const char *left, const char *right)
+{
+    std::cerr << std::endl << "CHECK 1: npos(" << (strlen(right)+1) << ") " << left << " ?= " << right;
+    testComparisonStdFull(left, right);
+    const size_t maxN = 2 + min(strlen(left), strlen(right));
+    for (size_t n = 0; n <= maxN; ++n) {
+        std::cerr << std::endl << "CHECK 2: " << n << '/' << maxN << ' ' << left << " ?= " << right;
+        testComparisonStdN(left, right, n);
+        std::cerr << std::endl;
+    }
+}
+
+static void
+testComparisonStd(const char *s1, const char *s2)
+{
+    testComparisonStdOneWay(s1, s2);
+    testComparisonStdOneWay(s2, s1);
+}
+
 void
 testSBuf::testComparisons()
 {
     //same length
     SBuf s1("foo"),s2("foe");
     CPPUNIT_ASSERT(s1.cmp(s2)>0);
     CPPUNIT_ASSERT(s1.caseCmp(s2)>0);
     CPPUNIT_ASSERT(s2.cmp(s1)<0);
     CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
     CPPUNIT_ASSERT(s1 > s2);
     CPPUNIT_ASSERT(s2 < s1);
     CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
     //different lengths
     s1.assign("foo");
     s2.assign("foof");
     CPPUNIT_ASSERT(s1.cmp(s2)<0);
     CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
     CPPUNIT_ASSERT(s1 < s2);
     // specifying the max-length and overhanging size
     CPPUNIT_ASSERT_EQUAL(1,SBuf("foolong").caseCmp(SBuf("foo"), 5));
     // case-insensive comaprison
     s1 = "foo";
     s2 = "fOo";
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
     // \0-clenliness test
     s1.assign("f\0oo",4);
     s2.assign("f\0Oo",4);
     CPPUNIT_ASSERT(s1.cmp(s2) > 0);
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,3));
     CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
     CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
+
+    testComparisonStd("foo", "fooz");
+    testComparisonStd("foo", "foo");
+    testComparisonStd("foo", "f");
+    testComparisonStd("foo", "bar");
+
+    testComparisonStd("foo", "FOOZ");
+    testComparisonStd("foo", "FOO");
+    testComparisonStd("foo", "F");
+
+    // rare case C-string input matching SBuf with N>strlen(s)
+    {
+        char *right = xstrdup("foo34567890123456789012345678");
+        SBuf left(    "fooZXYWVUTSRQPONMLKJIHGFEDCBA");
+        // is 3 bytes in length. NEVER more.
+        right[3] = '\0';
+        left.setAt(3, '\0');
+
+        // pick another spot to truncate at if something goes horribly wrong.
+        right[14] = '\0';
+        left.setAt(14, '\0');
+
+        const size_t maxN = 20 + min(left.length(), strlen(right));
+        std::cerr << " loop=0-" << maxN << std::endl;
+        for (size_t n = 0; n <= maxN; ++n) {
+    std::cerr << std::endl << "CHECK 3: " << n << '/' << maxN << ' ' << left << " ?= " << right;
+            if (sign(strncmp(left.rawContent(), right, n)) != sign(left.cmp(SBuf(right), n)))
+               std::cerr << std::endl << " cmp(SBuf) " << n << ' ' << left << " ?= " << right;
+            CPPUNIT_ASSERT_EQUAL(sign(strncmp(left.rawContent(), right, n)), sign(left.cmp(SBuf(right), n)));
+ if (sign(strncmp(left.rawContent(), right, n)) != sign(left.cmp(right, n)) )
+    std::cerr << std::endl << " cmp(char*) " << n << ' ' << left << " ?= " << right;
+            CPPUNIT_ASSERT_EQUAL(sign(strncmp(left.rawContent(), right, n)), sign(left.cmp(right, n)));
+if (sign(strncasecmp(left.rawContent(), right, n)) != sign(left.caseCmp(SBuf(right), n)))
+    std::cerr << std::endl << " caseCmp(SBuf) " << n << ' ' << left << " ?= " << right;
+            CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left.rawContent(), right, n)), sign(left.caseCmp(SBuf(right), n)));
+
+if (sign(strncasecmp(left.rawContent(), right, n)) != sign(left.caseCmp(right, n)))
+    std::cerr << std::endl << " caseCmp(char*) " << n << ' ' << left << " ?= " << right;
+            CPPUNIT_ASSERT_EQUAL(sign(strncasecmp(left.rawContent(), right, n)), sign(left.caseCmp(right, n)));
+        std::cerr << std::endl;
+    }
+        xfree(right);
+    }
 }
 
 void
 testSBuf::testConsume()
 {
     SBuf s1(literal),s2,s3;
     s2=s1.consume(4);
     s3.assign("The ");
     CPPUNIT_ASSERT_EQUAL(s2,s3);
     s3.assign("quick brown fox jumped over the lazy dog");
     CPPUNIT_ASSERT_EQUAL(s1,s3);
     s1.consume(40);
     CPPUNIT_ASSERT_EQUAL(s1,SBuf());
 }
 
 void
 testSBuf::testRawContent()
 {
     SBuf s1(literal);
     SBuf s2(s1);

=== modified file 'src/tunnel.cc'
--- src/tunnel.cc	2014-02-21 10:46:19 +0000
+++ src/tunnel.cc	2014-04-11 02:54:38 +0000
@@ -856,41 +856,41 @@
      * be allowed.  yuck, I know.
      */
 
     if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
         /*
          * Check if this host is allowed to fetch MISSES from us (miss_access)
          * default is to allow.
          */
         ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
         ch.src_addr = request->client_addr;
         ch.my_addr = request->my_addr;
         if (ch.fastCheck() == ACCESS_DENIED) {
             debugs(26, 4, HERE << "MISS access forbidden.");
             err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request);
             *status_ptr = Http::scForbidden;
             errorSend(http->getConn()->clientConnection, err);
             return;
         }
     }
 
-    debugs(26, 3, HERE << "'" << RequestMethodStr(request->method) << " " << url << " " << request->http_ver << "'");
+    debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
     ++statCounter.server.all.requests;
     ++statCounter.server.other.requests;
 
     tunnelState = new TunnelStateData;
 #if USE_DELAY_POOLS
     tunnelState->server.setDelayId(DelayId::DelayClient(http));
 #endif
     tunnelState->url = xstrdup(url);
     tunnelState->request = request;
     tunnelState->server.size_ptr = size_ptr;
     tunnelState->status_ptr = status_ptr;
     tunnelState->client.conn = http->getConn()->clientConnection;
     tunnelState->al = al;
 
     comm_add_close_handler(tunnelState->client.conn->fd,
                            tunnelClientClosed,
                            tunnelState);
 
     AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
                                      CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));


