=== 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 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(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 /** * 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 { 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::CBDATA_CbDataList; /// \endcond SBufList ACLMethodData::dump() const { SBufList sl; CbDataList *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 **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 *q = new CbDataList (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::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 #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(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 = ""; if (http->getConn() != NULL && http->getConn()->getAuth() != NULL) proxy_auth_msg = http->getConn()->getAuth()->denyMessage(""); else if (http->request->auth_user_request != NULL) proxy_auth_msg = http->request->auth_user_request->denyMessage(""); #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 : "")); #if USE_AUTH @@ -1499,41 +1498,41 @@ if (!httpStateIsValid()) return; const Ssl::BumpMode bumpMode = answer == ACCESS_ALLOWED ? static_cast(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(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));