diff -u -r -N squid-3.5.21/ChangeLog squid-3.5.22/ChangeLog --- squid-3.5.21/ChangeLog 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/ChangeLog 2016-10-10 08:58:01.000000000 +1300 @@ -1,3 +1,17 @@ +Changes to squid-3.5.22 (09 Oct 2016): + + - Bug 4594: build failure with clang 3.9 + - Bug 4471: revalidation does not work when expired cached object lacks Last-Modified + - Bug 4302 pt2: IPv6 support for IPFilter v5 transparent interception + - Bug 4228: ./configure bug/typo in r14394 + - Bug 3819: "fd >= 0" assertion in file_write() during reconfiguration + - Bug 2833: Collapse internal revalidation requests (SMP-unaware caches) + - Fix logged request size (%http::>st) and other size-related %codes + - Fix some memory leaks from putenv() + - Fix memory leaks from url_rewrite_extras and store_id_extras on reconfigure/shutdown + - Fix segfault crash when debugging section 4 at level 9 + - HTTP: MUST ignore a [revalidation] response with an older Date header + Changes to squid-3.5.21 (08 Sep 2016): - Bug 4563: duplicate code in httpMakeVaryMark diff -u -r -N squid-3.5.21/configure squid-3.5.22/configure --- squid-3.5.21/configure 2016-09-09 07:00:42.000000000 +1200 +++ squid-3.5.22/configure 2016-10-10 09:04:24.000000000 +1300 @@ -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 3.5.21. +# Generated by GNU Autoconf 2.69 for Squid Web Proxy 3.5.22. # # Report bugs to . # @@ -595,8 +595,8 @@ # Identity of this package. PACKAGE_NAME='Squid Web Proxy' PACKAGE_TARNAME='squid' -PACKAGE_VERSION='3.5.21' -PACKAGE_STRING='Squid Web Proxy 3.5.21' +PACKAGE_VERSION='3.5.22' +PACKAGE_STRING='Squid Web Proxy 3.5.22' PACKAGE_BUGREPORT='http://bugs.squid-cache.org/' PACKAGE_URL='' @@ -1636,7 +1636,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 3.5.21 to adapt to many kinds of systems. +\`configure' configures Squid Web Proxy 3.5.22 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1707,7 +1707,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Squid Web Proxy 3.5.21:";; + short | recursive ) echo "Configuration of Squid Web Proxy 3.5.22:";; esac cat <<\_ACEOF @@ -2119,7 +2119,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Squid Web Proxy configure 3.5.21 +Squid Web Proxy configure 3.5.22 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -3223,7 +3223,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 3.5.21, which was +It was created by Squid Web Proxy $as_me 3.5.22, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4090,7 +4090,7 @@ # Define the identity of the package. PACKAGE='squid' - VERSION='3.5.21' + VERSION='3.5.22' cat >>confdefs.h <<_ACEOF @@ -30339,7 +30339,7 @@ fi if test "x$KRB5LIBS" = "x"; then - if test test "x$with_heimdal_krb5" = "xyes"; then + if test "x$with_heimdal_krb5" = "xyes"; then as_fn_error $? "Required Heimdal Kerberos library not found" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Heimdal Kerberos library not found" >&5 @@ -30857,7 +30857,7 @@ fi if test "x$KRB5LIBS" = "x"; then - if test test "x$with_gnugss" = "xyes"; then + if test "x$with_gnugss" = "xyes"; then as_fn_error $? "Required GNU GSS Kerberos library not found" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GNU GSS Kerberos library not found" >&5 @@ -41876,7 +41876,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 3.5.21, which was +This file was extended by Squid Web Proxy $as_me 3.5.22, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -41942,7 +41942,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 3.5.21 +Squid Web Proxy config.status 3.5.22 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -u -r -N squid-3.5.21/configure.ac squid-3.5.22/configure.ac --- squid-3.5.21/configure.ac 2016-09-09 07:00:41.000000000 +1200 +++ squid-3.5.22/configure.ac 2016-10-10 09:04:22.000000000 +1300 @@ -5,7 +5,7 @@ ## Please see the COPYING and CONTRIBUTORS files for details. ## -AC_INIT([Squid Web Proxy],[3.5.21],[http://bugs.squid-cache.org/],[squid]) +AC_INIT([Squid Web Proxy],[3.5.22],[http://bugs.squid-cache.org/],[squid]) AC_PREREQ(2.61) AC_CONFIG_HEADERS([include/autoconf.h]) AC_CONFIG_AUX_DIR(cfgaux) @@ -1778,7 +1778,7 @@ SQUID_CHECK_KRB5_FUNCS fi if test "x$KRB5LIBS" = "x"; then - if test test "x$with_heimdal_krb5" = "xyes"; then + if test "x$with_heimdal_krb5" = "xyes"; then AC_MSG_ERROR([Required Heimdal Kerberos library not found]) else AC_MSG_WARN([Heimdal Kerberos library not found]) @@ -1848,7 +1848,7 @@ SQUID_DEFINE_BOOL(HAVE_KRB5,$squid_cv_working_krb5,[KRB5 support]) fi if test "x$KRB5LIBS" = "x"; then - if test test "x$with_gnugss" = "xyes"; then + if test "x$with_gnugss" = "xyes"; then AC_MSG_ERROR([Required GNU GSS Kerberos library not found]) else AC_MSG_WARN([GNU GSS Kerberos library not found]) diff -u -r -N squid-3.5.21/doc/release-notes/release-3.5.html squid-3.5.22/doc/release-notes/release-3.5.html --- squid-3.5.21/doc/release-notes/release-3.5.html 2016-09-09 08:06:08.000000000 +1200 +++ squid-3.5.22/doc/release-notes/release-3.5.html 2016-10-10 12:34:07.000000000 +1300 @@ -2,10 +2,10 @@ - Squid 3.5.21 release notes + Squid 3.5.22 release notes -

Squid 3.5.21 release notes

+

Squid 3.5.22 release notes

Squid Developers


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

1. Notice

-

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

+

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

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

diff -u -r -N squid-3.5.21/helpers/basic_auth/DB/basic_db_auth.8 squid-3.5.22/helpers/basic_auth/DB/basic_db_auth.8 --- squid-3.5.21/helpers/basic_auth/DB/basic_db_auth.8 2016-09-09 08:06:12.000000000 +1200 +++ squid-3.5.22/helpers/basic_auth/DB/basic_db_auth.8 2016-10-10 12:34:14.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_DB_AUTH 8" -.TH BASIC_DB_AUTH 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH BASIC_DB_AUTH 8 "2016-10-09" "perl v5.24.1" "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 @@ -191,7 +187,7 @@ Keep a persistent database connection open between queries. .IP "\fB\-\-joomla\fR" 12 .IX Item "--joomla" -Tells helper that user database is Joomla \s-1DB. \s0 So their unusual salt +Tells helper that user database is Joomla \s-1DB.\s0 So their unusual salt hashing is understood. .SH "AUTHOR" .IX Header "AUTHOR" @@ -230,7 +226,7 @@ Report ideas for new improvements to the \fISquid Developers mailing list .SH "SEE ALSO" .IX Header "SEE ALSO" -squid (8), \s-1GPL \\fIs0\fR\|(7), +squid (8), \s-1GPL\s0 (7), .PP The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq .PP diff -u -r -N squid-3.5.21/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8 squid-3.5.22/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8 --- squid-3.5.21/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8 2016-09-09 08:06:18.000000000 +1200 +++ squid-3.5.22/helpers/basic_auth/MSNT-multi-domain/basic_msnt_multi_domain_auth.8 2016-10-10 12:34:22.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_MSNT_MULTI_DOMAIN_AUTH 1" -.TH BASIC_MSNT_MULTI_DOMAIN_AUTH 1 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH BASIC_MSNT_MULTI_DOMAIN_AUTH 1 "2016-10-09" "perl v5.24.1" "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 @@ -205,7 +201,7 @@ Report ideas for new improvements to the \fISquid Developers mailing list .SH "SEE ALSO" .IX Header "SEE ALSO" -squid (8), \s-1GPL \\fIs0\fR\|(7), +squid (8), \s-1GPL\s0 (7), .PP The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq .PP diff -u -r -N squid-3.5.21/helpers/basic_auth/POP3/basic_pop3_auth.8 squid-3.5.22/helpers/basic_auth/POP3/basic_pop3_auth.8 --- squid-3.5.21/helpers/basic_auth/POP3/basic_pop3_auth.8 2016-09-09 08:06:24.000000000 +1200 +++ squid-3.5.22/helpers/basic_auth/POP3/basic_pop3_auth.8 2016-10-10 12:34:31.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_POP3_AUTH 8" -.TH BASIC_POP3_AUTH 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH BASIC_POP3_AUTH 8 "2016-10-09" "perl v5.24.1" "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 @@ -202,7 +198,7 @@ Report ideas for new improvements to the \fISquid Developers mailing list .SH "SEE ALSO" .IX Header "SEE ALSO" -squid (8), \s-1GPL \\fIs0\fR\|(7), +squid (8), \s-1GPL\s0 (7), .PP The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq .PP diff -u -r -N squid-3.5.21/helpers/external_acl/delayer/ext_delayer_acl.8 squid-3.5.22/helpers/external_acl/delayer/ext_delayer_acl.8 --- squid-3.5.21/helpers/external_acl/delayer/ext_delayer_acl.8 2016-09-09 08:06:41.000000000 +1200 +++ squid-3.5.22/helpers/external_acl/delayer/ext_delayer_acl.8 2016-10-10 12:34:52.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "EXT_DELAYER_ACL 8" -.TH EXT_DELAYER_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH EXT_DELAYER_ACL 8 "2016-10-09" "perl v5.24.1" "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 @@ -225,7 +221,7 @@ Report ideas for new improvements to the \fISquid Developers mailing list .SH "SEE ALSO" .IX Header "SEE ALSO" -squid (8), \s-1GPL \\fIs0\fR\|(7), +squid (8), \s-1GPL\s0 (7), .PP The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq .PP diff -u -r -N squid-3.5.21/helpers/external_acl/SQL_session/ext_sql_session_acl.8 squid-3.5.22/helpers/external_acl/SQL_session/ext_sql_session_acl.8 --- squid-3.5.21/helpers/external_acl/SQL_session/ext_sql_session_acl.8 2016-09-09 08:06:50.000000000 +1200 +++ squid-3.5.22/helpers/external_acl/SQL_session/ext_sql_session_acl.8 2016-10-10 12:35:06.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "EXT_SQL_SESSION_ACL 8" -.TH EXT_SQL_SESSION_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH EXT_SQL_SESSION_ACL 8 "2016-10-09" "perl v5.24.1" "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 @@ -154,7 +150,7 @@ Taking an identity token to be validated (as determined by the external_acl_type format) it returns a username or tag associated with the identity token passed in. .PP -Common forms of identifiers are \s-1IP\s0 address, \s-1EUI \s0(\s-1MAC\s0) address, passwords, or \s-1UUID\s0 tokens. +Common forms of identifiers are \s-1IP\s0 address, \s-1EUI\s0 (\s-1MAC\s0) address, passwords, or \s-1UUID\s0 tokens. .PP This program uses Squid concurrency support. .SH "OPTIONS" @@ -225,7 +221,7 @@ Report ideas for new improvements to the \fISquid Developers mailing list .SH "SEE ALSO" .IX Header "SEE ALSO" -squid (8), \s-1GPL \\fIs0\fR\|(7), +squid (8), \s-1GPL\s0 (7), .PP The Squid \s-1FAQ\s0 wiki http://wiki.squid\-cache.org/SquidFaq .PP diff -u -r -N squid-3.5.21/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8 squid-3.5.22/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8 --- squid-3.5.21/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8 2016-09-09 08:06:55.000000000 +1200 +++ squid-3.5.22/helpers/external_acl/wbinfo_group/ext_wbinfo_group_acl.8 2016-10-10 12:35:12.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "EXT_WBINFO_GROUP_ACL 8" -.TH EXT_WBINFO_GROUP_ACL 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH EXT_WBINFO_GROUP_ACL 8 "2016-10-09" "perl v5.24.1" "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-3.5.21/helpers/log_daemon/DB/log_db_daemon.8 squid-3.5.22/helpers/log_daemon/DB/log_db_daemon.8 --- squid-3.5.21/helpers/log_daemon/DB/log_db_daemon.8 2016-09-09 08:06:58.000000000 +1200 +++ squid-3.5.22/helpers/log_daemon/DB/log_db_daemon.8 2016-10-10 12:35:15.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "LOG_DB_DAEMON 8" -.TH LOG_DB_DAEMON 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH LOG_DB_DAEMON 8 "2016-10-09" "perl v5.24.1" "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-3.5.21/helpers/storeid_rewrite/file/storeid_file_rewrite.8 squid-3.5.22/helpers/storeid_rewrite/file/storeid_file_rewrite.8 --- squid-3.5.21/helpers/storeid_rewrite/file/storeid_file_rewrite.8 2016-09-09 08:07:15.000000000 +1200 +++ squid-3.5.22/helpers/storeid_rewrite/file/storeid_file_rewrite.8 2016-10-10 12:35:38.000000000 +1300 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29) +.\" Automatically generated by Pod::Man 4.08 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is turned on, we'll generate index entries on stderr for +.\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -54,20 +54,16 @@ .\" Avoid warning from groff about undefined register 'F'. .de IX .. -.nr rF 0 -.if \n(.g .if rF .nr rF 1 -.if (\n(rF:(\n(.g==0)) \{ -. if \nF \{ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" .. -. if !\nF==2 \{ -. nr % 0 -. nr F 2 -. \} +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 . \} .\} -.rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. @@ -133,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "STOREID_FILE_REWRITE 8" -.TH STOREID_FILE_REWRITE 8 "2016-09-08" "perl v5.22.2" "User Contributed Perl Documentation" +.TH STOREID_FILE_REWRITE 8 "2016-10-09" "perl v5.24.1" "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 @@ -213,7 +209,7 @@ Report ideas for new improvements to the \fISquid Developers mailing list .SH "SEE ALSO" .IX Header "SEE ALSO" -squid (8), \s-1GPL \\fIs0\fR\|(7), +squid (8), \s-1GPL\s0 (7), .PP The Squid wiki http://wiki.squid\-cache.org/Features/StoreID .PP diff -u -r -N squid-3.5.21/include/version.h squid-3.5.22/include/version.h --- squid-3.5.21/include/version.h 2016-09-09 07:00:42.000000000 +1200 +++ squid-3.5.22/include/version.h 2016-10-10 09:04:24.000000000 +1300 @@ -7,7 +7,7 @@ */ #ifndef SQUID_RELEASE_TIME -#define SQUID_RELEASE_TIME 1473360998 +#define SQUID_RELEASE_TIME 1476043069 #endif /* diff -u -r -N squid-3.5.21/RELEASENOTES.html squid-3.5.22/RELEASENOTES.html --- squid-3.5.21/RELEASENOTES.html 2016-09-09 08:06:08.000000000 +1200 +++ squid-3.5.22/RELEASENOTES.html 2016-10-10 12:34:07.000000000 +1300 @@ -2,10 +2,10 @@ - Squid 3.5.21 release notes + Squid 3.5.22 release notes -

Squid 3.5.21 release notes

+

Squid 3.5.22 release notes

Squid Developers


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

1. Notice

-

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

+

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

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

diff -u -r -N squid-3.5.21/src/adaptation/ecap/XactionRep.cc squid-3.5.22/src/adaptation/ecap/XactionRep.cc --- squid-3.5.21/src/adaptation/ecap/XactionRep.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/adaptation/ecap/XactionRep.cc 2016-10-10 08:58:01.000000000 +1300 @@ -726,7 +726,7 @@ buf.append(" A?", 3); } - buf.Printf(" %s%u]", id.Prefix, id.value); + buf.Printf(" %s%u]", id.prefix(), id.value); buf.terminate(); diff -u -r -N squid-3.5.21/src/adaptation/History.cc squid-3.5.22/src/adaptation/History.cc --- squid-3.5.21/src/adaptation/History.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/adaptation/History.cc 2016-10-10 08:58:01.000000000 +1300 @@ -150,9 +150,9 @@ void Adaptation::History::recordMeta(const HttpHeader *lm) { lastMeta.clean(); - lastMeta.update(lm, NULL); + lastMeta.update(lm); - allMeta.update(lm, NULL); + allMeta.update(lm); allMeta.compact(); } diff -u -r -N squid-3.5.21/src/adaptation/icap/ModXact.cc squid-3.5.22/src/adaptation/icap/ModXact.cc --- squid-3.5.21/src/adaptation/icap/ModXact.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/adaptation/icap/ModXact.cc 2016-10-10 08:58:01.000000000 +1300 @@ -1259,31 +1259,32 @@ void Adaptation::Icap::ModXact::finalizeLogInfo() { - HttpRequest * request_ = NULL; - HttpRequest * adapted_request_ = NULL; - HttpReply * reply_ = NULL; - request_ = (virgin.cause? virgin.cause: dynamic_cast(virgin.header)); + HttpRequest *adapted_request_ = NULL; + HttpReply *adapted_reply_ = NULL; + HttpRequest *virgin_request_ = const_cast(&virginRequest()); if (!(adapted_request_ = dynamic_cast(adapted.header))) { - adapted_request_ = request_; - reply_ = dynamic_cast(adapted.header); + // if the request was not adapted, use virgin request to simplify + // the code further below + adapted_request_ = virgin_request_; + adapted_reply_ = dynamic_cast(adapted.header); } - Adaptation::Icap::History::Pointer h = (request_ ? request_->icapHistory() : NULL); + Adaptation::Icap::History::Pointer h = virgin_request_->icapHistory(); Must(h != NULL); // ICAPXaction::maybeLog calls only if there is a log al.icp.opcode = ICP_INVALID; al.url = h->log_uri.termedBuf(); const Adaptation::Icap::ServiceRep &s = service(); al.icap.reqMethod = s.cfg().method; - al.cache.caddr = request_->client_addr; + al.cache.caddr = virgin_request_->client_addr; - al.request = request_; + al.request = virgin_request_; HTTPMSGLOCK(al.request); al.adapted_request = adapted_request_; HTTPMSGLOCK(al.adapted_request); - if (reply_) { - al.reply = reply_; + if (adapted_reply_) { + al.reply = adapted_reply_; HTTPMSGLOCK(al.reply); } else al.reply = NULL; @@ -1296,25 +1297,29 @@ al.cache.ssluser = h->ssluser.termedBuf(); #endif al.cache.code = h->logType; - // XXX: should use icap-specific counters instead ? - al.http.clientRequestSz.payloadData = h->req_sz; + + const HttpMsg *virgin_msg = dynamic_cast(virgin.header); + if (!virgin_msg) + virgin_msg = virgin_request_; + assert(virgin_msg != virgin.cause); + al.http.clientRequestSz.header = virgin_msg->hdr_sz; + al.http.clientRequestSz.payloadData = virgin_msg->body_pipe->producedSize(); // leave al.icap.bodyBytesRead negative if no body if (replyHttpHeaderSize >= 0 || replyHttpBodySize >= 0) { const int64_t zero = 0; // to make max() argument types the same - al.icap.bodyBytesRead = - max(zero, replyHttpHeaderSize) + max(zero, replyHttpBodySize); + const uint64_t headerSize = max(zero, replyHttpHeaderSize); + const uint64_t bodySize = max(zero, replyHttpBodySize); + al.icap.bodyBytesRead = headerSize + bodySize; + al.http.clientReplySz.header = headerSize; + al.http.clientReplySz.payloadData = bodySize; } - if (reply_) { - al.http.code = reply_->sline.status(); - al.http.content_type = reply_->content_type.termedBuf(); - if (replyHttpBodySize >= 0) { - // XXX: should use icap-specific counters instead ? - al.http.clientReplySz.payloadData = replyHttpBodySize; - al.http.clientReplySz.header = reply_->hdr_sz; + if (adapted_reply_) { + al.http.code = adapted_reply_->sline.status(); + al.http.content_type = adapted_reply_->content_type.termedBuf(); + if (replyHttpBodySize >= 0) al.cache.highOffset = replyHttpBodySize; - } //don't set al.cache.objectSize because it hasn't exist yet Packer p; @@ -1323,7 +1328,7 @@ mb.init(); packerToMemInit(&p, &mb); - reply_->header.packInto(&p); + adapted_reply_->header.packInto(&p); al.headers.reply = xstrdup(mb.buf); packerClean(&p); diff -u -r -N squid-3.5.21/src/adaptation/icap/Xaction.cc squid-3.5.22/src/adaptation/icap/Xaction.cc --- squid-3.5.21/src/adaptation/icap/Xaction.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/adaptation/icap/Xaction.cc 2016-10-10 08:58:01.000000000 +1300 @@ -598,9 +598,7 @@ fillPendingStatus(buf); buf.append("/", 1); fillDoneStatus(buf); - - buf.Printf(" %s%u]", id.Prefix, id.value); - + buf.Printf(" %s%u]", id.prefix(), id.value); buf.terminate(); return buf.content(); diff -u -r -N squid-3.5.21/src/base/AsyncJob.cc squid-3.5.22/src/base/AsyncJob.cc --- squid-3.5.21/src/base/AsyncJob.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/base/AsyncJob.cc 2016-10-10 08:58:01.000000000 +1300 @@ -164,7 +164,7 @@ buf.Printf("Stopped, reason:"); buf.Printf("%s",stopReason); } - buf.Printf(" %s%u]", id.Prefix, id.value); + buf.Printf(" %s%u]", id.prefix(), id.value); buf.terminate(); return buf.content(); diff -u -r -N squid-3.5.21/src/base/InstanceId.h squid-3.5.22/src/base/InstanceId.h --- squid-3.5.21/src/base/InstanceId.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/base/InstanceId.h 2016-10-10 08:58:01.000000000 +1300 @@ -25,35 +25,41 @@ public: typedef unsigned int Value; ///< id storage type; \todo: parameterize? - InstanceId(): value(++Last ? Last : ++Last) {} + InstanceId(): value(0) {change();} operator Value() const { return value; } bool operator ==(const InstanceId &o) const { return value == o.value; } bool operator !=(const InstanceId &o) const { return !(*this == o); } - void change() {value = ++Last ? Last : ++Last;} + void change(); - /// prints Prefix followed by ID value; \todo: use HEX for value printing? + /// prints class-pecific prefix followed by ID value; \todo: use HEX for value printing? std::ostream &print(std::ostream &os) const; + /// returns the class-pecific prefix + const char * const prefix() const; + public: - static const char *Prefix; ///< Class shorthand string for debugging Value value; ///< instance identifier private: InstanceId(const InstanceId& right); ///< not implemented; IDs are unique InstanceId& operator=(const InstanceId &right); ///< not implemented - -private: - static Value Last; ///< the last used ID value }; /// convenience macro to instantiate Class-specific stuff in .cc files -#define InstanceIdDefinitions(Class, prefix) \ - template<> const char *InstanceId::Prefix = prefix; \ - template<> InstanceId::Value InstanceId::Last = 0; \ +#define InstanceIdDefinitions(Class, pfx) \ + template<> const char * const \ + InstanceId::prefix() const { \ + return pfx; \ + } \ template<> std::ostream & \ InstanceId::print(std::ostream &os) const { \ - return os << Prefix << value; \ + return os << pfx << value; \ + } \ + template<> void \ + InstanceId::change() { \ + static InstanceId::Value Last = 0; \ + value = ++Last ? Last : ++Last; \ } /// print the id diff -u -r -N squid-3.5.21/src/cache_cf.cc squid-3.5.22/src/cache_cf.cc --- squid-3.5.21/src/cache_cf.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/cache_cf.cc 2016-10-10 08:58:01.000000000 +1300 @@ -849,7 +849,7 @@ if (pwd->pw_dir && *pwd->pw_dir) { // putenv() leaks by design; avoid leaks when nothing changes static SBuf lastDir; - if (lastDir.isEmpty() || !lastDir.cmp(pwd->pw_dir)) { + if (lastDir.isEmpty() || lastDir.cmp(pwd->pw_dir) != 0) { lastDir = pwd->pw_dir; int len = strlen(pwd->pw_dir) + 6; char *env_str = (char *)xcalloc(len, 1); diff -u -r -N squid-3.5.21/src/cf.data.pre squid-3.5.22/src/cf.data.pre --- squid-3.5.21/src/cf.data.pre 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/cf.data.pre 2016-10-10 08:58:01.000000000 +1300 @@ -4427,13 +4427,35 @@ ICAP transaction log lines will correspond to a single access log line. - ICAP log uses logformat codes that make sense for an ICAP - transaction. Header-related codes are applied to the HTTP header - embedded in an ICAP server response, with the following caveats: - For REQMOD, there is no HTTP response header unless the ICAP - server performed request satisfaction. For RESPMOD, the HTTP - request header is the header sent to the ICAP server. For - OPTIONS, there are no HTTP headers. + ICAP log supports many access.log logformat %codes. In ICAP context, + HTTP message-related %codes are applied to the HTTP message embedded + in an ICAP message. Logformat "%http::>..." codes are used for HTTP + messages embedded in ICAP requests while "%http::<..." codes are used + for HTTP messages embedded in ICAP responses. For example: + + http::>h To-be-adapted HTTP message headers sent by Squid to + the ICAP service. For REQMOD transactions, these are + HTTP request headers. For RESPMOD, these are HTTP + response headers, but Squid currently cannot log them + (i.e., %http::>h will expand to "-" for RESPMOD). + + http::st Bytes sent to the ICAP server (TCP payload - only; i.e., what Squid writes to the socket). + icap::>st The total size of the ICAP request sent to the ICAP + server (ICAP headers + ICAP body), including chunking + metadata (if any). + + icap::a %icap::to/%03icap::Hs %icap::A %icap::to/%03icap::Hs %icap::http.method = request->method; aLogEntry->http.version = request->http_ver; aLogEntry->hier = request->hier; - if (request->content_length > 0) // negative when no body or unknown length - aLogEntry->http.clientRequestSz.payloadData += request->content_length; // XXX: actually adaptedRequest payload size ?? aLogEntry->cache.extuser = request->extacl_user.termedBuf(); // Adapted request, if any, inherits and then collects all the stats, but @@ -593,6 +591,9 @@ al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ? al->http.clientRequestSz.header = req_sz; + // the virgin request is saved to al->request + if (al->request && al->request->body_pipe != NULL) + al->http.clientRequestSz.payloadData = al->request->body_pipe->producedSize(); al->http.clientReplySz.header = out.headers_sz; // XXX: calculate without payload encoding or headers !! al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now. @@ -1236,7 +1237,7 @@ /* got modification time? */ if (spec.time >= 0) { - return http->storeEntry()->lastmod <= spec.time; + return !http->storeEntry()->modifiedSince(spec.time); } assert(0); /* should not happen */ @@ -2744,6 +2745,7 @@ request->my_addr = conn->clientConnection->local; request->myportname = conn->port->name; request->http_ver = http_ver; + request->hdr_sz = http->req_sz; // Link this HttpRequest to ConnStateData relatively early so the following complex handling can use it // TODO: this effectively obsoletes a lot of conn->FOO copying. That needs cleaning up later. diff -u -r -N squid-3.5.21/src/client_side_reply.cc squid-3.5.22/src/client_side_reply.cc --- squid-3.5.21/src/client_side_reply.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/client_side_reply.cc 2016-10-10 08:58:01.000000000 +1300 @@ -72,7 +72,8 @@ HTTPMSGUNLOCK(reply); } -clientReplyContext::clientReplyContext(ClientHttpRequest *clientContext) : http (cbdataReference(clientContext)), old_entry (NULL), old_sc(NULL), deleting(false) +clientReplyContext::clientReplyContext(ClientHttpRequest *clientContext) : http (cbdataReference(clientContext)), old_entry (NULL), old_sc(NULL), deleting(false), + collapsedRevalidation(crNone) {} /** Create an error in the store awaiting the client side to read it. @@ -245,9 +246,9 @@ clientReplyContext::processExpired() { const char *url = storeId(); - StoreEntry *entry = NULL; debugs(88, 3, "clientReplyContext::processExpired: '" << http->uri << "'"); - assert(http->storeEntry()->lastmod >= 0); + const time_t lastmod = http->storeEntry()->lastModified(); + assert(lastmod >= 0); /* * check if we are allowed to contact other servers * @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return @@ -267,16 +268,43 @@ #endif /* Prepare to make a new temporary request */ saveState(); - entry = storeCreateEntry(url, - http->log_uri, http->request->flags, http->request->method); - /* NOTE, don't call StoreEntry->lock(), storeCreateEntry() does it */ + + // TODO: support collapsed revalidation of Vary-controlled entries + const bool collapsingAllowed = Config.onoff.collapsed_forwarding && + !Store::Root().smpAware() && + http->request->vary_headers.isEmpty(); + + StoreEntry *entry = nullptr; + if (collapsingAllowed) { + if ((entry = storeGetPublicByRequest(http->request, ksRevalidation))) + entry->lock("clientReplyContext::processExpired#alreadyRevalidating"); + } + + if (entry) { + debugs(88, 5, "collapsed on existing revalidation entry: " << *entry); + collapsedRevalidation = crSlave; + } else { + entry = storeCreateEntry(url, + http->log_uri, http->request->flags, http->request->method); + /* NOTE, don't call StoreEntry->lock(), storeCreateEntry() does it */ + + if (collapsingAllowed) { + debugs(88, 5, "allow other revalidation requests to collapse on " << *entry); + Store::Root().allowCollapsing(entry, http->request->flags, + http->request->method); + collapsedRevalidation = crInitiator; + } else { + collapsedRevalidation = crNone; + } + } + sc = storeClientListAdd(entry, this); #if USE_DELAY_POOLS /* delay_id is already set on original store client */ sc->setDelayId(DelayId::DelayClient(http)); #endif - http->request->lastmod = old_entry->lastmod; + http->request->lastmod = lastmod; if (!http->request->header.has(HDR_IF_NONE_MATCH)) { ETag etag = {NULL, -1}; // TODO: make that a default ETag constructor @@ -284,17 +312,19 @@ http->request->etag = etag.str; } - debugs(88, 5, "clientReplyContext::processExpired : lastmod " << entry->lastmod ); + debugs(88, 5, "lastmod " << entry->lastModified()); http->storeEntry(entry); assert(http->out.offset == 0); assert(http->request->clientConnectionManager == http->getConn()); - /* - * A refcounted pointer so that FwdState stays around as long as - * this clientReplyContext does - */ - Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL; - FwdState::Start(conn, http->storeEntry(), http->request, http->al); + if (collapsedRevalidation != crSlave) { + /* + * A refcounted pointer so that FwdState stays around as long as + * this clientReplyContext does + */ + Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL; + FwdState::Start(conn, http->storeEntry(), http->request, http->al); + } /* Register with storage manager to receive updates when data comes in. */ @@ -358,7 +388,7 @@ if (deleting) return; - debugs(88, 3, "handleIMSReply: " << http->storeEntry()->url() << ", " << (long unsigned) result.length << " bytes" ); + debugs(88, 3, http->storeEntry()->url() << ", " << (long unsigned) result.length << " bytes"); if (http->storeEntry() == NULL) return; @@ -373,7 +403,7 @@ // request to origin was aborted if (EBIT_TEST(http->storeEntry()->flags, ENTRY_ABORTED)) { - debugs(88, 3, "handleIMSReply: request to origin aborted '" << http->storeEntry()->url() << "', sending old entry to client" ); + debugs(88, 3, "request to origin aborted '" << http->storeEntry()->url() << "', sending old entry to client"); http->logType = LOG_TCP_REFRESH_FAIL_OLD; sendClientOldEntry(); } @@ -391,13 +421,13 @@ // if client sent IMS - if (http->request->flags.ims && !old_entry->modifiedSince(http->request)) { + if (http->request->flags.ims && !old_entry->modifiedSince(http->request->ims, http->request->imslen)) { // forward the 304 from origin - debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and forwarding 304 to client"); + debugs(88, 3, "origin replied 304, revalidating existing entry and forwarding 304 to client"); sendClientUpstreamResponse(); } else { // send existing entry, it's still valid - debugs(88, 3, "handleIMSReply: origin replied 304, revalidating existing entry and sending " << + debugs(88, 3, "origin replied 304, revalidating existing entry and sending " << old_rep->sline.status() << " to client"); sendClientOldEntry(); } @@ -405,22 +435,37 @@ // origin replied with a non-error code else if (status > Http::scNone && status < Http::scInternalServerError) { - // forward response from origin - http->logType = LOG_TCP_REFRESH_MODIFIED; - debugs(88, 3, "handleIMSReply: origin replied " << status << ", replacing existing entry and forwarding to client"); - sendClientUpstreamResponse(); + const HttpReply *new_rep = http->storeEntry()->getReply(); + // RFC 7234 section 4: a cache MUST use the most recent response + // (as determined by the Date header field) + if (new_rep->olderThan(old_rep)) { + http->logType = LOG_TCP_REFRESH_IGNORED; + debugs(88, 3, "origin replied " << status << + " but with an older date header, sending old entry (" << + old_rep->sline.status() << ") to client"); + sendClientOldEntry(); + } else { + http->logType = LOG_TCP_REFRESH_MODIFIED; + debugs(88, 3, "origin replied " << status << + ", replacing existing entry and forwarding to client"); + + if (collapsedRevalidation) + http->storeEntry()->clearPublicKeyScope(); + + sendClientUpstreamResponse(); + } } // origin replied with an error else if (http->request->flags.failOnValidationError) { http->logType = LOG_TCP_REFRESH_FAIL_ERR; - debugs(88, 3, "handleIMSReply: origin replied with error " << status << + debugs(88, 3, "origin replied with error " << status << ", forwarding to client due to fail_on_validation_err"); sendClientUpstreamResponse(); } else { // ignore and let client have old entry http->logType = LOG_TCP_REFRESH_FAIL_OLD; - debugs(88, 3, "handleIMSReply: origin replied with error " << + debugs(88, 3, "origin replied with error " << status << ", sending old entry (" << old_rep->sline.status() << ") to client"); sendClientOldEntry(); } @@ -563,11 +608,12 @@ */ r->flags.needValidation = true; - if (e->lastmod < 0) { - debugs(88, 3, "validate HIT object? NO. Missing Last-Modified header. Do MISS."); + if (e->lastModified() < 0) { + debugs(88, 3, "validate HIT object? NO. Can't calculate entry modification time. Do MISS."); /* - * Previous reply didn't have a Last-Modified header, - * we cannot revalidate it. + * We cannot revalidate entries without knowing their + * modification time. + * XXX: BUG 1890 objects without Date do not get one added. */ http->logType = LOG_TCP_MISS; processMiss(); @@ -756,7 +802,7 @@ if (r.flags.ims) { // handle If-Modified-Since requests from the client - if (e->modifiedSince(&r)) { + if (e->modifiedSince(r.ims, r.imslen)) { http->logType = LOG_TCP_IMS_HIT; sendMoreData(result); return; diff -u -r -N squid-3.5.21/src/client_side_reply.h squid-3.5.22/src/client_side_reply.h --- squid-3.5.21/src/client_side_reply.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/client_side_reply.h 2016-10-10 08:58:01.000000000 +1300 @@ -133,6 +133,14 @@ store_client *old_sc; /* ... for entry to be validated */ bool deleting; + typedef enum { + crNone = 0, ///< collapsed revalidation is not allowed for this context + crInitiator, ///< we initiated collapsed revalidation request + crSlave ///< we collapsed on the existing revalidation request + } CollapsedRevalidation; + + CollapsedRevalidation collapsedRevalidation; + CBDATA_CLASS2(clientReplyContext); }; diff -u -r -N squid-3.5.21/src/client_side_request.cc squid-3.5.22/src/client_side_request.cc --- squid-3.5.21/src/client_side_request.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/client_side_request.cc 2016-10-10 08:58:01.000000000 +1300 @@ -336,7 +336,7 @@ * correctness. */ if (header) - request->header.update(header, NULL); + request->header.update(header); http->log_uri = xstrdup(urlCanonicalClean(request)); diff -u -r -N squid-3.5.21/src/errorpage.cc squid-3.5.22/src/errorpage.cc --- squid-3.5.21/src/errorpage.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/errorpage.cc 2016-10-10 08:58:01.000000000 +1300 @@ -358,7 +358,6 @@ bool strHdrAcptLangGetItem(const String &hdr, char *lang, int langLen, size_t &pos) { while (pos < hdr.size()) { - char *dt = lang; /* skip any initial whitespace. */ while (pos < hdr.size() && xisspace(hdr[pos])) @@ -372,6 +371,7 @@ * with preference given to an exact match. */ bool invalid_byte = false; + char *dt = lang; while (pos < hdr.size() && hdr[pos] != ';' && hdr[pos] != ',' && !xisspace(hdr[pos]) && dt < (lang + (langLen -1)) ) { if (!invalid_byte) { #if USE_HTTP_VIOLATIONS @@ -391,7 +391,6 @@ ++pos; } *dt = '\0'; // nul-terminated the filename content string before system use. - ++dt; // if we terminated the tag on garbage or ';' we need to skip to the next ',' or end of header. while (pos < hdr.size() && hdr[pos] != ',') @@ -400,7 +399,7 @@ if (pos < hdr.size() && hdr[pos] == ',') ++pos; - debugs(4, 9, HERE << "STATE: dt='" << dt << "', lang='" << lang << "', pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'"); + debugs(4, 9, "STATE: lang=" << lang << ", pos=" << pos << ", buf='" << ((pos < hdr.size()) ? hdr.substr(pos,hdr.size()) : "") << "'"); /* if we found anything we might use, try it. */ if (*lang != '\0' && !invalid_byte) diff -u -r -N squid-3.5.21/src/esi/Include.cc squid-3.5.22/src/esi/Include.cc --- squid-3.5.21/src/esi/Include.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/esi/Include.cc 2016-10-10 08:58:01.000000000 +1300 @@ -279,7 +279,7 @@ void ESIInclude::prepareRequestHeaders(HttpHeader &tempheaders, ESIVarState *vars) { - tempheaders.update (&vars->header(), NULL); + tempheaders.update (&vars->header()); tempheaders.removeHopByHopEntries(); } diff -u -r -N squid-3.5.21/src/format/Format.cc squid-3.5.22/src/format/Format.cc --- squid-3.5.21/src/format/Format.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/format/Format.cc 2016-10-10 08:58:01.000000000 +1300 @@ -309,6 +309,38 @@ *p = '\0'; } +/// XXX: Misnamed. TODO: Split reply; +#if USE_ADAPTATION + // al->icap.reqMethod is methodNone in access.log context + if (!msg && al->icap.reqMethod == Adaptation::methodReqmod) + msg = al->adapted_request; +#endif + return msg; +} + +/// XXX: Misnamed. See actualReplyHeader(). +/// \return HttpRequest or HttpReply for %http::>h. +static const HttpMsg * +actualRequestHeader(const AccessLogEntry::Pointer &al) +{ +#if USE_ADAPTATION + // al->icap.reqMethod is methodNone in access.log context + if (al->icap.reqMethod == Adaptation::methodRespmod) { + // XXX: for now AccessLogEntry lacks virgin response headers + return NULL; + } +#endif + return al->request; +} + void Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logSequenceNumber) const { @@ -547,8 +579,8 @@ case LFT_REQUEST_HEADER: - if (al->request) - sb = al->request->header.getByName(fmt->data.header.header); + if (const HttpMsg *msg = actualRequestHeader(al)) + sb = msg->header.getByName(fmt->data.header.header); out = sb.termedBuf(); @@ -567,15 +599,15 @@ break; - case LFT_REPLY_HEADER: - if (al->reply) - sb = al->reply->header.getByName(fmt->data.header.header); + case LFT_REPLY_HEADER: { + if (const HttpMsg *msg = actualReplyHeader(al)) + sb = msg->header.getByName(fmt->data.header.header); out = sb.termedBuf(); quote = 1; - - break; + } + break; #if USE_ADAPTATION case LFT_ADAPTATION_SUM_XACT_TIMES: @@ -757,8 +789,8 @@ break; #endif case LFT_REQUEST_HEADER_ELEM: - if (al->request) - sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + if (const HttpMsg *msg = actualRequestHeader(al)) + sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); out = sb.termedBuf(); @@ -776,18 +808,27 @@ break; - case LFT_REPLY_HEADER_ELEM: - if (al->reply) - sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + case LFT_REPLY_HEADER_ELEM: { + if (const HttpMsg *msg = actualReplyHeader(al)) + sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); out = sb.termedBuf(); quote = 1; - - break; + } + break; case LFT_REQUEST_ALL_HEADERS: - out = al->headers.request; +#if USE_ADAPTATION + if (al->icap.reqMethod == Adaptation::methodRespmod) { + // XXX: since AccessLogEntry::Headers lacks virgin response + // headers, do nothing for now + out = NULL; + } else +#endif + { + out = al->headers.request; + } quote = 1; @@ -802,6 +843,10 @@ case LFT_REPLY_ALL_HEADERS: out = al->headers.reply; +#if USE_ADAPTATION + if (!out && al->icap.reqMethod == Adaptation::methodReqmod) + out = al->headers.adapted_request; +#endif quote = 1; diff -u -r -N squid-3.5.21/src/fs/rock/RockSwapDir.cc squid-3.5.22/src/fs/rock/RockSwapDir.cc --- squid-3.5.21/src/fs/rock/RockSwapDir.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/fs/rock/RockSwapDir.cc 2016-10-10 08:58:01.000000000 +1300 @@ -134,7 +134,7 @@ e.lastref = basics.lastref; e.timestamp = basics.timestamp; e.expires = basics.expires; - e.lastmod = basics.lastmod; + e.lastModified(basics.lastmod); e.refcount = basics.refcount; e.flags = basics.flags; diff -u -r -N squid-3.5.21/src/fs/rock/RockSwapDir.h squid-3.5.22/src/fs/rock/RockSwapDir.h --- squid-3.5.21/src/fs/rock/RockSwapDir.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/fs/rock/RockSwapDir.h 2016-10-10 08:58:01.000000000 +1300 @@ -48,6 +48,7 @@ virtual void swappedOut(const StoreEntry &e); virtual void create(); virtual void parse(int index, char *path); + virtual bool smpAware() const { return true; } // temporary path to the shared memory map of first slots of cached entries SBuf inodeMapPath() const; diff -u -r -N squid-3.5.21/src/fs/ufs/RebuildState.cc squid-3.5.22/src/fs/ufs/RebuildState.cc --- squid-3.5.21/src/fs/ufs/RebuildState.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/fs/ufs/RebuildState.cc 2016-10-10 08:58:01.000000000 +1300 @@ -74,9 +74,11 @@ Fs::Ufs::RebuildState::RebuildStep(void *data) { RebuildState *rb = (RebuildState *)data; - rb->rebuildStep(); + if (!reconfiguring) + rb->rebuildStep(); - if (!rb->isDone()) + // delay storeRebuildComplete() when reconfiguring to protect storeCleanup() + if (!rb->isDone() || reconfiguring) eventAdd("storeRebuild", RebuildStep, rb, 0.01, 1); else { -- StoreController::store_dirs_rebuilding; @@ -199,7 +201,7 @@ tmpe.expires, tmpe.timestamp, tmpe.lastref, - tmpe.lastmod, + tmpe.lastModified(), tmpe.refcount, /* refcount */ tmpe.flags, /* flags */ (int) flags.clean)); @@ -326,7 +328,7 @@ currentEntry()->lastref = swapData.timestamp; currentEntry()->timestamp = swapData.timestamp; currentEntry()->expires = swapData.expires; - currentEntry()->lastmod = swapData.lastmod; + currentEntry()->lastModified(swapData.lastmod); currentEntry()->flags = swapData.flags; currentEntry()->refcount += swapData.refcount; sd->dereference(*currentEntry(), false); diff -u -r -N squid-3.5.21/src/fs/ufs/UFSStoreState.cc squid-3.5.22/src/fs/ufs/UFSStoreState.cc --- squid-3.5.21/src/fs/ufs/UFSStoreState.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/fs/ufs/UFSStoreState.cc 2016-10-10 08:58:01.000000000 +1300 @@ -421,7 +421,7 @@ if (flags.write_draining) return; - if (!theFile->canWrite()) + if (!theFile || !theFile->canWrite()) return; flags.write_draining = true; diff -u -r -N squid-3.5.21/src/fs/ufs/UFSSwapDir.cc squid-3.5.22/src/fs/ufs/UFSSwapDir.cc --- squid-3.5.21/src/fs/ufs/UFSSwapDir.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/fs/ufs/UFSSwapDir.cc 2016-10-10 08:58:01.000000000 +1300 @@ -87,7 +87,7 @@ s.timestamp = e.timestamp; s.lastref = e.lastref; s.expires = e.expires; - s.lastmod = e.lastmod; + s.lastmod = e.lastModified(); s.swap_file_sz = e.swap_file_sz; s.refcount = e.refcount; s.flags = e.flags; @@ -316,7 +316,8 @@ currentIOOptions(new ConfigOptionVector()), ioType(xstrdup(anIOType)), cur_size(0), - n_disk_objects(0) + n_disk_objects(0), + rebuilding_(false) { /* modulename is only set to disk modules that are built, by configure, * so the Find call should never return NULL here. @@ -723,6 +724,15 @@ void Fs::Ufs::UFSSwapDir::openLog() { + assert(NumberOfUFSDirs || !UFSDirToGlobalDirMapping); + ++NumberOfUFSDirs; + assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured); + + if (rebuilding_) { // we did not close the temporary log used for rebuilding + assert(swaplog_fd >= 0); + return; + } + char *logPath; logPath = logFile(); swaplog_fd = file_open(logPath, O_WRONLY | O_CREAT | O_BINARY); @@ -733,13 +743,6 @@ } debugs(50, 3, HERE << "Cache Dir #" << index << " log opened on FD " << swaplog_fd); - - if (0 == NumberOfUFSDirs) - assert(NULL == UFSDirToGlobalDirMapping); - - ++NumberOfUFSDirs; - - assert(NumberOfUFSDirs <= Config.cacheSwap.n_configured); } void @@ -748,18 +751,19 @@ if (swaplog_fd < 0) /* not open */ return; + --NumberOfUFSDirs; + assert(NumberOfUFSDirs >= 0); + if (!NumberOfUFSDirs) + safe_free(UFSDirToGlobalDirMapping); + + if (rebuilding_) // we cannot close the temporary log used for rebuilding + return; + file_close(swaplog_fd); debugs(47, 3, "Cache Dir #" << index << " log closed on FD " << swaplog_fd); swaplog_fd = -1; - - --NumberOfUFSDirs; - - assert(NumberOfUFSDirs >= 0); - - if (0 == NumberOfUFSDirs) - safe_free(UFSDirToGlobalDirMapping); } bool @@ -801,7 +805,7 @@ e->lastref = lastref; e->timestamp = timestamp; e->expires = expires; - e->lastmod = lastmod; + e->lastModified(lastmod); e->refcount = refcount; e->flags = newFlags; EBIT_CLR(e->flags, RELEASE_REQUEST); @@ -839,6 +843,9 @@ void Fs::Ufs::UFSSwapDir::closeTmpSwapLog() { + assert(rebuilding_); + rebuilding_ = false; + char *swaplog_path = xstrdup(logFile(NULL)); // where the swaplog should be char *tmp_path = xstrdup(logFile(".new")); // the temporary file we have generated int fd; @@ -864,6 +871,8 @@ FILE * Fs::Ufs::UFSSwapDir::openTmpSwapLog(int *clean_flag, int *zero_flag) { + assert(!rebuilding_); + char *swaplog_path = xstrdup(logFile(NULL)); char *clean_path = xstrdup(logFile(".last-clean")); char *new_path = xstrdup(logFile(".new")); @@ -897,6 +906,7 @@ } swaplog_fd = fd; + rebuilding_ = true; { const StoreSwapLogHeader header; @@ -1053,18 +1063,17 @@ cleanLog = NULL; } -void -Fs::Ufs::UFSSwapDir::CleanEvent(void *unused) +/// safely cleans a few unused files if possible +int +Fs::Ufs::UFSSwapDir::HandleCleanEvent() { static int swap_index = 0; int i; int j = 0; int n = 0; - /* - * Assert that there are UFS cache_dirs configured, otherwise - * we should never be called. - */ - assert(NumberOfUFSDirs); + + if (!NumberOfUFSDirs) + return 0; // probably in the middle of reconfiguration if (NULL == UFSDirToGlobalDirMapping) { SwapDir *sd; @@ -1106,6 +1115,13 @@ ++swap_index; } + return n; +} + +void +Fs::Ufs::UFSSwapDir::CleanEvent(void *) +{ + const int n = HandleCleanEvent(); eventAdd("storeDirClean", CleanEvent, NULL, 15.0 * exp(-0.25 * n), 1); } @@ -1283,13 +1299,18 @@ void Fs::Ufs::UFSSwapDir::logEntry(const StoreEntry & e, int op) const { + if (swaplog_fd < 0) { + debugs(36, 5, "cannot log " << e << " in the middle of reconfiguration"); + return; + } + StoreSwapLogData *s = new StoreSwapLogData; s->op = (char) op; s->swap_filen = e.swap_filen; s->timestamp = e.timestamp; s->lastref = e.lastref; s->expires = e.expires; - s->lastmod = e.lastmod; + s->lastmod = e.lastModified(); s->swap_file_sz = e.swap_file_sz; s->refcount = e.refcount; s->flags = e.flags; diff -u -r -N squid-3.5.21/src/fs/ufs/UFSSwapDir.h squid-3.5.22/src/fs/ufs/UFSSwapDir.h --- squid-3.5.21/src/fs/ufs/UFSSwapDir.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/fs/ufs/UFSSwapDir.h 2016-10-10 08:58:01.000000000 +1300 @@ -90,6 +90,7 @@ virtual void swappedOut(const StoreEntry &e); virtual uint64_t currentSize() const { return cur_size; } virtual uint64_t currentCount() const { return n_disk_objects; } + virtual bool smpAware() const { return false; } void unlinkFile(sfileno f); // move down when unlink is a virtual method @@ -145,6 +146,7 @@ bool pathIsDirectory(const char *path)const; int swaplog_fd; static EVH CleanEvent; + static int HandleCleanEvent(); /** Verify that the the CacheDir exists * * If this returns < 0, then Squid exits, complains about swap @@ -164,6 +166,7 @@ char const *ioType; uint64_t cur_size; ///< currently used space in the storage area uint64_t n_disk_objects; ///< total number of objects stored + bool rebuilding_; ///< whether RebuildState is writing the new swap.state }; } //namespace Ufs diff -u -r -N squid-3.5.21/src/htcp.cc squid-3.5.22/src/htcp.cc --- squid-3.5.21/src/htcp.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/htcp.cc 2016-10-10 08:58:01.000000000 +1300 @@ -886,8 +886,8 @@ if (e && e->expires > -1) hdr.putTime(HDR_EXPIRES, e->expires); - if (e && e->lastmod > -1) - hdr.putTime(HDR_LAST_MODIFIED, e->lastmod); + if (e && e->lastModified() > -1) + hdr.putTime(HDR_LAST_MODIFIED, e->lastModified()); hdr.packInto(&p); diff -u -r -N squid-3.5.21/src/http.cc squid-3.5.22/src/http.cc --- squid-3.5.21/src/http.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/http.cc 2016-10-10 08:58:01.000000000 +1300 @@ -84,7 +84,8 @@ HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"), Client(theFwdState), lastChunk(0), header_bytes_read(0), reply_bytes_read(0), - body_bytes_truncated(0), httpChunkDecoder(NULL) + body_bytes_truncated(0), httpChunkDecoder(NULL), + sawDateGoBack(false) { debugs(11,5,HERE << "HttpStateData " << this << " created"); ignoreCacheControl = false; @@ -169,6 +170,14 @@ mustStop("HttpStateData::httpTimeout"); } +static StoreEntry * +findPreviouslyCachedEntry(StoreEntry *newEntry) { + assert(newEntry->mem_obj); + return newEntry->mem_obj->request ? + storeGetPublicByRequest(newEntry->mem_obj->request) : + storeGetPublic(newEntry->mem_obj->storeId(), newEntry->mem_obj->method); +} + /// Remove an existing public store entry if the incoming response (to be /// stored in a currently private entry) is going to invalidate it. static void @@ -176,7 +185,6 @@ { int remove = 0; int forbidden = 0; - StoreEntry *pe; // If the incoming response already goes into a public entry, then there is // nothing to remove. This protects ready-for-collapsing entries as well. @@ -235,12 +243,7 @@ if (!remove && !forbidden) return; - assert(e->mem_obj); - - if (e->mem_obj->request) - pe = storeGetPublicByRequest(e->mem_obj->request); - else - pe = storeGetPublic(e->mem_obj->storeId(), e->mem_obj->method); + StoreEntry *pe = findPreviouslyCachedEntry(e); if (pe != NULL) { assert(e != pe); @@ -331,6 +334,13 @@ return 0; } + // RFC 7234 section 4: a cache MUST use the most recent response + // (as determined by the Date header field) + if (sawDateGoBack) { + debugs(22, 3, "NO because " << *entry << " has an older date header."); + return 0; + } + // Check for Surrogate/1.0 protocol conditions // NP: reverse-proxy traffic our parent server has instructed us never to cache if (surrogateNoStore) { @@ -886,7 +896,10 @@ /* Check if object is cacheable or not based on reply code */ debugs(11, 3, "HTTP CODE: " << rep->sline.status()); - if (neighbors_do_private_keys) + if (const StoreEntry *oldEntry = findPreviouslyCachedEntry(entry)) + sawDateGoBack = rep->olderThan(oldEntry->getReply()); + + if (neighbors_do_private_keys && !sawDateGoBack) httpMaybeRemovePublic(entry, rep->sline.status()); bool varyFailure = false; diff -u -r -N squid-3.5.21/src/http.h squid-3.5.22/src/http.h --- squid-3.5.21/src/http.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/http.h 2016-10-10 08:58:01.000000000 +1300 @@ -112,6 +112,9 @@ bool peerSupportsConnectionPinning() const; ChunkedCodingParser *httpChunkDecoder; + /// Whether we received a Date header older than that of a matching + /// cached response. + bool sawDateGoBack; private: CBDATA_CLASS2(HttpStateData); }; diff -u -r -N squid-3.5.21/src/HttpHeader.cc squid-3.5.22/src/HttpHeader.cc --- squid-3.5.21/src/HttpHeader.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/HttpHeader.cc 2016-10-10 08:58:01.000000000 +1300 @@ -450,7 +450,7 @@ HttpHeader::HttpHeader(const HttpHeader &other): owner(other.owner), len(other.len), conflictingContentLength_(false) { httpHeaderMaskInit(&mask, 0); - update(&other, NULL); // will update the mask as well + update(&other); // will update the mask as well } HttpHeader::~HttpHeader() @@ -465,7 +465,7 @@ // we do not really care, but the caller probably does assert(owner == other.owner); clean(); - update(&other, NULL); // will update the mask as well + update(&other); // will update the mask as well len = other.len; conflictingContentLength_ = other.conflictingContentLength_; } @@ -535,26 +535,71 @@ } } +/// check whether the fresh header has any new/changed updatable fields +bool +HttpHeader::needUpdate(HttpHeader const *fresh) const +{ + for (unsigned int i = 0; i < fresh->entries.size(); ++i) { + const HttpHeaderEntry *e = fresh->entries[i]; + if (!e || skipUpdateHeader(e->id)) + continue; + String value; + const char *name = e->name.termedBuf(); + if (!getByNameIfPresent(name, value) || + (value != fresh->getByName(name))) + return true; + } + return false; +} + /* use fresh entries to replace old ones */ void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask) { assert (old); - old->update (fresh, denied_mask); + old->update(fresh); } void -HttpHeader::update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask) +HttpHeader::updateWarnings() { - const HttpHeaderEntry *e; + int count = 0; HttpHeaderPos pos = HttpHeaderInitPos; + + // RFC 7234, section 4.3.4: delete 1xx warnings and retain 2xx warnings + while (HttpHeaderEntry *e = getEntry(&pos)) { + if (e->id == HDR_WARNING && (e->getInt()/100 == 1) ) + delAt(pos, count); + } +} + +bool +HttpHeader::skipUpdateHeader(const http_hdr_type id) const +{ + // RFC 7234, section 4.3.4: use fields other from Warning for update + return id == HDR_WARNING; +} + +bool +HttpHeader::update(HttpHeader const *fresh) +{ assert(fresh); assert(this != fresh); + // Optimization: Finding whether a header field changed is expensive + // and probably not worth it except for collapsed revalidation needs. + if (Config.onoff.collapsed_forwarding && !needUpdate(fresh)) + return false; + + updateWarnings(); + + const HttpHeaderEntry *e; + HttpHeaderPos pos = HttpHeaderInitPos; + while ((e = fresh->getEntry(&pos))) { /* deny bad guys (ok to check for HDR_OTHER) here */ - if (denied_mask && CBIT_TEST(*denied_mask, e->id)) + if (skipUpdateHeader(e->id)) continue; if (e->id != HDR_OTHER) @@ -567,13 +612,14 @@ while ((e = fresh->getEntry(&pos))) { /* deny bad guys (ok to check for HDR_OTHER) here */ - if (denied_mask && CBIT_TEST(*denied_mask, e->id)) + if (skipUpdateHeader(e->id)) continue; debugs(55, 7, "Updating header '" << HeadersAttrs[e->id].name << "' in cached entry"); addEntry(e->clone()); } + return true; } /* just handy in parsing: resets and returns false */ @@ -1720,7 +1766,6 @@ HttpHeaderEntry::getInt() const { assert_eid (id); - assert (Headers[id].type == ftInt); int val = -1; int ok = httpHeaderParseInt(value.termedBuf(), &val); httpHeaderNoteParsedEntry(id, value, !ok); @@ -1734,7 +1779,6 @@ HttpHeaderEntry::getInt64() const { assert_eid (id); - assert (Headers[id].type == ftInt64); int64_t val = -1; int ok = httpHeaderParseOffset(value.termedBuf(), &val); httpHeaderNoteParsedEntry(id, value, !ok); diff -u -r -N squid-3.5.21/src/HttpHeader.h squid-3.5.22/src/HttpHeader.h --- squid-3.5.21/src/HttpHeader.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/HttpHeader.h 2016-10-10 08:58:01.000000000 +1300 @@ -217,7 +217,7 @@ /* Interface functions */ void clean(); void append(const HttpHeader * src); - void update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask); + bool update(HttpHeader const *fresh); void compact(); int reset(); int parse(const char *header_start, const char *header_end); @@ -278,6 +278,9 @@ protected: /** \deprecated Public access replaced by removeHopByHopEntries() */ void removeConnectionHeaderEntries(); + bool needUpdate(const HttpHeader *fresh) const; + bool skipUpdateHeader(const http_hdr_type id) const; + void updateWarnings(); private: HttpHeaderEntry *findLastEntry(http_hdr_type id) const; diff -u -r -N squid-3.5.21/src/HttpReply.cc squid-3.5.22/src/HttpReply.cc --- squid-3.5.21/src/HttpReply.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/HttpReply.cc 2016-10-10 08:58:01.000000000 +1300 @@ -24,40 +24,6 @@ #include "Store.h" #include "StrList.h" -/* local constants */ - -/* If we receive a 304 from the origin during a cache revalidation, we must - * update the headers of the existing entry. Specifically, we need to update all - * end-to-end headers and not any hop-by-hop headers (rfc2616 13.5.3). - * - * This is not the whole story though: since it is possible for a faulty/malicious - * origin server to set headers it should not in a 304, we must explicitly ignore - * these too. Specifically all entity-headers except those permitted in a 304 - * (rfc2616 10.3.5) must be ignored. - * - * The list of headers we don't update is made up of: - * all hop-by-hop headers - * all entity-headers except Expires and Content-Location - */ -static HttpHeaderMask Denied304HeadersMask; -static http_hdr_type Denied304HeadersArr[] = { - // hop-by-hop headers - HDR_CONNECTION, HDR_KEEP_ALIVE, HDR_PROXY_AUTHENTICATE, HDR_PROXY_AUTHORIZATION, - HDR_TE, HDR_TRAILER, HDR_TRANSFER_ENCODING, HDR_UPGRADE, - // entity headers - HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH, - HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_LAST_MODIFIED -}; - -/* module initialization */ -void -httpReplyInitModule(void) -{ - assert(Http::scNone == 0); // HttpReply::parse() interface assumes that - httpHeaderMaskInit(&Denied304HeadersMask, 0); - httpHeaderCalcMask(&Denied304HeadersMask, Denied304HeadersArr, countof(Denied304HeadersArr)); -} - HttpReply::HttpReply() : HttpMsg(hoReply), date (0), last_modified (0), expires (0), surrogate_control (NULL), content_range (NULL), keep_alive (0), protoPrefix("HTTP/"), bodySizeMax(-2) @@ -271,20 +237,23 @@ return 1; } -void +bool HttpReply::updateOnNotModified(HttpReply const * freshRep) { assert(freshRep); + /* update raw headers */ + if (!header.update(&freshRep->header)) + return false; + /* clean cache */ hdrCacheClean(); - /* update raw headers */ - header.update(&freshRep->header, - (const HttpHeaderMask *) &Denied304HeadersMask); header.compact(); /* init cache */ hdrCacheInit(); + + return true; } /* internal routines */ @@ -659,3 +628,11 @@ return newValue; } +bool +HttpReply::olderThan(const HttpReply *them) const +{ + if (!them || !them->date || !date) + return false; + return date < them->date; +} + diff -u -r -N squid-3.5.21/src/HttpReply.h squid-3.5.22/src/HttpReply.h --- squid-3.5.21/src/HttpReply.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/HttpReply.h 2016-10-10 08:58:01.000000000 +1300 @@ -72,7 +72,7 @@ virtual bool inheritProperties(const HttpMsg *aMsg); - void updateOnNotModified(HttpReply const *other); + bool updateOnNotModified(HttpReply const *other); /** set commonly used info with one call */ void setHeaders(Http::StatusCode status, @@ -112,6 +112,10 @@ virtual void hdrCacheInit(); + /// whether our Date header value is smaller than theirs + /// \returns false if any information is missing + bool olderThan(const HttpReply *them) const; + private: /** initialize */ void init(); diff -u -r -N squid-3.5.21/src/ip/Intercept.cc squid-3.5.22/src/ip/Intercept.cc --- squid-3.5.21/src/ip/Intercept.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/ip/Intercept.cc 2016-10-10 08:58:01.000000000 +1300 @@ -207,16 +207,22 @@ debugs(89, warningLevel, "IPF (IPFilter v4) NAT does not support IPv6. Please upgrade to IPFilter v5.1"); warningLevel = (warningLevel + 1) % 10; return false; + } + newConn->local.getInAddr(natLookup.nl_inip); + newConn->remote.getInAddr(natLookup.nl_outip); #else natLookup.nl_v = 6; - } else { + newConn->local.getInAddr(natLookup.nl_inipaddr.in6); + newConn->remote.getInAddr(natLookup.nl_outipaddr.in6); + } + else { natLookup.nl_v = 4; -#endif + newConn->local.getInAddr(natLookup.nl_inipaddr.in4); + newConn->remote.getInAddr(natLookup.nl_outipaddr.in4); } +#endif natLookup.nl_inport = htons(newConn->local.port()); - newConn->local.getInAddr(natLookup.nl_inip); natLookup.nl_outport = htons(newConn->remote.port()); - newConn->remote.getInAddr(natLookup.nl_outip); // ... and the TCP flag natLookup.nl_flags = IPN_TCP; @@ -281,7 +287,14 @@ debugs(89, 9, HERE << "address: " << newConn); return false; } else { +#if IPFILTER_VERSION < 5000003 newConn->local = natLookup.nl_realip; +#else + if (newConn->remote.isIPv6()) + newConn->local = natLookup.nl_realipaddr.in6; + else + newConn->local = natLookup.nl_realipaddr.in4; +#endif newConn->local.port(ntohs(natLookup.nl_realport)); debugs(89, 5, HERE << "address NAT: " << newConn); return true; diff -u -r -N squid-3.5.21/src/ipc/StoreMap.cc squid-3.5.22/src/ipc/StoreMap.cc --- squid-3.5.21/src/ipc/StoreMap.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/ipc/StoreMap.cc 2016-10-10 08:58:01.000000000 +1300 @@ -491,7 +491,7 @@ basics.timestamp = from.timestamp; basics.lastref = from.lastref; basics.expires = from.expires; - basics.lastmod = from.lastmod; + basics.lastmod = from.lastModified(); basics.swap_file_sz = from.swap_file_sz; basics.refcount = from.refcount; basics.flags = from.flags; diff -u -r -N squid-3.5.21/src/LogTags.h squid-3.5.22/src/LogTags.h --- squid-3.5.21/src/LogTags.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/LogTags.h 2016-10-10 08:58:01.000000000 +1300 @@ -25,6 +25,7 @@ LOG_TCP_REFRESH_FAIL_OLD, // refresh from origin failed, stale reply sent LOG_TCP_REFRESH_FAIL_ERR, // refresh from origin failed, error forwarded LOG_TCP_REFRESH_MODIFIED, // refresh from origin replaced existing entry + LOG_TCP_REFRESH_IGNORED, // refresh from origin ignored, stale entry sent LOG_TCP_CLIENT_REFRESH_MISS, LOG_TCP_IMS_HIT, LOG_TCP_SWAPFAIL_MISS, diff -u -r -N squid-3.5.21/src/main.cc squid-3.5.22/src/main.cc --- squid-3.5.21/src/main.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/main.cc 2016-10-10 08:58:01.000000000 +1300 @@ -1069,8 +1069,6 @@ httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */ - httpReplyInitModule(); /* must go before accepting replies */ - errorInitialize(); accessLogInit(); diff -u -r -N squid-3.5.21/src/MemBlob.h squid-3.5.22/src/MemBlob.h --- squid-3.5.21/src/MemBlob.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/MemBlob.h 2016-10-10 08:58:01.000000000 +1300 @@ -72,7 +72,7 @@ */ bool canAppend(const size_type off, const size_type n) const { // TODO: ignore offset (and adjust size) when the blob is not shared? - return isAppendOffset(off) && willFit(n); + return (isAppendOffset(off) && willFit(n)) || !n; } /** adjusts internal object state as if exactly n bytes were append()ed diff -u -r -N squid-3.5.21/src/MemStore.cc squid-3.5.22/src/MemStore.cc --- squid-3.5.21/src/MemStore.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/MemStore.cc 2016-10-10 08:58:01.000000000 +1300 @@ -281,7 +281,7 @@ e.lastref = basics.lastref; e.timestamp = basics.timestamp; e.expires = basics.expires; - e.lastmod = basics.lastmod; + e.lastModified(basics.lastmod); e.refcount = basics.refcount; e.flags = basics.flags; diff -u -r -N squid-3.5.21/src/MemStore.h squid-3.5.22/src/MemStore.h --- squid-3.5.21/src/MemStore.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/MemStore.h 2016-10-10 08:58:01.000000000 +1300 @@ -63,6 +63,7 @@ virtual void maintain(); virtual bool anchorCollapsed(StoreEntry &collapsed, bool &inSync); virtual bool updateCollapsed(StoreEntry &collapsed); + virtual bool smpAware() const { return true; } static int64_t EntryLimit(); diff -u -r -N squid-3.5.21/src/peer_digest.cc squid-3.5.22/src/peer_digest.cc --- squid-3.5.21/src/peer_digest.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/peer_digest.cc 2016-10-10 08:58:01.000000000 +1300 @@ -359,7 +359,7 @@ /* set lastmod to trigger IMS request if possible */ if (old_e) - e->lastmod = old_e->lastmod; + e->lastModified(old_e->lastModified()); /* push towards peer cache */ debugs(72, 3, "peerDigestRequest: forwarding to fwdStart..."); @@ -942,8 +942,8 @@ debugs(72, 3, "peerDigestFetchFinish: expires: " << (long int) fetch->expires << " (" << std::showpos << (int) (fetch->expires - squid_curtime) << "), lmt: " << - std::noshowpos << (long int) fetch->entry->lastmod << " (" << - std::showpos << (int) (fetch->entry->lastmod - squid_curtime) << + std::noshowpos << (long int) fetch->entry->lastModified() << " (" << + std::showpos << (int) (fetch->entry->lastModified() - squid_curtime) << ")"); } diff -u -r -N squid-3.5.21/src/redirect.cc squid-3.5.22/src/redirect.cc --- squid-3.5.21/src/redirect.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/redirect.cc 2016-10-10 08:58:01.000000000 +1300 @@ -369,11 +369,13 @@ } if (Config.redirector_extras) { + delete redirectorExtrasFmt; redirectorExtrasFmt = new ::Format::Format("url_rewrite_extras"); (void)redirectorExtrasFmt->parse(Config.redirector_extras); } if (Config.storeId_extras) { + delete storeIdExtrasFmt; storeIdExtrasFmt = new ::Format::Format("store_id_extras"); (void)storeIdExtrasFmt->parse(Config.storeId_extras); } @@ -388,9 +390,6 @@ * When and if needed for more helpers a separated shutdown * method will be added for each of them. */ - if (!storeIds && !redirectors) - return; - if (redirectors) helperShutdown(redirectors); diff -u -r -N squid-3.5.21/src/refresh.cc squid-3.5.22/src/refresh.cc --- squid-3.5.21/src/refresh.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/refresh.cc 2016-10-10 08:58:01.000000000 +1300 @@ -186,13 +186,8 @@ } // 3. If there is a Last-Modified header, try the last-modified factor algorithm. - if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) { - - /* lastmod_delta is the difference between the last-modified date of the response - * and the time we cached it. It's how "old" the response was when we got it. - */ - time_t lastmod_delta = entry->timestamp - entry->lastmod; - + const time_t lastmod_delta = entry->timestamp - entry->lastModified(); + if (lastmod_delta > 0) { /* stale_age is the age of the response when it became/becomes stale according to * the last-modified factor algorithm. It's how long we can consider the response * fresh from the time we cached it. @@ -553,8 +548,8 @@ /* Does not need refresh. This is certainly cachable */ return true; - if (entry->lastmod < 0) - /* Last modified is needed to do a refresh */ + if (entry->lastModified() < 0) + /* We should know entry's modification time to do a refresh */ return false; if (entry->mem_obj == NULL) diff -u -r -N squid-3.5.21/src/ssl/PeerConnector.cc squid-3.5.22/src/ssl/PeerConnector.cc --- squid-3.5.21/src/ssl/PeerConnector.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/ssl/PeerConnector.cc 2016-10-10 08:58:01.000000000 +1300 @@ -771,7 +771,7 @@ } if (serverConn != NULL) buf.Printf(" FD %d", serverConn->fd); - buf.Printf(" %s%u]", id.Prefix, id.value); + buf.Printf(" %s%u]", id.prefix(), id.value); buf.terminate(); return buf.content(); diff -u -r -N squid-3.5.21/src/ssl/support.cc squid-3.5.22/src/ssl/support.cc --- squid-3.5.21/src/ssl/support.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/ssl/support.cc 2016-10-10 08:58:01.000000000 +1300 @@ -1350,7 +1350,6 @@ ssl_read_method(int fd, char *buf, int len) { SSL *ssl = fd_table[fd].ssl; - int i; #if DONT_DO_THIS @@ -1361,7 +1360,10 @@ #endif - i = SSL_read(ssl, buf, len); + int i = SSL_read(ssl, buf, len); + if (i > 0) { + (void)VALGRIND_MAKE_MEM_DEFINED(buf, i); + } if (i > 0 && SSL_pending(ssl) > 0) { debugs(83, 2, "SSL FD " << fd << " is pending"); diff -u -r -N squid-3.5.21/src/stat.cc squid-3.5.22/src/stat.cc --- squid-3.5.21/src/stat.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/stat.cc 2016-10-10 08:58:01.000000000 +1300 @@ -77,7 +77,6 @@ /* LOCALS */ static const char *describeStatuses(const StoreEntry *); -static const char *describeTimestamps(const StoreEntry *); static void statAvgTick(void *notused); static void statAvgDump(StoreEntry *, int minutes, int hours); #if STAT_GRAPHS @@ -328,18 +327,6 @@ return buf; } -static const char * -describeTimestamps(const StoreEntry * entry) -{ - LOCAL_ARRAY(char, buf, 256); - snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d", - (int) entry->timestamp, - (int) entry->lastref, - (int) entry->lastmod, - (int) entry->expires); - return buf; -} - static void statStoreEntry(MemBuf * mb, StoreEntry * e) { @@ -347,7 +334,7 @@ mb->Printf("KEY %s\n", e->getMD5Text()); mb->Printf("\t%s\n", describeStatuses(e)); mb->Printf("\t%s\n", storeEntryFlags(e)); - mb->Printf("\t%s\n", describeTimestamps(e)); + mb->Printf("\t%s\n", e->describeTimestamps()); mb->Printf("\t%d locks, %d clients, %d refs\n", (int) e->locks(), storePendingNClients(e), diff -u -r -N squid-3.5.21/src/store.cc squid-3.5.22/src/store.cc --- squid-3.5.21/src/store.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/store.cc 2016-10-10 08:58:01.000000000 +1300 @@ -162,12 +162,12 @@ } void -StoreEntry::makePublic() +StoreEntry::makePublic(const KeyScope scope) { /* This object can be cached for a long time */ if (!EBIT_TEST(flags, RELEASE_REQUEST)) - setPublicKey(); + setPublicKey(scope); } void @@ -355,7 +355,7 @@ timestamp(-1), lastref(-1), expires(-1), - lastmod(-1), + lastModified_(-1), swap_file_sz(0), refcount(0), flags(0), @@ -585,19 +585,19 @@ } StoreEntry * -storeGetPublicByRequestMethod(HttpRequest * req, const HttpRequestMethod& method) +storeGetPublicByRequestMethod(HttpRequest * req, const HttpRequestMethod& method, const KeyScope keyScope) { - return Store::Root().get(storeKeyPublicByRequestMethod(req, method)); + return Store::Root().get(storeKeyPublicByRequestMethod(req, method, keyScope)); } StoreEntry * -storeGetPublicByRequest(HttpRequest * req) +storeGetPublicByRequest(HttpRequest * req, const KeyScope keyScope) { - StoreEntry *e = storeGetPublicByRequestMethod(req, req->method); + StoreEntry *e = storeGetPublicByRequestMethod(req, req->method, keyScope); if (e == NULL && req->method == Http::METHOD_HEAD) /* We can generate a HEAD reply from a cached GET object */ - e = storeGetPublicByRequestMethod(req, Http::METHOD_GET); + e = storeGetPublicByRequestMethod(req, Http::METHOD_GET, keyScope); return e; } @@ -653,10 +653,8 @@ } void -StoreEntry::setPublicKey() +StoreEntry::setPublicKey(const KeyScope scope) { - const cache_key *newkey; - if (key && !EBIT_TEST(flags, KEY_PRIVATE)) return; /* is already public */ @@ -680,80 +678,35 @@ assert(!EBIT_TEST(flags, RELEASE_REQUEST)); - if (mem_obj->request) { - HttpRequest *request = mem_obj->request; - - if (mem_obj->vary_headers.isEmpty()) { - /* First handle the case where the object no longer varies */ - request->vary_headers.clear(); - } else { - if (!request->vary_headers.isEmpty() && request->vary_headers.cmp(mem_obj->vary_headers) != 0) { - /* Oops.. the variance has changed. Kill the base object - * to record the new variance key - */ - request->vary_headers.clear(); /* free old "bad" variance key */ - if (StoreEntry *pe = storeGetPublic(mem_obj->storeId(), mem_obj->method)) - pe->release(); - } - - /* Make sure the request knows the variance status */ - if (request->vary_headers.isEmpty()) - request->vary_headers = httpMakeVaryMark(request, mem_obj->getReply()); - } - - // TODO: storeGetPublic() calls below may create unlocked entries. - // We should add/use storeHas() API or lock/unlock those entries. - if (!mem_obj->vary_headers.isEmpty() && !storeGetPublic(mem_obj->storeId(), mem_obj->method)) { - /* Create "vary" base object */ - String vary; - StoreEntry *pe = storeCreateEntry(mem_obj->storeId(), mem_obj->logUri(), request->flags, request->method); - /* We are allowed to do this typecast */ - HttpReply *rep = new HttpReply; - rep->setHeaders(Http::scOkay, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000); - vary = mem_obj->getReply()->header.getList(HDR_VARY); - - if (vary.size()) { - /* Again, we own this structure layout */ - rep->header.putStr(HDR_VARY, vary.termedBuf()); - vary.clean(); - } - -#if X_ACCELERATOR_VARY - vary = mem_obj->getReply()->header.getList(HDR_X_ACCELERATOR_VARY); - - if (vary.size() > 0) { - /* Again, we own this structure layout */ - rep->header.putStr(HDR_X_ACCELERATOR_VARY, vary.termedBuf()); - vary.clean(); - } - -#endif - pe->replaceHttpReply(rep, false); // no write until key is public - - pe->timestampsSet(); - - pe->makePublic(); + adjustVary(); + forcePublicKey(calcPublicKey(scope)); +} - pe->startWriting(); // after makePublic() +void +StoreEntry::clearPublicKeyScope() +{ + if (!key || EBIT_TEST(flags, KEY_PRIVATE)) + return; // probably the old public key was deleted or made private - pe->complete(); + // TODO: adjustVary() when collapsed revalidation supports that - pe->unlock("StoreEntry::setPublicKey+Vary"); - } + const cache_key *newKey = calcPublicKey(ksDefault); + if (!storeKeyHashCmp(key, newKey)) + return; // probably another collapsed revalidation beat us to this change - newkey = storeKeyPublicByRequest(mem_obj->request); - } else - newkey = storeKeyPublic(mem_obj->storeId(), mem_obj->method); + forcePublicKey(newKey); +} +/// Unconditionally sets public key for this store entry. +/// Releases the old entry with the same public key (if any). +void +StoreEntry::forcePublicKey(const cache_key *newkey) +{ if (StoreEntry *e2 = (StoreEntry *)hash_lookup(store_table, newkey)) { + assert(e2 != this); debugs(20, 3, "Making old " << *e2 << " private."); e2->setPrivateKey(); e2->release(); - - if (mem_obj->request) - newkey = storeKeyPublicByRequest(mem_obj->request); - else - newkey = storeKeyPublic(mem_obj->storeId(), mem_obj->method); } if (key) @@ -767,6 +720,84 @@ storeDirSwapLog(this, SWAP_LOG_ADD); } +/// Calculates correct public key for feeding forcePublicKey(). +/// Assumes adjustVary() has been called for this entry already. +const cache_key *StoreEntry::calcPublicKey(const KeyScope keyScope) { + assert(mem_obj); + return mem_obj->request ? storeKeyPublicByRequest(mem_obj->request, keyScope) : + storeKeyPublic(mem_obj->storeId(), mem_obj->method, keyScope); +} + +/// Updates mem_obj->request->vary_headers to reflect the current Vary. +/// The vary_headers field is used to calculate the Vary marker key. +/// Releases the old Vary marker with an outdated key (if any). +void StoreEntry::adjustVary() { + assert(mem_obj); + + if (!mem_obj->request) + return; + + HttpRequest *request = mem_obj->request; + + if (mem_obj->vary_headers.isEmpty()) { + /* First handle the case where the object no longer varies */ + request->vary_headers.clear(); + } else { + if (!request->vary_headers.isEmpty() && request->vary_headers.cmp(mem_obj->vary_headers) != 0) { + /* Oops.. the variance has changed. Kill the base object + * to record the new variance key + */ + request->vary_headers.clear(); /* free old "bad" variance key */ + if (StoreEntry *pe = storeGetPublic(mem_obj->storeId(), mem_obj->method)) + pe->release(); + } + + /* Make sure the request knows the variance status */ + if (request->vary_headers.isEmpty()) + request->vary_headers = httpMakeVaryMark(request, mem_obj->getReply()); + } + + // TODO: storeGetPublic() calls below may create unlocked entries. + // We should add/use storeHas() API or lock/unlock those entries. + if (!mem_obj->vary_headers.isEmpty() && !storeGetPublic(mem_obj->storeId(), mem_obj->method)) { + /* Create "vary" base object */ + String vary; + StoreEntry *pe = storeCreateEntry(mem_obj->storeId(), mem_obj->logUri(), request->flags, request->method); + /* We are allowed to do this typecast */ + HttpReply *rep = new HttpReply; + rep->setHeaders(Http::scOkay, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000); + vary = mem_obj->getReply()->header.getList(HDR_VARY); + + if (vary.size()) { + /* Again, we own this structure layout */ + rep->header.putStr(HDR_VARY, vary.termedBuf()); + vary.clean(); + } + +#if X_ACCELERATOR_VARY + vary = mem_obj->getReply()->header.getList(HDR_X_ACCELERATOR_VARY); + + if (vary.size() > 0) { + /* Again, we own this structure layout */ + rep->header.putStr(HDR_X_ACCELERATOR_VARY, vary.termedBuf()); + vary.clean(); + } + +#endif + pe->replaceHttpReply(rep, false); // no write until key is public + + pe->timestampsSet(); + + pe->makePublic(); + + pe->startWriting(); // after makePublic() + + pe->complete(); + + pe->unlock("StoreEntry::forcePublicKey+Vary"); + } +} + StoreEntry * storeCreatePureEntry(const char *url, const char *log_url, const RequestFlags &flags, const HttpRequestMethod& method) { @@ -1549,7 +1580,7 @@ return 1; } -void +bool StoreEntry::timestampsSet() { const HttpReply *reply = getReply(); @@ -1587,14 +1618,27 @@ served_date -= (squid_curtime - request_sent); } + time_t exp = 0; if (reply->expires > 0 && reply->date > -1) - expires = served_date + (reply->expires - reply->date); + exp = served_date + (reply->expires - reply->date); else - expires = reply->expires; + exp = reply->expires; + + if (timestamp == served_date && expires == exp) { + // if the reply lacks LMT, then we now know that our effective + // LMT (i.e., timestamp) will stay the same, otherwise, old and + // new modification times must match + if (reply->last_modified < 0 || reply->last_modified == lastModified()) + return false; // nothing has changed + } + + expires = exp; - lastmod = reply->last_modified; + lastModified_ = reply->last_modified; timestamp = served_date; + + return true; } void @@ -1625,7 +1669,7 @@ debugs(20, l, "StoreEntry->timestamp: " << timestamp); debugs(20, l, "StoreEntry->lastref: " << lastref); debugs(20, l, "StoreEntry->expires: " << expires); - debugs(20, l, "StoreEntry->lastmod: " << lastmod); + debugs(20, l, "StoreEntry->lastModified_: " << lastModified_); debugs(20, l, "StoreEntry->swap_file_sz: " << swap_file_sz); debugs(20, l, "StoreEntry->refcount: " << refcount); debugs(20, l, "StoreEntry->flags: " << storeEntryFlags(this)); @@ -1756,7 +1800,7 @@ mem_obj->reset(); HttpReply *rep = (HttpReply *) getReply(); // bypass const rep->reset(); - expires = lastmod = timestamp = -1; + expires = lastModified_ = timestamp = -1; } /* @@ -1966,13 +2010,10 @@ } bool -StoreEntry::modifiedSince(HttpRequest * request) const +StoreEntry::modifiedSince(const time_t ims, const int imslen) const { int object_length; - time_t mod_time = lastmod; - - if (mod_time < 0) - mod_time = timestamp; + const time_t mod_time = lastModified(); debugs(88, 3, "modifiedSince: '" << url() << "'"); @@ -1987,16 +2028,16 @@ if (object_length < 0) object_length = contentLen(); - if (mod_time > request->ims) { + if (mod_time > ims) { debugs(88, 3, "--> YES: entry newer than client"); return true; - } else if (mod_time < request->ims) { + } else if (mod_time < ims) { debugs(88, 3, "--> NO: entry older than client"); return false; - } else if (request->imslen < 0) { + } else if (imslen < 0) { debugs(88, 3, "--> NO: same LMT, no client length"); return false; - } else if (request->imslen == object_length) { + } else if (imslen == object_length) { debugs(88, 3, "--> NO: same LMT, same length"); return false; } else { @@ -2093,6 +2134,18 @@ return true; } +const char * +StoreEntry::describeTimestamps() const +{ + LOCAL_ARRAY(char, buf, 256); + snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d", + static_cast(timestamp), + static_cast(lastref), + static_cast(lastModified_), + static_cast(expires)); + return buf; +} + std::ostream &operator <<(std::ostream &os, const StoreEntry &e) { os << "e:"; diff -u -r -N squid-3.5.21/src/store_dir.cc squid-3.5.22/src/store_dir.cc --- squid-3.5.21/src/store_dir.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/store_dir.cc 2016-10-10 08:58:01.000000000 +1300 @@ -77,7 +77,7 @@ debugs(47, DBG_IMPORTANT, "Using Least Load store dir selection"); } - if (UsingSmp() && IamWorkerProcess() && Config.onoff.collapsed_forwarding) { + if (UsingSmp() && IamWorkerProcess() && Config.onoff.collapsed_forwarding && smpAware()) { transients = new Transients; transients->init(); } @@ -916,7 +916,8 @@ StoreController::allowCollapsing(StoreEntry *e, const RequestFlags &reqFlags, const HttpRequestMethod &reqMethod) { - e->makePublic(); // this is needed for both local and SMP collapsing + const KeyScope keyScope = reqFlags.refresh ? ksRevalidation : ksDefault; + e->makePublic(keyScope); // this is needed for both local and SMP collapsing if (transients) transients->startWriting(e, reqFlags, reqMethod); debugs(20, 3, "may " << (transients && e->mem_obj->xitTable.index >= 0 ? @@ -1003,6 +1004,12 @@ return found; } +bool +StoreController::smpAware() const +{ + return memStore || (swapDir.getRaw() && swapDir->smpAware()); +} + StoreHashIndex::StoreHashIndex() { if (store_table) @@ -1267,6 +1274,19 @@ return new StoreSearchHashIndex (this); } +bool +StoreHashIndex::smpAware() const +{ + for (int i = 0; i < Config.cacheSwap.n_configured; ++i) { + // A mix is not supported, but we conservatively check every + // dir because features like collapsed revalidation should + // currently be disabled if any dir is SMP-aware + if (dir(i).smpAware()) + return true; + } + return false; +} + CBDATA_CLASS_INIT(StoreSearchHashIndex); StoreSearchHashIndex::StoreSearchHashIndex(RefCount aSwapDir) : diff -u -r -N squid-3.5.21/src/Store.h squid-3.5.22/src/Store.h --- squid-3.5.21/src/Store.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/Store.h 2016-10-10 08:58:01.000000000 +1300 @@ -23,6 +23,7 @@ #include "MemObject.h" #include "Range.h" #include "RemovalPolicy.h" +#include "store_key_md5.h" #include "StoreIOBuffer.h" #include "StoreStats.h" @@ -93,9 +94,13 @@ void abort(); void unlink(); - void makePublic(); + void makePublic(const KeyScope keyScope = ksDefault); void makePrivate(); - void setPublicKey(); + void setPublicKey(const KeyScope keyScope = ksDefault); + /// Resets existing public key to a public key with default scope, + /// releasing the old default-scope entry (if any). + /// Does nothing if the existing public key already has default scope. + void clearPublicKeyScope(); void setPrivateKey(); void expireNow(); void releaseRequest(); @@ -130,7 +135,7 @@ void registerAbort(STABH * cb, void *); void reset(); void setMemStatus(mem_status_t); - void timestampsSet(); + bool timestampsSet(); void unregisterAbort(); void destroyMemObject(); int checkTooSmall(); @@ -138,7 +143,16 @@ void delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer callback); void setNoDelay (bool const); - bool modifiedSince(HttpRequest * request) const; + void lastModified(const time_t when) { lastModified_ = when; } + /// \returns entry's 'effective' modification time + time_t lastModified() const { + // may still return -1 if timestamp is not set + return lastModified_ < 0 ? timestamp : lastModified_; + } + /// \returns a formatted string with entry's timestamps + const char *describeTimestamps() const; + // TODO: consider removing currently unsupported imslen parameter + bool modifiedSince(const time_t ims, const int imslen = -1) const; /// has ETag matching at least one of the If-Match etags bool hasIfMatchEtag(const HttpRequest &request) const; /// has ETag matching at least one of the If-None-Match etags @@ -155,7 +169,9 @@ time_t timestamp; time_t lastref; time_t expires; - time_t lastmod; +private: + time_t lastModified_; ///< received Last-Modified value or -1; use lastModified() +public: uint64_t swap_file_sz; uint16_t refcount; uint16_t flags; @@ -228,6 +244,9 @@ private: bool checkTooBig() const; + void forcePublicKey(const cache_key *newkey); + void adjustVary(); + const cache_key *calcPublicKey(const KeyScope keyScope); static MemAllocator *pool; @@ -430,6 +449,9 @@ /// update a local collapsed entry with fresh info from this cache (if any) virtual bool updateCollapsed(StoreEntry &collapsed) { return false; } + /// whether this storage is capable of serving multiple workers + virtual bool smpAware() const = 0; + private: static RefCount CurrentRoot; }; @@ -450,10 +472,10 @@ StoreEntry *storeGetPublic(const char *uri, const HttpRequestMethod& method); /// \ingroup StoreAPI -StoreEntry *storeGetPublicByRequest(HttpRequest * request); +StoreEntry *storeGetPublicByRequest(HttpRequest * request, const KeyScope keyScope = ksDefault); /// \ingroup StoreAPI -StoreEntry *storeGetPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method); +StoreEntry *storeGetPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method, const KeyScope keyScope = ksDefault); /// \ingroup StoreAPI /// Like storeCreatePureEntry(), but also locks the entry and sets entry key. diff -u -r -N squid-3.5.21/src/StoreHashIndex.h squid-3.5.22/src/StoreHashIndex.h --- squid-3.5.21/src/StoreHashIndex.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/StoreHashIndex.h 2016-10-10 08:58:01.000000000 +1300 @@ -59,6 +59,8 @@ virtual StoreSearch *search(String const url, HttpRequest *); + virtual bool smpAware() const; + private: /* migration logic */ StorePointer store(int const x) const; diff -u -r -N squid-3.5.21/src/store_key_md5.cc squid-3.5.22/src/store_key_md5.cc --- squid-3.5.21/src/store_key_md5.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/store_key_md5.cc 2016-10-10 08:58:01.000000000 +1300 @@ -96,7 +96,7 @@ } const cache_key * -storeKeyPublic(const char *url, const HttpRequestMethod& method) +storeKeyPublic(const char *url, const HttpRequestMethod& method, const KeyScope keyScope) { static cache_key digest[SQUID_MD5_DIGEST_LENGTH]; unsigned char m = (unsigned char) method.id(); @@ -104,18 +104,20 @@ SquidMD5Init(&M); SquidMD5Update(&M, &m, sizeof(m)); SquidMD5Update(&M, (unsigned char *) url, strlen(url)); + if (keyScope) + SquidMD5Update(&M, &keyScope, sizeof(keyScope)); SquidMD5Final(digest, &M); return digest; } const cache_key * -storeKeyPublicByRequest(HttpRequest * request) +storeKeyPublicByRequest(HttpRequest * request, const KeyScope keyScope) { - return storeKeyPublicByRequestMethod(request, request->method); + return storeKeyPublicByRequestMethod(request, request->method, keyScope); } const cache_key * -storeKeyPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method) +storeKeyPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method, const KeyScope keyScope) { static cache_key digest[SQUID_MD5_DIGEST_LENGTH]; unsigned char m = (unsigned char) method.id(); @@ -125,6 +127,9 @@ SquidMD5Update(&M, &m, sizeof(m)); SquidMD5Update(&M, (unsigned char *) url, strlen(url)); + if (keyScope) + SquidMD5Update(&M, &keyScope, sizeof(keyScope)); + if (!request->vary_headers.isEmpty()) { SquidMD5Update(&M, request->vary_headers.rawContent(), request->vary_headers.length()); debugs(20, 3, "updating public key by vary headers: " << request->vary_headers << " for: " << url); diff -u -r -N squid-3.5.21/src/store_key_md5.h squid-3.5.22/src/store_key_md5.h --- squid-3.5.21/src/store_key_md5.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/store_key_md5.h 2016-10-10 08:58:01.000000000 +1300 @@ -17,14 +17,19 @@ class HttpRequestMethod; class HttpRequest; +typedef enum { + ksDefault, + ksRevalidation +} KeyScope; + cache_key *storeKeyDup(const cache_key *); cache_key *storeKeyCopy(cache_key *, const cache_key *); void storeKeyFree(const cache_key *); const cache_key *storeKeyScan(const char *); const char *storeKeyText(const cache_key *); -const cache_key *storeKeyPublic(const char *, const HttpRequestMethod&); -const cache_key *storeKeyPublicByRequest(HttpRequest *); -const cache_key *storeKeyPublicByRequestMethod(HttpRequest *, const HttpRequestMethod&); +const cache_key *storeKeyPublic(const char *, const HttpRequestMethod&, const KeyScope keyScope = ksDefault); +const cache_key *storeKeyPublicByRequest(HttpRequest *, const KeyScope keyScope = ksDefault); +const cache_key *storeKeyPublicByRequestMethod(HttpRequest *, const HttpRequestMethod&, const KeyScope keyScope = ksDefault); const cache_key *storeKeyPrivate(const char *, const HttpRequestMethod&, int); int storeKeyHashBuckets(int); int storeKeyNull(const cache_key *); diff -u -r -N squid-3.5.21/src/store_rebuild.cc squid-3.5.22/src/store_rebuild.cc --- squid-3.5.21/src/store_rebuild.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/store_rebuild.cc 2016-10-10 08:58:01.000000000 +1300 @@ -254,7 +254,7 @@ what->timestamp = tmp->timestamp; what->lastref = tmp->lastref; what->expires = tmp->expires; - what->lastmod = tmp->lastmod; + what->lastModified(tmp->lastmod); what->swap_file_sz = tmp->swap_file_sz; what->refcount = tmp->refcount; what->flags = tmp->flags; diff -u -r -N squid-3.5.21/src/SwapDir.h squid-3.5.22/src/SwapDir.h --- squid-3.5.21/src/SwapDir.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/SwapDir.h 2016-10-10 08:58:01.000000000 +1300 @@ -51,6 +51,7 @@ virtual void memoryDisconnect(StoreEntry &e); virtual void allowCollapsing(StoreEntry *e, const RequestFlags &reqFlags, const HttpRequestMethod &reqMethod); virtual void syncCollapsed(const sfileno xitIndex); + virtual bool smpAware() const; virtual void init(); @@ -158,6 +159,7 @@ virtual void getStats(StoreInfoStats &stats) const; virtual void stat (StoreEntry &anEntry) const; virtual StoreSearch *search(String const url, HttpRequest *) = 0; + virtual bool smpAware() const { return false; } /* migrated from store_dir.cc */ bool objectSizeIsAcceptable(int64_t objsize) const; diff -u -r -N squid-3.5.21/src/tests/stub_store.cc squid-3.5.22/src/tests/stub_store.cc --- squid-3.5.21/src/tests/stub_store.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/tests/stub_store.cc 2016-10-10 08:58:01.000000000 +1300 @@ -42,9 +42,9 @@ void StoreEntry::trimMemory(const bool preserveSwappable) STUB void StoreEntry::abort() STUB void StoreEntry::unlink() STUB -void StoreEntry::makePublic() STUB +void StoreEntry::makePublic(const KeyScope keyScope) STUB void StoreEntry::makePrivate() STUB -void StoreEntry::setPublicKey() STUB +void StoreEntry::setPublicKey(const KeyScope keyScope) STUB void StoreEntry::setPrivateKey() STUB void StoreEntry::expireNow() STUB void StoreEntry::releaseRequest() STUB @@ -67,13 +67,13 @@ void StoreEntry::registerAbort(STABH * cb, void *) STUB void StoreEntry::reset() STUB void StoreEntry::setMemStatus(mem_status_t) STUB -void StoreEntry::timestampsSet() STUB +bool StoreEntry::timestampsSet() STUB_RETVAL(false) void StoreEntry::unregisterAbort() STUB void StoreEntry::destroyMemObject() STUB int StoreEntry::checkTooSmall() STUB_RETVAL(0) void StoreEntry::delayAwareRead(const Comm::ConnectionPointer&, char *buf, int len, AsyncCall::Pointer callback) STUB void StoreEntry::setNoDelay (bool const) STUB -bool StoreEntry::modifiedSince(HttpRequest * request) const STUB_RETVAL(false) +bool StoreEntry::modifiedSince(const time_t ims, const int imslen) const STUB_RETVAL(false); bool StoreEntry::hasIfMatchEtag(const HttpRequest &request) const STUB_RETVAL(false) bool StoreEntry::hasIfNoneMatchEtag(const HttpRequest &request) const STUB_RETVAL(false) RefCount StoreEntry::store() const STUB_RETVAL(NULL) @@ -125,8 +125,8 @@ size_t storeEntryInUse() STUB_RETVAL(0) void storeEntryReplaceObject(StoreEntry *, HttpReply *) STUB StoreEntry *storeGetPublic(const char *uri, const HttpRequestMethod& method) STUB_RETVAL(NULL) -StoreEntry *storeGetPublicByRequest(HttpRequest * request) STUB_RETVAL(NULL) -StoreEntry *storeGetPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method) STUB_RETVAL(NULL) +StoreEntry *storeGetPublicByRequest(HttpRequest * request, const KeyScope keyScope) STUB_RETVAL(NULL) +StoreEntry *storeGetPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method, const KeyScope keyScope) STUB_RETVAL(NULL) StoreEntry *storeCreateEntry(const char *, const char *, const RequestFlags &, const HttpRequestMethod&) STUB_RETVAL(NULL) StoreEntry *storeCreatePureEntry(const char *storeId, const char *logUrl, const RequestFlags &, const HttpRequestMethod&) STUB_RETVAL(NULL) void storeInit(void) STUB diff -u -r -N squid-3.5.21/src/tests/testRock.cc squid-3.5.22/src/tests/testRock.cc --- squid-3.5.21/src/tests/testRock.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/tests/testRock.cc 2016-10-10 08:58:01.000000000 +1300 @@ -143,8 +143,6 @@ httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */ - httpReplyInitModule(); /* must go before accepting replies */ - mem_policy = createRemovalPolicy(Config.replPolicy); inited = true; diff -u -r -N squid-3.5.21/src/tests/testStoreController.cc squid-3.5.22/src/tests/testStoreController.cc --- squid-3.5.21/src/tests/testStoreController.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/tests/testStoreController.cc 2016-10-10 08:58:01.000000000 +1300 @@ -113,7 +113,7 @@ e->lastref = squid_curtime; e->timestamp = squid_curtime; e->expires = squid_curtime; - e->lastmod = squid_curtime; + e->lastModified(squid_curtime); e->refcount = 1; EBIT_CLR(e->flags, RELEASE_REQUEST); EBIT_CLR(e->flags, KEY_PRIVATE); diff -u -r -N squid-3.5.21/src/tests/testStore.h squid-3.5.22/src/tests/testStore.h --- squid-3.5.21/src/tests/testStore.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/tests/testStore.h 2016-10-10 08:58:01.000000000 +1300 @@ -76,6 +76,8 @@ virtual bool dereference(StoreEntry &, bool) { return true; } virtual StoreSearch *search(String const url, HttpRequest *); + + virtual bool smpAware() const { return false; } }; typedef RefCount TestStorePointer; diff -u -r -N squid-3.5.21/src/tests/testStoreHashIndex.cc squid-3.5.22/src/tests/testStoreHashIndex.cc --- squid-3.5.21/src/tests/testStoreHashIndex.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/tests/testStoreHashIndex.cc 2016-10-10 08:58:01.000000000 +1300 @@ -94,7 +94,7 @@ e->lastref = squid_curtime; e->timestamp = squid_curtime; e->expires = squid_curtime; - e->lastmod = squid_curtime; + e->lastModified(squid_curtime); e->refcount = 1; EBIT_CLR(e->flags, RELEASE_REQUEST); EBIT_CLR(e->flags, KEY_PRIVATE); diff -u -r -N squid-3.5.21/src/tests/testUfs.cc squid-3.5.22/src/tests/testUfs.cc --- squid-3.5.21/src/tests/testUfs.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/tests/testUfs.cc 2016-10-10 08:58:01.000000000 +1300 @@ -75,8 +75,6 @@ httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */ - httpReplyInitModule(); /* must go before accepting replies */ - inited = true; } diff -u -r -N squid-3.5.21/src/Transients.cc squid-3.5.22/src/Transients.cc --- squid-3.5.21/src/Transients.cc 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/Transients.cc 2016-10-10 08:58:01.000000000 +1300 @@ -197,7 +197,8 @@ e->mem_obj->xitTable.io = MemObject::ioReading; e->mem_obj->xitTable.index = index; - e->setPublicKey(); + // TODO: Support collapsed revalidation for SMP-aware caches + e->setPublicKey(ksDefault); assert(e->key); // How do we know its SMP- and not just locally-collapsed? A worker gets diff -u -r -N squid-3.5.21/src/Transients.h squid-3.5.22/src/Transients.h --- squid-3.5.21/src/Transients.h 2016-09-09 06:56:46.000000000 +1200 +++ squid-3.5.22/src/Transients.h 2016-10-10 08:58:01.000000000 +1300 @@ -72,6 +72,7 @@ virtual bool dereference(StoreEntry &, bool); virtual void markForUnlink(StoreEntry &e); virtual void maintain(); + virtual bool smpAware() const { return true; } static int64_t EntryLimit();