diff --git a/.gitignore b/.gitignore index c3b9d49..47e6daa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,2 @@ /varnish-modules-0.12.1.tar.gz /varnish-modules-0.15.0.tar.gz -/varnish-modules-0032ed8.tar.gz -/varnish-modules-0.16.0.tar.gz -/varnish-modules-4d6593c.tar.gz -/varnish-modules-0.17.1.tar.gz -/varnish-modules-0.18.0.tar.gz -/varnish-modules-0.19.0.tar.gz -/varnish-modules-0.20.0.tar.gz -/varnish-modules-0.21.0.tar.gz -/varnish-modules-0.22.0.tar.gz -/varnish-modules-0.24.0.tar.gz -/varnish-modules-0.25.0.tar.gz -/varnish-modules-0.26.0.tar.gz -/varnish-modules-0.27.0.tar.gz -/varnish-modules-0.28.0.tar.gz diff --git a/sources b/sources index f25bbdd..220d464 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (varnish-modules-0.28.0.tar.gz) = 796f95ea6f8b69f6e4fb3daf327c4a6cccc9b6c927d8daace753aad7e443c1f937020465924e472ad65bb0a10e2e5bf85b6228afe3257dbfba0091750fbf300a +SHA512 (varnish-modules-0.15.0.tar.gz) = f24bc7e00db8eb53e4730b9b6d9adb9442d26ad5b07f3e09541b686e41d437113b8bca75f9ac47bc0ec54475fafb0eefc46b98ccee92d9360aaf660b4826ec9e diff --git a/varnish-0.15.0.add.bootstrap.patch b/varnish-0.15.0.add.bootstrap.patch deleted file mode 100644 index ad233c7..0000000 --- a/varnish-0.15.0.add.bootstrap.patch +++ /dev/null @@ -1,44 +0,0 @@ ---- /dev/null 2019-09-18 14:09:23.308277474 +0200 -+++ bootstrap 2019-09-24 09:55:24.218322744 +0200 -@@ -0,0 +1,41 @@ -+#!/bin/sh -+ -+warn() { -+ echo "WARNING: $@" 1>&2 -+} -+ -+case `uname -s` in -+Darwin) -+ LIBTOOLIZE=glibtoolize -+ ;; -+FreeBSD) -+ LIBTOOLIZE=libtoolize -+ ;; -+Linux) -+ LIBTOOLIZE=libtoolize -+ ;; -+SunOS) -+ LIBTOOLIZE=libtoolize -+ ;; -+*) -+ warn "unrecognized platform:" `uname -s` -+ LIBTOOLIZE=libtoolize -+esac -+ -+# check for varnishapi.m4 in custom paths -+dataroot=$(pkg-config --variable=datarootdir varnishapi 2>/dev/null) -+if [ -z "$dataroot" ] ; then -+ cat >&2 <<'EOF' -+Package varnishapi was not found in the pkg-config search path. -+Perhaps you should add the directory containing `varnishapi.pc' -+to the PKG_CONFIG_PATH environment variable -+EOF -+ exit 1 -+fi -+set -ex -+mkdir -p m4 -+aclocal -I m4 -I ${dataroot}/aclocal -+$LIBTOOLIZE --copy --force -+autoheader -+automake --add-missing --copy --foreign -+autoconf diff --git a/varnish-modules-0.15.0-vmod-tcp-int.patch b/varnish-modules-0.15.0-vmod-tcp-int.patch new file mode 100644 index 0000000..bc31cf4 --- /dev/null +++ b/varnish-modules-0.15.0-vmod-tcp-int.patch @@ -0,0 +1,13 @@ +diff --git a/src/vmod_tcp.c b/src/vmod_tcp.c +index fee4bd3..e1c5dfa 100644 +--- a/src/vmod_tcp.c ++++ b/src/vmod_tcp.c +@@ -174,7 +174,7 @@ vmod_set_socket_pace(VRT_CTX, VCL_INT rate) + sizeof(pacerate)) != 0) + VSLb(ctx->vsl, SLT_VCL_Error, "set_socket_pace(): Error setting pace rate."); + else +- VSLb(ctx->vsl, SLT_VCL_Log, "vmod-tcp: Socket paced to %lu KB/s.", rate); ++ VSLb(ctx->vsl, SLT_VCL_Log, "vmod-tcp: Socket paced to %d KB/s.", pacerate); + + # ifndef NDEBUG + int retval; diff --git a/varnish-modules-0.15.0.add.bootstrap.patch b/varnish-modules-0.15.0.add.bootstrap.patch deleted file mode 100644 index c2106ba..0000000 --- a/varnish-modules-0.15.0.add.bootstrap.patch +++ /dev/null @@ -1,44 +0,0 @@ ---- /dev/null 2019-09-28 14:48:27.937320545 +0200 -+++ bootstrap 2019-09-29 00:35:05.782099759 +0200 -@@ -0,0 +1,41 @@ -+#!/bin/sh -+ -+warn() { -+ echo "WARNING: $@" 1>&2 -+} -+ -+case `uname -s` in -+Darwin) -+ LIBTOOLIZE=glibtoolize -+ ;; -+FreeBSD) -+ LIBTOOLIZE=libtoolize -+ ;; -+Linux) -+ LIBTOOLIZE=libtoolize -+ ;; -+SunOS) -+ LIBTOOLIZE=libtoolize -+ ;; -+*) -+ warn "unrecognized platform:" `uname -s` -+ LIBTOOLIZE=libtoolize -+esac -+ -+# check for varnishapi.m4 in custom paths -+dataroot=$(pkg-config --variable=datarootdir varnishapi 2>/dev/null) -+if [ -z "$dataroot" ] ; then -+ cat >&2 <<'EOF' -+Package varnishapi was not found in the pkg-config search path. -+Perhaps you should add the directory containing `varnishapi.pc' -+to the PKG_CONFIG_PATH environment variable -+EOF -+ exit 1 -+fi -+set -ex -+mkdir -p m4 -+aclocal -I m4 -I ${dataroot}/aclocal -+$LIBTOOLIZE --copy --force -+autoheader -+automake --add-missing --copy --foreign -+autoconf diff --git a/varnish-modules-0.15.0.nigoroll_to_fe1a981_compatible_with_varnish-6.3.0.patch b/varnish-modules-0.15.0.nigoroll_to_fe1a981_compatible_with_varnish-6.3.0.patch deleted file mode 100644 index e0932c2..0000000 --- a/varnish-modules-0.15.0.nigoroll_to_fe1a981_compatible_with_varnish-6.3.0.patch +++ /dev/null @@ -1,3143 +0,0 @@ -diff --git a/README.rst b/README.rst -index 7b757ed..709d82f 100644 ---- a/README.rst -+++ b/README.rst -@@ -1,3 +1,10 @@ -+Status of this repository -+========================= -+ -+This repository is based upon -+https://github.com/varnish/varnish-modules with necessary adjustments -+for varnish-cache master. It is being maintained by https://uplex.de/ -+ - Varnish module collection by Varnish Software - ============================================= - -@@ -49,14 +56,13 @@ If you are using the distro provided packages:: - - Then proceed to the configure and build:: - -- ./bootstrap # If running from git. - ./configure - make - make check # optional - sudo make install - - --The resulting loadable modules (``libvmod_foo*.so`` files) will be installed to -+The resulting loadable modules (``libvmod_*.so`` files) will be installed to - the Varnish module directory. (default `/usr/lib/varnish/vmods/`) - - -@@ -86,6 +92,18 @@ The source git tree lives on Github: https://github.com/varnish/varnish-modules - All source code is placed in the master git branch. Pull requests and issue - reporting are appreciated. - -+Unlike building from releases, you need to first bootstrap the build system -+when you work from git:: -+ -+ ./bootstrap -+ ./configure -+ make -+ make check # recommended -+ -+If the ``configure`` step succeeds but the ``make`` step fails, check for -+warnings in the ``./configure`` output or the ``config.log`` file. You may be -+missing bootstrap dependencies not required by release archives. -+ - Porting - ------- - -diff --git a/configure.ac b/configure.ac -index 294ece3..df55b41 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -7,7 +7,7 @@ AC_CONFIG_AUX_DIR([build-aux]) - AC_CONFIG_SRCDIR(src/vmod_cookie.vcc) - AC_CONFIG_HEADERS(config.h) - --AM_INIT_AUTOMAKE([1.11 foreign]) -+AM_INIT_AUTOMAKE([1.12.2 foreign]) - AM_SILENT_RULES([yes]) - AM_EXTRA_RECURSIVE_TARGETS([rst-docs]) - -diff --git a/docs/vmod_cookie.rst b/docs/vmod_cookie.rst -index d7a3666..892fe40 100644 ---- a/docs/vmod_cookie.rst -+++ b/docs/vmod_cookie.rst -@@ -4,25 +4,42 @@ - .. Edit vmod.vcc and run make instead - .. - --.. role:: ref(emphasis) - --.. _vmod_cookie(3): -- --=========== --vmod_cookie --=========== -+:tocdepth: 1 - ----------------------- --Varnish Cookie Module ----------------------- -+.. _vmod_cookie(3): - --:Manual section: 3 -+=================================== -+VMOD cookie - Varnish Cookie Module -+=================================== - - SYNOPSIS - ======== - --import cookie [from "path"] ; -- -+.. parsed-literal:: -+ -+ import cookie [from "path"] -+ -+ :ref:`vmod_cookie.clean` -+ -+ :ref:`vmod_cookie.delete` -+ -+ :ref:`vmod_cookie.filter` -+ -+ :ref:`vmod_cookie.filter_except` -+ -+ :ref:`vmod_cookie.format_rfc1123` -+ -+ :ref:`vmod_cookie.get` -+ -+ :ref:`vmod_cookie.get_string` -+ -+ :ref:`vmod_cookie.isset` -+ -+ :ref:`vmod_cookie.parse` -+ -+ :ref:`vmod_cookie.set` -+ - DESCRIPTION - =========== - -@@ -34,8 +51,8 @@ but a set comma-separated list of cookies. A filter() method removes a comma- - separated list of cookies. - - A convenience function for formatting the Set-Cookie Expires date field --is also included. To actually manipulate the Set-Cookie response headers, --vmod-header should be used instead though. -+is also included. If there are multiple Set-Cookie headers vmod-header -+should be used. - - The state loaded with cookie.parse() has a lifetime of the current request - or backend request context. To pass variables to the backend request, store -@@ -71,28 +88,11 @@ Filtering example:: - - .. vcl-end - --CONTENTS --======== -- --* :ref:`func_clean` --* :ref:`func_delete` --* :ref:`func_filter` --* :ref:`func_filter_except` --* :ref:`func_format_rfc1123` --* :ref:`func_get` --* :ref:`func_get_string` --* :ref:`func_isset` --* :ref:`func_parse` --* :ref:`func_set` - --.. _func_clean: -+.. _vmod_cookie.clean: - --clean ------- -- --:: -- -- VOID clean(PRIV_TASK) -+VOID clean() -+------------ - - Description - Clean up previously parsed cookies. It is not necessary to run clean() -@@ -104,14 +104,10 @@ Example - cookie.clean(); - } - --.. _func_delete: -- --delete -------- -- --:: -+.. _vmod_cookie.delete: - -- VOID delete(PRIV_TASK, STRING cookiename) -+VOID delete(STRING cookiename) -+------------------------------ - - Description - Delete `cookiename` from internal vmod storage if it exists. -@@ -125,14 +121,10 @@ Example - // get_string() will now yield "cookie1: value1"; - } - --.. _func_filter: -+.. _vmod_cookie.filter: - --filter -------- -- --:: -- -- VOID filter(PRIV_TASK, STRING filterstring) -+VOID filter(STRING filterstring) -+-------------------------------- - - Description - Delete all cookies from internal vmod storage that are in the -@@ -148,14 +140,10 @@ Example - // "cookie3: value3"; - } - --.. _func_filter_except: -- --filter_except --------------- -- --:: -+.. _vmod_cookie.filter_except: - -- VOID filter_except(PRIV_TASK, STRING filterstring) -+VOID filter_except(STRING filterstring) -+--------------------------------------- - - Description - Delete all cookies from internal vmod storage that is not in the -@@ -170,14 +158,10 @@ Example - // "cookie1: value1; cookie2: value2;"; - } - --.. _func_format_rfc1123: -+.. _vmod_cookie.format_rfc1123: - --format_rfc1123 ---------------- -- --:: -- -- STRING format_rfc1123(TIME now, DURATION timedelta) -+STRING format_rfc1123(TIME now, DURATION timedelta) -+--------------------------------------------------- - - Description - Get a RFC1123 formatted date string suitable for inclusion in a -@@ -193,14 +177,10 @@ Example - set resp.http.Set-Cookie = "userid=" + req.http.userid + "; Expires=" + cookie.format_rfc1123(now, 5m) + "; httpOnly"; - } - --.. _func_get: -- --get ----- -- --:: -+.. _vmod_cookie.get: - -- STRING get(PRIV_TASK, STRING cookiename) -+STRING get(STRING cookiename) -+----------------------------- - - Description - Get the value of `cookiename`, as stored in internal vmod storage. If `cookiename` does not exist an empty string is returned. -@@ -213,14 +193,10 @@ Example - std.log("cookie1 value is: " + cookie.get("cookie1")); - } - --.. _func_get_string: -+.. _vmod_cookie.get_string: - --get_string ------------ -- --:: -- -- STRING get_string(PRIV_TASK) -+STRING get_string() -+------------------- - - Description - Get a Cookie string value with all cookies in internal vmod storage. Does -@@ -234,14 +210,10 @@ Example - set req.http.cookie = cookie.get_string(); - } - --.. _func_isset: -- --isset ------- -- --:: -+.. _vmod_cookie.isset: - -- BOOL isset(PRIV_TASK, STRING cookiename) -+BOOL isset(STRING cookiename) -+----------------------------- - - Description - Check if `cookiename` is set in the internal vmod storage. -@@ -257,14 +229,10 @@ Example - } - } - --.. _func_parse: -+.. _vmod_cookie.parse: - --parse ------- -- --:: -- -- VOID parse(PRIV_TASK, STRING cookieheader) -+VOID parse(STRING cookieheader) -+------------------------------- - - Description - Parse the cookie string in `cookieheader`. If state already exists, clean() will be run first. -@@ -275,16 +243,10 @@ Example - cookie.parse(req.http.Cookie); - } - -+.. _vmod_cookie.set: - -- --.. _func_set: -- --set ----- -- --:: -- -- VOID set(PRIV_TASK, STRING cookiename, STRING value) -+VOID set(STRING cookiename, STRING value) -+----------------------------------------- - - Description - Set the internal vmod storage for `cookiename` to `value`. -@@ -296,5 +258,3 @@ Example - cookie.set("cookie1", "value1"); - std.log("cookie1 value is: " + cookie.get("cookie1")); - } -- -- -diff --git a/docs/vmod_header.rst b/docs/vmod_header.rst -index 50f64db..1789727 100644 ---- a/docs/vmod_header.rst -+++ b/docs/vmod_header.rst -@@ -4,25 +4,30 @@ - .. Edit vmod.vcc and run make instead - .. - --.. role:: ref(emphasis) - --.. _vmod_header(3): -+:tocdepth: 1 - --=========== --vmod_header --=========== -- ------------------------- --Header VMOD for Varnish ------------------------- -+.. _vmod_header(3): - --:Manual section: 3 -+===================================== -+VMOD header - Header VMOD for Varnish -+===================================== - - SYNOPSIS - ======== - --import header [from "path"] ; -- -+.. parsed-literal:: -+ -+ import header [from "path"] -+ -+ :ref:`vmod_header.append` -+ -+ :ref:`vmod_header.copy` -+ -+ :ref:`vmod_header.get` -+ -+ :ref:`vmod_header.remove` -+ - DESCRIPTION - =========== - -@@ -51,22 +56,10 @@ Example:: - .. vcl-end - - --CONTENTS --======== -- --* :ref:`func_append` --* :ref:`func_copy` --* :ref:`func_get` --* :ref:`func_remove` -- --.. _func_append: -+.. _vmod_header.append: - --append -------- -- --:: -- -- VOID append(HEADER, STRING) -+VOID append(HEADER, STRING) -+--------------------------- - - Description - Append an extra occurrence to an existing header. -@@ -74,14 +67,10 @@ Example - :: - header.append(beresp.http.Set-Cookie, "foo=bar") - --.. _func_copy: -- --copy ------ -+.. _vmod_header.copy: - --:: -- -- VOID copy(HEADER, HEADER) -+VOID copy(HEADER, HEADER) -+------------------------- - - Description - Copy all source headers to a new header. -@@ -89,14 +78,10 @@ Example - :: - header.copy(beresp.http.set-cookie, beresp.http.x-old-cookie); - --.. _func_get: -- --get ----- -+.. _vmod_header.get: - --:: -- -- STRING get(PRIV_CALL, HEADER header, STRING regex) -+STRING get(HEADER header, STRING regex) -+--------------------------------------- - - Description - Fetches the value of the first `header` that matches the given -@@ -105,17 +90,13 @@ Example - :: - set beresp.http.xusr = header.get(beresp.http.set-cookie,"user="); - --.. _func_remove: -- --remove -------- -+.. _vmod_header.remove: - --:: -- -- VOID remove(PRIV_CALL, HEADER header, STRING regex) -+VOID remove(HEADER header, STRING regex) -+---------------------------------------- - - Description -- Remove all occurences of `header` that matches `regex`. -+ Remove all occurrences of `header` that matches `regex`. - Example - :: - header.remove(beresp.http.set-cookie,"^(?!(funcookie=))"); -@@ -135,4 +116,3 @@ BUGS - - You can't use dynamic regular expressions, which also holds true for normal - regular expressions in regsub(). -- -diff --git a/docs/vmod_saintmode.rst b/docs/vmod_saintmode.rst -index ceaaf44..801cc92 100644 ---- a/docs/vmod_saintmode.rst -+++ b/docs/vmod_saintmode.rst -@@ -4,26 +4,34 @@ - .. Edit vmod.vcc and run make instead - .. - --.. role:: ref(emphasis) - --.. _vmod_saintmode(3): -- --============== --vmod_saintmode --============== -+:tocdepth: 1 - ----------------------------- --Saint mode backend director ----------------------------- -+.. _vmod_saintmode(3): - --:Manual section: 3 -+============================================ -+VMOD saintmode - Saint mode backend director -+============================================ - - SYNOPSIS - ======== - --import saintmode [from "path"] ; -- -- -+.. parsed-literal:: -+ -+ import saintmode [from "path"] -+ -+ :ref:`vmod_saintmode.blacklist` -+ -+ :ref:`vmod_saintmode.status` -+ -+ :ref:`vmod_saintmode.saintmode` -+ -+ :ref:`vmod_saintmode.saintmode.backend` -+ -+ :ref:`vmod_saintmode.saintmode.blacklist_count` -+ -+ :ref:`vmod_saintmode.saintmode.is_healthy` -+ - DESCRIPTION - =========== - -@@ -95,23 +103,10 @@ Example:: - .. vcl-end - - --CONTENTS --======== -- --* :ref:`func_blacklist` --* :ref:`obj_saintmode` --* :ref:`func_saintmode.backend` --* :ref:`func_saintmode.blacklist_count` --* :ref:`func_status` -- --.. _func_blacklist: -- --blacklist ----------- -- --:: -+.. _vmod_saintmode.blacklist: - -- VOID blacklist(PRIV_VCL, DURATION expires) -+VOID blacklist(DURATION expires) -+-------------------------------- - - Marks the backend as sick for a specific object. Used in vcl_backend_response. - Corresponds to the use of ``beresp.saintmode`` in Varnish 3.0. Only available -@@ -126,15 +121,10 @@ Example:: - } - } - -+.. _vmod_saintmode.status: - --.. _func_status: -- --status -------- -- --:: -- -- STRING status(PRIV_VCL) -+STRING status() -+--------------- - - Returns a JSON formatted status string suitable for use in vcl_synth. - -@@ -164,38 +154,33 @@ Example JSON output: - ] - } - -+.. _vmod_saintmode.saintmode: - --.. _obj_saintmode: -- --saintmode ----------- -+new xsaintmode = saintmode.saintmode(BACKEND backend, INT threshold) -+-------------------------------------------------------------------- - - :: - -- new OBJ = saintmode(PRIV_VCL, BACKEND backend, INT threshold) -+ new xsaintmode = saintmode.saintmode( -+ BACKEND backend, -+ INT threshold -+ ) - - Constructs a saintmode director object. The ``threshold`` argument sets - the saintmode threshold, which is the maximum number of items that can be - blacklisted before the whole backend is regarded as sick. Corresponds with the - ``saintmode_threshold`` parameter of Varnish 3.0. - --Setting threshold to 0 disables saintmode, not the threshold. -- - Example:: - - sub vcl_init { - new sm = saintmode.saintmode(b, 10); - } - -+.. _vmod_saintmode.saintmode.backend: - --.. _func_saintmode.backend: -- --saintmode.backend ------------------- -- --:: -- -- BACKEND saintmode.backend() -+BACKEND xsaintmode.backend() -+---------------------------- - - Used for assigning the backend from the saintmode object. - -@@ -205,15 +190,10 @@ Example:: - set bereq.backend = sm.backend(); - } - -+.. _vmod_saintmode.saintmode.blacklist_count: - --.. _func_saintmode.blacklist_count: -- --saintmode.blacklist_count --------------------------- -- --:: -- -- INT saintmode.blacklist_count() -+INT xsaintmode.blacklist_count() -+-------------------------------- - - Returns the number of objects currently blacklisted for a saintmode - director object. -@@ -226,3 +206,11 @@ Example: - set resp.http.troublecount = sm.blacklist_count(); - } - -+.. _vmod_saintmode.saintmode.is_healthy: -+ -+BOOL xsaintmode.is_healthy() -+---------------------------- -+ -+Checks if the object is currently blacklisted for a saintmode director object. -+If there are no valid objects available (called from vcl_hit or vcl_recv), -+the function will fall back to the backend's health function. -diff --git a/docs/vmod_tcp.rst b/docs/vmod_tcp.rst -index b37c863..5015443 100644 ---- a/docs/vmod_tcp.rst -+++ b/docs/vmod_tcp.rst -@@ -4,25 +4,30 @@ - .. Edit vmod.vcc and run make instead - .. - --.. role:: ref(emphasis) - --.. _vmod_tcp(3): -- --======== --vmod_tcp --======== -+:tocdepth: 1 - ---------- --TCP vmod ---------- -+.. _vmod_tcp(3): - --:Manual section: 3 -+=================== -+VMOD tcp - TCP vmod -+=================== - - SYNOPSIS - ======== - --import tcp [from "path"] ; -- -+.. parsed-literal:: -+ -+ import tcp [from "path"] -+ -+ :ref:`vmod_tcp.congestion_algorithm` -+ -+ :ref:`vmod_tcp.dump_info` -+ -+ :ref:`vmod_tcp.get_estimated_rtt` -+ -+ :ref:`vmod_tcp.set_socket_pace` -+ - DESCRIPTION - =========== - -@@ -59,22 +64,10 @@ Example:: - .. vcl-end - - --CONTENTS --======== -- --* :ref:`func_congestion_algorithm` --* :ref:`func_dump_info` --* :ref:`func_get_estimated_rtt` --* :ref:`func_set_socket_pace` -- --.. _func_congestion_algorithm: -+.. _vmod_tcp.congestion_algorithm: - --congestion_algorithm ---------------------- -- --:: -- -- INT congestion_algorithm(STRING algorithm) -+INT congestion_algorithm(STRING algorithm) -+------------------------------------------ - - Set the client socket congestion control algorithm to S. Returns 0 on success, and -1 on error. - -@@ -84,15 +77,10 @@ Example:: - set req.http.x-tcp = tcp.congestion_algorithm("cubic"); - } - -+.. _vmod_tcp.dump_info: - --.. _func_dump_info: -- --dump_info ----------- -- --:: -- -- VOID dump_info() -+VOID dump_info() -+---------------- - - Write the contents of the TCP_INFO data structure into varnishlog. - -@@ -107,17 +95,10 @@ Example varnishlog output:: - - VCL_Log tcpi2: pmtu=1500 rtt=152000 rttvar=76000 snd_cwnd=10 advmss=1448 reordering=3 - - VCL_Log getsockopt() returned: cubic - -+.. _vmod_tcp.get_estimated_rtt: - -- -- --.. _func_get_estimated_rtt: -- --get_estimated_rtt ------------------- -- --:: -- -- REAL get_estimated_rtt() -+REAL get_estimated_rtt() -+------------------------ - - Get the estimated round-trip-time for the client socket. Unit: milliseconds. - -@@ -127,15 +108,10 @@ Example:: - std.log("client is far away."); - } - -+.. _vmod_tcp.set_socket_pace: - --.. _func_set_socket_pace: -- --set_socket_pace ----------------- -- --:: -- -- VOID set_socket_pace(INT) -+VOID set_socket_pace(INT) -+------------------------- - - Set socket pacing on client-side TCP connection to PACE KB/s. Network interface - used must be using a supported scheduler. (fq) -@@ -143,5 +119,3 @@ used must be using a supported scheduler. (fq) - Example:: - - tcp.set_socket_pace(1000); -- -- -diff --git a/docs/vmod_var.rst b/docs/vmod_var.rst -index d5f7a2d..fe7dcce 100644 ---- a/docs/vmod_var.rst -+++ b/docs/vmod_var.rst -@@ -4,26 +4,56 @@ - .. Edit vmod.vcc and run make instead - .. - --.. role:: ref(emphasis) - --.. _vmod_var(3): -+:tocdepth: 1 - --======== --vmod_var --======== -- ---------------------------------- --Variable support for Varnish VCL ---------------------------------- -+.. _vmod_var(3): - --:Manual section: 3 -+=========================================== -+VMOD var - Variable support for Varnish VCL -+=========================================== - - SYNOPSIS - ======== - --import var [from "path"] ; -- -- -+.. parsed-literal:: -+ -+ import var [from "path"] -+ -+ :ref:`vmod_var.set` -+ -+ :ref:`vmod_var.get` -+ -+ :ref:`vmod_var.global_set` -+ -+ :ref:`vmod_var.global_get` -+ -+ :ref:`vmod_var.set_int` -+ -+ :ref:`vmod_var.get_int` -+ -+ :ref:`vmod_var.set_string` -+ -+ :ref:`vmod_var.get_string` -+ -+ :ref:`vmod_var.set_real` -+ -+ :ref:`vmod_var.get_real` -+ -+ :ref:`vmod_var.set_duration` -+ -+ :ref:`vmod_var.get_duration` -+ -+ :ref:`vmod_var.set_ip` -+ -+ :ref:`vmod_var.get_ip` -+ -+ :ref:`vmod_var.set_backend` -+ -+ :ref:`vmod_var.get_backend` -+ -+ :ref:`vmod_var.clear` -+ - This VMOD implements basic variable support in VCL. - - It supports strings, integers and real numbers. There are methods to get and -@@ -82,183 +112,122 @@ Example:: - .. vcl-end - - --CONTENTS --======== -- --* :ref:`func_clear` --* :ref:`func_get` --* :ref:`func_get_duration` --* :ref:`func_get_int` --* :ref:`func_get_ip` --* :ref:`func_get_real` --* :ref:`func_get_string` --* :ref:`func_global_get` --* :ref:`func_global_set` --* :ref:`func_set` --* :ref:`func_set_duration` --* :ref:`func_set_int` --* :ref:`func_set_ip` --* :ref:`func_set_real` --* :ref:`func_set_string` -- --.. _func_set: -+.. _vmod_var.set: - --set ----- -- --:: -- -- VOID set(PRIV_TASK, STRING key, STRING value) -+VOID set(STRING key, STRING value) -+---------------------------------- - - Set `key` to `value`. - --.. _func_get: -- --get ----- -+.. _vmod_var.get: - --:: -- -- STRING get(PRIV_TASK, STRING) -+STRING get(STRING) -+------------------ - - Get `key` with data type STRING. If stored `key` is not a STRING an empty string is returned. - --.. _func_global_set: -- --global_set ------------ -+.. _vmod_var.global_set: - --:: -+VOID global_set(STRING, STRING) -+------------------------------- - -- VOID global_set(STRING, STRING) - --.. _func_global_get: - --global_get ------------ -+.. _vmod_var.global_get: - --:: -+STRING global_get(STRING) -+------------------------- - -- STRING global_get(STRING) - --.. _func_set_int: - --set_int --------- -+.. _vmod_var.set_int: - --:: -- -- VOID set_int(PRIV_TASK, STRING key, INT value) -+VOID set_int(STRING key, INT value) -+----------------------------------- - - Set `key` to `value`. - --.. _func_get_int: -- --get_int --------- -- --:: -+.. _vmod_var.get_int: - -- INT get_int(PRIV_TASK, STRING key) -+INT get_int(STRING key) -+----------------------- - - Get `key` with data type INT. If stored `key` is not an INT zero will be returned. - --.. _func_set_string: -- --set_string ------------ -- --:: -+.. _vmod_var.set_string: - -- VOID set_string(PRIV_TASK, STRING key, STRING value) -+VOID set_string(STRING key, STRING value) -+----------------------------------------- - - Identical to set(). - --.. _func_get_string: -+.. _vmod_var.get_string: - --get_string ------------ -- --:: -- -- STRING get_string(PRIV_TASK, STRING key) -+STRING get_string(STRING key) -+----------------------------- - - Identical to get(). - --.. _func_set_real: -- --set_real ---------- -+.. _vmod_var.set_real: - --:: -- -- VOID set_real(PRIV_TASK, STRING key, REAL value) -+VOID set_real(STRING key, REAL value) -+------------------------------------- - - Set `key` to `value`. - --.. _func_get_real: -- --get_real ---------- -+.. _vmod_var.get_real: - --:: -- -- REAL get_real(PRIV_TASK, STRING key) -+REAL get_real(STRING key) -+------------------------- - - Get `key` with data type REAL. If stored `key` is not a REAL zero will be returned. - --.. _func_set_duration: -- --set_duration -------------- -+.. _vmod_var.set_duration: - --:: -- -- VOID set_duration(PRIV_TASK, STRING key, DURATION value) -+VOID set_duration(STRING key, DURATION value) -+--------------------------------------------- - - Set `key` to `value`. - --.. _func_get_duration: -+.. _vmod_var.get_duration: - --get_duration -------------- -- --:: -- -- DURATION get_duration(PRIV_TASK, STRING key) -+DURATION get_duration(STRING key) -+--------------------------------- - - Get `key` with data type DURATION. If stored `key` is not a DURATION zero will be returned. - --.. _func_set_ip: -+.. _vmod_var.set_ip: - --set_ip -------- -+VOID set_ip(STRING key, IP value) -+--------------------------------- - --:: -+Set `key` to `value`. - -- VOID set_ip(PRIV_TASK, STRING key, IP value) -+.. _vmod_var.get_ip: - --Set `key` to `value`. -+IP get_ip(STRING key) -+--------------------- - --.. _func_get_ip: -+Get `key` with data type IP. If stored `key` is not an IP null will be returned. - --get_ip -------- -+.. _vmod_var.set_backend: - --:: -+VOID set_backend(STRING key, BACKEND value) -+------------------------------------------- - -- IP get_ip(PRIV_TASK, STRING key) -+Set `key` to `value`. - --Get `key` with data type IP. If stored `key` is not an IP null will be returned. -+.. _vmod_var.get_backend: - --.. _func_clear: -+BACKEND get_backend(STRING key) -+------------------------------- - --clear ------- -+Get `key` with data type BACKEND. If stored `key` is not a BACKEND, -+null will be returned. - --:: -+.. _vmod_var.clear: - -- VOID clear(PRIV_TASK) -+VOID clear() -+------------ - - Clear all non-global variables. -- -diff --git a/docs/vmod_vsthrottle.rst b/docs/vmod_vsthrottle.rst -index 2593224..403aa7f 100644 ---- a/docs/vmod_vsthrottle.rst -+++ b/docs/vmod_vsthrottle.rst -@@ -4,25 +4,30 @@ - .. Edit vmod.vcc and run make instead - .. - --.. role:: ref(emphasis) - --.. _vmod_vsthrottle(3): -- --=============== --vmod_vsthrottle --=============== -+:tocdepth: 1 - ----------------- --Throttling VMOD ----------------- -+.. _vmod_vsthrottle(3): - --:Manual section: 3 -+================================= -+VMOD vsthrottle - Throttling VMOD -+================================= - - SYNOPSIS - ======== - --import vsthrottle [from "path"] ; -- -+.. parsed-literal:: -+ -+ import vsthrottle [from "path"] -+ -+ :ref:`vmod_vsthrottle.is_denied` -+ -+ :ref:`vmod_vsthrottle.return_token` -+ -+ :ref:`vmod_vsthrottle.remaining` -+ -+ :ref:`vmod_vsthrottle.blocked` -+ - DESCRIPTION - =========== - -@@ -37,6 +42,12 @@ The request rate is specified as the number of requests permitted over - a period. To keep things simple, this is passed as two separate - parameters, 'limit' and 'period'. - -+If an optional duration 'block' is specified, then access is denied -+altogether for that period of time after the rate limit is -+reached. This is a way to entirely turn away a particularly -+troublesome source of traffic for a while, rather than let them back -+in as soon as the rate slips back under the threshold. -+ - This VMOD implements a `token bucket algorithm`_. State associated - with the token bucket for each key is stored in-memory using BSD's - red-black tree implementation. -@@ -58,8 +69,9 @@ Example:: - sub vcl_recv { - # Varnish will set client.identity for you based on client IP. - -- if (vsthrottle.is_denied(client.identity, 15, 10s)) { -- # Client has exceeded 15 reqs per 10s -+ if (vsthrottle.is_denied(client.identity, 15, 10s, 30s)) { -+ # Client has exceeded 15 reqs per 10s. -+ # When this happens, block altogether for the next 30s. - return (synth(429, "Too Many Requests")); - } - -@@ -78,33 +90,37 @@ Example:: - - .. vcl-end - --CONTENTS --======== -- --* :ref:`func_is_denied` --* :ref:`func_remaining` - --.. _func_is_denied: -+.. _vmod_vsthrottle.is_denied: - --is_denied ----------- -+BOOL is_denied(STRING key, INT limit, DURATION period, DURATION block) -+---------------------------------------------------------------------- - - :: - -- BOOL is_denied(STRING key, INT limit, DURATION period) -+ BOOL is_denied( -+ STRING key, -+ INT limit, -+ DURATION period, -+ DURATION block=0 -+ ) - - Arguments: - - - key: A unique identifier to define what is being throttled - more examples below - - limit: How many requests in the specified period - - period: The time period -+ - block: a period to deny all access after hitting the threshold. Default is 0s - - Description - Can be used to rate limit the traffic for a specific key to a -- maximum of 'limit' requests per 'period' time. A token bucket -- is uniquely identified by the triplet of its key, limit and -- period, so using the same key multiple places with different -- rules will create multiple token buckets. -+ maximum of 'limit' requests per 'period' time. If 'block' is > 0s, -+ (0s by default), then always deny for 'key' for that length of time -+ after hitting the threshold. -+ -+ Note: A token bucket is uniquely identified by the 4-tuple of its -+ key, limit, period and block, so using the same key multiple places -+ with different rules will create multiple token buckets. - - Example - :: -@@ -118,20 +134,69 @@ Example - # ... - } - -+.. _vmod_vsthrottle.return_token: -+ -+VOID return_token(STRING key, INT limit, DURATION period, DURATION block) -+------------------------------------------------------------------------- -+ -+:: -+ -+ VOID return_token( -+ STRING key, -+ INT limit, -+ DURATION period, -+ DURATION block=0 -+ ) - --.. _func_remaining: -+Arguments: -+ - Same arguments as is_denied() -+ -+Description -+ Increment (by one) the number of tokens in the specified bucket. is_denied() -+ decrements the bucket by one token and return_token() adds it back. -+ Using these two, you can effectively make a token bucket act like a limit on -+ concurrent requests instead of requests / time. -+ -+ Note: This function doesn't enforce anything, it merely credits a token to -+ appropriate bucket. -+ -+ Warning: If streaming is enabled (beresp.do_stream = true) as it is by -+ default now, vcl_deliver() is called *before* the response is sent -+ to the client (who may download it slowly). Thus you may credit the token -+ back too early if you use return_token() in vcl_backend_response(). -+ -+Example -+ :: - --remaining ----------- -+ sub vcl_recv { -+ if (vsthrottle.is_denied(client.identity, 20, 20s)) { -+ # Client has more than 20 concurrent requests -+ return (synth(429, "Too Many Requests In Flight")); -+ } -+ -+ # ... -+ } -+ -+ sub vcl_deliver { -+ vsthrottle.return_token(client.identity, 10, 10s); -+ } -+ -+.. _vmod_vsthrottle.remaining: -+ -+INT remaining(STRING key, INT limit, DURATION period, DURATION block) -+--------------------------------------------------------------------- - - :: - -- INT remaining(STRING key, INT limit, DURATION period) -+ INT remaining( -+ STRING key, -+ INT limit, -+ DURATION period, -+ DURATION block=0 -+ ) - - Arguments: -- - key: A unique identifier to define what is being throttled -- - limit: How many requests in the specified period -- - period: The time period -+ - Same arguments as is_denied() - - Description - -@@ -147,3 +212,36 @@ Example - set resp.http.X-RateLimit-Remaining = vsthrottle.remaining(client.identity, 15, 10s); - } - -+.. _vmod_vsthrottle.blocked: -+ -+DURATION blocked(STRING key, INT limit, DURATION period, DURATION block) -+------------------------------------------------------------------------ -+ -+:: -+ -+ DURATION blocked( -+ STRING key, -+ INT limit, -+ DURATION period, -+ DURATION block -+ ) -+ -+Arguments: -+ - Same arguments as is_denied() -+ -+Description -+ -+ If the token bucket identified by the four parameters has been -+ blocked by use of the 'block' parameter in 'is_denied()', then -+ return the time remaining in the block. If it is not blocked, -+ return 0s. This can be used to inform clients how long they -+ will be locked out. -+ -+ -+Example -+ :: -+ -+ sub vcl_deliver { -+ set resp.http.Retry-After -+ = vsthrottle.blocked(client.identity, 15, 10s, 30s); -+ } -diff --git a/docs/vmod_xkey.rst b/docs/vmod_xkey.rst -index 40c22c2..86da183 100644 ---- a/docs/vmod_xkey.rst -+++ b/docs/vmod_xkey.rst -@@ -4,25 +4,26 @@ - .. Edit vmod.vcc and run make instead - .. - --.. role:: ref(emphasis) - --.. _vmod_xkey(3): -- --========= --vmod_xkey --========= -+:tocdepth: 1 - ------------------------------------------ --Surrogate keys support for Varnish Cache ------------------------------------------ -+.. _vmod_xkey(3): - --:Manual section: 3 -+==================================================== -+VMOD xkey - Surrogate keys support for Varnish Cache -+==================================================== - - SYNOPSIS - ======== - --import xkey [from "path"] ; -+.. parsed-literal:: - -+ import xkey [from "path"] -+ -+ :ref:`vmod_xkey.purge` -+ -+ :ref:`vmod_xkey.softpurge` -+ - DESCRIPTION - =========== - -@@ -39,13 +40,13 @@ Similarly with an e-commerce site, where various SKUs are often - referenced on a page. - - Hash keys are specified in the ``xkey`` response header. Multiple keys --can be specified per header line with a space --separator. Alternatively, they can be specified in multiple ``xkey`` -+can be specified per header line with spaces and/or commas as -+separators. Alternatively, they can be specified in multiple ``xkey`` - response headers. - - Preferably the secondary hash keys are set from the backend --application, but can also be set from VCL in ``vcl_backend_response`` --as in the above example. -+application, but the header can also be set from VCL in -+``vcl_backend_response``. - - .. vcl-start - -@@ -65,10 +66,14 @@ VCL example:: - if (client.ip !~ purgers) { - return (synth(403, "Forbidden")); - } -- set req.http.n-gone = xkey.purge(req.http.xkey-purge); -- # or: set req.http.n-gone = xkey.softpurge(req.http.xkey-purge) -- -- return (synth(200, "Invalidated "+req.http.n-gone+" objects")); -+ if (req.http.xkey) { -+ set req.http.n-gone = xkey.purge(req.http.xkey); -+ # or: set req.http.n-gone = xkey.softpurge(req.http.xkey) -+ -+ return (synth(200, "Invalidated "+req.http.n-gone+" objects")); -+ } else { -+ return (purge); -+ } - } - } - -@@ -88,9 +93,6 @@ header for a certain page might look like this:: - xkey: 166412 - xkey: 234323 - --Alternatively you may instead use a single header with space separated --values like ``xkey: 8155054 166412 234323``. -- - This requires a bit of VCL to be in place. The VCL can be found above. - - Then, in order to keep the web in sync with the database, a trigger is -@@ -98,17 +100,10 @@ set up in the database. When an SKU is updated this will trigger an - HTTP request towards the Varnish server, clearing out every object - with the matching xkey header:: - -- PURGE / HTTP/1.1 -+ GET / HTTP/1.1 - Host: www.example.com - xkey-purge: 166412 - --Several ``xkey-purge`` headers are also supported like in the response --example above, and you may also here use a single header with space --seperated values like ``xkey-purge: 166412 234323``. -- --Unlike `xkey` header for responses, purge header is fully configurable --by means of adjusting the name of the header in the VCL example above. -- - Note the xkey-purge header. It is probably a good idea to protect - this with an ACL so random people from the Internet cannot purge your - cache. -@@ -122,20 +117,11 @@ Varnish will find the objects and clear them out, responding with:: - - The objects are now cleared. - --CONTENTS --======== -- --* :ref:`func_purge` --* :ref:`func_softpurge` -- --.. _func_purge: - --purge ------- -+.. _vmod_xkey.purge: - --:: -- -- INT purge(STRING keys) -+INT purge(STRING keys) -+---------------------- - - Description - Purges all objects hashed on any key found in the ``keys`` argument. -@@ -143,15 +129,10 @@ Description - - The ``keys`` may contain a list of space-separated ids. - -+.. _vmod_xkey.softpurge: - --.. _func_softpurge: -- --softpurge ----------- -- --:: -- -- INT softpurge(STRING keys) -+INT softpurge(STRING keys) -+-------------------------- - - Description - Performs a "soft purge" for all objects hashed on any key found in the -@@ -160,5 +141,3 @@ Description - A softpurge differs from a regular purge in that it resets an - object's TTL but keeps it available for grace mode and conditional - requests for the remainder of its configured grace and keep time. -- -- -diff --git a/src/Makefile.am b/src/Makefile.am -index 36ca267..6a4b48a 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -143,6 +143,7 @@ VMOD_TESTS = \ - tests/vsthrottle/test01.vtc \ - tests/vsthrottle/test02.vtc \ - tests/vsthrottle/test03.vtc \ -+ tests/vsthrottle/test04.vtc \ - tests/xkey/test01.vtc \ - tests/xkey/test02.vtc \ - tests/xkey/test03.vtc \ -@@ -150,7 +151,8 @@ VMOD_TESTS = \ - tests/xkey/test05.vtc \ - tests/xkey/test06.vtc \ - tests/xkey/test07.vtc \ -- tests/xkey/test08.vtc -+ tests/xkey/test08.vtc \ -+ tests/xkey/test09.vtc - - SOFTPURGE_TESTS = \ - tests/softpurge/01-load.vtc \ -diff --git a/src/tests/saintmode/test02.vtc b/src/tests/saintmode/test02.vtc -index aa97734..bd8b537 100644 ---- a/src/tests/saintmode/test02.vtc -+++ b/src/tests/saintmode/test02.vtc -@@ -51,6 +51,8 @@ varnish v1 -vcl+backend { - - } -start - -+varnish v1 -cliok "backend.list" -+ - client c1 { - txreq -url "/a" - rxresp -diff --git a/src/tests/tcp/02-congestion.vtc b/src/tests/tcp/02-congestion.vtc -index 2972f6d..e0c09a6 100644 ---- a/src/tests/tcp/02-congestion.vtc -+++ b/src/tests/tcp/02-congestion.vtc -@@ -20,9 +20,12 @@ varnish v1 -vcl+backend { - client c1 { - txreq -url "/" - rxresp -- expect resp.http.a == "0" -- expect resp.http.b == "-1" -- expect resp.http.c == "0" -+ # XXX: it would be better to skip the test altogether when we -+ # don't have struct tcp_info available on the system. -+ # See https://github.com/varnish/varnish-modules/issues/115 -+ expect resp.http.a <= 0 -+ expect resp.http.b == -1 -+ expect resp.http.c <= 0 - } - - client c1 -run -diff --git a/src/tests/vsthrottle/test04.vtc b/src/tests/vsthrottle/test04.vtc -new file mode 100644 -index 0000000..bef9ecf ---- /dev/null -+++ b/src/tests/vsthrottle/test04.vtc -@@ -0,0 +1,40 @@ -+varnishtest "Test vsthrottle return_token()" -+ -+server s1 { -+ rxreq -+ txresp -+} -start -+ -+varnish v1 -vcl+backend { -+ import vsthrottle from "${vmod_builddir}/.libs/libvmod_vsthrottle.so"; -+ -+ sub vcl_deliver { -+ set resp.http.foo-count0 = vsthrottle.remaining("foo", 1, 1s); -+ if (!vsthrottle.is_denied("foo", 1, 1s)) { -+ set resp.http.f1 = "OK"; -+ } -+ set resp.http.foo-count1 = vsthrottle.remaining("foo", 1, 1s); -+ -+ if (!vsthrottle.is_denied("foo", 1, 1s)) { -+ set resp.http.f2 = "OK"; -+ } -+ set resp.http.foo-count2 = vsthrottle.remaining("foo", 1, 1s); -+ -+ vsthrottle.return_token("foo", 1, 1s); -+ -+ set resp.http.foo-count3 = vsthrottle.remaining("foo", 1, 1s); -+ } -+} -start -+ -+client c1 { -+ txreq -url "/" -+ rxresp -+ expect resp.http.foo-count0 == "1" -+ expect resp.http.f1 == "OK" -+ expect resp.http.foo-count1 == "0" -+ expect resp.http.f2 == -+ expect resp.http.foo-count2 == "0" -+ expect resp.http.foo-count3 == "1" -+} -+ -+client c1 -run -diff --git a/src/tests/xkey/test09.vtc b/src/tests/xkey/test09.vtc -new file mode 100644 -index 0000000..c010c37 ---- /dev/null -+++ b/src/tests/xkey/test09.vtc -@@ -0,0 +1,66 @@ -+varnishtest "Test xkey vmod multiple keys, comma separated" -+# https://github.com/varnish/varnish-modules/issues/102 -+ -+server s1 { -+ rxreq -+ txresp -hdr "xkey: asdf, fdsa" -+ -+ rxreq -+ txresp -hdr "xkey: qwer, rewq" -+} -start -+ -+varnish v1 -vcl+backend { -+ import xkey from "${vmod_builddir}/.libs/libvmod_xkey.so"; -+ -+ sub vcl_recv { -+ if (req.http.xkey-purge) { -+ if (xkey.purge(req.http.xkey-purge) != 0) { -+ return (synth(200, "Purged")); -+ } else { -+ return (synth(404, "No key")); -+ } -+ } -+ } -+ -+ sub vcl_backend_response { -+ set beresp.ttl = 60s; -+ set beresp.grace = 0s; -+ set beresp.keep = 0s; -+ } -+ -+ sub vcl_synth { -+ set resp.http.reason = resp.reason; -+ } -+} -start -+ -+client c1 { -+ txreq -+ rxresp -+ txreq -url /2 -+ rxresp -+} -run -+ -+varnish v1 -expect n_object == 2 -+ -+client c1 { -+ # Test the purge using the asdf key, so we check that we didn't include the comma -+ txreq -hdr "xkey-purge: asdf" -+ rxresp -+ expect resp.status == 200 -+ expect resp.http.reason == "Purged" -+} -run -+ -+delay 1 -+ -+varnish v1 -expect n_object == 1 -+ -+client c1 { -+ txreq -hdr "xkey-purge: rewq" -+ rxresp -+ expect resp.status == 200 -+ expect resp.http.reason == "Purged" -+} -run -+ -+delay 1 -+ -+varnish v1 -expect n_object == 0 -diff --git a/src/vmod_bodyaccess.c b/src/vmod_bodyaccess.c -index d1f324f..a8a8951 100644 ---- a/src/vmod_bodyaccess.c -+++ b/src/vmod_bodyaccess.c -@@ -114,6 +114,26 @@ bodyaccess_log_cb(struct req *req, void *priv, void *ptr, size_t len) - - return (bodyaccess_log(priv, ptr, len)); - } -+#elif defined(HAVE_OBJITERATE_F) && defined(OBJ_ITER_FLUSH) -+static int -+bodyaccess_bcat_cb(void *priv, unsigned flush, const void *ptr, ssize_t len) -+{ -+ -+ AN(priv); -+ -+ (void)flush; -+ return (VSB_bcat(priv, ptr, len)); -+} -+ -+static int -+bodyaccess_log_cb(void *priv, unsigned flush, const void *ptr, ssize_t len) -+{ -+ -+ AN(priv); -+ -+ (void)flush; -+ return (bodyaccess_log(priv, ptr, len)); -+} - #elif defined(HAVE_OBJITERATE_F) - static int - bodyaccess_bcat_cb(void *priv, int flush, const void *ptr, ssize_t len) -@@ -187,6 +207,8 @@ vmod_hash_req_body(VRT_CTX) - VCL_INT - vmod_len_req_body(VRT_CTX) - { -+ uint64_t u; -+ - CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); - CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); - -@@ -202,7 +224,10 @@ vmod_len_req_body(VRT_CTX) - return (-1); - } - -- return (ctx->req->req_bodybytes); -+ AZ(ObjGetU64(ctx->req->wrk, ctx->req->body_oc, OA_LEN, &u)); -+ AZ(u > INT64_MAX); -+ -+ return ((VCL_INT)u); - } - - VCL_INT -diff --git a/src/vmod_bodyaccess.vcc b/src/vmod_bodyaccess.vcc -index d5cdf61..55666fc 100644 ---- a/src/vmod_bodyaccess.vcc -+++ b/src/vmod_bodyaccess.vcc -@@ -1,4 +1,4 @@ --$Module bodyaccess 3 Varnish Module for request body access -+$Module bodyaccess 3 "Varnish Module for request body access" - - DESCRIPTION - =========== -diff --git a/src/vmod_cookie.vcc b/src/vmod_cookie.vcc -index edd383a..0f49bad 100644 ---- a/src/vmod_cookie.vcc -+++ b/src/vmod_cookie.vcc -@@ -1,4 +1,4 @@ --$Module cookie 3 Varnish Cookie Module -+$Module cookie 3 "Varnish Cookie Module" - DESCRIPTION - =========== - -diff --git a/src/vmod_header.c b/src/vmod_header.c -index 798afdb..ea6b5d5 100644 ---- a/src/vmod_header.c -+++ b/src/vmod_header.c -@@ -193,7 +193,7 @@ header_http_cphdr(VRT_CTX, const struct http *hp, const char *hdr, - * vmod entrypoint. Sets up the header mutex. - */ - int --event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e) -+vmod_event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e) - { - (void)ctx; - (void)priv; -diff --git a/src/vmod_header.vcc b/src/vmod_header.vcc -index 5df8dc6..4a5b27c 100644 ---- a/src/vmod_header.vcc -+++ b/src/vmod_header.vcc -@@ -1,4 +1,4 @@ --$Module header 3 Header VMOD for Varnish -+$Module header 3 "Header VMOD for Varnish" - DESCRIPTION - =========== - -@@ -57,7 +57,7 @@ Example - $Function VOID remove(PRIV_CALL, HEADER header, STRING regex) - - Description -- Remove all occurences of `header` that matches `regex`. -+ Remove all occurrences of `header` that matches `regex`. - Example - :: - header.remove(beresp.http.set-cookie,"^(?!(funcookie=))"); -diff --git a/src/vmod_saintmode.c b/src/vmod_saintmode.c -index 26191cc..b0e4ac6 100644 ---- a/src/vmod_saintmode.c -+++ b/src/vmod_saintmode.c -@@ -35,14 +35,16 @@ - - #include "vmod_config.h" - --#include "cache/cache_director.h" --#include "cache/cache_backend.h" -- - #include "vsb.h" - #include "vtim.h" - - #include "vcc_saintmode_if.h" - -+static VCL_BOOL v_matchproto_(vdi_healthy_f) -+healthy(VRT_CTX, VCL_BACKEND, VCL_TIME *); -+static VCL_BACKEND v_matchproto_(vdi_resolve_f) -+resolve(VRT_CTX, VCL_BACKEND); -+ - struct trouble { - unsigned magic; - #define TROUBLE_MAGIC 0x4211ab21 -@@ -54,7 +56,7 @@ struct trouble { - struct vmod_saintmode_saintmode { - unsigned magic; - #define VMOD_SAINTMODE_MAGIC 0xa03756e4 -- struct director sdir[1]; -+ const struct director *sdir; - const struct director *be; - pthread_mutex_t mtx; - unsigned threshold; -@@ -63,6 +65,14 @@ struct vmod_saintmode_saintmode { - VTAILQ_HEAD(, trouble) troublelist; - }; - -+static const struct vdi_methods vmod_saintmode_methods[1] = {{ -+ .magic = VDI_METHODS_MAGIC, -+ .type = "saintmode", -+ .healthy = healthy, -+ .resolve = resolve -+}}; -+ -+ - struct saintmode_objs { - unsigned magic; - #define SAINTMODE_OBJS_MAGIC 0x9aa7beec -@@ -253,23 +263,26 @@ is_digest_healthy(const struct director *dir, - } - - /* All adapted from PHK's saintmode implementation in Varnish 3.0 */ --static unsigned --healthy(const struct director *dir, const struct busyobj *bo, double *changed) -+static VCL_BOOL v_matchproto_(vdi_healthy_f) -+healthy(VRT_CTX, VCL_BACKEND dir, VCL_TIME *changed) - { - struct vmod_saintmode_saintmode *sm; -+ const struct busyobj *bo; - unsigned retval; - const uint8_t* digest; - double t_prev; - struct vsl_log* vsl; - -+ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); - CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC); - CAST_OBJ_NOTNULL(sm, dir->priv, VMOD_SAINTMODE_MAGIC); - CHECK_OBJ_NOTNULL(sm->be, DIRECTOR_MAGIC); -+ bo = ctx->bo; - CHECK_OBJ_ORNULL(bo, BUSYOBJ_MAGIC); - - /* Saintmode is disabled, or list is empty */ - if (sm->threshold == 0 || sm->n_trouble == 0) -- return (sm->be->healthy(sm->be, bo, changed)); -+ return (VRT_Healthy(ctx, sm->be, changed)); - - if (!bo) { - digest = NULL; -@@ -282,7 +295,7 @@ healthy(const struct director *dir, const struct busyobj *bo, double *changed) - } - - retval = is_digest_healthy(dir, digest, t_prev, vsl); -- return (retval ? sm->be->healthy(sm->be, bo, changed) : 0); -+ return (retval ? VRT_Healthy(ctx, sm->be, changed) : 0); - } - - VCL_BOOL -@@ -303,19 +316,17 @@ vmod_saintmode_is_healthy(VRT_CTX, struct vmod_saintmode_saintmode *sm) - return is_digest_healthy(sm->sdir, digest, - ctx->req->t_prev, ctx->req->vsl); - } else -- return healthy(sm->sdir, ctx->bo, NULL); -+ return healthy(ctx, sm->sdir, NULL); - } - --static const struct director * --resolve(const struct director *dir, struct worker *wrk, struct busyobj *bo) { -+static VCL_BACKEND v_matchproto_(vdi_resolve_f) -+resolve(VRT_CTX, VCL_BACKEND dir) { - struct vmod_saintmode_saintmode *sm; -- double changed = 0.0; - - CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC); - CAST_OBJ_NOTNULL(sm, dir->priv, VMOD_SAINTMODE_MAGIC); -- (void)wrk; - -- if (!healthy(dir, bo, &changed)) -+ if (!healthy(ctx, dir, NULL)) - return (NULL); - - return (sm->be); -@@ -342,15 +353,7 @@ vmod_saintmode__init(VRT_CTX, struct vmod_saintmode_saintmode **smp, - sm->be = be; - VTAILQ_INIT(&sm->troublelist); - -- sm->sdir->magic = DIRECTOR_MAGIC; -- sm->sdir->resolve = resolve; -- sm->sdir->healthy = healthy; --#ifdef HAVE_DIRECTOR_ADMIN_HEALTH -- sm->sdir->admin_health = VDI_AH_HEALTHY; --#endif -- REPLACE(sm->sdir->vcl_name, vcl_name); -- sm->sdir->name = "saintmode"; -- sm->sdir->priv = sm; -+ sm->sdir = VRT_AddDirector(ctx, vmod_saintmode_methods, sm, "%s", vcl_name); - - if (!priv->priv) { - ALLOC_OBJ(sm_objs, SAINTMODE_OBJS_MAGIC); -@@ -380,7 +383,7 @@ vmod_saintmode__fini(struct vmod_saintmode_saintmode **smp) { - FREE_OBJ(tr); - } - -- free(sm->sdir->vcl_name); -+ VRT_DelDirector(&sm->sdir); - AZ(pthread_mutex_destroy(&sm->mtx)); - - /* We can no longer refer to the sm_objs after this -diff --git a/src/vmod_saintmode.vcc b/src/vmod_saintmode.vcc -index 4315e43..27f8ba0 100644 ---- a/src/vmod_saintmode.vcc -+++ b/src/vmod_saintmode.vcc -@@ -1,4 +1,4 @@ --$Module saintmode 3 Saint mode backend director -+$Module saintmode 3 "Saint mode backend director" - - DESCRIPTION - =========== -diff --git a/src/vmod_softpurge.c b/src/vmod_softpurge.c -index 9273de5..0e46c25 100644 ---- a/src/vmod_softpurge.c -+++ b/src/vmod_softpurge.c -@@ -52,8 +52,12 @@ vmod_softpurge(VRT_CTX) - CHECK_OBJ_NOTNULL(ctx->req->wrk, WORKER_MAGIC); - oh = ctx->req->objcore->objhead; - CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); -- spc = WS_Reserve(ctx->ws, 0); -- assert(spc >= sizeof *ocp); -+ spc = WS_ReserveAll(ctx->ws); -+ if (spc < sizeof *ocp) { -+ WS_Release(ctx->ws, 0); -+ VRT_fail(ctx, "insufficient workspace"); -+ return; -+ } - - nobj = 0; - ocp = (void*)ctx->ws->f; -diff --git a/src/vmod_softpurge.vcc b/src/vmod_softpurge.vcc -index 20252dd..aaf9a1c 100644 ---- a/src/vmod_softpurge.vcc -+++ b/src/vmod_softpurge.vcc -@@ -1,4 +1,4 @@ --$Module softpurge Soft purge vmod -+$Module softpurge 3 "Soft purge vmod" - DESCRIPTION - =========== - -diff --git a/src/vmod_tcp.c b/src/vmod_tcp.c -index fee4bd3..570be45 100644 ---- a/src/vmod_tcp.c -+++ b/src/vmod_tcp.c -@@ -174,7 +174,7 @@ vmod_set_socket_pace(VRT_CTX, VCL_INT rate) - sizeof(pacerate)) != 0) - VSLb(ctx->vsl, SLT_VCL_Error, "set_socket_pace(): Error setting pace rate."); - else -- VSLb(ctx->vsl, SLT_VCL_Log, "vmod-tcp: Socket paced to %lu KB/s.", rate); -+ VSLb(ctx->vsl, SLT_VCL_Log, "vmod-tcp: Socket paced to %jd KB/s.", (intmax_t)rate); - - # ifndef NDEBUG - int retval; -diff --git a/src/vmod_tcp.vcc b/src/vmod_tcp.vcc -index 8659770..fddf7c6 100644 ---- a/src/vmod_tcp.vcc -+++ b/src/vmod_tcp.vcc -@@ -1,4 +1,4 @@ --$Module tcp 3 TCP vmod -+$Module tcp 3 "TCP vmod" - DESCRIPTION - =========== - -diff --git a/src/vmod_var.vcc b/src/vmod_var.vcc -index 719b182..7af5cf1 100644 ---- a/src/vmod_var.vcc -+++ b/src/vmod_var.vcc -@@ -1,4 +1,4 @@ --$Module var 3 Variable support for Varnish VCL -+$Module var 3 "Variable support for Varnish VCL" - - This VMOD implements basic variable support in VCL. - -diff --git a/src/vmod_vsthrottle.c b/src/vmod_vsthrottle.c -index ff1719c..e088860 100644 ---- a/src/vmod_vsthrottle.c -+++ b/src/vmod_vsthrottle.c -@@ -58,7 +58,7 @@ struct tbucket { - double block; - long tokens; - long capacity; -- VRB_ENTRY(tbucket) tree; -+ VRBT_ENTRY(tbucket) tree; - }; - - static int -@@ -67,9 +67,9 @@ keycmp(const struct tbucket *b1, const struct tbucket *b2) - return (memcmp(b1->digest, b2->digest, sizeof b1->digest)); - } - --VRB_HEAD(tbtree, tbucket); --VRB_PROTOTYPE_STATIC(tbtree, tbucket, tree, keycmp); --VRB_GENERATE_STATIC(tbtree, tbucket, tree, keycmp); -+VRBT_HEAD(tbtree, tbucket); -+VRBT_PROTOTYPE_STATIC(tbtree, tbucket, tree, keycmp); -+VRBT_GENERATE_STATIC(tbtree, tbucket, tree, keycmp); - - /* To lessen potential mutex contention, we partition the buckets into - N_PART partitions. */ -@@ -119,12 +119,12 @@ get_bucket(const unsigned char *digest, long limit, double period, double now) - - INIT_OBJ(&k, TBUCKET_MAGIC); - memcpy(&k.digest, digest, sizeof k.digest); -- b = VRB_FIND(tbtree, &v->buckets, &k); -+ b = VRBT_FIND(tbtree, &v->buckets, &k); - if (b) { - CHECK_OBJ_NOTNULL(b, TBUCKET_MAGIC); - } else { - b = tb_alloc(digest, limit, period, now); -- AZ(VRB_INSERT(tbtree, &v->buckets, b)); -+ AZ(VRBT_INSERT(tbtree, &v->buckets, b)); - } - return (b); - } -@@ -205,6 +205,32 @@ vmod_is_denied(VRT_CTX, VCL_STRING key, VCL_INT limit, VCL_DURATION period, - return (ret); - } - -+VCL_VOID -+vmod_return_token(VRT_CTX, VCL_STRING key, VCL_INT limit, VCL_DURATION period, -+ VCL_DURATION block) -+{ -+ struct tbucket *b; -+ double now; -+ -+ struct vsthrottle *v; -+ unsigned char digest[SHA256_LEN]; -+ unsigned part; -+ -+ (void)ctx; -+ -+ if (!key) -+ return; -+ do_digest(digest, key, limit, period, block); -+ -+ part = digest[0] & N_PART_MASK; -+ v = &vsthrottle[part]; -+ AZ(pthread_mutex_lock(&v->mtx)); -+ now = VTIM_mono(); -+ b = get_bucket(digest, limit, period, now); -+ b->tokens++; -+ AZ(pthread_mutex_unlock(&v->mtx)); -+} -+ - /* Clean up expired entries. */ - static void - run_gc(double now, unsigned part) -@@ -213,11 +239,11 @@ run_gc(double now, unsigned part) - struct tbtree *buckets = &vsthrottle[part].buckets; - - /* XXX: Assert mtx is held ... */ -- VRB_FOREACH_SAFE(x, tbtree, buckets, y) { -+ VRBT_FOREACH_SAFE(x, tbtree, buckets, y) { - CHECK_OBJ_NOTNULL(x, TBUCKET_MAGIC); - if (now - x->last_used > x->period) { -- VRB_REMOVE(tbtree, buckets, x); -- free(x); -+ VRBT_REMOVE(tbtree, buckets, x); -+ FREE_OBJ(x); - } - } - } -@@ -291,9 +317,9 @@ fini(void *priv) - - for (p = 0; p < N_PART; ++p ) { - struct vsthrottle *v = &vsthrottle[p]; -- VRB_FOREACH_SAFE(x, tbtree, &v->buckets, y) { -+ VRBT_FOREACH_SAFE(x, tbtree, &v->buckets, y) { - CHECK_OBJ_NOTNULL(x, TBUCKET_MAGIC); -- VRB_REMOVE(tbtree, &v->buckets, x); -+ VRBT_REMOVE(tbtree, &v->buckets, x); - free(x); - } - } -@@ -302,7 +328,7 @@ fini(void *priv) - } - - int --event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e) -+vmod_event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e) - { - if (e != VCL_EVENT_LOAD) - return (0); -@@ -318,7 +344,7 @@ event_function(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e) - struct vsthrottle *v = &vsthrottle[p]; - v->magic = VSTHROTTLE_MAGIC; - AZ(pthread_mutex_init(&v->mtx, NULL)); -- VRB_INIT(&v->buckets); -+ VRBT_INIT(&v->buckets); - } - } - n_init++; -diff --git a/src/vmod_vsthrottle.vcc b/src/vmod_vsthrottle.vcc -index 1f10080..72a8839 100644 ---- a/src/vmod_vsthrottle.vcc -+++ b/src/vmod_vsthrottle.vcc -@@ -1,4 +1,4 @@ --$Module vsthrottle 3 Throttling VMOD -+$Module vsthrottle 3 "Throttling VMOD" - DESCRIPTION - =========== - -@@ -71,16 +71,17 @@ Arguments: - - key: A unique identifier to define what is being throttled - more examples below - - limit: How many requests in the specified period - - period: The time period -- - block: a period to deny all access after meeting the threshold -+ - block: a period to deny all access after hitting the threshold. Default is 0s - - Description - Can be used to rate limit the traffic for a specific key to a - maximum of 'limit' requests per 'period' time. If 'block' is > 0s, - (0s by default), then always deny for 'key' for that length of time -- after hitting the threshold. A token bucket is uniquely identified -- by the 4-tuple of its key, limit, period and block, so using the -- same key multiple places with different rules will create multiple -- token buckets. -+ after hitting the threshold. -+ -+ Note: A token bucket is uniquely identified by the 4-tuple of its -+ key, limit, period and block, so using the same key multiple places -+ with different rules will create multiple token buckets. - - Example - :: -@@ -95,14 +96,48 @@ Example - } - - -+$Function VOID return_token(STRING key, INT limit, DURATION period, -+ DURATION block=0) -+ -+Arguments: -+ - Same arguments as is_denied() -+ -+Description -+ Increment (by one) the number of tokens in the specified bucket. is_denied() -+ decrements the bucket by one token and return_token() adds it back. -+ Using these two, you can effectively make a token bucket act like a limit on -+ concurrent requests instead of requests / time. -+ -+ Note: This function doesn't enforce anything, it merely credits a token to -+ appropriate bucket. -+ -+ Warning: If streaming is enabled (beresp.do_stream = true) as it is by -+ default now, vcl_deliver() is called *before* the response is sent -+ to the client (who may download it slowly). Thus you may credit the token -+ back too early if you use return_token() in vcl_backend_response(). -+ -+Example -+ :: -+ -+ sub vcl_recv { -+ if (vsthrottle.is_denied(client.identity, 20, 20s)) { -+ # Client has more than 20 concurrent requests -+ return (synth(429, "Too Many Requests In Flight")); -+ } -+ -+ # ... -+ } -+ -+ sub vcl_deliver { -+ vsthrottle.return_token(client.identity, 10, 10s); -+ } -+ -+ - $Function INT remaining(STRING key, INT limit, DURATION period, - DURATION block=0) - - Arguments: -- - key: A unique identifier to define what is being throttled -- - limit: How many requests in the specified period -- - period: The time period -- - block: duration to block, defaults to 0s -+ - Same arguments as is_denied() - - Description - -@@ -122,10 +157,7 @@ $Function DURATION blocked(STRING key, INT limit, DURATION period, - DURATION block) - - Arguments: -- - key: A unique identifier to define what is being throttled -- - limit: How many requests in the specified period -- - period: The time period -- - block: duration to block -+ - Same arguments as is_denied() - - Description - -diff --git a/src/vmod_xkey.c b/src/vmod_xkey.c -index 3cf8069..ff825fd 100644 ---- a/src/vmod_xkey.c -+++ b/src/vmod_xkey.c -@@ -51,23 +51,23 @@ uintptr_t xkey_cb_handle; - - struct xkey_hashkey { - char digest[DIGEST_LEN]; -- VRB_ENTRY(xkey_hashkey) entry; -+ VRBT_ENTRY(xkey_hashkey) entry; - }; - static int xkey_hashcmp(const struct xkey_hashkey *k1, - const struct xkey_hashkey *k2); --VRB_HEAD(xkey_hashtree, xkey_hashkey); --static struct xkey_hashtree xkey_hashtree = VRB_INITIALIZER(&xkey_hashtree); --VRB_PROTOTYPE(xkey_hashtree, xkey_hashkey, entry, xkey_hashcmp); -+VRBT_HEAD(xkey_hashtree, xkey_hashkey); -+static struct xkey_hashtree xkey_hashtree = VRBT_INITIALIZER(&xkey_hashtree); -+VRBT_PROTOTYPE(xkey_hashtree, xkey_hashkey, entry, xkey_hashcmp); - - struct xkey_ptrkey { - uintptr_t ptr; -- VRB_ENTRY(xkey_ptrkey) entry; -+ VRBT_ENTRY(xkey_ptrkey) entry; - }; - static int xkey_ptrcmp(const struct xkey_ptrkey *k1, - const struct xkey_ptrkey *k2); --VRB_HEAD(xkey_octree, xkey_ptrkey); --static struct xkey_octree xkey_octree = VRB_INITIALIZER(&xkey_octree); --VRB_PROTOTYPE(xkey_octree, xkey_ptrkey, entry, xkey_ptrcmp) -+VRBT_HEAD(xkey_octree, xkey_ptrkey); -+static struct xkey_octree xkey_octree = VRBT_INITIALIZER(&xkey_octree); -+VRBT_PROTOTYPE(xkey_octree, xkey_ptrkey, entry, xkey_ptrcmp) - - struct xkey_hashhead; - struct xkey_ochead; -@@ -114,8 +114,8 @@ static struct { - - /*******************/ - --VRB_GENERATE(xkey_hashtree, xkey_hashkey, entry, xkey_hashcmp); --VRB_GENERATE(xkey_octree, xkey_ptrkey, entry, xkey_ptrcmp); -+VRBT_GENERATE(xkey_hashtree, xkey_hashkey, entry, xkey_hashcmp); -+VRBT_GENERATE(xkey_octree, xkey_ptrkey, entry, xkey_ptrcmp); - - static int - xkey_hashcmp(const struct xkey_hashkey *k1, const struct xkey_hashkey *k2) -@@ -246,7 +246,7 @@ xkey_hashtree_lookup(const unsigned char *digest, unsigned len) - AN(digest); - assert(len == sizeof(key.digest)); - memcpy(&key.digest, digest, len); -- pkey = VRB_FIND(xkey_hashtree, &xkey_hashtree, &key); -+ pkey = VRBT_FIND(xkey_hashtree, &xkey_hashtree, &key); - if (pkey != NULL) - CAST_OBJ_NOTNULL(head, (void *)pkey, XKEY_HASHHEAD_MAGIC); - return (head); -@@ -262,7 +262,7 @@ xkey_hashtree_insert(const unsigned char *digest, unsigned len) - head = xkey_hashhead_new(); - assert(len == sizeof(head->key.digest)); - memcpy(&head->key.digest, digest, len); -- key = VRB_INSERT(xkey_hashtree, &xkey_hashtree, &head->key); -+ key = VRBT_INSERT(xkey_hashtree, &xkey_hashtree, &head->key); - if (key != NULL) { - xkey_hashhead_delete(&head); - CAST_OBJ_NOTNULL(head, (void *)key, XKEY_HASHHEAD_MAGIC); -@@ -278,7 +278,7 @@ xkey_octree_lookup(uintptr_t ptr) - - AN(ptr); - key.ptr = ptr; -- pkey = VRB_FIND(xkey_octree, &xkey_octree, &key); -+ pkey = VRBT_FIND(xkey_octree, &xkey_octree, &key); - if (pkey) - CAST_OBJ_NOTNULL(head, (void *)pkey, XKEY_OCHEAD_MAGIC); - return (head); -@@ -293,7 +293,7 @@ xkey_octree_insert(uintptr_t ptr) - AN(ptr); - head = xkey_ochead_new(); - head->key.ptr = ptr; -- key = VRB_INSERT(xkey_octree, &xkey_octree, &head->key); -+ key = VRBT_INSERT(xkey_octree, &xkey_octree, &head->key); - if (key != NULL) { - xkey_ochead_delete(&head); - CAST_OBJ_NOTNULL(head, (void *)key, XKEY_OCHEAD_MAGIC); -@@ -342,7 +342,7 @@ xkey_remove(struct xkey_ochead **pochead) - oc->hashhead = NULL; - VTAILQ_REMOVE(&hashhead->ocs, oc, list_hashhead); - if (VTAILQ_EMPTY(&hashhead->ocs)) { -- VRB_REMOVE(xkey_hashtree, &xkey_hashtree, -+ VRBT_REMOVE(xkey_hashtree, &xkey_hashtree, - &hashhead->key); - xkey_hashhead_delete(&hashhead); - } -@@ -351,7 +351,7 @@ xkey_remove(struct xkey_ochead **pochead) - xkey_oc_delete(&oc); - } - AN(VTAILQ_EMPTY(&ochead->ocs)); -- VRB_REMOVE(xkey_octree, &xkey_octree, &ochead->key); -+ VRBT_REMOVE(xkey_octree, &xkey_octree, &ochead->key); - xkey_ochead_delete(&ochead); - } - -@@ -364,19 +364,19 @@ xkey_cleanup(void) - struct xkey_ochead *ochead; - struct xkey_oc *oc; - -- VRB_FOREACH(hashkey, xkey_hashtree, &xkey_hashtree) { -+ VRBT_FOREACH(hashkey, xkey_hashtree, &xkey_hashtree) { - CAST_OBJ_NOTNULL(hashhead, (void *)hashkey, - XKEY_HASHHEAD_MAGIC); - VTAILQ_CONCAT(&xkey_pool.ocs, &hashhead->ocs, list_ochead); - VTAILQ_INSERT_HEAD(&xkey_pool.hashheads, hashhead, list); - } -- VRB_INIT(&xkey_hashtree); -+ VRBT_INIT(&xkey_hashtree); - -- VRB_FOREACH(ockey, xkey_octree, &xkey_octree) { -+ VRBT_FOREACH(ockey, xkey_octree, &xkey_octree) { - CAST_OBJ_NOTNULL(ochead, (void *)ockey, XKEY_OCHEAD_MAGIC); - VTAILQ_INSERT_HEAD(&xkey_pool.ocheads, ochead, list); - } -- VRB_INIT(&xkey_octree); -+ VRBT_INIT(&xkey_octree); - - while (!VTAILQ_EMPTY(&xkey_pool.hashheads)) { - hashhead = VTAILQ_FIRST(&xkey_pool.hashheads); -@@ -410,11 +410,11 @@ xkey_tok(const char **b, const char **e) - t = *b; - AN(t); - -- while (isblank(*t)) -+ while (*t == ',' || isblank(*t)) - t++; - *b = t; - -- while (*t != '\0' && !isblank(*t)) -+ while (*t != '\0' && *t != ',' && !isblank(*t)) - t++; - *e = t; - return (*b < *e); -diff --git a/src/vmod_xkey.vcc b/src/vmod_xkey.vcc -index 637d4e8..3e6553c 100644 ---- a/src/vmod_xkey.vcc -+++ b/src/vmod_xkey.vcc -@@ -1,4 +1,4 @@ --$Module xkey 3 Surrogate keys support for Varnish Cache -+$Module xkey 3 "Surrogate keys support for Varnish Cache" - DESCRIPTION - =========== - -@@ -15,8 +15,8 @@ Similarly with an e-commerce site, where various SKUs are often - referenced on a page. - - Hash keys are specified in the ``xkey`` response header. Multiple keys --can be specified per header line with a space --separator. Alternatively, they can be specified in multiple ``xkey`` -+can be specified per header line with spaces and/or commas as -+separators. Alternatively, they can be specified in multiple ``xkey`` - response headers. - - Preferably the secondary hash keys are set from the backend -@@ -93,7 +93,7 @@ Varnish will find the objects and clear them out, responding with:: - The objects are now cleared. - - $ABI strict --$Event vmod_event -+$Event event - $Function INT purge(STRING keys) - - Description -diff --git a/src/vtree.h b/src/vtree.h -deleted file mode 100644 -index b88d9d2..0000000 ---- a/src/vtree.h -+++ /dev/null -@@ -1,770 +0,0 @@ --/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ --/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ --/* $FreeBSD: release/9.0.0/sys/sys/tree.h 189204 2009-03-01 04:57:23Z bms $ */ -- --/*- -- * Copyright 2002 Niels Provos -- * All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. Redistributions in binary form must reproduce the above copyright -- * notice, this list of conditions and the following disclaimer in the -- * documentation and/or other materials provided with the distribution. -- * -- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- */ -- --#ifndef _VTREE_H_ --#define _VTREE_H_ -- --#ifndef __unused --#define __unused __attribute__((__unused__)) --#endif -- --/* -- * This file defines data structures for different types of trees: -- * splay trees and red-black trees. -- * -- * A splay tree is a self-organizing data structure. Every operation -- * on the tree causes a splay to happen. The splay moves the requested -- * node to the root of the tree and partly rebalances it. -- * -- * This has the benefit that request locality causes faster lookups as -- * the requested nodes move to the top of the tree. On the other hand, -- * every lookup causes memory writes. -- * -- * The Balance Theorem bounds the total access time for m operations -- * and n inserts on an initially empty tree as O((m + n)lg n). The -- * amortized cost for a sequence of m accesses to a splay tree is O(lg n); -- * -- * A red-black tree is a binary search tree with the node color as an -- * extra attribute. It fulfills a set of conditions: -- * - every search path from the root to a leaf consists of the -- * same number of black nodes, -- * - each red node (except for the root) has a black parent, -- * - each leaf node is black. -- * -- * Every operation on a red-black tree is bounded as O(lg n). -- * The maximum height of a red-black tree is 2lg (n+1). -- */ -- --#define VSPLAY_HEAD(name, type) \ --struct name { \ -- struct type *sph_root; /* root of the tree */ \ --} -- --#define VSPLAY_INITIALIZER(root) \ -- { NULL } -- --#define VSPLAY_INIT(root) do { \ -- (root)->sph_root = NULL; \ --} while (/*CONSTCOND*/ 0) -- --#define VSPLAY_ENTRY(type) \ --struct { \ -- struct type *spe_left; /* left element */ \ -- struct type *spe_right; /* right element */ \ --} -- --#define VSPLAY_LEFT(elm, field) (elm)->field.spe_left --#define VSPLAY_RIGHT(elm, field) (elm)->field.spe_right --#define VSPLAY_ROOT(head) (head)->sph_root --#define VSPLAY_EMPTY(head) (VSPLAY_ROOT(head) == NULL) -- --/* VSPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold VSPLAY_{RIGHT,LEFT} */ --#define VSPLAY_ROTATE_RIGHT(head, tmp, field) do { \ -- VSPLAY_LEFT((head)->sph_root, field) = VSPLAY_RIGHT(tmp, field);\ -- VSPLAY_RIGHT(tmp, field) = (head)->sph_root; \ -- (head)->sph_root = tmp; \ --} while (/*CONSTCOND*/ 0) -- --#define VSPLAY_ROTATE_LEFT(head, tmp, field) do { \ -- VSPLAY_RIGHT((head)->sph_root, field) = VSPLAY_LEFT(tmp, field);\ -- VSPLAY_LEFT(tmp, field) = (head)->sph_root; \ -- (head)->sph_root = tmp; \ --} while (/*CONSTCOND*/ 0) -- --#define VSPLAY_LINKLEFT(head, tmp, field) do { \ -- VSPLAY_LEFT(tmp, field) = (head)->sph_root; \ -- tmp = (head)->sph_root; \ -- (head)->sph_root = VSPLAY_LEFT((head)->sph_root, field); \ --} while (/*CONSTCOND*/ 0) -- --#define VSPLAY_LINKRIGHT(head, tmp, field) do { \ -- VSPLAY_RIGHT(tmp, field) = (head)->sph_root; \ -- tmp = (head)->sph_root; \ -- (head)->sph_root = VSPLAY_RIGHT((head)->sph_root, field); \ --} while (/*CONSTCOND*/ 0) -- --#define VSPLAY_ASSEMBLE(head, node, left, right, field) do { \ -- VSPLAY_RIGHT(left, field) = VSPLAY_LEFT((head)->sph_root, field);\ -- VSPLAY_LEFT(right, field) = VSPLAY_RIGHT((head)->sph_root, field);\ -- VSPLAY_LEFT((head)->sph_root, field) = VSPLAY_RIGHT(node, field);\ -- VSPLAY_RIGHT((head)->sph_root, field) = VSPLAY_LEFT(node, field);\ --} while (/*CONSTCOND*/ 0) -- --/* Generates prototypes and inline functions */ -- --#define VSPLAY_PROTOTYPE(name, type, field, cmp) \ --void name##_VSPLAY(struct name *, struct type *); \ --void name##_VSPLAY_MINMAX(struct name *, int); \ --struct type *name##_VSPLAY_INSERT(struct name *, struct type *); \ --struct type *name##_VSPLAY_REMOVE(struct name *, struct type *); \ -- \ --/* Finds the node with the same key as elm */ \ --static __inline struct type * \ --name##_VSPLAY_FIND(struct name *head, struct type *elm) \ --{ \ -- if (VSPLAY_EMPTY(head)) \ -- return(NULL); \ -- name##_VSPLAY(head, elm); \ -- if ((cmp)(elm, (head)->sph_root) == 0) \ -- return (head->sph_root); \ -- return (NULL); \ --} \ -- \ --static __inline struct type * \ --name##_VSPLAY_NEXT(struct name *head, struct type *elm) \ --{ \ -- name##_VSPLAY(head, elm); \ -- if (VSPLAY_RIGHT(elm, field) != NULL) { \ -- elm = VSPLAY_RIGHT(elm, field); \ -- while (VSPLAY_LEFT(elm, field) != NULL) { \ -- elm = VSPLAY_LEFT(elm, field); \ -- } \ -- } else \ -- elm = NULL; \ -- return (elm); \ --} \ -- \ --static __inline struct type * \ --name##_VSPLAY_MIN_MAX(struct name *head, int val) \ --{ \ -- name##_VSPLAY_MINMAX(head, val); \ -- return (VSPLAY_ROOT(head)); \ --} -- --/* Main splay operation. -- * Moves node close to the key of elm to top -- */ --#define VSPLAY_GENERATE(name, type, field, cmp) \ --struct type * \ --name##_VSPLAY_INSERT(struct name *head, struct type *elm) \ --{ \ -- if (VSPLAY_EMPTY(head)) { \ -- VSPLAY_LEFT(elm, field) = VSPLAY_RIGHT(elm, field) = NULL; \ -- } else { \ -- int __comp; \ -- name##_VSPLAY(head, elm); \ -- __comp = (cmp)(elm, (head)->sph_root); \ -- if(__comp < 0) { \ -- VSPLAY_LEFT(elm, field) = VSPLAY_LEFT((head)->sph_root, field);\ -- VSPLAY_RIGHT(elm, field) = (head)->sph_root; \ -- VSPLAY_LEFT((head)->sph_root, field) = NULL; \ -- } else if (__comp > 0) { \ -- VSPLAY_RIGHT(elm, field) = VSPLAY_RIGHT((head)->sph_root, field);\ -- VSPLAY_LEFT(elm, field) = (head)->sph_root; \ -- VSPLAY_RIGHT((head)->sph_root, field) = NULL; \ -- } else \ -- return ((head)->sph_root); \ -- } \ -- (head)->sph_root = (elm); \ -- return (NULL); \ --} \ -- \ --struct type * \ --name##_VSPLAY_REMOVE(struct name *head, struct type *elm) \ --{ \ -- struct type *__tmp; \ -- if (VSPLAY_EMPTY(head)) \ -- return (NULL); \ -- name##_VSPLAY(head, elm); \ -- if ((cmp)(elm, (head)->sph_root) == 0) { \ -- if (VSPLAY_LEFT((head)->sph_root, field) == NULL) { \ -- (head)->sph_root = VSPLAY_RIGHT((head)->sph_root, field);\ -- } else { \ -- __tmp = VSPLAY_RIGHT((head)->sph_root, field); \ -- (head)->sph_root = VSPLAY_LEFT((head)->sph_root, field);\ -- name##_VSPLAY(head, elm); \ -- VSPLAY_RIGHT((head)->sph_root, field) = __tmp; \ -- } \ -- return (elm); \ -- } \ -- return (NULL); \ --} \ -- \ --void \ --name##_VSPLAY(struct name *head, struct type *elm) \ --{ \ -- struct type __node, *__left, *__right, *__tmp; \ -- int __comp; \ --\ -- VSPLAY_LEFT(&__node, field) = VSPLAY_RIGHT(&__node, field) = NULL;\ -- __left = __right = &__node; \ --\ -- while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ -- if (__comp < 0) { \ -- __tmp = VSPLAY_LEFT((head)->sph_root, field); \ -- if (__tmp == NULL) \ -- break; \ -- if ((cmp)(elm, __tmp) < 0){ \ -- VSPLAY_ROTATE_RIGHT(head, __tmp, field);\ -- if (VSPLAY_LEFT((head)->sph_root, field) == NULL)\ -- break; \ -- } \ -- VSPLAY_LINKLEFT(head, __right, field); \ -- } else if (__comp > 0) { \ -- __tmp = VSPLAY_RIGHT((head)->sph_root, field); \ -- if (__tmp == NULL) \ -- break; \ -- if ((cmp)(elm, __tmp) > 0){ \ -- VSPLAY_ROTATE_LEFT(head, __tmp, field); \ -- if (VSPLAY_RIGHT((head)->sph_root, field) == NULL)\ -- break; \ -- } \ -- VSPLAY_LINKRIGHT(head, __left, field); \ -- } \ -- } \ -- VSPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ --} \ -- \ --/* Splay with either the minimum or the maximum element \ -- * Used to find minimum or maximum element in tree. \ -- */ \ --void name##_VSPLAY_MINMAX(struct name *head, int __comp) \ --{ \ -- struct type __node, *__left, *__right, *__tmp; \ --\ -- VSPLAY_LEFT(&__node, field) = VSPLAY_RIGHT(&__node, field) = NULL;\ -- __left = __right = &__node; \ --\ -- while (1) { \ -- if (__comp < 0) { \ -- __tmp = VSPLAY_LEFT((head)->sph_root, field); \ -- if (__tmp == NULL) \ -- break; \ -- if (__comp < 0){ \ -- VSPLAY_ROTATE_RIGHT(head, __tmp, field);\ -- if (VSPLAY_LEFT((head)->sph_root, field) == NULL)\ -- break; \ -- } \ -- VSPLAY_LINKLEFT(head, __right, field); \ -- } else if (__comp > 0) { \ -- __tmp = VSPLAY_RIGHT((head)->sph_root, field); \ -- if (__tmp == NULL) \ -- break; \ -- if (__comp > 0) { \ -- VSPLAY_ROTATE_LEFT(head, __tmp, field); \ -- if (VSPLAY_RIGHT((head)->sph_root, field) == NULL)\ -- break; \ -- } \ -- VSPLAY_LINKRIGHT(head, __left, field); \ -- } \ -- } \ -- VSPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ --} -- --#define VSPLAY_NEGINF -1 --#define VSPLAY_INF 1 -- --#define VSPLAY_INSERT(name, x, y) name##_VSPLAY_INSERT(x, y) --#define VSPLAY_REMOVE(name, x, y) name##_VSPLAY_REMOVE(x, y) --#define VSPLAY_FIND(name, x, y) name##_VSPLAY_FIND(x, y) --#define VSPLAY_NEXT(name, x, y) name##_VSPLAY_NEXT(x, y) --#define VSPLAY_MIN(name, x) (VSPLAY_EMPTY(x) ? NULL \ -- : name##_VSPLAY_MIN_MAX(x, VSPLAY_NEGINF)) --#define VSPLAY_MAX(name, x) (VSPLAY_EMPTY(x) ? NULL \ -- : name##_VSPLAY_MIN_MAX(x, VSPLAY_INF)) -- --#define VSPLAY_FOREACH(x, name, head) \ -- for ((x) = VSPLAY_MIN(name, head); \ -- (x) != NULL; \ -- (x) = VSPLAY_NEXT(name, head, x)) -- --/* Macros that define a red-black tree */ --#define VRB_HEAD(name, type) \ --struct name { \ -- struct type *rbh_root; /* root of the tree */ \ --} -- --#define VRB_INITIALIZER(root) \ -- { NULL } -- --#define VRB_INIT(root) do { \ -- (root)->rbh_root = NULL; \ --} while (/*CONSTCOND*/ 0) -- --#define VRB_BLACK 0 --#define VRB_RED 1 --#define VRB_ENTRY(type) \ --struct { \ -- struct type *rbe_left; /* left element */ \ -- struct type *rbe_right; /* right element */ \ -- struct type *rbe_parent; /* parent element */ \ -- int rbe_color; /* node color */ \ --} -- --#define VRB_LEFT(elm, field) (elm)->field.rbe_left --#define VRB_RIGHT(elm, field) (elm)->field.rbe_right --#define VRB_PARENT(elm, field) (elm)->field.rbe_parent --#define VRB_COLOR(elm, field) (elm)->field.rbe_color --#define VRB_ROOT(head) (head)->rbh_root --#define VRB_EMPTY(head) (VRB_ROOT(head) == NULL) -- --#define VRB_SET(elm, parent, field) do { \ -- VRB_PARENT(elm, field) = parent; \ -- VRB_LEFT(elm, field) = VRB_RIGHT(elm, field) = NULL; \ -- VRB_COLOR(elm, field) = VRB_RED; \ --} while (/*CONSTCOND*/ 0) -- --#define VRB_SET_BLACKRED(black, red, field) do { \ -- VRB_COLOR(black, field) = VRB_BLACK; \ -- VRB_COLOR(red, field) = VRB_RED; \ --} while (/*CONSTCOND*/ 0) -- --#ifndef VRB_AUGMENT --#define VRB_AUGMENT(x) do {} while (0) --#endif -- --#define VRB_ROTATE_LEFT(head, elm, tmp, field) do { \ -- (tmp) = VRB_RIGHT(elm, field); \ -- if ((VRB_RIGHT(elm, field) = VRB_LEFT(tmp, field)) != NULL) { \ -- VRB_PARENT(VRB_LEFT(tmp, field), field) = (elm); \ -- } \ -- VRB_AUGMENT(elm); \ -- if ((VRB_PARENT(tmp, field) = VRB_PARENT(elm, field)) != NULL) {\ -- if ((elm) == VRB_LEFT(VRB_PARENT(elm, field), field)) \ -- VRB_LEFT(VRB_PARENT(elm, field), field) = (tmp);\ -- else \ -- VRB_RIGHT(VRB_PARENT(elm, field), field) = (tmp);\ -- } else \ -- (head)->rbh_root = (tmp); \ -- VRB_LEFT(tmp, field) = (elm); \ -- VRB_PARENT(elm, field) = (tmp); \ -- VRB_AUGMENT(tmp); \ -- if ((VRB_PARENT(tmp, field))) \ -- VRB_AUGMENT(VRB_PARENT(tmp, field)); \ --} while (/*CONSTCOND*/ 0) -- --#define VRB_ROTATE_RIGHT(head, elm, tmp, field) do { \ -- (tmp) = VRB_LEFT(elm, field); \ -- if ((VRB_LEFT(elm, field) = VRB_RIGHT(tmp, field)) != NULL) { \ -- VRB_PARENT(VRB_RIGHT(tmp, field), field) = (elm); \ -- } \ -- VRB_AUGMENT(elm); \ -- if ((VRB_PARENT(tmp, field) = VRB_PARENT(elm, field)) != NULL) {\ -- if ((elm) == VRB_LEFT(VRB_PARENT(elm, field), field)) \ -- VRB_LEFT(VRB_PARENT(elm, field), field) = (tmp);\ -- else \ -- VRB_RIGHT(VRB_PARENT(elm, field), field) = (tmp);\ -- } else \ -- (head)->rbh_root = (tmp); \ -- VRB_RIGHT(tmp, field) = (elm); \ -- VRB_PARENT(elm, field) = (tmp); \ -- VRB_AUGMENT(tmp); \ -- if ((VRB_PARENT(tmp, field))) \ -- VRB_AUGMENT(VRB_PARENT(tmp, field)); \ --} while (/*CONSTCOND*/ 0) -- --/* Generates prototypes and inline functions */ --#define VRB_PROTOTYPE(name, type, field, cmp) \ -- VRB_PROTOTYPE_INTERNAL(name, type, field, cmp,) --#define VRB_PROTOTYPE_STATIC(name, type, field, cmp) \ -- VRB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) --#define VRB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ --/*lint -esym(528, name##_VRB_*) */ \ --attr void name##_VRB_INSERT_COLOR(struct name *, struct type *); \ --attr void name##_VRB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ --attr struct type *name##_VRB_REMOVE(struct name *, struct type *); \ --attr struct type *name##_VRB_INSERT(struct name *, struct type *); \ --attr struct type *name##_VRB_FIND(const struct name *, const struct type *); \ --attr struct type *name##_VRB_NFIND(const struct name *, const struct type *); \ --attr struct type *name##_VRB_NEXT(struct type *); \ --attr struct type *name##_VRB_PREV(struct type *); \ --attr struct type *name##_VRB_MINMAX(const struct name *, int); \ -- \ -- --/* Main rb operation. -- * Moves node close to the key of elm to top -- */ --#define VRB_GENERATE(name, type, field, cmp) \ -- VRB_GENERATE_INTERNAL(name, type, field, cmp,) --#define VRB_GENERATE_STATIC(name, type, field, cmp) \ -- VRB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) --#define VRB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ --attr void \ --name##_VRB_INSERT_COLOR(struct name *head, struct type *elm) \ --{ \ -- struct type *parent, *gparent, *tmp; \ -- while ((parent = VRB_PARENT(elm, field)) != NULL && \ -- VRB_COLOR(parent, field) == VRB_RED) { \ -- gparent = VRB_PARENT(parent, field); \ -- if (parent == VRB_LEFT(gparent, field)) { \ -- tmp = VRB_RIGHT(gparent, field); \ -- if (tmp && VRB_COLOR(tmp, field) == VRB_RED) { \ -- VRB_COLOR(tmp, field) = VRB_BLACK; \ -- VRB_SET_BLACKRED(parent, gparent, field);\ -- elm = gparent; \ -- continue; \ -- } \ -- if (VRB_RIGHT(parent, field) == elm) { \ -- VRB_ROTATE_LEFT(head, parent, tmp, field);\ -- tmp = parent; \ -- parent = elm; \ -- elm = tmp; \ -- } \ -- VRB_SET_BLACKRED(parent, gparent, field); \ -- VRB_ROTATE_RIGHT(head, gparent, tmp, field); \ -- } else { \ -- tmp = VRB_LEFT(gparent, field); \ -- if (tmp && VRB_COLOR(tmp, field) == VRB_RED) { \ -- VRB_COLOR(tmp, field) = VRB_BLACK; \ -- VRB_SET_BLACKRED(parent, gparent, field);\ -- elm = gparent; \ -- continue; \ -- } \ -- if (VRB_LEFT(parent, field) == elm) { \ -- VRB_ROTATE_RIGHT(head, parent, tmp, field);\ -- tmp = parent; \ -- parent = elm; \ -- elm = tmp; \ -- } \ -- VRB_SET_BLACKRED(parent, gparent, field); \ -- VRB_ROTATE_LEFT(head, gparent, tmp, field); \ -- } \ -- } \ -- VRB_COLOR(head->rbh_root, field) = VRB_BLACK; \ --} \ -- \ --attr void \ --name##_VRB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ --{ \ -- struct type *tmp; \ -- while ((elm == NULL || VRB_COLOR(elm, field) == VRB_BLACK) && \ -- elm != VRB_ROOT(head)) { \ -- AN(parent); \ -- if (VRB_LEFT(parent, field) == elm) { \ -- tmp = VRB_RIGHT(parent, field); \ -- if (VRB_COLOR(tmp, field) == VRB_RED) { \ -- VRB_SET_BLACKRED(tmp, parent, field); \ -- VRB_ROTATE_LEFT(head, parent, tmp, field);\ -- tmp = VRB_RIGHT(parent, field); \ -- } \ -- if ((VRB_LEFT(tmp, field) == NULL || \ -- VRB_COLOR(VRB_LEFT(tmp, field), field) == VRB_BLACK) &&\ -- (VRB_RIGHT(tmp, field) == NULL || \ -- VRB_COLOR(VRB_RIGHT(tmp, field), field) == VRB_BLACK)) {\ -- VRB_COLOR(tmp, field) = VRB_RED; \ -- elm = parent; \ -- parent = VRB_PARENT(elm, field); \ -- } else { \ -- if (VRB_RIGHT(tmp, field) == NULL || \ -- VRB_COLOR(VRB_RIGHT(tmp, field), field) == VRB_BLACK) {\ -- struct type *oleft; \ -- if ((oleft = VRB_LEFT(tmp, field)) \ -- != NULL) \ -- VRB_COLOR(oleft, field) = VRB_BLACK;\ -- VRB_COLOR(tmp, field) = VRB_RED;\ -- VRB_ROTATE_RIGHT(head, tmp, oleft, field);\ -- tmp = VRB_RIGHT(parent, field); \ -- } \ -- VRB_COLOR(tmp, field) = VRB_COLOR(parent, field);\ -- VRB_COLOR(parent, field) = VRB_BLACK; \ -- if (VRB_RIGHT(tmp, field)) \ -- VRB_COLOR(VRB_RIGHT(tmp, field), field) = VRB_BLACK;\ -- VRB_ROTATE_LEFT(head, parent, tmp, field);\ -- elm = VRB_ROOT(head); \ -- break; \ -- } \ -- } else { \ -- tmp = VRB_LEFT(parent, field); \ -- if (VRB_COLOR(tmp, field) == VRB_RED) { \ -- VRB_SET_BLACKRED(tmp, parent, field); \ -- VRB_ROTATE_RIGHT(head, parent, tmp, field);\ -- tmp = VRB_LEFT(parent, field); \ -- } \ -- if ((VRB_LEFT(tmp, field) == NULL || \ -- VRB_COLOR(VRB_LEFT(tmp, field), field) == VRB_BLACK) &&\ -- (VRB_RIGHT(tmp, field) == NULL || \ -- VRB_COLOR(VRB_RIGHT(tmp, field), field) == VRB_BLACK)) {\ -- VRB_COLOR(tmp, field) = VRB_RED; \ -- elm = parent; \ -- parent = VRB_PARENT(elm, field); \ -- } else { \ -- if (VRB_LEFT(tmp, field) == NULL || \ -- VRB_COLOR(VRB_LEFT(tmp, field), field) == VRB_BLACK) {\ -- struct type *oright; \ -- if ((oright = VRB_RIGHT(tmp, field)) \ -- != NULL) \ -- VRB_COLOR(oright, field) = VRB_BLACK;\ -- VRB_COLOR(tmp, field) = VRB_RED;\ -- VRB_ROTATE_LEFT(head, tmp, oright, field);\ -- tmp = VRB_LEFT(parent, field); \ -- } \ -- VRB_COLOR(tmp, field) = VRB_COLOR(parent, field);\ -- VRB_COLOR(parent, field) = VRB_BLACK; \ -- if (VRB_LEFT(tmp, field)) \ -- VRB_COLOR(VRB_LEFT(tmp, field), field) = VRB_BLACK;\ -- VRB_ROTATE_RIGHT(head, parent, tmp, field);\ -- elm = VRB_ROOT(head); \ -- break; \ -- } \ -- } \ -- } \ -- if (elm) \ -- VRB_COLOR(elm, field) = VRB_BLACK; \ --} \ -- \ --attr struct type * \ --name##_VRB_REMOVE(struct name *head, struct type *elm) \ --{ \ -- struct type *child, *parent, *old = elm; \ -- int color; \ -- if (VRB_LEFT(elm, field) == NULL) \ -- child = VRB_RIGHT(elm, field); \ -- else if (VRB_RIGHT(elm, field) == NULL) \ -- child = VRB_LEFT(elm, field); \ -- else { \ -- struct type *left; \ -- elm = VRB_RIGHT(elm, field); \ -- while ((left = VRB_LEFT(elm, field)) != NULL) \ -- elm = left; \ -- child = VRB_RIGHT(elm, field); \ -- parent = VRB_PARENT(elm, field); \ -- color = VRB_COLOR(elm, field); \ -- if (child) \ -- VRB_PARENT(child, field) = parent; \ -- if (parent) { \ -- if (VRB_LEFT(parent, field) == elm) \ -- VRB_LEFT(parent, field) = child; \ -- else \ -- VRB_RIGHT(parent, field) = child; \ -- VRB_AUGMENT(parent); \ -- } else \ -- VRB_ROOT(head) = child; \ -- if (VRB_PARENT(elm, field) == old) \ -- parent = elm; \ -- (elm)->field = (old)->field; \ -- if (VRB_PARENT(old, field)) { \ -- if (VRB_LEFT(VRB_PARENT(old, field), field) == old)\ -- VRB_LEFT(VRB_PARENT(old, field), field) = elm;\ -- else \ -- VRB_RIGHT(VRB_PARENT(old, field), field) = elm;\ -- VRB_AUGMENT(VRB_PARENT(old, field)); \ -- } else \ -- VRB_ROOT(head) = elm; \ -- VRB_PARENT(VRB_LEFT(old, field), field) = elm; \ -- if (VRB_RIGHT(old, field)) \ -- VRB_PARENT(VRB_RIGHT(old, field), field) = elm; \ -- if (parent) { \ -- left = parent; \ -- do { \ -- VRB_AUGMENT(left); \ -- } while ((left = VRB_PARENT(left, field)) != NULL); \ -- } \ -- goto color; \ -- } \ -- parent = VRB_PARENT(elm, field); \ -- color = VRB_COLOR(elm, field); \ -- if (child) \ -- VRB_PARENT(child, field) = parent; \ -- if (parent) { \ -- if (VRB_LEFT(parent, field) == elm) \ -- VRB_LEFT(parent, field) = child; \ -- else \ -- VRB_RIGHT(parent, field) = child; \ -- VRB_AUGMENT(parent); \ -- } else \ -- VRB_ROOT(head) = child; \ --color: \ -- if (color == VRB_BLACK) { \ -- name##_VRB_REMOVE_COLOR(head, parent, child); \ -- } \ -- return (old); \ --} \ -- \ --/* Inserts a node into the RB tree */ \ --attr struct type * \ --name##_VRB_INSERT(struct name *head, struct type *elm) \ --{ \ -- struct type *tmp; \ -- struct type *parent = NULL; \ -- int comp = 0; \ -- tmp = VRB_ROOT(head); \ -- while (tmp) { \ -- parent = tmp; \ -- comp = (cmp)(elm, parent); \ -- if (comp < 0) \ -- tmp = VRB_LEFT(tmp, field); \ -- else if (comp > 0) \ -- tmp = VRB_RIGHT(tmp, field); \ -- else \ -- return (tmp); \ -- } \ -- VRB_SET(elm, parent, field); \ -- if (parent != NULL) { \ -- if (comp < 0) \ -- VRB_LEFT(parent, field) = elm; \ -- else \ -- VRB_RIGHT(parent, field) = elm; \ -- VRB_AUGMENT(parent); \ -- } else \ -- VRB_ROOT(head) = elm; \ -- name##_VRB_INSERT_COLOR(head, elm); \ -- return (NULL); \ --} \ -- \ --/* Finds the node with the same key as elm */ \ --attr struct type * \ --name##_VRB_FIND(const struct name *head, const struct type *elm) \ --{ \ -- struct type *tmp = VRB_ROOT(head); \ -- int comp; \ -- while (tmp) { \ -- comp = cmp(elm, tmp); \ -- if (comp < 0) \ -- tmp = VRB_LEFT(tmp, field); \ -- else if (comp > 0) \ -- tmp = VRB_RIGHT(tmp, field); \ -- else \ -- return (tmp); \ -- } \ -- return (NULL); \ --} \ -- \ --/* Finds the first node greater than or equal to the search key */ \ --attr struct type * \ --name##_VRB_NFIND(const struct name *head, const struct type *elm) \ --{ \ -- struct type *tmp = VRB_ROOT(head); \ -- struct type *res = NULL; \ -- int comp; \ -- while (tmp) { \ -- comp = cmp(elm, tmp); \ -- if (comp < 0) { \ -- res = tmp; \ -- tmp = VRB_LEFT(tmp, field); \ -- } \ -- else if (comp > 0) \ -- tmp = VRB_RIGHT(tmp, field); \ -- else \ -- return (tmp); \ -- } \ -- return (res); \ --} \ -- \ --/* ARGSUSED */ \ --attr struct type * \ --name##_VRB_NEXT(struct type *elm) \ --{ \ -- if (VRB_RIGHT(elm, field)) { \ -- elm = VRB_RIGHT(elm, field); \ -- while (VRB_LEFT(elm, field)) \ -- elm = VRB_LEFT(elm, field); \ -- } else { \ -- if (VRB_PARENT(elm, field) && \ -- (elm == VRB_LEFT(VRB_PARENT(elm, field), field))) \ -- elm = VRB_PARENT(elm, field); \ -- else { \ -- while (VRB_PARENT(elm, field) && \ -- (elm == VRB_RIGHT(VRB_PARENT(elm, field), field)))\ -- elm = VRB_PARENT(elm, field); \ -- elm = VRB_PARENT(elm, field); \ -- } \ -- } \ -- return (elm); \ --} \ -- \ --/* ARGSUSED */ \ --attr struct type * \ --name##_VRB_PREV(struct type *elm) \ --{ \ -- if (VRB_LEFT(elm, field)) { \ -- elm = VRB_LEFT(elm, field); \ -- while (VRB_RIGHT(elm, field)) \ -- elm = VRB_RIGHT(elm, field); \ -- } else { \ -- if (VRB_PARENT(elm, field) && \ -- (elm == VRB_RIGHT(VRB_PARENT(elm, field), field))) \ -- elm = VRB_PARENT(elm, field); \ -- else { \ -- while (VRB_PARENT(elm, field) && \ -- (elm == VRB_LEFT(VRB_PARENT(elm, field), field)))\ -- elm = VRB_PARENT(elm, field); \ -- elm = VRB_PARENT(elm, field); \ -- } \ -- } \ -- return (elm); \ --} \ -- \ --attr struct type * \ --name##_VRB_MINMAX(const struct name *head, int val) \ --{ \ -- struct type *tmp = VRB_ROOT(head); \ -- struct type *parent = NULL; \ -- while (tmp) { \ -- parent = tmp; \ -- if (val < 0) \ -- tmp = VRB_LEFT(tmp, field); \ -- else \ -- tmp = VRB_RIGHT(tmp, field); \ -- } \ -- return (parent); \ --} -- --#define VRB_NEGINF -1 --#define VRB_INF 1 -- --#define VRB_INSERT(name, x, y) name##_VRB_INSERT(x, y) --#define VRB_REMOVE(name, x, y) name##_VRB_REMOVE(x, y) --#define VRB_FIND(name, x, y) name##_VRB_FIND(x, y) --#define VRB_NFIND(name, x, y) name##_VRB_NFIND(x, y) --#define VRB_NEXT(name, x, y) name##_VRB_NEXT(y) --#define VRB_PREV(name, x, y) name##_VRB_PREV(y) --#define VRB_MIN(name, x) name##_VRB_MINMAX(x, VRB_NEGINF) --#define VRB_MAX(name, x) name##_VRB_MINMAX(x, VRB_INF) -- --#define VRB_FOREACH(x, name, head) \ -- for ((x) = VRB_MIN(name, head); \ -- (x) != NULL; \ -- (x) = name##_VRB_NEXT(x)) -- --#define VRB_FOREACH_FROM(x, name, y) \ -- for ((x) = (y); \ -- ((x) != NULL) && ((y) = name##_VRB_NEXT(x), (x) != NULL); \ -- (x) = (y)) -- --#define VRB_FOREACH_SAFE(x, name, head, y) \ -- for ((x) = VRB_MIN(name, head); \ -- ((x) != NULL) && ((y) = name##_VRB_NEXT(x), (x) != NULL); \ -- (x) = (y)) -- --#define VRB_FOREACH_REVERSE(x, name, head) \ -- for ((x) = VRB_MAX(name, head); \ -- (x) != NULL; \ -- (x) = name##_VRB_PREV(x)) -- --#define VRB_FOREACH_REVERSE_FROM(x, name, y) \ -- for ((x) = (y); \ -- ((x) != NULL) && ((y) = name##_VRB_PREV(x), (x) != NULL); \ -- (x) = (y)) -- --#define VRB_FOREACH_REVERSE_SAFE(x, name, head, y) \ -- for ((x) = VRB_MAX(name, head); \ -- ((x) != NULL) && ((y) = name##_VRB_PREV(x), (x) != NULL); \ -- (x) = (y)) -- --#endif /* _VTREE_H_ */ diff --git a/varnish-modules.spec b/varnish-modules.spec index 1c05255..5fd27f7 100644 --- a/varnish-modules.spec +++ b/varnish-modules.spec @@ -1,55 +1,51 @@ %global varnishver %(pkg-config --silence-errors --modversion varnishapi || echo 0) -%global docutils python3-docutils -%global rst2man rst2man Name: varnish-modules -Version: 0.28.0 +Version: 0.15.0 Release: 5%{?dist} Summary: A collection of modules ("vmods") extending Varnish VCL -License: BSD-2-Clause -URL: https://github.com/varnish/varnish-modules -Source: https://github.com/varnish/%{name}/releases/download/%{version}/%{name}-%{version}.tar.gz - +License: BSD +URL: https://github.com/varnish/%{name} +Source: https://download.varnish-software.com/varnish-modules/%{name}-%{version}.tar.gz +Patch10: varnish-modules-0.15.0_fix_saintmode_for_varnish_6.1.patch +Patch11: varnish-modules-0.15.0_fix_simple_formatting_bug.patch BuildRequires: gcc BuildRequires: make BuildRequires: pkgconfig(varnishapi) BuildRequires: varnish -# Build from a git checkout -#BuildRequires: automake -#BuildRequires: autoconf -#BuildRequires: libtool -BuildRequires: %docutils +Requires: varnish -Requires: varnish = %varnishver +Provides: vmod-bodyaccess = %{version}-%{release} +Provides: vmod-cookie = %{version}-%{release} +Provides: vmod-header = %{version}-%{release} +Provides: vmod-saintmode = %{version}-%{release} +Provides: vmod-tcp = %{version}-%{release} +Provides: vmod-var = %{version}-%{release} +Provides: vmod-vsthrottle = %{version}-%{release} +Provides: vmod-xkey = %{version}-%{release} -Provides: vmod(accept)%{_isa} = %{version}-%{release} -Provides: vmod(bodyaccess)%{_isa} = %{version}-%{release} -Provides: vmod(header)%{_isa} = %{version}-%{release} -Provides: vmod(saintmode)%{_isa} = %{version}-%{release} -Provides: vmod(tcp)%{_isa} = %{version}-%{release} -Provides: vmod(var)%{_isa} = %{version}-%{release} -Provides: vmod(vsthrottle)%{_isa} = %{version}-%{release} -Provides: vmod(xkey)%{_isa} = %{version}-%{release} -Provides: vmod(str)%{_isa} = %{version}-%{release} %description This is a collection of modules ("vmods") extending Varnish VCL used for describing HTTP request/response policies with additional -capabilities. This collection contains the following vmods: -bodyaccess, header, saintmode, tcp, var, vsthrottle, xkey +capabilities. This collection contains the following vmods (previously +kept individually): cookie, vsthrottle, header, saintmode, softpurge, +tcp, var, xkey %prep -%autosetup +%setup -q +%if "%varnishver" >= "6.1" +%patch10 -p1 +%endif +%patch11 -p1 %build -#sh bootstrap -export RST2MAN=%{rst2man} -%configure +%configure %make_build @@ -60,174 +56,16 @@ rm %{buildroot}%{_pkgdocdir}/LICENSE # Rather use license macro %check -%ifarch %ix86 %arm ppc -# 64-bit specific test -sed -i 's,tests/xkey/test12.vtc,,' src/Makefile -%endif %make_build check VERBOSE=1 %files -#doc docs AUTHORS CHANGES.rst COPYING README.rst -%doc AUTHORS CHANGES.rst COPYING README.md +%doc docs AUTHORS CHANGES.rst COPYING README.rst %license LICENSE %{_libdir}/varnish/vmods/* %{_mandir}/man3/*.3* - %changelog -* Fri Jul 17 2026 Fedora Release Engineering - 0.28.0-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild - -* Thu May 21 2026 Ingvar Hagelund - 0.28.0-4 -- Built for varnish-9.0.3 - -* Fri May 15 2026 Ingvar Hagelund - 0.28.0-3 -- Built for varnish-9.0.2 - -* Thu Apr 30 2026 Ingvar Hagelund - 0.28.0-2 -- Built for varnish-9.0.1 - -* Mon Apr 13 2026 Ingvar Hagelund - 0.28.0-1 -- New upstream release varnish-modules-0.28.0, built for varnish-9.0.0 - -* Sat Jan 17 2026 Fedora Release Engineering - 0.27.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild - -* Mon Jan 05 2026 Ingvar Hagelund - 0.27.0-1 -- New upstream release varnish-modules-0.27.0 - -* Wed Nov 19 2025 Ingvar Hagelund - 0.26.0-5 -- Rebuilt for varnish-7.7.3-2, rhbz#2407456 - -* Mon Sep 15 2025 Ingvar Hagelund - 0.26.0-4 -- Rebuilt for varnish-7.7.3 - -* Fri Jul 25 2025 Fedora Release Engineering - 0.26.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Sun May 25 2025 Ingvar Hagelund - 0.26.1-2 -- Rebuilt for varnish-7.7.1 - -* Wed Mar 26 2025 Ingvar Hagelund - 0.26.0-1 -- New upstream release for varnish-7.7.0 - -* Sun Jan 19 2025 Fedora Release Engineering - 0.25.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Fri Dec 06 2024 Ingvar Hagelund - 0.25.0-2 -- Rebuilt for varnish-7.6.1 - -* Tue Sep 17 2024 Ingvar Hagelund - 0.25.0-1 -- New upsteam release matching varnish-7.6.0 - -* Sat Jul 20 2024 Fedora Release Engineering - 0.24.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Tue Apr 02 2024 Ingvar Hagelund - 0.24.0 -- New upstream release matching varnish-7.5.0 - -* Sat Jan 27 2024 Fedora Release Engineering - 0.22.0-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Wed Nov 15 2023 Ingvar Hagelund - 0.22.0-4 -- Rebuilt for varnish-7.4.2 - -* Sat Jul 22 2023 Fedora Release Engineering - 0.22.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - -* Tue Jun 06 2023 LuboÅ¡ Uhliarik - 0.22.0-2 -- SPDX migration - -* Sun Mar 19 2023 Ingvar Hagelund - 0.22.0-1 -- New upstream release -- Built for varnish-7.3.0 - -* Sat Jan 21 2023 Fedora Release Engineering - 0.21.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - -* Sun Nov 13 2022 Ingvar Hagelund - 0.21.0-2 -- Built for varnish-7.2.1 - -* Mon Sep 26 2022 Ingvar Hagelund - 0.21.0-1 -- New upstream release -- Removed unused macros from specfile -- Built for varnish-7.2.0 - -* Mon Aug 15 2022 Ingvar Hagelund - 0.20.0-3 -- Built for varnish-7.1.1 - -* Sat Jul 23 2022 Fedora Release Engineering - 0.20.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild - -* Tue Mar 29 2022 Ingvar Hagelund - 0.20.0-1 -- Built for varnish-7.1.0 -- Now provides vmod(name) instead of vmod-name, matching varnish' provides - -* Thu Feb 10 2022 Ingvar Hagelund - 0.19.0-4 -- Built for varnish-7.0.2 - -* Sat Jan 22 2022 Fedora Release Engineering - 0.19.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild - -* Tue Jan 18 2022 Ingvar Hagelund - 0.19.0-2 -- Built for varnish-7.0.1 - -* Thu Sep 23 2021 Ingvar Hagelund - 0.19.0-1 -- New upstream release -- Built for varnish-7.0.0 - -* Fri Jul 23 2021 Fedora Release Engineering - 0.18.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild - -* Sat Jul 17 2021 Ingvar Hagelund 0.18.0-2 -- Rebuilt for varnish-6.6.1 - -* Tue May 18 2021 Ingvar Hagelund 0.18.0-1 -- New upstream release -- Rebuilt for varnish-6.6.0 - -* Wed Mar 17 2021 Ingvar Hagelund 0.17.1-1 -- New upstream release -- Switched back to original varnish github upstream, as it has catched up -- Includes fix for CVE-2021-28543, VSV00006, bz#1939669 - -* Wed Jan 27 2021 Fedora Release Engineering - 0.17.0-0.3.klarlack.20200916git4d6593c -- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild - -* Tue Sep 29 2020 Ingvar Hagelund - 0.17.0-0.2.klarlack.20200916git -- Rebuilt for varnish-6.5.1 - -* Wed Sep 16 2020 Ingvar Hagelund - 0.17.0-0.1.klarlack.20200916git -- Switched upstream to Nils Goroll's fork which is the defacto current upstream -- Synced description to reality -- This is a snapshot build that needs autotools for building -- Rebuilt for varnish-6.5.0 - -* Mon Aug 17 2020 Ingvar Hagelund - 0.16.0-3 -- Rebuilt for varnish-6.4.0 - -* Wed Jul 29 2020 Fedora Release Engineering - 0.16.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild - -* Sat Mar 28 2020 Ingvar Hagelund - 0.16.0-1 -- New upstream release - -* Tue Mar 17 2020 Ingvar Hagelund - 0.16.0-0.1.20200317git21d0c84 -- Snapshot from 6.4 branch, rebuilt against varnish-6.4.0 -- Removed patches merged upstream -- Delete 64-bit specific test on 32-bit arches - -* Fri Jan 31 2020 Fedora Release Engineering - 0.15.0-8 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild - -* Sun Sep 29 2019 Ingvar Hagelund - 0.15.0-7 -- Added patch from Nils Goroll, compatibility for varnish-6.3, closes bz#1736943 -- Rebuilt against varnish-6.3.0 - -* Sat Jul 27 2019 Fedora Release Engineering - 0.15.0-6 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild - * Fri Feb 15 2019 Ingvar Hagelund - 0.15.0-5 - Install docs in correct docdir @@ -251,14 +89,17 @@ sed -i 's,tests/xkey/test12.vtc,,' src/Makefile - Simplified configure step - Dependencies cleanup -* Sat Jul 14 2018 Fedora Release Engineering - 0.12.1-7 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild +* Tue Apr 24 2018 Lubos¡ Uhliarik - 0.12.16 +- use rst2man binary for both python2 and python3 -* Fri Feb 09 2018 Fedora Release Engineering - 0.12.1-6 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild +* Mon Apr 16 2018 Joe Orton - 0.12.1-4.4 +- fix abi requires (#1566046) -* Sat Oct 21 2017 Dridi Boukelmoune 0.12.1-5 -- Update varnishabi requirement for f28 +* Thu Mar 29 2018 Joe Orton - 0.12.1-4.2 +- fix use of rst2man with python3-docutils + +* Wed Mar 28 2018 Joe Orton - 0.12.1-4.1 +- add Python build conditionals * Thu Aug 03 2017 Fedora Release Engineering - 0.12.1-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild @@ -293,3 +134,5 @@ sed -i 's,tests/xkey/test12.vtc,,' src/Makefile - First wrap for fedora - Uses some old-style specfile components for el5 compatibility, including the usage of the BuildRoot header and cleaning the buildroot before install + +