diff -u -r -N squid-4.14/acinclude/os-deps.m4 squid-4.15/acinclude/os-deps.m4 --- squid-4.14/acinclude/os-deps.m4 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/acinclude/os-deps.m4 2021-05-10 14:04:15.000000000 +1200 @@ -792,6 +792,7 @@ AC_CACHE_CHECK([for operational CPU clock access], squid_cv_cpu_profiler_works, AC_PREPROC_IFELSE([AC_LANG_SOURCE([[ +#include #if defined(__GNUC__) && ( defined(__i386) || defined(__i386__) ) // okay #elif defined(__GNUC__) && ( defined(__x86_64) || defined(__x86_64__) ) @@ -800,6 +801,8 @@ // okay #elif defined(_M_IX86) && defined(_MSC_VER) /* x86 platform on Microsoft C Compiler ONLY */ // okay +#elif defined(HAVE_CLOCK_GETTIME_NSEC_NP) && defined(CLOCK_MONOTONIC_RAW) +// okay #else #error This CPU is unsupported. No profiling available here. #endif diff -u -r -N squid-4.14/ChangeLog squid-4.15/ChangeLog --- squid-4.14/ChangeLog 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/ChangeLog 2021-05-10 14:04:15.000000000 +1200 @@ -1,3 +1,19 @@ +Changes in squid-4.15 (10 May 2021): + + - Bug 5112: Excessively loud chunked reply parsing error reporting + - Bug 5106: Broken cache manager URL parsing + - Bug 5104: Memory leak in RFC 2169 response parsing + - Bug 3556: "FD ... is not an open socket" for accept() problems + - Profiling: CPU timing implemented for MAC non-x86 + - Fix HttpHeaderStats definition to include hoErrorDetail + - Fix Squid-to-client write_timeout triggers client_lifetime timeout + - Limit HeaderLookupTable_t::lookup() to BadHdr and specific IDs + - Handle more Range requests + - Handle more partial responses + - Stop processing a response if the Store entry is gone + - ... and some portability fixes + - ... and some documentation updates + Changes in squid-4.14 (02 Feb 2021): - Regression Fix: support for non-lowercase Transfer-Encoding value diff -u -r -N squid-4.14/configure squid-4.15/configure --- squid-4.14/configure 2021-02-08 14:36:29.000000000 +1300 +++ squid-4.15/configure 2021-05-10 22:35:34.000000000 +1200 @@ -1,7 +1,7 @@ #! /bin/sh # From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.14. +# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.15. # # Report bugs to . # @@ -595,8 +595,8 @@ # Identity of this package. PACKAGE_NAME='Squid Web Proxy' PACKAGE_TARNAME='squid' -PACKAGE_VERSION='4.14' -PACKAGE_STRING='Squid Web Proxy 4.14' +PACKAGE_VERSION='4.15' +PACKAGE_STRING='Squid Web Proxy 4.15' PACKAGE_BUGREPORT='http://bugs.squid-cache.org/' PACKAGE_URL='' @@ -1656,7 +1656,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Squid Web Proxy 4.14 to adapt to many kinds of systems. +\`configure' configures Squid Web Proxy 4.15 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1727,7 +1727,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Squid Web Proxy 4.14:";; + short | recursive ) echo "Configuration of Squid Web Proxy 4.15:";; esac cat <<\_ACEOF @@ -2166,7 +2166,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Squid Web Proxy configure 4.14 +Squid Web Proxy configure 4.15 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -3270,7 +3270,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Squid Web Proxy $as_me 4.14, which was +It was created by Squid Web Proxy $as_me 4.15, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4132,7 +4132,7 @@ # Define the identity of the package. PACKAGE='squid' - VERSION='4.14' + VERSION='4.15' cat >>confdefs.h <<_ACEOF @@ -37412,6 +37412,17 @@ # Default OFF. This is a debug feature. Only check and enable if forced ON. if test "x$enable_cpu_profiling" = "xyes"; then + for ac_func in clock_gettime_nsec_np +do : + ac_fn_cxx_check_func "$LINENO" "clock_gettime_nsec_np" "ac_cv_func_clock_gettime_nsec_np" +if test "x$ac_cv_func_clock_gettime_nsec_np" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_CLOCK_GETTIME_NSEC_NP 1 +_ACEOF + +fi +done + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for operational CPU clock access" >&5 $as_echo_n "checking for operational CPU clock access... " >&6; } @@ -37421,6 +37432,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +#include #if defined(__GNUC__) && ( defined(__i386) || defined(__i386__) ) // okay #elif defined(__GNUC__) && ( defined(__x86_64) || defined(__x86_64__) ) @@ -37429,6 +37441,8 @@ // okay #elif defined(_M_IX86) && defined(_MSC_VER) /* x86 platform on Microsoft C Compiler ONLY */ // okay +#elif defined(HAVE_CLOCK_GETTIME_NSEC_NP) && defined(CLOCK_MONOTONIC_RAW) +// okay #else #error This CPU is unsupported. No profiling available here. #endif @@ -44605,7 +44619,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Squid Web Proxy $as_me 4.14, which was +This file was extended by Squid Web Proxy $as_me 4.15, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -44671,7 +44685,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -Squid Web Proxy config.status 4.14 +Squid Web Proxy config.status 4.15 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -u -r -N squid-4.14/configure.ac squid-4.15/configure.ac --- squid-4.14/configure.ac 2021-02-08 14:36:29.000000000 +1300 +++ squid-4.15/configure.ac 2021-05-10 22:35:34.000000000 +1200 @@ -5,7 +5,7 @@ ## Please see the COPYING and CONTRIBUTORS files for details. ## -AC_INIT([Squid Web Proxy],[4.14],[http://bugs.squid-cache.org/],[squid]) +AC_INIT([Squid Web Proxy],[4.15],[http://bugs.squid-cache.org/],[squid]) AC_PREREQ(2.61) AC_CONFIG_HEADERS([include/autoconf.h]) AC_CONFIG_AUX_DIR(cfgaux) @@ -2816,6 +2816,7 @@ ]) # Default OFF. This is a debug feature. Only check and enable if forced ON. if test "x$enable_cpu_profiling" = "xyes"; then + AC_CHECK_FUNCS(clock_gettime_nsec_np) SQUID_CHECK_FUNCTIONAL_CPU_PROFILER if test "x$squid_cv_cpu_profiler_works" = "xno"; then AC_MSG_ERROR([CPU profiling will not be functional in this build.]) diff -u -r -N squid-4.14/CONTRIBUTORS squid-4.15/CONTRIBUTORS --- squid-4.14/CONTRIBUTORS 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/CONTRIBUTORS 2021-05-10 14:04:15.000000000 +1200 @@ -105,6 +105,7 @@ Dan Searle Dan Searle Dave Dykstra + David Carlier David Hill David Isaacs David J N Begley @@ -250,6 +251,7 @@ Jorge Ivan Burgos Aguilar Jose Luis Godoy Jose-Marcio Martins da Cruz + Joshua Rogers Joshua Root Joshua Root JPP diff -u -r -N squid-4.14/doc/release-notes/release-4.html squid-4.15/doc/release-notes/release-4.html --- squid-4.14/doc/release-notes/release-4.html 2021-02-08 14:41:40.000000000 +1300 +++ squid-4.15/doc/release-notes/release-4.html 2021-05-10 22:40:02.000000000 +1200 @@ -3,10 +3,10 @@ - Squid 4.14 release notes + Squid 4.15 release notes -

Squid 4.14 release notes

+

Squid 4.15 release notes

Squid Developers


@@ -64,7 +64,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.14.

+

The Squid Team are pleased to announce the release of Squid-4.15.

This new release is available for download from http://www.squid-cache.org/Versions/v4/ or the mirrors.

diff -u -r -N squid-4.14/errors/TRANSLATORS squid-4.15/errors/TRANSLATORS --- squid-4.14/errors/TRANSLATORS 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/errors/TRANSLATORS 2021-05-10 14:04:15.000000000 +1200 @@ -109,7 +109,7 @@ Russian Andrew L. Davydov Serbian Zoran Verovski Serbian Dragutin Cirkovic -Simplify Chinese Wang DaQing +Simplified Chinese Wang DaQing Slovak Peter Hanecak Spanish Javier Puche Spanish Roberto Lumbreras diff -u -r -N squid-4.14/include/autoconf.h.in squid-4.15/include/autoconf.h.in --- squid-4.14/include/autoconf.h.in 2021-02-08 14:36:21.000000000 +1300 +++ squid-4.15/include/autoconf.h.in 2021-05-10 22:35:27.000000000 +1200 @@ -118,6 +118,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_BYTESWAP_H +/* Define to 1 if you have the `clock_gettime_nsec_np' function. */ +#undef HAVE_CLOCK_GETTIME_NSEC_NP + /* Define to 1 if you have the `closedir' function. */ #undef HAVE_CLOSEDIR diff -u -r -N squid-4.14/include/version.h squid-4.15/include/version.h --- squid-4.14/include/version.h 2021-02-08 14:36:29.000000000 +1300 +++ squid-4.15/include/version.h 2021-05-10 22:35:34.000000000 +1200 @@ -7,7 +7,7 @@ */ #ifndef SQUID_RELEASE_TIME -#define SQUID_RELEASE_TIME 1612748178 +#define SQUID_RELEASE_TIME 1620642924 #endif /* diff -u -r -N squid-4.14/lib/profiler/get_tick.h squid-4.15/lib/profiler/get_tick.h --- squid-4.14/lib/profiler/get_tick.h 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/lib/profiler/get_tick.h 2021-05-10 14:04:15.000000000 +1200 @@ -10,6 +10,7 @@ #define _PROFILER_GET_TICK_H_ #if USE_XPROF_STATS +#include /* * Ensure that any changes here are synchronised with SQUID_CHECK_FUNCTIONAL_CPU_PROFILER @@ -67,6 +68,14 @@ return regs; } +#elif defined(HAVE_CLOCK_GETTIME_NSEC_NP) && defined(CLOCK_MONOTONIC_RAW) + +static inline hrtime_t +get_tick() +{ + return clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW); +} + #else /* This CPU is unsupported. Short-circuit, no profiling here */ // #error for configure tests to prevent library construction diff -u -r -N squid-4.14/RELEASENOTES.html squid-4.15/RELEASENOTES.html --- squid-4.14/RELEASENOTES.html 2021-02-08 14:41:40.000000000 +1300 +++ squid-4.15/RELEASENOTES.html 2021-05-10 22:40:02.000000000 +1200 @@ -3,10 +3,10 @@ - Squid 4.14 release notes + Squid 4.15 release notes -

Squid 4.14 release notes

+

Squid 4.15 release notes

Squid Developers


@@ -64,7 +64,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.14.

+

The Squid Team are pleased to announce the release of Squid-4.15.

This new release is available for download from http://www.squid-cache.org/Versions/v4/ or the mirrors.

diff -u -r -N squid-4.14/src/acl/ConnMark.cc squid-4.15/src/acl/ConnMark.cc --- squid-4.14/src/acl/ConnMark.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/acl/ConnMark.cc 2021-05-10 14:04:15.000000000 +1200 @@ -16,6 +16,8 @@ #include "http/Stream.h" #include "sbuf/Stream.h" +#include + bool Acl::ConnMark::empty() const { diff -u -r -N squid-4.14/src/acl/external/delayer/ext_delayer_acl.8 squid-4.15/src/acl/external/delayer/ext_delayer_acl.8 --- squid-4.14/src/acl/external/delayer/ext_delayer_acl.8 2021-02-08 14:41:43.000000000 +1300 +++ squid-4.15/src/acl/external/delayer/ext_delayer_acl.8 2021-05-10 22:40:06.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_DELAYER_ACL 8" -.TH EXT_DELAYER_ACL 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH EXT_DELAYER_ACL 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.15/src/acl/external/SQL_session/ext_sql_session_acl.8 --- squid-4.14/src/acl/external/SQL_session/ext_sql_session_acl.8 2021-02-08 14:41:43.000000000 +1300 +++ squid-4.15/src/acl/external/SQL_session/ext_sql_session_acl.8 2021-05-10 22:40:07.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_SQL_SESSION_ACL 8" -.TH EXT_SQL_SESSION_ACL 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH EXT_SQL_SESSION_ACL 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.15/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 --- squid-4.14/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2021-02-08 14:41:43.000000000 +1300 +++ squid-4.15/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2021-05-10 22:40:07.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_WBINFO_GROUP_ACL 8" -.TH EXT_WBINFO_GROUP_ACL 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH EXT_WBINFO_GROUP_ACL 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/auth/basic/DB/basic_db_auth.8 squid-4.15/src/auth/basic/DB/basic_db_auth.8 --- squid-4.14/src/auth/basic/DB/basic_db_auth.8 2021-02-08 14:41:44.000000000 +1300 +++ squid-4.15/src/auth/basic/DB/basic_db_auth.8 2021-05-10 22:40:08.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_DB_AUTH 8" -.TH BASIC_DB_AUTH 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH BASIC_DB_AUTH 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.15/src/auth/basic/POP3/basic_pop3_auth.8 --- squid-4.14/src/auth/basic/POP3/basic_pop3_auth.8 2021-02-08 14:41:45.000000000 +1300 +++ squid-4.15/src/auth/basic/POP3/basic_pop3_auth.8 2021-05-10 22:40:08.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_POP3_AUTH 8" -.TH BASIC_POP3_AUTH 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH BASIC_POP3_AUTH 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/cache_manager.cc squid-4.15/src/cache_manager.cc --- squid-4.14/src/cache_manager.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/cache_manager.cc 2021-05-10 14:04:15.000000000 +1200 @@ -26,7 +26,9 @@ #include "mgr/Forwarder.h" #include "mgr/FunAction.h" #include "mgr/QueryParams.h" +#include "parser/Tokenizer.h" #include "protos.h" +#include "sbuf/Stream.h" #include "sbuf/StringConvert.h" #include "SquidConfig.h" #include "SquidTime.h" @@ -147,82 +149,87 @@ return cmd->profile->creator->create(cmd); } +static const CharacterSet & +MgrFieldChars(const AnyP::ProtocolType &protocol) +{ + // Deprecated cache_object:// scheme used '@' to delimit passwords + if (protocol == AnyP::PROTO_CACHE_OBJECT) { + static const CharacterSet fieldChars = CharacterSet("cache-object-field", "@?#").complement(); + return fieldChars; + } + + static const CharacterSet actionChars = CharacterSet("mgr-field", "?#").complement(); + return actionChars; +} + /** - \ingroup CacheManagerInternal * define whether the URL is a cache-manager URL and parse the action * requested by the user. Checks via CacheManager::ActionProtection() that the * item is accessible by the user. - \retval CacheManager::cachemgrStateData state object for the following handling - \retval NULL if the action can't be found or can't be accessed by the user + * + * Syntax: + * + * scheme "://" authority [ '/squid-internal-mgr' ] path-absolute [ '@' unreserved ] '?' query-string + * + * see RFC 3986 for definitions of scheme, authority, path-absolute, query-string + * + * \returns Mgr::Command object with action to perform and parameters it might use */ Mgr::Command::Pointer -CacheManager::ParseUrl(const char *url) +CacheManager::ParseUrl(const AnyP::Uri &uri) { - int t; - LOCAL_ARRAY(char, host, MAX_URL); - LOCAL_ARRAY(char, request, MAX_URL); - LOCAL_ARRAY(char, password, MAX_URL); - LOCAL_ARRAY(char, params, MAX_URL); - host[0] = 0; - request[0] = 0; - password[0] = 0; - params[0] = 0; - int pos = -1; - int len = strlen(url); - Must(len > 0); - t = sscanf(url, "cache_object://%[^/]/%[^@?]%n@%[^?]?%s", host, request, &pos, password, params); - if (t < 3) { - t = sscanf(url, "cache_object://%[^/]/%[^?]%n?%s", host, request, &pos, params); - } - if (t < 1) { - t = sscanf(url, "http://%[^/]/squid-internal-mgr/%[^?]%n?%s", host, request, &pos, params); - } - if (t < 1) { - t = sscanf(url, "https://%[^/]/squid-internal-mgr/%[^?]%n?%s", host, request, &pos, params); - } - if (t < 2) { - if (strncmp("cache_object://",url,15)==0) - xstrncpy(request, "menu", MAX_URL); - else - xstrncpy(request, "index", MAX_URL); - } + Parser::Tokenizer tok(uri.path()); -#if _SQUID_OS2_ - if (t == 2 && request[0] == '\0') { - /* - * emx's sscanf insists of returning 2 because it sets request - * to null - */ - if (strncmp("cache_object://",url,15)==0) - xstrncpy(request, "menu", MAX_URL); - else - xstrncpy(request, "index", MAX_URL); - } -#endif + static const SBuf internalMagicPrefix("/squid-internal-mgr/"); + if (!tok.skip(internalMagicPrefix) && !tok.skip('/')) + throw TextException("invalid URL path", Here()); + + Mgr::Command::Pointer cmd = new Mgr::Command(); + cmd->params.httpUri = SBufToString(uri.absolute()); - debugs(16, 3, HERE << "MGR request: t=" << t << ", host='" << host << "', request='" << request << "', pos=" << pos << - ", password='" << password << "', params='" << params << "'"); + const auto &fieldChars = MgrFieldChars(uri.getScheme()); - Mgr::ActionProfile::Pointer profile = findAction(request); - if (!profile) { - debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' not found"); - return NULL; + SBuf action; + if (!tok.prefix(action, fieldChars)) { + if (uri.getScheme() == AnyP::PROTO_CACHE_OBJECT) { + static const SBuf menuReport("menu"); + action = menuReport; + } else { + static const SBuf indexReport("index"); + action = indexReport; + } } + cmd->params.actionName = SBufToString(action); + + const auto profile = findAction(action.c_str()); + if (!profile) + throw TextException(ToSBuf("action '", action, "' not found"), Here()); const char *prot = ActionProtection(profile); - if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) { - debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' is " << prot); - return NULL; + if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) + throw TextException(ToSBuf("action '", action, "' is ", prot), Here()); + cmd->profile = profile; + + SBuf passwd; + if (uri.getScheme() == AnyP::PROTO_CACHE_OBJECT && tok.skip('@')) { + (void)tok.prefix(passwd, fieldChars); + cmd->params.password = SBufToString(passwd); } - Mgr::Command::Pointer cmd = new Mgr::Command; - if (!Mgr::QueryParams::Parse(params, cmd->params.queryParams)) - return NULL; - cmd->profile = profile; - cmd->params.httpUri = url; - cmd->params.userName = String(); - cmd->params.password = password; - cmd->params.actionName = request; + // TODO: fix when AnyP::Uri::parse() separates path?query#fragment + SBuf params; + if (tok.skip('?')) { + params = tok.remaining(); + Mgr::QueryParams::Parse(tok, cmd->params.queryParams); + } + + if (!tok.skip('#') && !tok.atEnd()) + throw TextException("invalid characters in URL", Here()); + // else ignore #fragment (if any) + + debugs(16, 3, "MGR request: host=" << uri.host() << ", action=" << action << + ", password=" << passwd << ", params=" << params); + return cmd; } @@ -305,11 +312,15 @@ void CacheManager::Start(const Comm::ConnectionPointer &client, HttpRequest * request, StoreEntry * entry) { - debugs(16, 3, "CacheManager::Start: '" << entry->url() << "'" ); + debugs(16, 3, "request-url= '" << request->url << "', entry-url='" << entry->url() << "'"); - Mgr::Command::Pointer cmd = ParseUrl(entry->url()); - if (!cmd) { - ErrorState *err = new ErrorState(ERR_INVALID_URL, Http::scNotFound, request); + Mgr::Command::Pointer cmd; + try { + cmd = ParseUrl(request->url); + + } catch (...) { + debugs(16, 2, "request URL error: " << CurrentException); + const auto err = new ErrorState(ERR_INVALID_URL, Http::scNotFound, request); err->url = xstrdup(entry->url()); errorAppendEntry(entry, err); entry->expires = squid_curtime; @@ -473,4 +484,3 @@ } return instance; } - diff -u -r -N squid-4.14/src/CacheManager.h squid-4.15/src/CacheManager.h --- squid-4.14/src/CacheManager.h 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/CacheManager.h 2021-05-10 14:04:15.000000000 +1200 @@ -9,6 +9,7 @@ #ifndef SQUID_CACHEMANAGER_H #define SQUID_CACHEMANAGER_H +#include "anyp/forward.h" #include "comm/forward.h" #include "mgr/Action.h" #include "mgr/ActionProfile.h" @@ -50,7 +51,7 @@ protected: CacheManager() {} ///< use Instance() instead - Mgr::CommandPointer ParseUrl(const char *url); + Mgr::CommandPointer ParseUrl(const AnyP::Uri &); void ParseHeaders(const HttpRequest * request, Mgr::ActionParams ¶ms); int CheckPassword(const Mgr::Command &cmd); char *PasswdGet(Mgr::ActionPasswordList *, const char *); diff -u -r -N squid-4.14/src/cbdata.cc squid-4.15/src/cbdata.cc --- squid-4.14/src/cbdata.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/cbdata.cc 2021-05-10 14:04:15.000000000 +1200 @@ -16,6 +16,7 @@ #include "Store.h" #include +#include #if USE_CBDATA_DEBUG #include @@ -46,8 +47,6 @@ #endif -#define OFFSET_OF(TYPE, MEMBER) ((size_t) &(((TYPE) *)0)->(MEMBER)) - /** * Manage a set of registered callback data pointers. * One of the easiest ways to make Squid coredump is to issue a @@ -91,6 +90,15 @@ {} ~cbdata(); + static cbdata *FromUserData(const void *p) { +#if WITH_VALGRIND + return cbdata_htable.at(p); +#else + const auto t = static_cast(p) - offsetof(cbdata, data); + return reinterpret_cast(const_cast(t)); +#endif + } + int valid; int32_t locks; cbdata_type type; @@ -116,25 +124,14 @@ #if !WITH_VALGRIND size_t dataSize() const { return sizeof(data);} - static long MakeOffset(); - static const long Offset; #endif /* MUST be the last per-instance member */ void *data; }; -const long cbdata::Cookie((long)0xDEADBEEF); -#if !WITH_VALGRIND -const long cbdata::Offset(MakeOffset()); +static_assert(std::is_standard_layout::value, "the behavior of offsetof(cbdata) is defined"); -long -cbdata::MakeOffset() -{ - cbdata *zero = (cbdata *)0L; - void **dataOffset = &zero->data; - return (long)dataOffset; -} -#endif +const long cbdata::Cookie((long)0xDEADBEEF); static OBJH cbdataDump; #if USE_CBDATA_DEBUG @@ -186,8 +183,7 @@ snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type); #if !WITH_VALGRIND - assert((size_t)cbdata::Offset == (sizeof(cbdata) - ((cbdata *)NULL)->dataSize())); - size += cbdata::Offset; + size += offsetof(cbdata, data); #endif cbdata_index[type].pool = memPoolCreate(label, size); @@ -297,12 +293,7 @@ void * cbdataInternalFree(void *p, const char *file, int line) { - cbdata *c; -#if WITH_VALGRIND - c = cbdata_htable.at(p); -#else - c = (cbdata *) (((char *) p) - cbdata::Offset); -#endif + auto *c = cbdata::FromUserData(p); #if USE_CBDATA_DEBUG debugs(45, 3, p << " " << file << ":" << line); #else @@ -333,16 +324,10 @@ cbdataInternalLock(const void *p) #endif { - cbdata *c; - if (p == NULL) return; -#if WITH_VALGRIND - c = cbdata_htable.at(p); -#else - c = (cbdata *) (((char *) p) - cbdata::Offset); -#endif + auto *c = cbdata::FromUserData(p); #if USE_CBDATA_DEBUG debugs(45, 3, p << "=" << (c ? c->locks + 1 : -1) << " " << file << ":" << line); @@ -365,16 +350,10 @@ cbdataInternalUnlock(const void *p) #endif { - cbdata *c; - if (p == NULL) return; -#if WITH_VALGRIND - c = cbdata_htable.at(p); -#else - c = (cbdata *) (((char *) p) - cbdata::Offset); -#endif + auto *c = cbdata::FromUserData(p); #if USE_CBDATA_DEBUG debugs(45, 3, p << "=" << (c ? c->locks - 1 : -1) << " " << file << ":" << line); @@ -411,18 +390,12 @@ int cbdataReferenceValid(const void *p) { - cbdata *c; - if (p == NULL) return 1; /* A NULL pointer cannot become invalid */ debugs(45, 9, p); -#if WITH_VALGRIND - c = cbdata_htable.at(p); -#else - c = (cbdata *) (((char *) p) - cbdata::Offset); -#endif + const auto c = cbdata::FromUserData(p); c->check(__LINE__); @@ -502,7 +475,7 @@ #if WITH_VALGRIND int obj_size = pool->objectSize(); #else - int obj_size = pool->objectSize() - cbdata::Offset; + int obj_size = pool->objectSize() - offsetof(cbdata, data); #endif storeAppendPrintf(sentry, "%s\t%d\t%ld\t%ld\n", pool->objectType() + 7, obj_size, (long int)pool->getMeter().inuse.currentLevel(), (long int)obj_size * pool->getMeter().inuse.currentLevel()); } diff -u -r -N squid-4.14/src/clients/Client.cc squid-4.15/src/clients/Client.cc --- squid-4.14/src/clients/Client.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/clients/Client.cc 2021-05-10 14:04:15.000000000 +1200 @@ -533,8 +533,11 @@ maybePurgeOthers(); // adaptation may overwrite old offset computed using the virgin response - const bool partial = theFinalReply->contentRange(); - currentOffset = partial ? theFinalReply->contentRange()->spec.offset : 0; + currentOffset = 0; + if (const auto cr = theFinalReply->contentRange()) { + if (cr->spec.offset != HttpHdrRangeSpec::UnknownPosition) + currentOffset = cr->spec.offset; + } } /// whether to prevent caching of an otherwise cachable response diff -u -r -N squid-4.14/src/client_side.cc squid-4.15/src/client_side.cc --- squid-4.14/src/client_side.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/client_side.cc 2021-05-10 14:04:15.000000000 +1200 @@ -728,8 +728,8 @@ * warning: assumes that HTTP headers for individual ranges at the * time of the actuall assembly will be exactly the same as * the headers when clientMRangeCLen() is called */ -int -ClientHttpRequest::mRangeCLen() +int64_t +ClientHttpRequest::mRangeCLen() const { int64_t clen = 0; MemBuf mb; diff -u -r -N squid-4.14/src/client_side_request.cc squid-4.15/src/client_side_request.cc --- squid-4.14/src/client_side_request.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/client_side_request.cc 2021-05-10 14:04:15.000000000 +1200 @@ -1094,9 +1094,6 @@ * iter up at this point. */ node->readBuffer.offset = request->range->lowestOffset(0); - http->range_iter.pos = request->range->begin(); - http->range_iter.end = request->range->end(); - http->range_iter.valid = true; } } @@ -1954,6 +1951,30 @@ #include "client_side_request.cci" #endif +// XXX: This should not be a _request_ method. Move range_iter elsewhere. +int64_t +ClientHttpRequest::prepPartialResponseGeneration() +{ + assert(request); + assert(request->range); + + range_iter.pos = request->range->begin(); + range_iter.end = request->range->end(); + range_iter.debt_size = 0; + const auto multipart = request->range->specs.size() > 1; + if (multipart) + range_iter.boundary = rangeBoundaryStr(); + range_iter.valid = true; // TODO: Remove. + range_iter.updateSpec(); // TODO: Refactor to initialize rather than update. + + assert(range_iter.pos != range_iter.end); + const auto &firstRange = *range_iter.pos; + assert(firstRange); + out.offset = firstRange->offset; + + return multipart ? mRangeCLen() : firstRange->length; +} + #if USE_ADAPTATION /// Initiate an asynchronous adaptation transaction which will call us back. void diff -u -r -N squid-4.14/src/client_side_request.h squid-4.15/src/client_side_request.h --- squid-4.14/src/client_side_request.h 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/client_side_request.h 2021-05-10 14:04:15.000000000 +1200 @@ -131,7 +131,7 @@ dlink_node active; dlink_list client_stream; - int mRangeCLen(); + int64_t mRangeCLen() const; ClientRequestContext *calloutContext; void doCallouts(); @@ -148,6 +148,11 @@ /// neither the current request nor the parsed request URI are known void setErrorUri(const char *errorUri); + /// Prepares to satisfy a Range request with a generated HTTP 206 response. + /// Initializes range_iter state to allow raw range_iter access. + /// \returns Content-Length value for the future response; never negative + int64_t prepPartialResponseGeneration(); + /// Build an error reply. For use with the callouts. void calloutsError(const err_type error, const int errDetail); diff -u -r -N squid-4.14/src/comm/TcpAcceptor.cc squid-4.15/src/comm/TcpAcceptor.cc --- squid-4.14/src/comm/TcpAcceptor.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/comm/TcpAcceptor.cc 2021-05-10 14:04:15.000000000 +1200 @@ -374,7 +374,13 @@ } Must(sock >= 0); + + // Sync with Comm ASAP so that abandoned details can properly close(). + // XXX : these are not all HTTP requests. use a note about type and ip:port details-> + // so we end up with a uniform "(HTTP|FTP-data|HTTPS|...) remote-ip:remote-port" + fd_open(sock, FD_SOCKET, "HTTP Request"); details->fd = sock; + details->remote = *gai; // lookup the local-end details of this new connection @@ -419,10 +425,6 @@ } /* fdstat update */ - // XXX : these are not all HTTP requests. use a note about type and ip:port details-> - // so we end up with a uniform "(HTTP|FTP-data|HTTPS|...) remote-ip:remote-port" - fd_open(sock, FD_SOCKET, "HTTP Request"); - fdd_table[sock].close_file = NULL; fdd_table[sock].close_line = 0; diff -u -r -N squid-4.14/src/comm.cc squid-4.15/src/comm.cc --- squid-4.14/src/comm.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/comm.cc 2021-05-10 14:04:15.000000000 +1200 @@ -1585,6 +1585,7 @@ debugs(5, 5, "checkTimeouts: FD " << fd << " auto write timeout"); Comm::SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0); COMMIO_FD_WRITECB(fd)->finish(Comm::COMM_ERROR, ETIMEDOUT); + continue; } else if (AlreadyTimedOut(F)) continue; diff -u -r -N squid-4.14/src/gopher.cc squid-4.15/src/gopher.cc --- squid-4.14/src/gopher.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/gopher.cc 2021-05-10 14:04:15.000000000 +1200 @@ -740,7 +740,10 @@ assert(buf == gopherState->replybuf); - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { + // XXX: Should update delayId, statCounter, etc. before bailing + if (!entry->isAccepting()) { + debugs(10, 3, "terminating due to bad " << *entry); + // TODO: Do not abuse connection for triggering cleanup. gopherState->serverConn->close(); return; } @@ -837,6 +840,13 @@ statCounter.server.other.kbytes_out += size; } + if (!entry->isAccepting()) { + debugs(10, 3, "terminating due to bad " << *entry); + // TODO: Do not abuse connection for triggering cleanup. + gopherState->serverConn->close(); + return; + } + if (errflag) { ErrorState *err; err = new ErrorState(ERR_WRITE_ERROR, Http::scServiceUnavailable, gopherState->fwd->request); diff -u -r -N squid-4.14/src/http/RegisteredHeaders.cc squid-4.15/src/http/RegisteredHeaders.cc --- squid-4.14/src/http/RegisteredHeaders.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/http/RegisteredHeaders.cc 2021-05-10 14:04:15.000000000 +1200 @@ -37,7 +37,7 @@ const HeaderTableRecord& HeaderLookupTable_t::lookup (const char *buf, const std::size_t len) const { const HeaderTableRecord *r = HttpHeaderHashTable::lookup(buf, len); - if (!r) + if (!r || r->id == Http::HdrType::OTHER) return BadHdr; return *r; } diff -u -r -N squid-4.14/src/http/Stream.cc squid-4.15/src/http/Stream.cc --- squid-4.14/src/http/Stream.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/http/Stream.cc 2021-05-10 14:04:15.000000000 +1200 @@ -163,12 +163,13 @@ return start; } - } else if (reply && reply->contentRange()) { + } else if (const auto cr = reply ? reply->contentRange() : nullptr) { /* request does not have ranges, but reply does */ /** \todo FIXME: should use range_iter_pos on reply, as soon as reply->content_range * becomes HttpHdrRange rather than HttpHdrRangeSpec. */ - return http->out.offset + reply->contentRange()->spec.offset; + if (cr->spec.offset != HttpHdrRangeSpec::UnknownPosition) + return http->out.offset + cr->spec.offset; } return http->out.offset; @@ -232,6 +233,10 @@ // did we get at least what we expected, based on range specs? + // this Content-Range does not tell us how many bytes to expect + if (bytesExpected == HttpHdrRangeSpec::UnknownPosition) + return STREAM_NONE; + if (bytesSent == bytesExpected) // got everything return STREAM_COMPLETE; @@ -444,59 +449,27 @@ } else { /* XXX: TODO: Review, this unconditional set may be wrong. */ rep->sline.set(rep->sline.version, Http::scPartialContent); - // web server responded with a valid, but unexpected range. - // will (try-to) forward as-is. - //TODO: we should cope with multirange request/responses - // TODO: review, since rep->content_range is always nil here. - bool replyMatchRequest = contentRange != nullptr ? - request->range->contains(contentRange->spec) : - true; + + // before range_iter accesses + const auto actual_clen = http->prepPartialResponseGeneration(); + const int spec_count = http->request->range->specs.size(); - int64_t actual_clen = -1; debugs(33, 3, "range spec count: " << spec_count << " virgin clen: " << rep->content_length); assert(spec_count > 0); /* append appropriate header(s) */ if (spec_count == 1) { - if (!replyMatchRequest) { - hdr->putContRange(contentRange); - actual_clen = rep->content_length; - //http->range_iter.pos = rep->content_range->spec.begin(); - (*http->range_iter.pos)->offset = contentRange->spec.offset; - (*http->range_iter.pos)->length = contentRange->spec.length; - - } else { - HttpHdrRange::iterator pos = http->request->range->begin(); - assert(*pos); - /* append Content-Range */ - - if (!contentRange) { - /* No content range, so this was a full object we are - * sending parts of. - */ - httpHeaderAddContRange(hdr, **pos, rep->content_length); - } - - /* set new Content-Length to the actual number of bytes - * transmitted in the message-body */ - actual_clen = (*pos)->length; - } + const auto singleSpec = *http->request->range->begin(); + assert(singleSpec); + httpHeaderAddContRange(hdr, *singleSpec, rep->content_length); } else { /* multipart! */ - /* generate boundary string */ - http->range_iter.boundary = http->rangeBoundaryStr(); /* delete old Content-Type, add ours */ hdr->delById(Http::HdrType::CONTENT_TYPE); httpHeaderPutStrf(hdr, Http::HdrType::CONTENT_TYPE, "multipart/byteranges; boundary=\"" SQUIDSTRINGPH "\"", SQUIDSTRINGPRINT(http->range_iter.boundary)); - /* Content-Length is not required in multipart responses - * but it is always nice to have one */ - actual_clen = http->mRangeCLen(); - - /* http->out needs to start where we want data at */ - http->out.offset = http->range_iter.currentSpec()->offset; } /* replace Content-Length header */ @@ -504,9 +477,6 @@ hdr->delById(Http::HdrType::CONTENT_LENGTH); hdr->putInt64(Http::HdrType::CONTENT_LENGTH, actual_clen); debugs(33, 3, "actual content length: " << actual_clen); - - /* And start the range iter off */ - http->range_iter.updateSpec(); } } diff -u -r -N squid-4.14/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.15/src/http/url_rewriters/LFS/url_lfs_rewrite.8 --- squid-4.14/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2021-02-08 14:41:45.000000000 +1300 +++ squid-4.15/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2021-05-10 22:40:09.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "URL_LFS_REWRITE 8" -.TH URL_LFS_REWRITE 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH URL_LFS_REWRITE 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/http.cc squid-4.15/src/http.cc --- squid-4.14/src/http.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/http.cc 2021-05-10 14:04:15.000000000 +1200 @@ -65,15 +65,6 @@ #include "DelayPools.h" #endif -#define SQUID_ENTER_THROWING_CODE() try { -#define SQUID_EXIT_THROWING_CODE(status) \ - status = true; \ - } \ - catch (const std::exception &e) { \ - debugs (11, 1, "Exception error:" << e.what()); \ - status = false; \ - } - CBDATA_CLASS_INIT(HttpStateData); static const char *const crlf = "\r\n"; @@ -1235,6 +1226,11 @@ Must(!flags.headers_parsed); } + if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { + abortTransaction("store entry aborted while we were waiting for processReply()"); + return; + } + if (!flags.headers_parsed) { // have not parsed headers yet? PROF_start(HttpStateData_processReplyHeader); processReplyHeader(); @@ -1366,26 +1362,25 @@ bool HttpStateData::decodeAndWriteReplyBody() { - const char *data = NULL; - int len; - bool wasThereAnException = false; assert(flags.chunked); assert(httpChunkDecoder); - SQUID_ENTER_THROWING_CODE(); - MemBuf decodedData; - decodedData.init(); - httpChunkDecoder->setPayloadBuffer(&decodedData); - const bool doneParsing = httpChunkDecoder->parse(inBuf); - inBuf = httpChunkDecoder->remaining(); // sync buffers after parse - len = decodedData.contentSize(); - data=decodedData.content(); - addVirginReplyBody(data, len); - if (doneParsing) { - lastChunk = 1; - flags.do_next_read = false; + try { + MemBuf decodedData; + decodedData.init(); + httpChunkDecoder->setPayloadBuffer(&decodedData); + const bool doneParsing = httpChunkDecoder->parse(inBuf); + inBuf = httpChunkDecoder->remaining(); // sync buffers after parse + addVirginReplyBody(decodedData.content(), decodedData.contentSize()); + if (doneParsing) { + lastChunk = 1; + flags.do_next_read = false; + } + return true; + } + catch (...) { + debugs (11, 2, "de-chunking failure: " << CurrentException); } - SQUID_EXIT_THROWING_CODE(wasThereAnException); - return wasThereAnException; + return false; } /** diff -u -r -N squid-4.14/src/HttpHdrContRange.cc squid-4.15/src/HttpHdrContRange.cc --- squid-4.14/src/HttpHdrContRange.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/HttpHdrContRange.cc 2021-05-10 14:04:15.000000000 +1200 @@ -161,9 +161,13 @@ ++p; - if (*p == '*') + if (*p == '*') { + if (!known_spec(range->spec.offset)) { + debugs(68, 2, "invalid (*/*) content-range-spec near: '" << str << "'"); + return 0; + } range->elength = range_spec_unknown; - else if (!httpHeaderParseOffset(p, &range->elength)) + } else if (!httpHeaderParseOffset(p, &range->elength)) return 0; else if (range->elength <= 0) { /* Additional paranoidal check for BUG2155 - entity-length MUST be > 0 */ @@ -174,6 +178,12 @@ return 0; } + // reject unsatisfied-range and such; we only use well-defined ranges today + if (!known_spec(range->spec.offset) || !known_spec(range->spec.length)) { + debugs(68, 2, "unwanted content-range-spec near: '" << str << "'"); + return 0; + } + debugs(68, 8, "parsed content-range field: " << (long int) range->spec.offset << "-" << (long int) range->spec.offset + range->spec.length - 1 << " / " << diff -u -r -N squid-4.14/src/HttpHdrRange.cc squid-4.15/src/HttpHdrRange.cc --- squid-4.14/src/HttpHdrRange.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/HttpHdrRange.cc 2021-05-10 14:04:15.000000000 +1200 @@ -526,23 +526,6 @@ return true; } -bool -HttpHdrRange::contains(const HttpHdrRangeSpec& r) const -{ - assert(r.length >= 0); - HttpHdrRangeSpec::HttpRange rrange(r.offset, r.offset + r.length); - - for (const_iterator i = begin(); i != end(); ++i) { - HttpHdrRangeSpec::HttpRange irange((*i)->offset, (*i)->offset + (*i)->length); - HttpHdrRangeSpec::HttpRange intersection = rrange.intersection(irange); - - if (intersection.start == irange.start && intersection.size() == irange.size()) - return true; - } - - return false; -} - const HttpHdrRangeSpec * HttpHdrRangeIter::currentSpec() const { diff -u -r -N squid-4.14/src/HttpHeader.cc squid-4.15/src/HttpHeader.cc --- squid-4.14/src/HttpHeader.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/HttpHeader.cc 2021-05-10 14:04:15.000000000 +1200 @@ -33,6 +33,7 @@ #include "util.h" #include +#include /* XXX: the whole set of API managing the entries vector should be rethought * after the parse4r-ng effort is complete. @@ -72,7 +73,7 @@ /* header accounting */ // NP: keep in sync with enum http_hdr_owner_type -static HttpHeaderStat HttpHeaderStats[] = { +static std::array HttpHeaderStats = { HttpHeaderStat(/*hoNone*/ "all", NULL), #if USE_HTCP HttpHeaderStat(/*hoHtcpReply*/ "HTCP reply", &ReplyHeadersMask), @@ -80,11 +81,10 @@ HttpHeaderStat(/*hoRequest*/ "request", &RequestHeadersMask), HttpHeaderStat(/*hoReply*/ "reply", &ReplyHeadersMask) #if USE_OPENSSL - /* hoErrorDetail */ + , HttpHeaderStat(/*hoErrorDetail*/ "error detail templates", nullptr) #endif /* hoEnd */ }; -static int HttpHeaderStatCount = countof(HttpHeaderStats); static int HeaderEntryParsedCount = 0; @@ -127,8 +127,8 @@ CBIT_SET(ReplyHeadersMask,h); } - /* header stats initialized by class constructor */ - assert(HttpHeaderStatCount == hoReply + 1); + assert(HttpHeaderStats[0].label && "httpHeaderInitModule() called via main()"); + assert(HttpHeaderStats[hoEnd-1].label && "HttpHeaderStats created with all elements"); /* init dependent modules */ httpHdrCcInitModule(); @@ -1607,6 +1607,9 @@ assert(hs); assert(e); + if (!hs->owner_mask) + return; // these HttpHeaderStat objects were not meant to be dumped here + dump_stat = hs; storeAppendPrintf(e, "\nHeader Stats: %s\n", hs->label); storeAppendPrintf(e, "\nField type distribution\n"); @@ -1632,7 +1635,6 @@ void httpHeaderStoreReport(StoreEntry * e) { - int i; assert(e); HttpHeaderStats[0].parsedCount = @@ -1644,9 +1646,8 @@ HttpHeaderStats[0].busyDestroyedCount = HttpHeaderStats[hoRequest].busyDestroyedCount + HttpHeaderStats[hoReply].busyDestroyedCount; - for (i = 1; i < HttpHeaderStatCount; ++i) { - httpHeaderStatDump(HttpHeaderStats + i, e); - } + for (const auto &stats: HttpHeaderStats) + httpHeaderStatDump(&stats, e); /* field stats for all messages */ storeAppendPrintf(e, "\nHttp Fields Stats (replies and requests)\n"); diff -u -r -N squid-4.14/src/HttpHeaderRange.h squid-4.15/src/HttpHeaderRange.h --- squid-4.14/src/HttpHeaderRange.h 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/HttpHeaderRange.h 2021-05-10 14:04:15.000000000 +1200 @@ -18,8 +18,11 @@ class HttpReply; class Packable; -/* http byte-range-spec */ - +// TODO: Refactor to disambiguate and provide message-specific APIs. +/// either byte-range-spec (in a request Range header) +/// or suffix-byte-range-spec (in a request Range header) +/// or byte-range part of byte-range-resp (in a response Content-Range header) +/// or "*" part of unsatisfied-range (in a response Content-Range header) class HttpHdrRangeSpec { MEMPROXY_CLASS(HttpHdrRangeSpec); @@ -78,7 +81,6 @@ int64_t firstOffset() const; int64_t lowestOffset(int64_t) const; bool offsetLimitExceeded(const int64_t limit) const; - bool contains(const HttpHdrRangeSpec& r) const; std::vector specs; private: @@ -100,9 +102,9 @@ void updateSpec(); int64_t debt() const; void debt(int64_t); - int64_t debt_size; /* bytes left to send from the current spec */ + int64_t debt_size = 0; /* bytes left to send from the current spec */ String boundary; /* boundary for multipart responses */ - bool valid; + bool valid = false; }; #endif /* SQUID_HTTPHEADERRANGE_H */ diff -u -r -N squid-4.14/src/log/DB/log_db_daemon.8 squid-4.15/src/log/DB/log_db_daemon.8 --- squid-4.14/src/log/DB/log_db_daemon.8 2021-02-08 14:41:46.000000000 +1300 +++ squid-4.15/src/log/DB/log_db_daemon.8 2021-05-10 22:40:09.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "LOG_DB_DAEMON 8" -.TH LOG_DB_DAEMON 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH LOG_DB_DAEMON 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/mgr/QueryParams.cc squid-4.15/src/mgr/QueryParams.cc --- squid-4.14/src/mgr/QueryParams.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/mgr/QueryParams.cc 2021-05-10 14:04:15.000000000 +1200 @@ -14,6 +14,10 @@ #include "mgr/IntParam.h" #include "mgr/QueryParams.h" #include "mgr/StringParam.h" +#include "parser/Tokenizer.h" +#include "sbuf/StringConvert.h" + +#include Mgr::QueryParam::Pointer Mgr::QueryParams::get(const String& name) const @@ -65,61 +69,76 @@ return iter; } -bool -Mgr::QueryParams::ParseParam(const String& paramStr, Param& param) +/** + * Parses the value part of a "param=value" URL section. + * Value can be a comma-separated list of integers or an opaque string. + * + * value = *pchar | ( 1*DIGIT *( ',' 1*DIGIT ) ) + * + * \note opaque string may be a list with a non-integer (e.g., "1,2,3,z") + */ +Mgr::QueryParam::Pointer +ParseParamValue(const SBuf &rawValue) +{ + static const CharacterSet comma("comma", ","); + + Parser::Tokenizer tok(rawValue); + std::vector array; + int64_t intVal = 0; + while (tok.int64(intVal, 10, false)) { + Must(intVal >= std::numeric_limits::min()); + Must(intVal <= std::numeric_limits::max()); + array.emplace_back(intVal); + // integer list has comma between values. + // Require at least one potential DIGIT after the skipped ',' + if (tok.remaining().length() > 1) + (void)tok.skipOne(comma); + } + + if (tok.atEnd()) + return new Mgr::IntParam(array); + else + return new Mgr::StringParam(SBufToString(rawValue)); +} + +/** + * Syntax: + * query = [ param *( '&' param ) ] + * param = name '=' value + * name = [a-zA-Z0-9]+ + * value = *pchar | ( 1*DIGIT *( ',' 1*DIGIT ) ) + */ +void +Mgr::QueryParams::Parse(Parser::Tokenizer &tok, QueryParams &aParams) { - bool parsed = false; - regmatch_t pmatch[3]; - regex_t intExpr; - regcomp(&intExpr, "^([a-z][a-z0-9_]*)=([0-9]+((,[0-9]+))*)$", REG_EXTENDED | REG_ICASE); - regex_t stringExpr; - regcomp(&stringExpr, "^([a-z][a-z0-9_]*)=([^&= ]+)$", REG_EXTENDED | REG_ICASE); - if (regexec(&intExpr, paramStr.termedBuf(), 3, pmatch, 0) == 0) { - param.first = paramStr.substr(pmatch[1].rm_so, pmatch[1].rm_eo); - std::vector array; - int n = pmatch[2].rm_so; - for (int i = n; i < pmatch[2].rm_eo; ++i) { - if (paramStr[i] == ',') { - array.push_back(atoi(paramStr.substr(n, i).termedBuf())); - n = i + 1; - } - } - if (n < pmatch[2].rm_eo) - array.push_back(atoi(paramStr.substr(n, pmatch[2].rm_eo).termedBuf())); - param.second = new IntParam(array); - parsed = true; - } else if (regexec(&stringExpr, paramStr.termedBuf(), 3, pmatch, 0) == 0) { - param.first = paramStr.substr(pmatch[1].rm_so, pmatch[1].rm_eo); - param.second = new StringParam(paramStr.substr(pmatch[2].rm_so, pmatch[2].rm_eo)); - parsed = true; - } - regfree(&stringExpr); - regfree(&intExpr); - return parsed; -} - -bool -Mgr::QueryParams::Parse(const String& aParamsStr, QueryParams& aParams) -{ - if (aParamsStr.size() != 0) { - Param param; - size_t n = 0; - size_t len = aParamsStr.size(); - for (size_t i = n; i < len; ++i) { - if (aParamsStr[i] == '&') { - if (!ParseParam(aParamsStr.substr(n, i), param)) - return false; - aParams.params.push_back(param); - n = i + 1; - } - } - if (n < len) { - if (!ParseParam(aParamsStr.substr(n, len), param)) - return false; - aParams.params.push_back(param); - } + static const CharacterSet nameChars = CharacterSet("param-name", "_") + CharacterSet::ALPHA + CharacterSet::DIGIT; + static const CharacterSet valueChars = CharacterSet("param-value", "&= #").complement(); + static const CharacterSet delimChars("param-delim", "&"); + + while (!tok.atEnd()) { + + // TODO: remove '#' processing when AnyP::Uri splits 'query#fragment' properly + // #fragment handled by caller. Do not throw. + if (tok.remaining()[0] == '#') + return; + + if (tok.skipAll(delimChars)) + continue; + + SBuf nameStr; + if (!tok.prefix(nameStr, nameChars)) + throw TextException("invalid query parameter name", Here()); + if (!tok.skip('=')) + throw TextException("missing parameter value", Here()); + + SBuf valueStr; + if (!tok.prefix(valueStr, valueChars)) + throw TextException("missing or malformed parameter value", Here()); + + const auto name = SBufToString(nameStr); + const auto value = ParseParamValue(valueStr); + aParams.params.emplace_back(name, value); } - return true; } Mgr::QueryParam::Pointer @@ -138,4 +157,3 @@ } return NULL; } - diff -u -r -N squid-4.14/src/mgr/QueryParams.h squid-4.15/src/mgr/QueryParams.h --- squid-4.14/src/mgr/QueryParams.h 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/mgr/QueryParams.h 2021-05-10 14:04:15.000000000 +1200 @@ -13,9 +13,11 @@ #include "ipc/forward.h" #include "mgr/QueryParam.h" +#include "parser/Tokenizer.h" #include "SquidString.h" -#include + #include +#include namespace Mgr { @@ -32,15 +34,13 @@ void pack(Ipc::TypedMsgHdr& msg) const; ///< store params into msg void unpack(const Ipc::TypedMsgHdr& msg); ///< load params from msg /// parses the query string parameters - static bool Parse(const String& aParamsStr, QueryParams& aParams); + static void Parse(Parser::Tokenizer &, QueryParams &); private: /// find query parameter by name Params::const_iterator find(const String& name) const; /// creates a parameter of the specified type static QueryParam::Pointer CreateParam(QueryParam::Type aType); - /// parses string like "param=value"; returns true if success - static bool ParseParam(const String& paramStr, Param& param); private: Params params; diff -u -r -N squid-4.14/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.15/src/security/cert_validators/fake/security_fake_certverify.8 --- squid-4.14/src/security/cert_validators/fake/security_fake_certverify.8 2021-02-08 14:41:46.000000000 +1300 +++ squid-4.15/src/security/cert_validators/fake/security_fake_certverify.8 2021-05-10 22:40:09.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "SECURITY_FAKE_CERTVERIFY 8" -.TH SECURITY_FAKE_CERTVERIFY 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH SECURITY_FAKE_CERTVERIFY 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/security/ServerOptions.cc squid-4.15/src/security/ServerOptions.cc --- squid-4.14/src/security/ServerOptions.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/security/ServerOptions.cc 2021-05-10 14:04:15.000000000 +1200 @@ -24,6 +24,8 @@ #endif #endif +#include + Security::ServerOptions & Security::ServerOptions::operator =(const Security::ServerOptions &old) { if (this != &old) { diff -u -r -N squid-4.14/src/snmp_core.cc squid-4.15/src/snmp_core.cc --- squid-4.14/src/snmp_core.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/snmp_core.cc 2021-05-10 14:04:15.000000000 +1200 @@ -947,7 +947,7 @@ } // if we aborted before the lst octet was found, return false. - safe_free(name); + safe_free(*name); return false; } diff -u -r -N squid-4.14/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.15/src/store/id_rewriters/file/storeid_file_rewrite.8 --- squid-4.14/src/store/id_rewriters/file/storeid_file_rewrite.8 2021-02-08 14:41:44.000000000 +1300 +++ squid-4.15/src/store/id_rewriters/file/storeid_file_rewrite.8 2021-05-10 22:40:07.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "STOREID_FILE_REWRITE 8" -.TH STOREID_FILE_REWRITE 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH STOREID_FILE_REWRITE 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/src/tests/stub_libmgr.cc squid-4.15/src/tests/stub_libmgr.cc --- squid-4.14/src/tests/stub_libmgr.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/tests/stub_libmgr.cc 2021-05-10 14:04:15.000000000 +1200 @@ -174,11 +174,10 @@ Mgr::QueryParam::Pointer Mgr::QueryParams::get(const String& name) const STUB_RETVAL(Mgr::QueryParam::Pointer(NULL)) void Mgr::QueryParams::pack(Ipc::TypedMsgHdr& msg) const STUB void Mgr::QueryParams::unpack(const Ipc::TypedMsgHdr& msg) STUB -bool Mgr::QueryParams::Parse(const String& aParamsStr, QueryParams& aParams) STUB_RETVAL(false) +void Mgr::QueryParams::Parse(Parser::Tokenizer &, QueryParams &) STUB //private: //Params::const_iterator Mgr::QueryParams::find(const String& name) const STUB_RETVAL(new Mgr::Params::const_iterator(*this)) Mgr::QueryParam::Pointer Mgr::QueryParams::CreateParam(QueryParam::Type aType) STUB_RETVAL(Mgr::QueryParam::Pointer(NULL)) -bool Mgr::QueryParams::ParseParam(const String& paramStr, Param& param) STUB_RETVAL(false) #include "mgr/Registration.h" //void Mgr::RegisterAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic); diff -u -r -N squid-4.14/src/tests/testCacheManager.cc squid-4.15/src/tests/testCacheManager.cc --- squid-4.14/src/tests/testCacheManager.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/tests/testCacheManager.cc 2021-05-10 14:04:15.000000000 +1200 @@ -7,6 +7,7 @@ */ #include "squid.h" +#include "anyp/Uri.h" #include "CacheManager.h" #include "mgr/Action.h" #include "Store.h" @@ -17,11 +18,19 @@ CPPUNIT_TEST_SUITE_REGISTRATION( testCacheManager ); +/// Provides test code access to CacheManager internal symbols +class CacheManagerInternals : public CacheManager +{ +public: + void ParseUrl(const AnyP::Uri &u) { CacheManager::ParseUrl(u); } +}; + /* init memory pools */ void testCacheManager::setUp() { Mem::Init(); + AnyP::UriScheme::Init(); } /* @@ -66,3 +75,146 @@ CPPUNIT_ASSERT_EQUAL(1,(int)sentry->flags); } +void +testCacheManager::testParseUrl() +{ + auto *mgr = static_cast(CacheManager::GetInstance()); + CPPUNIT_ASSERT(mgr != nullptr); + + std::vector validSchemes = { + AnyP::PROTO_CACHE_OBJECT, + AnyP::PROTO_HTTP, + AnyP::PROTO_HTTPS, + AnyP::PROTO_FTP + }; + + AnyP::Uri mgrUrl; + mgrUrl.host("localhost"); + mgrUrl.port(3128); + + const std::vector magicPrefixes = { + "/", + "/squid-internal-mgr/" + }; + + const std::vector validActions = { + "", + "menu" + }; + + const std::vector invalidActions = { + "INVALID" // any unregistered name + }; + + const std::vector validParams = { + "", + "?", + "?&", + "?&&&&&&&&&&&&", + "?foo=bar", + "?0123456789=bar", + "?foo=bar&", + "?foo=bar&&&&", + "?&foo=bar", + "?&&&&foo=bar", + "?&foo=bar&", + "?&&&&foo=bar&&&&", + "?foo=?_weird?~`:[]stuff&bar=okay&&&&&&", + "?intlist=1", + "?intlist=1,2,3,4,5", + "?string=1a", + "?string=1,2,3,4,z", + "?string=1,2,3,4,[0]", + "?intlist=1,2,3,4,5&string=1,2,3,4,y" + }; + + const std::vector invalidParams = { + "?/", + "?foo", + "?/foo", + "?foo/", + "?foo=", + "?foo=&", + "?=foo", + "? foo=bar", + "? &", + "?& ", + "?=&", + "?&=", + "? &&&", + "?& &&", + "?&& &", + "?=&&&", + "?&=&&", + "?&&=&" + }; + + const std::vector validFragments = { + "", + "#", + "##", + "#?a=b", + "#fragment" + }; + + for (const auto &scheme : validSchemes) { + mgrUrl.setScheme(scheme); + + for (const auto *magic : magicPrefixes) { + + // all schemes except cache_object require magic path prefix bytes + if (scheme != AnyP::PROTO_CACHE_OBJECT && strlen(magic) <= 2) + continue; + + /* Check the parser accepts all the valid cases */ + + for (const auto *action : validActions) { + for (const auto *param : validParams) { + for (const auto *frag : validFragments) { + try { + SBuf bits; + bits.append(magic); + bits.append(action); + bits.append(param); + bits.append(frag); + mgrUrl.path(bits); + + (void)mgr->ParseUrl(mgrUrl); + } catch (...) { + std::cerr << std::endl + << "FAIL: " << mgrUrl + << Debug::Extra << "error: " << CurrentException << std::endl; + CPPUNIT_FAIL("rejected a valid URL"); + } + } + } + } + + /* Check that invalid parameters are rejected */ + + for (const auto *action : validActions) { + for (const auto *param : invalidParams) { + for (const auto *frag : validFragments) { + try { + SBuf bits; + bits.append(magic); + bits.append(action); + bits.append(param); + bits.append(frag); + mgrUrl.path(bits); + + (void)mgr->ParseUrl(mgrUrl); + + std::cerr << std::endl + << "FAIL: " << mgrUrl + << Debug::Extra << "error: should be rejected due to '" << param << "'" << std::endl; + } catch (const TextException &e) { + continue; // success. caught bad input + } + CPPUNIT_FAIL("failed to reject an invalid URL"); + } + } + } + } + } +} diff -u -r -N squid-4.14/src/tests/testCacheManager.h squid-4.15/src/tests/testCacheManager.h --- squid-4.14/src/tests/testCacheManager.h 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/tests/testCacheManager.h 2021-05-10 14:04:15.000000000 +1200 @@ -20,6 +20,7 @@ CPPUNIT_TEST_SUITE( testCacheManager ); CPPUNIT_TEST( testCreate ); CPPUNIT_TEST( testRegister ); + CPPUNIT_TEST( testParseUrl ); CPPUNIT_TEST_SUITE_END(); public: @@ -28,6 +29,7 @@ protected: void testCreate(); void testRegister(); + void testParseUrl(); }; #endif diff -u -r -N squid-4.14/src/urn.cc squid-4.15/src/urn.cc --- squid-4.14/src/urn.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/urn.cc 2021-05-10 14:04:15.000000000 +1200 @@ -244,6 +244,12 @@ return; } + if (!e->isAccepting()) { + debugs(52, 3, "terminating due to bad " << *e); + delete urnState; + return; + } + /* Update reqofs to point to where in the buffer we'd be */ urnState->reqofs += result.length; @@ -412,6 +418,7 @@ } debugs(52, 3, "urnParseReply: Found " << i << " URLs"); + xfree(buf); return list; } diff -u -r -N squid-4.14/src/whois.cc squid-4.15/src/whois.cc --- squid-4.14/src/whois.cc 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/src/whois.cc 2021-05-10 14:04:15.000000000 +1200 @@ -120,6 +120,16 @@ debugs(75, 3, HERE << conn << " read " << aBufferLength << " bytes"); debugs(75, 5, "{" << aBuffer << "}"); + // TODO: Honor delay pools. + + // XXX: Update statCounter before bailing + if (!entry->isAccepting()) { + debugs(52, 3, "terminating due to bad " << *entry); + // TODO: Do not abuse connection for triggering cleanup. + conn->close(); + return; + } + if (flag != Comm::OK) { debugs(50, 2, conn << ": read failure: " << xstrerr(xerrno)); diff -u -r -N squid-4.14/tools/helper-mux/helper-mux.8 squid-4.15/tools/helper-mux/helper-mux.8 --- squid-4.14/tools/helper-mux/helper-mux.8 2021-02-08 14:41:47.000000000 +1300 +++ squid-4.15/tools/helper-mux/helper-mux.8 2021-05-10 22:40:10.000000000 +1200 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "HELPER-MUX 8" -.TH HELPER-MUX 8 "2021-02-08" "perl v5.32.0" "User Contributed Perl Documentation" +.TH HELPER-MUX 8 "2021-05-10" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff -u -r -N squid-4.14/tools/squidclient/squidclient.1 squid-4.15/tools/squidclient/squidclient.1 --- squid-4.14/tools/squidclient/squidclient.1 2021-02-05 11:13:34.000000000 +1300 +++ squid-4.15/tools/squidclient/squidclient.1 2021-05-10 14:04:15.000000000 +1200 @@ -219,7 +219,7 @@ . .if !'po4a'hide' .TP .if !'po4a'hide' .B "\-g count" -Ping mode, perform\ +Ping mode, perform .I count iterations (default is to loop until interrupted). .