diff --git a/vmod/Makefile.am b/vmod/Makefile.am index 5f3fa9250f6..c8f63540700 100644 --- a/vmod/Makefile.am +++ b/vmod/Makefile.am @@ -28,6 +28,7 @@ vmod_vcc_files = vmod_debug_vcc = include $(srcdir)/automake_boilerplate_blob.am +include $(srcdir)/automake_boilerplate_builtin_http2.am include $(srcdir)/automake_boilerplate_cookie.am include $(srcdir)/automake_boilerplate_debug.am include $(srcdir)/automake_boilerplate_directors.am diff --git a/vmod/automake_boilerplate_builtin_http2.am b/vmod/automake_boilerplate_builtin_http2.am new file mode 100644 index 00000000000..aa9e0194654 --- /dev/null +++ b/vmod/automake_boilerplate_builtin_http2.am @@ -0,0 +1,42 @@ +# Generated by vmodtool.py --boilerplate. + +vmod_builtin_http2_vcc ?= $(srcdir)/vmod_builtin_http2.vcc + +vmod_vcc_files += $(vmod_builtin_http2_vcc) + +vmod_LTLIBRARIES += libvmod_builtin_http2.la + +libvmod_builtin_http2_la_SOURCES = \ + vmod_builtin_http2.c + +libvmod_builtin_http2_la_CFLAGS = + +vmodtoolargs_builtin_http2 ?= --strict --boilerplate -o vcc_builtin_http2_if +vmod_builtin_http2_symbols_regex ?= Vmod_builtin_http2_Data + +libvmod_builtin_http2_la_LDFLAGS = \ + -export-symbols-regex $(vmod_builtin_http2_symbols_regex) \ + $(AM_LDFLAGS) \ + $(VMOD_LDFLAGS) + +nodist_libvmod_builtin_http2_la_SOURCES = vcc_builtin_http2_if.c vcc_builtin_http2_if.h + +EXTRA_libvmod_builtin_http2_la_DEPENDENCIES = $(nodist_libvmod_builtin_http2_la_SOURCES) + +EXTRA_DIST += automake_boilerplate_builtin_http2.am + +$(libvmod_builtin_http2_la_OBJECTS): vcc_builtin_http2_if.h + +vcc_builtin_http2_if.h vmod_builtin_http2.rst vmod_builtin_http2.man.rst: vcc_builtin_http2_if.c + +# A doc-change will not update mtime on the .h and .c files, so a +# touch(1) is necessary to signal that vmodtool was in fact run. +vcc_builtin_http2_if.c: $(VMODTOOL) $(srcdir)/vmod_builtin_http2.vcc + @PYTHON@ $(VMODTOOL) $(vmodtoolargs_builtin_http2) $(srcdir)/vmod_builtin_http2.vcc + touch vcc_builtin_http2_if.c + +clean-local: clean-vmod-builtin_http2 + +clean-vmod-builtin_http2: + rm -f $(nodist_libvmod_builtin_http2_la_SOURCES) + rm -f vmod_builtin_http2.rst vmod_builtin_http2.man.rst diff --git a/vmod/tests/builtin_http2_b00000.vtc b/vmod/tests/builtin_http2_b00000.vtc new file mode 100644 index 00000000000..b340bed1ae3 --- /dev/null +++ b/vmod/tests/builtin_http2_b00000.vtc @@ -0,0 +1,90 @@ +varnishtest "VMOD builtin_http2 basics" + +varnish v1 -arg "-p feature=+http2" -vcl { + import builtin_http2; + + backend proforma none; + + sub vcl_recv { + return(synth(200)); + } + + sub vcl_synth { + set resp.http.http2-is = builtin_http2.is(); + set resp.body = ""; + return (deliver); + } +} -start + +client c1 { + txreq + rxresp + expect resp.status == 200 + expect resp.http.http2-is == false +} -start + +client c2 { + stream 7 { + txreq + rxresp + expect resp.status == 200 + expect resp.http.http2-is == true + } -run +} -start + +client c1 -wait +client c2 -wait + +# coverage +varnish v1 -vcl { + import builtin_http2; + + backend proforma none; + + sub vcl_recv { + return(synth(200)); + } + + sub vcl_synth { + set resp.http.rapid-reset-o = builtin_http2.rapid_reset(10ms); + set resp.http.rapid-reset-n = builtin_http2.rapid_reset(); + set resp.http.rapid-reset-limit-o = builtin_http2.rapid_reset_limit(100); + set resp.http.rapid-reset-limit-n = builtin_http2.rapid_reset_limit(); + set resp.http.rapid-reset-period-o = builtin_http2.rapid_reset_period(10s); + set resp.http.rapid-reset-period-n = builtin_http2.rapid_reset_period(); + set resp.http.rapid-reset-budget = builtin_http2.rapid_reset_allowance(); + set resp.body = ""; + return (deliver); + } +} + +client c1 { + txreq + rxresp + expect resp.status == 200 + expect resp.http.rapid-reset-o == -1.000 + expect resp.http.rapid-reset-n == -1.000 + expect resp.http.rapid-reset-limit-o == -1 + expect resp.http.rapid-reset-limit-n == -1 + expect resp.http.rapid-reset-period-o == -1.000 + expect resp.http.rapid-reset-period-n == -1.000 + expect resp.http.rapid-reset-budget == -1.000 +} -start + +client c2 { + stream 7 { + txreq + rxresp + expect resp.status == 200 + expect resp.http.rapid-reset-o == 0.001 + expect resp.http.rapid-reset-n == 0.010 + expect resp.http.rapid-reset-limit-o == 0 + expect resp.http.rapid-reset-limit-n == 100 + expect resp.http.rapid-reset-period-o == 60.000 + expect resp.http.rapid-reset-period-n == 10.000 + expect resp.http.rapid-reset-budget == 100.000 + } -run +} -start + +client c1 -wait +client c2 -wait diff --git a/vmod/vmod_builtin_http2.c b/vmod/vmod_builtin_http2.c new file mode 100644 index 00000000000..6476c81864b --- /dev/null +++ b/vmod/vmod_builtin_http2.c @@ -0,0 +1,98 @@ +/*- + * Copyright 2023 UPLEX - Nils Goroll Systemoptimierung + * All rights reserved. + * + * Author: Nils Goroll + * + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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. + * + */ + +#include "config.h" + +#include "cache/cache_varnishd.h" + +#include "vcc_builtin_http2_if.h" + +#include "cache/cache_transport.h" +#include "http2/cache_http2.h" + +static struct h2_sess * +h2get(VRT_CTX) +{ + struct h2_sess *h2; + uintptr_t *up; + + CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); + CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); // $Restrict client + if (ctx->req->transport != &HTTP2_transport) + return (NULL); + AZ(SES_Get_proto_priv(ctx->req->sp, &up)); + CAST_OBJ_NOTNULL(h2, (void *)*up, H2_SESS_MAGIC); + return (h2); +} +VCL_BOOL +vmod_is(VRT_CTX) +{ + struct h2_sess *h2 = h2get(ctx); + + return (h2 != NULL); +} + +#define GETSET(type, name, argname) \ +type \ +vmod_ ## name(VRT_CTX, struct VARGS(name) *args) \ +{ \ + struct h2_sess *h2 = h2get(ctx); \ + type r; \ + \ + if (h2 == NULL) \ + return (-1); \ + \ + if (! args->valid_ ## argname) \ + return (h2->name); \ + if (h2->name == args->argname) \ + return (h2->name); \ + \ + Lck_Lock(&h2->sess->mtx); \ + r = h2->name; \ + h2->name = args->argname; \ + h2->rst_budget = h2->rapid_reset_limit; \ + h2->last_rst = ctx->now; \ + Lck_Unlock(&h2->sess->mtx); \ + return (r); \ +} + +GETSET(VCL_DURATION, rapid_reset, threshold) +GETSET(VCL_INT, rapid_reset_limit, number) +GETSET(VCL_DURATION, rapid_reset_period, duration) + +VCL_REAL +vmod_rapid_reset_budget(VRT_CTX) +{ + struct h2_sess *h2 = h2get(ctx); + + if (h2 == NULL) + return (-1); + + return (h2->rst_budget); +} diff --git a/vmod/vmod_builtin_http2.vcc b/vmod/vmod_builtin_http2.vcc new file mode 100644 index 00000000000..bd596566582 --- /dev/null +++ b/vmod/vmod_builtin_http2.vcc @@ -0,0 +1,93 @@ +#- +# Copyright 2023 UPLEX - Nils Goroll Systemoptimierung +# All rights reserved. +# +# Author: Nils Goroll +# +# SPDX-License-Identifier: BSD-2-Clause +# +# 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 AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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. + +$ABI strict +$Module builtin_http2 3 "Module to control the built-in HTTP2 transport" + +DESCRIPTION +=========== + +This VMOD contains functions to control the HTTP2 transport built into +Varnish-Cache. + +$Function BOOL is() +$Restrict client + +Returns true when called on a session handled by the built-in HTTP2 transport. + +$Function DURATION rapid_reset([DURATION threshold]) +$Restrict client + +Get and optionally set the ``h2_rapid_reset`` parameter (See +:ref:`varnishd(1)`) for this HTTP2 session only. + +Returns -1 when used outside the HTTP2 transport. Otherwise returns +the previous value. + +If the call leads to a change in the rate limit parameters, the +current budget as retuned by +`builtin_http2.rapid_reset_budget()`_ is reset. + +$Function INT rapid_reset_limit([INT number]) +$Restrict client + +Get and optionally set the ``h2_rapid_reset_limit`` parameter (See +:ref:`varnishd(1)`) for this HTTP2 session only. + +Returns -1 when used outside the HTTP2 transport. Otherwise returns +the previous value. + +If the call leads to a change in the rate limit parameters, the +current budget as retuned by +`builtin_http2.rapid_reset_budget()`_ is reset. + +$Function DURATION rapid_reset_period([DURATION duration]) +$Restrict client + +Get and optionally set the ``h2_rapid_reset_period`` parameter (See +:ref:`varnishd(1)`) for this HTTP2 session only. + +Returns -1 when used outside the HTTP2 transport. Otherwise returns +the previous value. + +If the call leads to a change in the rate limit parameters, the +current budget as retuned by +`builtin_http2.rapid_reset_budget()`_ is reset. + +$Function REAL rapid_reset_budget() +$Restrict client + +Return how many RST frames classified as "rapid" the client is still +allowed to send before the session is going to be closed. + +SEE ALSO +======== + +* :ref:`varnishd(1)` +* :ref:`vsl(7)`