From nils.goroll at uplex.de Fri Mar 1 11:28:08 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 11:28:08 +0000 (UTC) Subject: [master] ca9829339 Fix mode for JAIL_FIXFD_FILE in the unix jail Message-ID: <20240301112808.AC0FE929A@lists.varnish-cache.org> commit ca98293398db21f9392cce0c762afde37872badb Author: Nils Goroll Date: Fri Mar 1 12:24:44 2024 +0100 Fix mode for JAIL_FIXFD_FILE in the unix jail Very much looks like copy-pasta in ede8c3dbe84b131d7e1240f28f2eb16c2818c309 JAIL_FIXFD_VSMMGT and JAIL_FIXFD_VSMWRK work on directories but, as the name implies, JAIL_FIXFD_FILE not. diff --git a/bin/varnishd/mgt/mgt_jail_unix.c b/bin/varnishd/mgt/mgt_jail_unix.c index d979c00f0..f84d63c2e 100644 --- a/bin/varnishd/mgt/mgt_jail_unix.c +++ b/bin/varnishd/mgt/mgt_jail_unix.c @@ -296,7 +296,7 @@ vju_fixfd(int fd, enum jail_fixfd_e what) switch (what) { case JAIL_FIXFD_FILE: - AZ(fchmod(fd, 0750)); + AZ(fchmod(fd, 0600)); AZ(fchown(fd, vju_wrkuid, vju_wrkgid)); break; case JAIL_FIXFD_VSMMGT: From dridi.boukelmoune at gmail.com Fri Mar 1 11:38:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 1 Mar 2024 11:38:06 +0000 (UTC) Subject: [master] 55fecc94d vtc: Bump stack for ESI tests tight on 32bit systems Message-ID: <20240301113806.D86DD9C21@lists.varnish-cache.org> commit 55fecc94d3ca59ab156f1e76746bbeefeaec07d8 Author: Dridi Boukelmoune Date: Fri Mar 1 12:34:09 2024 +0100 vtc: Bump stack for ESI tests tight on 32bit systems Refs #4063 diff --git a/bin/varnishtest/tests/e00016.vtc b/bin/varnishtest/tests/e00016.vtc index 142032366..180f1a769 100644 --- a/bin/varnishtest/tests/e00016.vtc +++ b/bin/varnishtest/tests/e00016.vtc @@ -26,10 +26,11 @@ server s1 { } } -start -varnish v1 \ - -syntax 4.0 \ - -arg "-p feature=+esi_disable_xml_check" \ - -vcl+backend { +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" +varnish v1 -cliok "param.set feature +esi_disable_xml_check" + +varnish v1 -syntax 4.0 -vcl+backend { sub vcl_backend_response { set beresp.do_esi = true; } diff --git a/bin/varnishtest/tests/e00030.vtc b/bin/varnishtest/tests/e00030.vtc index ff2016fb9..424207020 100644 --- a/bin/varnishtest/tests/e00030.vtc +++ b/bin/varnishtest/tests/e00030.vtc @@ -1,7 +1,6 @@ varnishtest "Test req_top.* in an ESI context" -varnish v1 -arg "-p feature=+esi_disable_xml_check" \ - -errvcl {Variable is read only.} { +varnish v1 -errvcl {Variable is read only.} { backend foo None; sub vcl_recv { @@ -52,6 +51,10 @@ server s1 { txresp } -start +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" +varnish v1 -cliok "param.set feature +esi_disable_xml_check" + varnish v1 -vcl+backend { sub vcl_recv { if (req.esi_level > 0) { diff --git a/bin/varnishtest/tests/e00034.vtc b/bin/varnishtest/tests/e00034.vtc index 2749b3df3..b0e93ba8e 100644 --- a/bin/varnishtest/tests/e00034.vtc +++ b/bin/varnishtest/tests/e00034.vtc @@ -72,6 +72,9 @@ server s1 { } } -start +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" + varnish v1 -syntax 4.1 -vcl+backend { import debug; diff --git a/bin/varnishtest/tests/l00003.vtc b/bin/varnishtest/tests/l00003.vtc index 1e94845df..5ecef3faa 100644 --- a/bin/varnishtest/tests/l00003.vtc +++ b/bin/varnishtest/tests/l00003.vtc @@ -14,6 +14,9 @@ server s1 { txresp -body {123} } -start +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" + varnish v1 -vcl+backend { sub vcl_backend_response { if (bereq.url != "/2") { diff --git a/bin/varnishtest/tests/r01737.vtc b/bin/varnishtest/tests/r01737.vtc index 845b1de3a..454bd96e8 100644 --- a/bin/varnishtest/tests/r01737.vtc +++ b/bin/varnishtest/tests/r01737.vtc @@ -23,7 +23,11 @@ server s1 { rxresp } -start -varnish v1 -arg "-p feature=+esi_disable_xml_check" -vcl+backend { +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" +varnish v1 -cliok "param.set feature +esi_disable_xml_check" + +varnish v1 -vcl+backend { sub vcl_backend_response { set beresp.do_esi = true; } diff --git a/bin/varnishtest/tests/r01781.vtc b/bin/varnishtest/tests/r01781.vtc index 4801d0613..31e21bf9a 100644 --- a/bin/varnishtest/tests/r01781.vtc +++ b/bin/varnishtest/tests/r01781.vtc @@ -13,7 +13,11 @@ server s1 { txresp -body {Foo} } -start -varnish v1 -arg "-p feature=+esi_disable_xml_check" -vcl+backend { +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" +varnish v1 -cliok "param.set feature +esi_disable_xml_check" + +varnish v1 -vcl+backend { sub vcl_backend_response { set beresp.do_gzip = true; set beresp.do_esi = true; diff --git a/bin/varnishtest/tests/r01878.vtc b/bin/varnishtest/tests/r01878.vtc index 14831d35b..2d8a0f1fa 100644 --- a/bin/varnishtest/tests/r01878.vtc +++ b/bin/varnishtest/tests/r01878.vtc @@ -14,6 +14,9 @@ server s1 { txresp -hdr "id: bar" -body "<3>bar" } -start +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" + varnish v1 -vcl+backend { sub vcl_backend_response { if (bereq.url != "/bar") { diff --git a/bin/varnishtest/tests/r02849.vtc b/bin/varnishtest/tests/r02849.vtc index 3022bcf78..f7860ab35 100644 --- a/bin/varnishtest/tests/r02849.vtc +++ b/bin/varnishtest/tests/r02849.vtc @@ -22,6 +22,9 @@ server s1 { txresp -body {} } -start +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" + varnish v1 -vcl+backend { sub vcl_recv { if (req.url == "/l3") { diff --git a/bin/varnishtest/tests/v00042.vtc b/bin/varnishtest/tests/v00042.vtc index b378a2731..3d77175ea 100644 --- a/bin/varnishtest/tests/v00042.vtc +++ b/bin/varnishtest/tests/v00042.vtc @@ -33,6 +33,9 @@ server s1 { txresp } -start +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" + varnish v1 -vcl+backend { import debug; diff --git a/bin/varnishtest/tests/v00043.vtc b/bin/varnishtest/tests/v00043.vtc index 49edc6b1a..0d9e6cb93 100644 --- a/bin/varnishtest/tests/v00043.vtc +++ b/bin/varnishtest/tests/v00043.vtc @@ -71,7 +71,11 @@ varnish v1 -errvcl "Not available in subroutine 'vcl_init'" { } } -varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend { +# give enough stack to 32bit systems +varnish v1 -cliok "param.set thread_pool_stack 80k" +varnish v1 -cliok "param.set debug +syncvsl" + +varnish v1 -vcl+backend { import debug; sub vcl_init { From dridi.boukelmoune at gmail.com Fri Mar 1 14:07:04 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 1 Mar 2024 14:07:04 +0000 (UTC) Subject: [master] d92ca5087 varnishd: always shutdown both ends to a backend Message-ID: <20240301140705.2D01E100498@lists.varnish-cache.org> commit d92ca50874db7397345601cb2d16b425a9df7f6f Author: Asad Sajjad Ahmed Date: Mon Feb 19 13:01:41 2024 +0100 varnishd: always shutdown both ends to a backend Signed-off-by: Asad Sajjad Ahmed diff --git a/bin/varnishd/cache/cache_conn_pool.c b/bin/varnishd/cache/cache_conn_pool.c index 131fc20da..c879dd669 100644 --- a/bin/varnishd/cache/cache_conn_pool.c +++ b/bin/varnishd/cache/cache_conn_pool.c @@ -231,7 +231,7 @@ VCP_Rel(struct conn_pool **cpp) cp->n_conn--; assert(pfd->state == PFD_STATE_AVAIL); pfd->state = PFD_STATE_CLEANUP; - (void)shutdown(pfd->fd, SHUT_WR); + (void)shutdown(pfd->fd, SHUT_RDWR); cp->n_kill++; } while (cp->n_kill) { diff --git a/bin/varnishtest/tests/b00083.vtc b/bin/varnishtest/tests/b00083.vtc new file mode 100644 index 000000000..f648c30e1 --- /dev/null +++ b/bin/varnishtest/tests/b00083.vtc @@ -0,0 +1,47 @@ +varnishtest "VCP FIN-WAIT2" + +server s1 { + rxreq + txresp + + # Leave the TCP connection open in the FIN-WAIT2 state + delay 1000 +} -start + +server s2 { + rxreq + txresp +} -start + +varnish v1 -vcl { + backend s1 { + .host = "${s1_sock}"; + } +} -start + +# The waiter depend on the backend_idle_timeout for when to give up and +# close the connection, so bump it up a bit. +varnish v1 -cliok "param.set backend_idle_timeout 120" + +# The shutdown is done on the CLI thread, and it blocks until the waiter has +# killed the connection. So bump cli_timeout up as well +varnish v1 -cliok "param.set cli_timeout 120" + +client c1 { + txreq -url "/" + rxresp +} -run + +varnish v1 -vcl { + backend s2 { + .host = "${s2_sock}"; + } +} + +varnish v1 -cliok "vcl.use vcl2" +varnish v1 -cliok "vcl.discard vcl1" + +varnish v1 -expect n_backend == 1 +varnish v1 -expect backend_conn == 1 +varnish v1 -expect backend_reuse == 0 +varnish v1 -expect backend_recycle == 1 From nils.goroll at uplex.de Fri Mar 1 14:09:06 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 14:09:06 +0000 (UTC) Subject: [master] a73e6a5b8 For BackendClose, also log the short tag as with SessClose Message-ID: <20240301140906.B8E4B100688@lists.varnish-cache.org> commit a73e6a5b8ee4543f82cafeb3ce5e377963ca6ed3 Author: Nils Goroll Date: Mon Jan 29 16:56:09 2024 +0100 For BackendClose, also log the short tag as with SessClose this is for consistency, to simplify parsing and to reduce the amount of data logged with VSL. Motivated by #4042 diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c index 61be0aa27..7b273c5b7 100644 --- a/bin/varnishd/cache/cache_backend.c +++ b/bin/varnishd/cache/cache_backend.c @@ -240,7 +240,7 @@ vbe_dir_finish(VRT_CTX, VCL_BACKEND d) bo->htc->priv = NULL; if (bo->htc->doclose != SC_NULL || bp->proxy_header != 0) { VSLb(bo->vsl, SLT_BackendClose, "%d %s close %s", *PFD_Fd(pfd), - VRT_BACKEND_string(d), bo->htc->doclose->desc); + VRT_BACKEND_string(d), bo->htc->doclose->name); VCP_Close(&pfd); AZ(pfd); Lck_Lock(bp->director->mtx); diff --git a/include/tbl/vsl_tags.h b/include/tbl/vsl_tags.h index 378916cab..b5a3596c0 100644 --- a/include/tbl/vsl_tags.h +++ b/include/tbl/vsl_tags.h @@ -155,7 +155,7 @@ SLTM(BackendClose, 0, "Backend connection closed", "The format is::\n\n" "\t%d %s %s [ %s ]\n" "\t| | | |\n" - "\t| | | +- Optional reason\n" + "\t| | | +- Optional reason, see SessClose for explanation\n" "\t| | +------ \"close\" or \"recycle\"\n" "\t| +--------- Backend display name\n" "\t+------------ Connection file descriptor\n" From nils.goroll at uplex.de Fri Mar 1 14:43:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 14:43:05 +0000 (UTC) Subject: [master] 20aee1b7d Partly revert "Close VDPs for error conditions in cnt_transmit()" Message-ID: <20240301144305.A33FA1019A6@lists.varnish-cache.org> commit 20aee1b7d0f58c3669f763518264e686f5b39c7b Author: Nils Goroll Date: Wed Feb 28 13:49:52 2024 +0100 Partly revert "Close VDPs for error conditions in cnt_transmit()" This reverts the code change from commit 6d423aa5c60940ebde76c91f0a482767346df405, keeps the test case and adds a VDP_Close() for the case that the transport deliver function is not called. Part 2 of the fix for #4067 Conflicts: bin/varnishd/cache/cache_req_fsm.c diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c index e84407647..ed97a0110 100644 --- a/bin/varnishd/cache/cache_req_fsm.c +++ b/bin/varnishd/cache/cache_req_fsm.c @@ -467,6 +467,8 @@ cnt_transmit(struct worker *wrk, struct req *req) VCL_StackVDP(req, req->vcl, req->vdp_filter_list)) { VSLb(req->vsl, SLT_Error, "Failure to push processors"); req->doclose = SC_OVERLOAD; + req->acct.resp_bodybytes += + VDP_Close(req->vdc, req->objcore, boc); } else { if (status < 200 || status == 204) { // rfc7230,l,1691,1695 @@ -504,9 +506,6 @@ cnt_transmit(struct worker *wrk, struct req *req) req->doclose = SC_TX_ERROR; } - if (req->doclose != SC_NULL) - req->acct.resp_bodybytes += VDP_Close(req->vdc, req->objcore, boc); - if (boc != NULL) HSH_DerefBoc(wrk, req->objcore); From nils.goroll at uplex.de Fri Mar 1 14:43:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 14:43:05 +0000 (UTC) Subject: [master] 2d494dc7c In transport delivery functions, close VDPs always Message-ID: <20240301144305.988F91019A4@lists.varnish-cache.org> commit 2d494dc7c6b3adb53c7679ba13929ffa530aa8b5 Author: Nils Goroll Date: Wed Feb 28 13:48:17 2024 +0100 In transport delivery functions, close VDPs always Part 1 of the fix for #4067 diff --git a/bin/varnishd/cache/cache_esi_deliver.c b/bin/varnishd/cache/cache_esi_deliver.c index 936191ea3..dd921c0f9 100644 --- a/bin/varnishd/cache/cache_esi_deliver.c +++ b/bin/varnishd/cache/cache_esi_deliver.c @@ -850,6 +850,17 @@ static const struct vdp ved_ved = { .fini = ved_vdp_fini, }; +static void +ved_close(struct req *req, struct boc *boc, int error) +{ + req->acct.resp_bodybytes += VDP_Close(req->vdc, req->objcore, boc); + + if (! error) + return; + req->top->topreq->vdc->retval = -1; + req->top->topreq->doclose = req->doclose; +} + /*--------------------------------------------------------------------*/ static void v_matchproto_(vtr_deliver_f) @@ -868,19 +879,22 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); - if (wantbody == 0) + if (wantbody == 0) { + ved_close(req, boc, 0); return; + } status = req->resp->status % 1000; if (!ecx->incl_cont && status != 200 && status != 204) { - req->top->topreq->vdc->retval = -1; - req->top->topreq->doclose = req->doclose; + ved_close(req, boc, 1); return; } - if (boc == NULL && ObjGetLen(req->wrk, req->objcore) == 0) + if (boc == NULL && ObjGetLen(req->wrk, req->objcore) == 0) { + ved_close(req, boc, 0); return; + } if (http_GetHdr(req->resp, H_Content_Encoding, &p)) i = http_coding_eq(p, gzip); @@ -899,7 +913,10 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) if (req->objcore->flags & OC_F_FAILED) { /* No way of signalling errors in the middle of - the ESI body. Omit this ESI fragment. */ + * the ESI body. Omit this ESI fragment. + * XXX change error argument to 1 + */ + ved_close(req, boc, 0); return; } @@ -926,10 +943,5 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) if (i && req->doclose == SC_NULL) req->doclose = SC_REM_CLOSE; - req->acct.resp_bodybytes += VDP_Close(req->vdc, req->objcore, boc); - - if (i && !ecx->incl_cont) { - req->top->topreq->vdc->retval = -1; - req->top->topreq->doclose = req->doclose; - } + ved_close(req, boc, i && !ecx->incl_cont); } diff --git a/bin/varnishd/http1/cache_http1_deliver.c b/bin/varnishd/http1/cache_http1_deliver.c index d82443367..15bc706b9 100644 --- a/bin/varnishd/http1/cache_http1_deliver.c +++ b/bin/varnishd/http1/cache_http1_deliver.c @@ -40,7 +40,7 @@ /*--------------------------------------------------------------------*/ static void -v1d_error(struct req *req, const char *msg) +v1d_error(struct req *req, struct boc *boc, const char *msg) { static const char r_500[] = "HTTP/1.1 500 Internal Server Error\r\n" @@ -57,6 +57,8 @@ v1d_error(struct req *req, const char *msg) req->wrk->stats->client_resp_500++; VTCP_Assert(write(req->sp->fd, r_500, sizeof r_500 - 1)); req->doclose = SC_TX_EOF; + + req->acct.resp_bodybytes += VDP_Close(req->vdc, req->objcore, boc); } /*-------------------------------------------------------------------- @@ -98,18 +100,18 @@ V1D_Deliver(struct req *req, struct boc *boc, int sendbody) INIT_OBJ(ctx, VRT_CTX_MAGIC); VCL_Req2Ctx(ctx, req); if (VDP_Push(ctx, req->vdc, req->ws, VDP_v1l, NULL)) { - v1d_error(req, "Failure to push v1d processor"); + v1d_error(req, boc, "Failure to push v1d processor"); return; } } if (WS_Overflowed(req->ws)) { - v1d_error(req, "workspace_client overflow"); + v1d_error(req, boc, "workspace_client overflow"); return; } if (WS_Overflowed(req->sp->ws)) { - v1d_error(req, "workspace_session overflow"); + v1d_error(req, boc, "workspace_session overflow"); return; } @@ -118,7 +120,7 @@ V1D_Deliver(struct req *req, struct boc *boc, int sendbody) cache_param->http1_iovs); if (WS_Overflowed(req->wrk->aws)) { - v1d_error(req, "workspace_thread overflow"); + v1d_error(req, boc, "workspace_thread overflow"); return; } From nils.goroll at uplex.de Fri Mar 1 14:43:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 14:43:05 +0000 (UTC) Subject: [master] bb3d027bf Ensure that transports call VDP_Close() Message-ID: <20240301144306.0530A1019AC@lists.varnish-cache.org> commit bb3d027bf6647185be548050243e1cb9d36741a7 Author: Nils Goroll Date: Wed Feb 28 15:04:39 2024 +0100 Ensure that transports call VDP_Close() diff --git a/bin/varnishd/cache/cache_deliver_proc.c b/bin/varnishd/cache/cache_deliver_proc.c index a6d9832ed..035cf526f 100644 --- a/bin/varnishd/cache/cache_deliver_proc.c +++ b/bin/varnishd/cache/cache_deliver_proc.c @@ -59,7 +59,15 @@ VDP_Panic(struct vsb *vsb, const struct vdp_ctx *vdc) VSB_cat(vsb, "},\n"); } - +/* + * Ensure that transports have called VDP_Close() + * to avoid leaks in VDPs + */ +void +VDP_Fini(struct vdp_ctx *vdc) +{ + assert(VTAILQ_EMPTY(&vdc->vdp)); +} void VDP_Init(struct vdp_ctx *vdc, struct worker *wrk, struct vsl_log *vsl, diff --git a/bin/varnishd/cache/cache_req.c b/bin/varnishd/cache/cache_req.c index cfea8fce2..bd457ff19 100644 --- a/bin/varnishd/cache/cache_req.c +++ b/bin/varnishd/cache/cache_req.c @@ -313,6 +313,8 @@ Req_Cleanup(struct sess *sp, struct worker *wrk, struct req *req) wrk->stats->ws_client_overflow++; wrk->seen_methods = 0; + + VDP_Fini(req->vdc); } /*---------------------------------------------------------------------- diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h index 540781821..0ce03cf0a 100644 --- a/bin/varnishd/cache/cache_varnishd.h +++ b/bin/varnishd/cache/cache_varnishd.h @@ -189,6 +189,7 @@ void VDI_Event(const struct director *d, enum vcl_event_e ev); void VDI_Init(void); /* cache_deliver_proc.c */ +void VDP_Fini(struct vdp_ctx *vdc); void VDP_Init(struct vdp_ctx *vdc, struct worker *wrk, struct vsl_log *vsl, struct req *req); uint64_t VDP_Close(struct vdp_ctx *, struct objcore *, struct boc *); From nils.goroll at uplex.de Fri Mar 1 16:11:06 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 16:11:06 +0000 (UTC) Subject: [master] 1cc722bfb Ensure PRIV_TASK and PRIV_TOP allocations never fail Message-ID: <20240301161106.29103104B66@lists.varnish-cache.org> commit 1cc722bfb1bca30c966475948314b04c59fc8065 Author: Nils Goroll Date: Wed Feb 28 10:16:45 2024 +0100 Ensure PRIV_TASK and PRIV_TOP allocations never fail this is in preparation of a follow up commit diff --git a/bin/varnishd/cache/cache_vrt_priv.c b/bin/varnishd/cache/cache_vrt_priv.c index 5ebce43b4..616f7c55f 100644 --- a/bin/varnishd/cache/cache_vrt_priv.c +++ b/bin/varnishd/cache/cache_vrt_priv.c @@ -40,9 +40,15 @@ #include "vcl.h" #include "vcc_interface.h" +enum vrt_priv_storage_e { + VRT_PRIV_ST_WS = 1, + VRT_PRIV_ST_HEAP +}; + struct vrt_priv { unsigned magic; #define VRT_PRIV_MAGIC 0x24157a52 + enum vrt_priv_storage_e storage; VRBT_ENTRY(vrt_priv) entry; struct vmod_priv priv[1]; uintptr_t vmod_id; @@ -138,23 +144,37 @@ vrt_priv_dynamic_get(const struct vrt_privs *privs, uintptr_t vmod_id) static struct vmod_priv * vrt_priv_dynamic(struct ws *ws, struct vrt_privs *privs, uintptr_t vmod_id) { + //lint --e{593} vp allocated, vp->priv returned struct vrt_priv *vp, *ovp; + enum vrt_priv_storage_e storage; AN(vmod_id); - /* even if ws is full, return any existing priv */ - if (WS_ReserveSize(ws, sizeof *vp) == 0) - return (vrt_priv_dynamic_get(privs, vmod_id)); + if (LIKELY(WS_ReserveSize(ws, sizeof *vp) != 0)) { + vp = WS_Reservation(ws); + storage = VRT_PRIV_ST_WS; + } + else { + vp = malloc(sizeof *vp); + storage = VRT_PRIV_ST_HEAP; + } + AN(vp); - vp = WS_Reservation(ws); INIT_OBJ(vp, VRT_PRIV_MAGIC); + vp->storage = storage; vp->vmod_id = vmod_id; ovp = VRBT_INSERT(vrt_privs, privs, vp); if (ovp == NULL) { - WS_Release(ws, sizeof *vp); + if (storage == VRT_PRIV_ST_WS) + WS_Release(ws, sizeof *vp); return (vp->priv); } - WS_Release(ws, 0); + if (storage == VRT_PRIV_ST_WS) + WS_Release(ws, 0); + else if (storage == VRT_PRIV_ST_HEAP) + free(vp); + else + WRONG("priv storage"); return (ovp->priv); } @@ -310,6 +330,8 @@ VCL_TaskLeave(VRT_CTX, struct vrt_privs *privs) VRBT_FOREACH_SAFE(vp, vrt_privs, privs, vp1) { CHECK_OBJ(vp, VRT_PRIV_MAGIC); VRT_priv_fini(ctx, vp->priv); + if (vp->storage == VRT_PRIV_ST_HEAP) + free(vp); } ZERO_OBJ(privs, sizeof *privs); } From nils.goroll at uplex.de Fri Mar 1 16:11:06 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 16:11:06 +0000 (UTC) Subject: [master] 7d06b8b98 Call VRT_priv_{task, top} for each PRIV_{TASK, TOP} argument Message-ID: <20240301161106.498DB104B6A@lists.varnish-cache.org> commit 7d06b8b98350de557568d712ff089d3c961d0618 Author: Nils Goroll Date: Wed Feb 28 11:31:16 2024 +0100 Call VRT_priv_{task,top} for each PRIV_{TASK,TOP} argument to avoid using stale pointers after a rollback. Before this change, we would call VRT_priv_* only once per subroutine, which can be *) a nice performance optimization, but leaves us with stale pointers after a rollback. Rather than adding complications for the rollback case just to keep the option of the "per subroutine pointer cache", just retrieve a fresh priv pointer every time. The other use of the per subroutine initialization was error handling, which needs additional code outside the function arguments, simply because a return statement is not possible within function arguments. We removed the requirement for error handling in the previous commit by making sure that VRT_priv_{task,top} always return a valid pointer. Fixes https://github.com/varnish/varnish-modules/issues/222 Alternative implementation to #4060 *) It is not an optimization in all cases, for example the priv pointers were intialized unconditionally, even if code using them was not reached - but then again, this is something C compilers might optimize... diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c index 1e94dbf76..8cda6f12d 100644 --- a/lib/libvcc/vcc_expr.c +++ b/lib/libvcc/vcc_expr.c @@ -401,7 +401,6 @@ vcc_priv_arg(struct vcc *tl, const char *p, struct symbol *sym) char buf[64]; struct inifin *ifp; const char *f = NULL; - struct procprivhead *marklist = NULL; AN(sym); AN(sym->vmod_name); @@ -417,31 +416,18 @@ vcc_priv_arg(struct vcc *tl, const char *p, struct symbol *sym) return (vcc_mk_expr(VOID, "&%s", buf)); } - if (!strcmp(p, "PRIV_TASK")) { + if (!strcmp(p, "PRIV_TASK")) f = "task"; - marklist = &tl->curproc->priv_tasks; - } else if (!strcmp(p, "PRIV_TOP")) { + else if (!strcmp(p, "PRIV_TOP")) { f = "top"; sym->r_methods &= VCL_MET_TASK_C; - marklist = &tl->curproc->priv_tops; } else { WRONG("Wrong PRIV_ type"); } AN(f); - AN(marklist); - bprintf(buf, "ARG_priv_%s_%s", f, sym->vmod_name); - - if (vcc_MarkPriv(tl, marklist, sym->vmod_name) == NULL) - VSB_printf(tl->curproc->prologue, - " struct vmod_priv *%s = " - "VRT_priv_%s(ctx, &VGC_vmod_%s);\n" - " if (%s == NULL) {\n" - " VRT_fail(ctx, \"failed to get %s priv " - "for vmod %s\");\n" - " return;\n" - " }\n", - buf, f, sym->vmod_name, buf, f, sym->vmod_name); - return (vcc_mk_expr(VOID, "%s", buf)); + + return (vcc_mk_expr(VOID, "VRT_priv_%s(ctx, &VGC_vmod_%s)", + f, sym->vmod_name)); } struct func_arg { From nils.goroll at uplex.de Fri Mar 1 16:11:06 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 16:11:06 +0000 (UTC) Subject: [master] 0bea9b1b5 vcc: retire the now unused procprivhead facility Message-ID: <20240301161106.7883C104B6E@lists.varnish-cache.org> commit 0bea9b1b5867aec3bfcaea26404601e385d5b603 Author: Nils Goroll Date: Wed Feb 28 11:55:27 2024 +0100 vcc: retire the now unused procprivhead facility We no longer need to mark used vmods in subroutines (see previous commit) diff --git a/lib/libvcc/vcc_compile.c b/lib/libvcc/vcc_compile.c index f3f9a2d70..082205a89 100644 --- a/lib/libvcc/vcc_compile.c +++ b/lib/libvcc/vcc_compile.c @@ -156,8 +156,6 @@ vcc_NewProc(struct vcc *tl, struct symbol *sym) AN(p); VTAILQ_INIT(&p->calls); VTAILQ_INIT(&p->uses); - VTAILQ_INIT(&p->priv_tasks); - VTAILQ_INIT(&p->priv_tops); VTAILQ_INSERT_TAIL(&tl->procs, p, list); p->prologue = VSB_new_auto(); AN(p->prologue); diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h index acd997281..93fb613c8 100644 --- a/lib/libvcc/vcc_compile.h +++ b/lib/libvcc/vcc_compile.h @@ -207,7 +207,6 @@ struct symbol { }; VTAILQ_HEAD(tokenhead, token); -VTAILQ_HEAD(procprivhead, procpriv); struct proc { unsigned magic; @@ -215,8 +214,6 @@ struct proc { const struct method *method; VTAILQ_HEAD(,proccall) calls; VTAILQ_HEAD(,procuse) uses; - struct procprivhead priv_tasks; - struct procprivhead priv_tops; VTAILQ_ENTRY(proc) list; struct token *name; unsigned ret_bitmap; @@ -483,8 +480,6 @@ extern const struct xrefuse XREF_ACTION[1]; void vcc_AddUses(struct vcc *, const struct token *, const struct token *, const struct symbol *sym, const struct xrefuse *use); int vcc_CheckUses(struct vcc *tl); -const char *vcc_MarkPriv(struct vcc *, struct procprivhead *, - const char *); #define ERRCHK(tl) do { if ((tl)->err) return; } while (0) #define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__) diff --git a/lib/libvcc/vcc_xref.c b/lib/libvcc/vcc_xref.c index 035c42cfb..6f72576a0 100644 --- a/lib/libvcc/vcc_xref.c +++ b/lib/libvcc/vcc_xref.c @@ -63,11 +63,6 @@ struct procuse { struct proc *fm; }; -struct procpriv { - VTAILQ_ENTRY(procpriv) list; - const char *vmod; -}; - /*--------------------------------------------------------------------*/ static void @@ -467,28 +462,3 @@ VCC_XrefTable(struct vcc *tl) Fc(tl, 0, "*/\n\n"); #include "vcc_namespace.h" } - -/*--------------------------------------------------------------------- - * mark vmod as referenced, return NULL if not yet marked, vmod if marked - */ - -const char * -vcc_MarkPriv(struct vcc *tl, struct procprivhead *head, - const char *vmod) -{ - struct procpriv *pp; - - AN(vmod); - - VTAILQ_FOREACH(pp, head, list) { - if (pp->vmod == vmod) - return (vmod); - AN(strcmp(pp->vmod, vmod)); - } - - pp = TlAlloc(tl, sizeof *pp); - assert(pp != NULL); - pp->vmod = vmod; - VTAILQ_INSERT_TAIL(head, pp, list); - return (NULL); -} From nils.goroll at uplex.de Fri Mar 1 16:26:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 16:26:05 +0000 (UTC) Subject: [master] aa3f6787b Flexelint polish Message-ID: <20240301162605.DC4B01057F3@lists.varnish-cache.org> commit aa3f6787b8e5cac4d014d3c0548b9179d8357597 Author: Nils Goroll Date: Fri Mar 1 17:16:49 2024 +0100 Flexelint polish Ref 2d494dc7c6b3adb53c7679ba13929ffa530aa8b5 bb3d027bf6647185be548050243e1cb9d36741a7 diff --git a/bin/varnishd/cache/cache_deliver_proc.c b/bin/varnishd/cache/cache_deliver_proc.c index 035cf526f..b0af89c74 100644 --- a/bin/varnishd/cache/cache_deliver_proc.c +++ b/bin/varnishd/cache/cache_deliver_proc.c @@ -64,7 +64,7 @@ VDP_Panic(struct vsb *vsb, const struct vdp_ctx *vdc) * to avoid leaks in VDPs */ void -VDP_Fini(struct vdp_ctx *vdc) +VDP_Fini(const struct vdp_ctx *vdc) { assert(VTAILQ_EMPTY(&vdc->vdp)); } diff --git a/bin/varnishd/cache/cache_esi_deliver.c b/bin/varnishd/cache/cache_esi_deliver.c index dd921c0f9..f9a97b085 100644 --- a/bin/varnishd/cache/cache_esi_deliver.c +++ b/bin/varnishd/cache/cache_esi_deliver.c @@ -943,5 +943,5 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) if (i && req->doclose == SC_NULL) req->doclose = SC_REM_CLOSE; - ved_close(req, boc, i && !ecx->incl_cont); + ved_close(req, boc, i && !ecx->incl_cont ? 1 : 0); } diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h index 0ce03cf0a..019b426dc 100644 --- a/bin/varnishd/cache/cache_varnishd.h +++ b/bin/varnishd/cache/cache_varnishd.h @@ -189,7 +189,7 @@ void VDI_Event(const struct director *d, enum vcl_event_e ev); void VDI_Init(void); /* cache_deliver_proc.c */ -void VDP_Fini(struct vdp_ctx *vdc); +void VDP_Fini(const struct vdp_ctx *vdc); void VDP_Init(struct vdp_ctx *vdc, struct worker *wrk, struct vsl_log *vsl, struct req *req); uint64_t VDP_Close(struct vdp_ctx *, struct objcore *, struct boc *); From nils.goroll at uplex.de Fri Mar 1 18:29:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Fri, 1 Mar 2024 18:29:05 +0000 (UTC) Subject: [master] 9e399f38e Consistently abort ESI transactions also for empty includes Message-ID: <20240301182905.A19FC109941@lists.varnish-cache.org> commit 9e399f38e7588c2c1593bce5747dd37b40ebc457 Author: Nils Goroll Date: Fri Mar 1 17:38:29 2024 +0100 Consistently abort ESI transactions also for empty includes When we introduced checking ESI includes for status 200 or 204, we would only (potentially, depending on the onerror attribute and esi_onerror_continue parameter) abort ESI processing for includes with a non-zero length. This patch makes behavior consistent to not depend on whether or not an include is empty. Fixes #4070 diff --git a/bin/varnishd/cache/cache_esi_deliver.c b/bin/varnishd/cache/cache_esi_deliver.c index f9a97b085..2c6318039 100644 --- a/bin/varnishd/cache/cache_esi_deliver.c +++ b/bin/varnishd/cache/cache_esi_deliver.c @@ -879,11 +879,6 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); - if (wantbody == 0) { - ved_close(req, boc, 0); - return; - } - status = req->resp->status % 1000; if (!ecx->incl_cont && status != 200 && status != 204) { @@ -891,6 +886,11 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) return; } + if (wantbody == 0) { + ved_close(req, boc, 0); + return; + } + if (boc == NULL && ObjGetLen(req->wrk, req->objcore) == 0) { ved_close(req, boc, 0); return; diff --git a/bin/varnishtest/tests/r03865.vtc b/bin/varnishtest/tests/r03865.vtc index aba495f27..b36e23f66 100644 --- a/bin/varnishtest/tests/r03865.vtc +++ b/bin/varnishtest/tests/r03865.vtc @@ -6,6 +6,11 @@ server s1 { txresp -hdr {surrogate-control: content="ESI/1.0"} \ -body {before after} + rxreq + expect req.url == "/abort0" + txresp -hdr {surrogate-control: content="ESI/1.0"} \ + -body {before after} + } -start varnish v1 -cliok "param.set feature +esi_disable_xml_check" @@ -15,6 +20,9 @@ varnish v1 -vcl+backend { if (bereq.url == "/fail") { return (error(604)); } + if (bereq.url == "/fail0") { + return (error(605)); + } } sub vcl_backend_response { set beresp.do_esi = beresp.http.surrogate-control ~ "ESI/1.0"; @@ -25,6 +33,10 @@ varnish v1 -vcl+backend { set beresp.body = "FOOBAR"; return(deliver); } + if (beresp.status == 605) { + set beresp.body = ""; + return(deliver); + } } } -start @@ -39,6 +51,18 @@ client c1 { expect resp.body == "before " } -run +client c1 { + # #4070 + txreq -url "/abort0" + non_fatal + rxresphdrs + expect resp.status == 200 + rxchunk + rxchunk + expect_close + expect resp.body == "before " +} -run + varnish v1 -cliok "param.set max_esi_depth 0" client c1 { From dridi.boukelmoune at gmail.com Fri Mar 1 18:56:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 1 Mar 2024 18:56:05 +0000 (UTC) Subject: [master] e8264aaf2 fetch: New VBF_Superseded entry for ExpKill records Message-ID: <20240301185605.DB59510AABB@lists.varnish-cache.org> commit e8264aaf2cec981e246347b88afbe7e7e101fc81 Author: Dridi Boukelmoune Date: Wed Jan 10 13:51:40 2024 +0100 fetch: New VBF_Superseded entry for ExpKill records diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c index 9a6ed4ec6..c6c26ada0 100644 --- a/bin/varnishd/cache/cache_fetch.c +++ b/bin/varnishd/cache/cache_fetch.c @@ -752,8 +752,12 @@ vbf_stp_fetchend(struct worker *wrk, struct busyobj *bo) ObjSetState(wrk, oc, BOS_FINISHED); VSLb_ts_busyobj(bo, "BerespBody", W_TIM_real(wrk)); - if (bo->stale_oc != NULL) + if (bo->stale_oc != NULL) { + VSL(SLT_ExpKill, NO_VXID, "VBF_Superseded x=%ju n=%ju", + VXID(ObjGetXID(wrk, bo->stale_oc)), + VXID(ObjGetXID(wrk, bo->fetch_objcore))); HSH_Kill(bo->stale_oc); + } return (F_STP_DONE); } diff --git a/bin/varnishtest/tests/b00039.vtc b/bin/varnishtest/tests/b00039.vtc index ba4285369..3a316c3a8 100644 --- a/bin/varnishtest/tests/b00039.vtc +++ b/bin/varnishtest/tests/b00039.vtc @@ -11,6 +11,7 @@ server s1 { txresp -status 304 } -start +varnish v1 -cliok "param.set vsl_mask +ExpKill" varnish v1 -vcl+backend { sub vcl_backend_response { set beresp.ttl = 2s; @@ -20,6 +21,13 @@ varnish v1 -vcl+backend { } } -start +logexpect l1 -v v1 -g raw -q ExpKill { + expect * 0 ExpKill "VBF_Superseded x=1002 n=1005" + expect * 0 ExpKill "EXP_Removed x=1002" + expect * 0 ExpKill "VBF_Superseded x=1005 n=1010" + expect * 0 ExpKill "EXP_Removed x=1005" +} -start + client c1 { txreq rxresp @@ -57,3 +65,5 @@ client c1 { expect resp.body == "Geoff Rules" expect resp.http.was-304 == "true" } -run + +logexpect l1 -wait diff --git a/include/tbl/vsl_tags.h b/include/tbl/vsl_tags.h index b5a3596c0..858256f26 100644 --- a/include/tbl/vsl_tags.h +++ b/include/tbl/vsl_tags.h @@ -367,6 +367,8 @@ SLTM(ExpKill, 0, "Object expiry event", "\tLogged when the expiry thread expires an object.\n\n" "EXP_Removed\n" "\tLogged when the expiry thread removes an object before expiry.\n\n" + "VBF_Superseded\n" + "\tLogged when an object supersedes another.\n\n" "LRU_Cand\n" "\tLogged when an object is evaluated for LRU force expiry.\n\n" "LRU\n" @@ -382,6 +384,7 @@ SLTM(ExpKill, 0, "Object expiry event", "\tEXP_Inspect p=%p e=%f f=0x%x\n" "\tEXP_Expired x=%u t=%f h=%u\n" "\tEXP_Removed x=%u t=%f h=%u\n" + "\tVBF_Superseded x=%u n=%u\n" "\tLRU_Cand p=%p f=0x%x r=%d\n" "\tLRU x=%u\n" "\tLRU_Fail\n" @@ -394,6 +397,7 @@ SLTM(ExpKill, 0, "Object expiry event", "\tf=0x%x Objcore flags\n" "\tr=%d Objcore refcount\n" "\tx=%u Object VXID\n" + "\tn=%u New object VXID\n" "\th=%u Objcore hits\n" "\n" ) From dridi.boukelmoune at gmail.com Fri Mar 1 18:56:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 1 Mar 2024 18:56:06 +0000 (UTC) Subject: [master] 241be56b9 expire: New MAIN.n_superseded counter Message-ID: <20240301185606.06C0810AABE@lists.varnish-cache.org> commit 241be56b946e5aab532994d542ac82757e319a25 Author: Dridi Boukelmoune Date: Wed Jan 10 14:00:06 2024 +0100 expire: New MAIN.n_superseded counter diff --git a/bin/varnishd/cache/cache_expire.c b/bin/varnishd/cache/cache_expire.c index 60aafb098..fb823e3cc 100644 --- a/bin/varnishd/cache/cache_expire.c +++ b/bin/varnishd/cache/cache_expire.c @@ -149,12 +149,16 @@ EXP_RefNewObjcore(struct objcore *oc) */ void -EXP_Remove(struct objcore *oc) +EXP_Remove(struct objcore *oc, const struct objcore *new_oc) { CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); + CHECK_OBJ_ORNULL(new_oc, OBJCORE_MAGIC); + if (oc->exp_flags & OC_EF_REFD) { Lck_Lock(&exphdl->mtx); + if (new_oc != NULL) + VSC_C_main->n_superseded++; if (oc->exp_flags & OC_EF_NEW) { /* EXP_Insert has not been called for this object * yet. Mark it for removal, and EXP_Insert will diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c index 6d982ddec..2cde33868 100644 --- a/bin/varnishd/cache/cache_hash.c +++ b/bin/varnishd/cache/cache_hash.c @@ -453,7 +453,7 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp) if (BAN_CheckObject(wrk, oc, req)) { oc->flags |= OC_F_DYING; - EXP_Remove(oc); + EXP_Remove(oc, NULL); continue; } @@ -743,7 +743,7 @@ HSH_Purge(struct worker *wrk, struct objhead *oh, vtim_real ttl_now, for (i = 0; i < j; i++) { CHECK_OBJ_NOTNULL(ocp[i], OBJCORE_MAGIC); if (is_purge) - EXP_Remove(ocp[i]); + EXP_Remove(ocp[i], NULL); else EXP_Rearm(ocp[i], ttl_now, ttl, grace, keep); (void)HSH_DerefObjCore(wrk, &ocp[i], 0); @@ -919,7 +919,7 @@ HSH_Kill(struct objcore *oc) Lck_Lock(&oc->objhead->mtx); oc->flags |= OC_F_DYING; Lck_Unlock(&oc->objhead->mtx); - EXP_Remove(oc); + EXP_Remove(oc, NULL); } /*==================================================================== @@ -946,7 +946,7 @@ HSH_Snipe(const struct worker *wrk, struct objcore *oc) Lck_Unlock(&oc->objhead->mtx); } if (retval) - EXP_Remove(oc); + EXP_Remove(oc, NULL); return (retval); } diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h index 019b426dc..a73ff7170 100644 --- a/bin/varnishd/cache/cache_varnishd.h +++ b/bin/varnishd/cache/cache_varnishd.h @@ -207,7 +207,7 @@ vtim_real EXP_Ttl(const struct req *, const struct objcore *); vtim_real EXP_Ttl_grace(const struct req *, const struct objcore *oc); void EXP_RefNewObjcore(struct objcore *); void EXP_Insert(struct worker *wrk, struct objcore *oc); -void EXP_Remove(struct objcore *); +void EXP_Remove(struct objcore *, const struct objcore *); #define EXP_Dttl(req, oc) (oc->ttl - (req->t_req - oc->t_origin)) diff --git a/lib/libvsc/VSC_main.vsc b/lib/libvsc/VSC_main.vsc index 14f3e266f..82542a4c5 100644 --- a/lib/libvsc/VSC_main.vsc +++ b/lib/libvsc/VSC_main.vsc @@ -397,6 +397,12 @@ Number of objects that expired from cache because of old age. +.. varnish_vsc:: n_superseded + :level: diag + :oneliner: Number of superseded objects + + Number of times an object was superseded by a new one. + .. varnish_vsc:: n_lru_nuked :oneliner: Number of LRU nuked objects From dridi.boukelmoune at gmail.com Fri Mar 1 18:56:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 1 Mar 2024 18:56:06 +0000 (UTC) Subject: [master] b7507f942 hash: New HSH_Replace() function Message-ID: <20240301185606.32C5F10AAC2@lists.varnish-cache.org> commit b7507f9421333cb51eaa0b8445116b282f186852 Author: Dridi Boukelmoune Date: Wed Jan 10 14:11:19 2024 +0100 hash: New HSH_Replace() function diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c index c6c26ada0..f49de59cf 100644 --- a/bin/varnishd/cache/cache_fetch.c +++ b/bin/varnishd/cache/cache_fetch.c @@ -756,7 +756,7 @@ vbf_stp_fetchend(struct worker *wrk, struct busyobj *bo) VSL(SLT_ExpKill, NO_VXID, "VBF_Superseded x=%ju n=%ju", VXID(ObjGetXID(wrk, bo->stale_oc)), VXID(ObjGetXID(wrk, bo->fetch_objcore))); - HSH_Kill(bo->stale_oc); + HSH_Replace(bo->stale_oc, bo->fetch_objcore); } return (F_STP_DONE); } diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c index 2cde33868..ce31aecf0 100644 --- a/bin/varnishd/cache/cache_hash.c +++ b/bin/varnishd/cache/cache_hash.c @@ -911,15 +911,26 @@ HSH_Unbusy(struct worker *wrk, struct objcore *oc) void HSH_Kill(struct objcore *oc) +{ + + HSH_Replace(oc, NULL); +} + +void +HSH_Replace(struct objcore *oc, const struct objcore *new_oc) { CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); CHECK_OBJ_NOTNULL(oc->objhead, OBJHEAD_MAGIC); + if (new_oc != NULL) { + CHECK_OBJ(new_oc, OBJCORE_MAGIC); + assert(oc->objhead == new_oc->objhead); + } Lck_Lock(&oc->objhead->mtx); oc->flags |= OC_F_DYING; Lck_Unlock(&oc->objhead->mtx); - EXP_Remove(oc, NULL); + EXP_Remove(oc, new_oc); } /*==================================================================== diff --git a/bin/varnishd/cache/cache_objhead.h b/bin/varnishd/cache/cache_objhead.h index 58b536502..2edfb5a88 100644 --- a/bin/varnishd/cache/cache_objhead.h +++ b/bin/varnishd/cache/cache_objhead.h @@ -67,6 +67,7 @@ enum lookup_e { void HSH_Fail(struct objcore *); void HSH_Kill(struct objcore *); +void HSH_Replace(struct objcore *, const struct objcore *); void HSH_Insert(struct worker *, const void *hash, struct objcore *, struct ban *); void HSH_Unbusy(struct worker *, struct objcore *); diff --git a/bin/varnishtest/tests/b00039.vtc b/bin/varnishtest/tests/b00039.vtc index 3a316c3a8..49afa4550 100644 --- a/bin/varnishtest/tests/b00039.vtc +++ b/bin/varnishtest/tests/b00039.vtc @@ -67,3 +67,5 @@ client c1 { } -run logexpect l1 -wait + +varnish v1 -expect MAIN.n_superseded == 2 From dridi.boukelmoune at gmail.com Mon Mar 4 11:38:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 4 Mar 2024 11:38:05 +0000 (UTC) Subject: [master] dd8882754 circleci: Update setup_remote_docker version Message-ID: <20240304113805.E6D5C11F73F@lists.varnish-cache.org> commit dd88827545c64f38c6d9362a92b548d801dd5f22 Author: Guillaume Quintard Date: Sat Feb 24 15:52:39 2024 +0100 circleci: Update setup_remote_docker version https://discuss.circleci.com/t/remote-docker-image-deprecations-and-eol-for-2024/50176 diff --git a/.circleci/config.yml b/.circleci/config.yml index 58cb84ca4..443128fe3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -223,8 +223,7 @@ jobs: - image: centos:7 working_directory: /workspace steps: - - setup_remote_docker: - version: 20.10.11 + - setup_remote_docker - run: name: Install docker command: yum install -y docker From dridi.boukelmoune at gmail.com Mon Mar 4 11:38:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 4 Mar 2024 11:38:06 +0000 (UTC) Subject: [master] 6178cd0e0 circleci: Add ubuntu:noble jobs Message-ID: <20240304113806.1755E11F742@lists.varnish-cache.org> commit 6178cd0e0d400367691909c0062bbc5e258803e4 Author: Guillaume Quintard Date: Fri Feb 23 22:09:31 2024 +0100 circleci: Add ubuntu:noble jobs diff --git a/.circleci/config.yml b/.circleci/config.yml index 443128fe3..6c1a39565 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -433,6 +433,10 @@ workflows: name: build_ubuntu_jammy dist: ubuntu release: jammy + - build: + name: build_ubuntu_noble + dist: ubuntu + release: noble - build: name: build_alpine dist: alpine @@ -458,6 +462,7 @@ workflows: - ubuntu:bionic - ubuntu:focal - ubuntu:jammy + - ubuntu:noble - debian:buster - debian:bullseye - debian:bookworm From dridi.boukelmoune at gmail.com Mon Mar 4 11:38:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 4 Mar 2024 11:38:06 +0000 (UTC) Subject: [master] 20d63fc31 circleci: Swap 32bit/sanitizer responsibilities Message-ID: <20240304113806.3497F11F745@lists.varnish-cache.org> commit 20d63fc31f1fdf292c06f2fae8a6fc50195f1cf9 Author: Guillaume Quintard Date: Wed Feb 28 10:42:28 2024 -0800 circleci: Swap 32bit/sanitizer responsibilities The current debian:latest image still ships a 32bit variant, whereas ubuntu:focal, next in line after ubuntu:bionic, no longer does. diff --git a/.circleci/config.yml b/.circleci/config.yml index 6c1a39565..41e46ede2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -405,11 +405,12 @@ workflows: dist: fedora release: latest make_target: witness.dot - # latest debian uses sanitizers + # oldest debian goes 32bit - build: name: build_debian_buster dist: debian release: buster + prefix: i386/ - build: name: build_debian_bullseye dist: debian @@ -418,11 +419,9 @@ workflows: name: build_debian_bookworm dist: debian release: bookworm - extra_conf: --enable-asan --enable-ubsan --enable-workspace-emulator - # oldest ubuntu goes 32bit + # latest ubuntu uses sanitizers - build: name: build_ubuntu_bionic - prefix: i386/ dist: ubuntu release: bionic - build: @@ -437,6 +436,7 @@ workflows: name: build_ubuntu_noble dist: ubuntu release: noble + extra_conf: --enable-asan --enable-ubsan --enable-workspace-emulator - build: name: build_alpine dist: alpine From dridi.boukelmoune at gmail.com Mon Mar 4 11:38:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 4 Mar 2024 11:38:06 +0000 (UTC) Subject: [master] 147891247 circleci: Retire ubuntu:bionic jobs Message-ID: <20240304113806.6304111F74A@lists.varnish-cache.org> commit 147891247f30de456da464c478805f16076fc18e Author: Guillaume Quintard Date: Thu Feb 29 09:56:57 2024 -0800 circleci: Retire ubuntu:bionic jobs diff --git a/.circleci/config.yml b/.circleci/config.yml index 41e46ede2..90851f72e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -209,7 +209,7 @@ jobs: description: the Linux distribution (debian|ubuntu) type: string release: - description: the release name (buster|bullseye|bionic|focal|jammy) + description: the release name (buster|bullseye|bookworm|focal|jammy|noble) type: string make_target: description: the make target to execute during the build @@ -419,11 +419,6 @@ workflows: name: build_debian_bookworm dist: debian release: bookworm - # latest ubuntu uses sanitizers - - build: - name: build_ubuntu_bionic - dist: ubuntu - release: bionic - build: name: build_ubuntu_focal dist: ubuntu @@ -459,7 +454,6 @@ workflows: matrix: parameters: platform: - - ubuntu:bionic - ubuntu:focal - ubuntu:jammy - ubuntu:noble From dridi.boukelmoune at gmail.com Tue Mar 5 05:46:07 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 05:46:07 +0000 (UTC) Subject: [master] 0804bbab4 circleci: Reduce concurrency of ubuntu:noble jobs Message-ID: <20240305054607.9AC6E11DBCA@lists.varnish-cache.org> commit 0804bbab49161d6912855661f1aeaf5c1963c7ec Author: Dridi Boukelmoune Date: Mon Mar 4 18:22:49 2024 +0100 circleci: Reduce concurrency of ubuntu:noble jobs In an attempt to avoid EAGAIN failures on pthread creations with ASAN and UBSAN sanitizers enabled. diff --git a/.circleci/config.yml b/.circleci/config.yml index 90851f72e..66144d11c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -353,7 +353,7 @@ jobs: << parameters.extra_conf >> sudo -u varnish \ --preserve-env=ASAN_OPTIONS,LSAN_OPTIONS,TSAN_OPTIONS,UBSAN_OPTIONS \ - make << parameters.make_target >> VERBOSE=1 -j 4 -k \ + make -j 4 -k << parameters.make_target >> VERBOSE=1 \ DISTCHECK_CONFIGURE_FLAGS="<< pipeline.parameters.configure_args >> \ << parameters.extra_conf >>" ' @@ -419,6 +419,7 @@ workflows: name: build_debian_bookworm dist: debian release: bookworm + # latest ubuntu uses sanitizers - build: name: build_ubuntu_focal dist: ubuntu @@ -432,6 +433,7 @@ workflows: dist: ubuntu release: noble extra_conf: --enable-asan --enable-ubsan --enable-workspace-emulator + make_target: check -j2 - build: name: build_alpine dist: alpine From dridi.boukelmoune at gmail.com Tue Mar 5 06:28:07 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 06:28:07 +0000 (UTC) Subject: [master] cffda50c8 esi: Restore the original onerror behavior Message-ID: <20240305062807.E006611F052@lists.varnish-cache.org> commit cffda50c8bb65206b1709a16ae6138264907e0a8 Author: Dridi Boukelmoune Date: Fri Mar 1 18:06:49 2024 +0100 esi: Restore the original onerror behavior This is a partial revert of 582ded6a2d6ae1a4467b1eb500f2725b42888016 to restore the assumed onerror=continue behavior for ESI includes, unless the feature flag esi_include_onerror is raised. The part of the change that considers all status codes besides 200 and 204 to be errors for ESI includes remains. A test case covers VCL's ability to "bless" error responses by overriding resp.status, allowing ESI delivery to continue on this criterion. Fixes #4053 diff --git a/bin/varnishd/cache/cache_esi_deliver.c b/bin/varnishd/cache/cache_esi_deliver.c index 2c6318039..24180e6d3 100644 --- a/bin/varnishd/cache/cache_esi_deliver.c +++ b/bin/varnishd/cache/cache_esi_deliver.c @@ -65,7 +65,7 @@ struct ecx { ssize_t l; int isgzip; int woken; - int incl_cont; + int abrt; struct req *preq; struct ecx *pecx; @@ -127,7 +127,7 @@ ved_include(struct req *preq, const char *src, const char *host, VSLb(preq->vsl, SLT_VCL_Error, "ESI depth limit reached (param max_esi_depth = %u)", cache_param->max_esi_depth); - if (!ecx->incl_cont) + if (ecx->abrt) preq->top->topreq->vdc->retval = -1; return; } @@ -384,11 +384,11 @@ ved_vdp_esi_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, Debug("SKIP1(%d)\n", (int)ecx->l); ecx->state = 4; break; - case VEC_IC: - ecx->incl_cont = + case VEC_IA: + ecx->abrt = FEATURE(FEATURE_ESI_INCLUDE_ONERROR); /* FALLTHROUGH */ - case VEC_IA: + case VEC_IC: ecx->p++; q = (void*)strchr((const char*)ecx->p, '\0'); AN(q); @@ -881,7 +881,7 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) status = req->resp->status % 1000; - if (!ecx->incl_cont && status != 200 && status != 204) { + if (ecx->abrt && status != 200 && status != 204) { ved_close(req, boc, 1); return; } @@ -943,5 +943,5 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) if (i && req->doclose == SC_NULL) req->doclose = SC_REM_CLOSE; - ved_close(req, boc, i && !ecx->incl_cont ? 1 : 0); + ved_close(req, boc, i && ecx->abrt); } diff --git a/bin/varnishtest/tests/r03241.vtc b/bin/varnishtest/tests/r03241.vtc index 54a485743..ac7fab446 100644 --- a/bin/varnishtest/tests/r03241.vtc +++ b/bin/varnishtest/tests/r03241.vtc @@ -4,8 +4,12 @@ varnishtest "ESI include out of workspace" server s1 { rxreq expect req.http.esi0 == "foo" - txresp -body {Before includeAfter include + txresp -body { + + Before include + + After include + } rxreq expect req.url == "/body1" @@ -43,11 +47,10 @@ logexpect l1 -v v1 -g raw { client c1 { txreq -hdr "Host: foo" - rxresphdrs + rxresp + # XXX this is actually wrong (missed include) + expect resp.bodylen == 57 expect resp.status == 200 - rxchunk - expect_close - expect resp.body == {Before include} } -run logexpect l1 -wait diff --git a/bin/varnishtest/tests/r04053.vtc b/bin/varnishtest/tests/r04053.vtc new file mode 100644 index 000000000..443d624a6 --- /dev/null +++ b/bin/varnishtest/tests/r04053.vtc @@ -0,0 +1,37 @@ +varnishtest "Override ESI status check for onerror=abort" + +server s1 { + rxreq + expect req.http.esi-level == 0 + txresp -body {before after} + + rxreq + expect req.http.esi-level == 1 + txresp -status 500 -hdr "transfer-encoding: chunked" + delay 0.1 + chunked 500 + chunkedlen 0 +} -start + +varnish v1 -cliok "param.set feature +esi_disable_xml_check" +varnish v1 -cliok "param.set feature +esi_include_onerror" + +varnish v1 -vcl+backend { + sub vcl_recv { + set req.http.esi-level = req.esi_level; + } + sub vcl_backend_response { + set beresp.do_esi = bereq.http.esi-level == "0"; + } + sub vcl_deliver { + if (req.esi_level > 0 && resp.status != 200) { + set resp.status = 200; + } + } +} -start + +client c1 { + txreq + rxresp + expect resp.body == "before 500 after" +} -run From dridi.boukelmoune at gmail.com Tue Mar 5 06:28:07 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 06:28:07 +0000 (UTC) Subject: [master] f19495802 vtc: Simplify r03241 and prune confusing comment Message-ID: <20240305062808.03B5E11F055@lists.varnish-cache.org> commit f19495802644ea8b181eb70f4bedf3f052b022fc Author: Dridi Boukelmoune Date: Fri Mar 1 18:17:50 2024 +0100 vtc: Simplify r03241 and prune confusing comment diff --git a/bin/varnishtest/tests/r03241.vtc b/bin/varnishtest/tests/r03241.vtc index ac7fab446..3dc19ad01 100644 --- a/bin/varnishtest/tests/r03241.vtc +++ b/bin/varnishtest/tests/r03241.vtc @@ -1,24 +1,16 @@ varnishtest "ESI include out of workspace" - server s1 { rxreq expect req.http.esi0 == "foo" - txresp -body { - - Before include - - After include - - } + txresp -body {before after} rxreq expect req.url == "/body1" expect req.http.esi0 != "foo" - txresp -body { - Included file - } + txresp -body "include" } -start +varnish v1 -cliok "param.set feature +esi_disable_xml_check" varnish v1 -vcl+backend { import vtc; @@ -48,9 +40,8 @@ logexpect l1 -v v1 -g raw { client c1 { txreq -hdr "Host: foo" rxresp - # XXX this is actually wrong (missed include) - expect resp.bodylen == 57 expect resp.status == 200 + expect resp.body == "before after" } -run logexpect l1 -wait From dridi.boukelmoune at gmail.com Tue Mar 5 06:28:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 06:28:08 +0000 (UTC) Subject: [master] c5b7a0140 doc: Better document ESI onerror behavior Message-ID: <20240305062808.2951D11F059@lists.varnish-cache.org> commit c5b7a0140729130d5b75fc769ac6ddf5d2f23b7c Author: Dridi Boukelmoune Date: Fri Mar 1 18:47:48 2024 +0100 doc: Better document ESI onerror behavior diff --git a/doc/sphinx/users-guide/esi.rst b/doc/sphinx/users-guide/esi.rst index 92fe5082d..0913f3eef 100644 --- a/doc/sphinx/users-guide/esi.rst +++ b/doc/sphinx/users-guide/esi.rst @@ -92,30 +92,43 @@ For example:: What happens when it fails ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -By default, the fragments must have ``resp.status`` 200 or 206 or -their inclusion will cause the parent request to abort. +By default, the fragments must have ``resp.status`` 200 or 204 or +their delivery will be considered failed. Likewise, if the fragment is a streaming fetch, and that fetch -fails, the parent request aborts. +fails, the fragment delivery is considered failed. If you include synthetic fragments, that is fragments created in ``vcl_backend_error{}`` or ``vcl_synth{}``, you must set -``(be)resp.status`` to 200 before ``return(deliver);`` +``(be)resp.status`` to 200 before ``return(deliver);``, for example +with a ``return (synth(200))`` or ``return (error(200))`` transition. + +Failure to properly deliver an ESI fragment has no effect on its +parent request delivery by default. The parent request can include +the ESI fragment with an ``onerror`` attribute:: + + + +This attribute is ignored by default. In fact, Varnish will treat +failures to deliver ESI fragments as if there was the attribute +``onerror="continue"``. In the absence of this attribute with this +specific value, Varnish should normally abort the delivery of the +parent request. We say "abort" rather than "fail", because by the time Varnish starts inserting the fragments, the HTTP response header has long since been sent, and it is no longer possible to change the parent requests's ``resp.status`` to a 5xx, so the only way to signal that -something is amiss, is to close the connection. +something is amiss, is to close the connection in the HTTP/1 case or +reset the stream for h2 sessions. However, it is possible to allow individual `` +Once this feature flag is enabled, a delivery failure can only continue +if an ``onerror`` attribute said so. Can an ESI fragment also use ESI-includes ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From dridi.boukelmoune at gmail.com Tue Mar 5 06:28:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 06:28:08 +0000 (UTC) Subject: [master] d2f603c5b esi: Skip the response body for onerror="continue" Message-ID: <20240305062808.4887011F05D@lists.varnish-cache.org> commit d2f603c5bc944fde221c28393e37606cf0136301 Author: Dridi Boukelmoune Date: Fri Mar 1 19:11:21 2024 +0100 esi: Skip the response body for onerror="continue" That is to say, when we can actually do that. diff --git a/bin/varnishd/cache/cache_esi_deliver.c b/bin/varnishd/cache/cache_esi_deliver.c index 24180e6d3..43c9c660f 100644 --- a/bin/varnishd/cache/cache_esi_deliver.c +++ b/bin/varnishd/cache/cache_esi_deliver.c @@ -881,8 +881,9 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) status = req->resp->status % 1000; - if (ecx->abrt && status != 200 && status != 204) { - ved_close(req, boc, 1); + if (FEATURE(FEATURE_ESI_INCLUDE_ONERROR) && + status != 200 && status != 204) { + ved_close(req, boc, ecx->abrt); return; } diff --git a/bin/varnishtest/tests/e00035.vtc b/bin/varnishtest/tests/e00035.vtc index 0fc59d749..164c5044f 100644 --- a/bin/varnishtest/tests/e00035.vtc +++ b/bin/varnishtest/tests/e00035.vtc @@ -8,7 +8,7 @@ server s1 { rxreq expect req.url == "/fail" - txresp -hdr "content-length: 100" -nolen + txresp -hdr "content-length: 100" delay 0.1 } -start @@ -17,6 +17,7 @@ varnish v1 -cliok "param.set feature +esi_include_onerror" varnish v1 -vcl+backend { sub vcl_backend_response { set beresp.do_esi = beresp.http.surrogate-control ~ "ESI/1.0"; + set beresp.do_stream = beresp.http.stream != "false"; unset beresp.http.surrogate-control; } } -start @@ -38,7 +39,7 @@ server s1 { rxreq expect req.url == "/fail" - txresp -hdr "content-length: 100" -nolen + txresp -hdr "content-length: 100" delay 0.1 } -start @@ -48,3 +49,24 @@ client c1 { rxresp expect resp.body == "before after" } -run + +server s1 -wait + +server s1 { + rxreq + expect req.url == "/continue-no-stream" + txresp -hdr {surrogate-control: content="ESI/1.0"} \ + -body {before after} + + rxreq + expect req.url == "/err" + txresp -hdr "content-encoding chunked" -hdr "stream: false" + chunked "incomplete" +} -start + +client c1 { + fatal + txreq -url "/continue-no-stream" + rxresp + expect resp.body == "before after" +} -run diff --git a/bin/varnishtest/tests/r03865.vtc b/bin/varnishtest/tests/r03865.vtc index b36e23f66..bd3736de2 100644 --- a/bin/varnishtest/tests/r03865.vtc +++ b/bin/varnishtest/tests/r03865.vtc @@ -93,7 +93,7 @@ client c1 { fatal txreq -url "/continue" rxresp - expect resp.body == "before FOOBAR after" + expect resp.body == "before after" } -run varnish v1 -cliok "param.set max_esi_depth 0" diff --git a/doc/sphinx/users-guide/esi.rst b/doc/sphinx/users-guide/esi.rst index 0913f3eef..209ade289 100644 --- a/doc/sphinx/users-guide/esi.rst +++ b/doc/sphinx/users-guide/esi.rst @@ -128,7 +128,10 @@ continue in case of failures, by setting:: param.set feature +esi_include_onerror Once this feature flag is enabled, a delivery failure can only continue -if an ``onerror`` attribute said so. +if an ``onerror`` attribute said so. The ESI specification states that +in that case the failing fragment is not delivered, which is honored based +on the status code, or based on the response body only when streaming is +disabled (see ``beresp.do_stream``). Can an ESI fragment also use ESI-includes ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From dridi.boukelmoune at gmail.com Tue Mar 5 07:15:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 07:15:06 +0000 (UTC) Subject: [master] 862e8cce6 circleci: Only run the test suite on alpine Message-ID: <20240305071506.4069B4354@lists.varnish-cache.org> commit 862e8cce6d066b7a8e0d4fd81d58194df632b832 Author: Dridi Boukelmoune Date: Tue Mar 5 07:47:47 2024 +0100 circleci: Only run the test suite on alpine There appears to be a race condition with distcheck where test-suite.log is removed and then another attempt at removing it fails: [...] test -z "test-suite.log" || rm -f test-suite.log rm -f libtool config.lt find . '(' -name '*.gcda' -o -name '*.gcda' ')' -exec rm '{}' ';' rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags rm -f cscope.out cscope.in.out cscope.po.out cscope.files find: ./test-suite.log: No such file or directory [...] It is unclear which find command is choking on test-suite.log, there doesn't seem to be a make rule running find and targeting this file. Could it be the find command listed in the output collecting file names like test-suite.log and then failing to test it against the -name filters after it got removed? That would be infortunate for a find implementation. Since alpine is not a platform we officially support, and after failing numerous times to reproduce the link outside of the CI environment, a simple make check is good enough and it will remove a lot of noise. diff --git a/.circleci/config.yml b/.circleci/config.yml index 66144d11c..9ade65a8b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -439,6 +439,7 @@ workflows: dist: alpine release: "latest" extra_conf: --without-contrib + make_target: check - build: name: build_archlinux dist: archlinux From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:07 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:07 +0000 (UTC) Subject: [master] 9d392361d vtim: Change the semantics of vtim_poll_tmo() Message-ID: <20240305085307.CF0CD655BA@lists.varnish-cache.org> commit 9d392361d76ace7a18c8eda7f0a46dcd4fe41c10 Author: Dridi Boukelmoune Date: Mon Feb 26 17:31:38 2024 +0100 vtim: Change the semantics of vtim_poll_tmo() From now on, INFINITY disables the timeout and NAN is no longer allowed. Refs #3045 diff --git a/bin/varnishd/http1/cache_http1_pipe.c b/bin/varnishd/http1/cache_http1_pipe.c index 98464ab46..dd8b9098b 100644 --- a/bin/varnishd/http1/cache_http1_pipe.c +++ b/bin/varnishd/http1/cache_http1_pipe.c @@ -149,7 +149,7 @@ V1P_Process(const struct req *req, int fd, struct v1p_acct *v1a, fds[1].revents = 0; tmo = cache_param->pipe_timeout; if (tmo == 0.) - tmo = NAN; + tmo = INFINITY; if (deadline > 0.) { tmo_task = deadline - VTIM_real(); tmo = vmin(tmo, tmo_task); diff --git a/lib/libvarnish/vtim.c b/lib/libvarnish/vtim.c index 01e218db5..33907432a 100644 --- a/lib/libvarnish/vtim.c +++ b/lib/libvarnish/vtim.c @@ -458,8 +458,9 @@ int VTIM_poll_tmo(vtim_dur tmo) { - if (isnan(tmo)) + if (isinf(tmo)) return (-1); + assert(!isnan(tmo)); return (vmax_t(int, 0, ((int)(tmo * 1e3)))); } From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:08 +0000 (UTC) Subject: [master] 2b4ee24c0 param: New duration tweak Message-ID: <20240305085308.18116655BE@lists.varnish-cache.org> commit 2b4ee24c0fe054f83c47f30f5355118847a4847a Author: Dridi Boukelmoune Date: Mon Feb 26 17:50:41 2024 +0100 param: New duration tweak For all intents and purposes, it currently is exactly the same as the timeout tweak. The duration parameters are either not really timeouts, or timeouts that cannot be disabled. In other words, the timeout tweak will grow the ability to formally disable a timeout. Refs #3045 diff --git a/bin/varnishd/common/common_param.h b/bin/varnishd/common/common_param.h index 30e033b7c..b26440f45 100644 --- a/bin/varnishd/common/common_param.h +++ b/bin/varnishd/common/common_param.h @@ -110,6 +110,7 @@ struct params { #define ptyp_bytes_u unsigned #define ptyp_debug debug_t #define ptyp_double double +#define ptyp_duration vtim_dur #define ptyp_experimental experimental_t #define ptyp_feature feature_t #define ptyp_poolparam struct poolparam @@ -129,6 +130,7 @@ struct params { #undef ptyp_bytes_u #undef ptyp_debug #undef ptyp_double +#undef ptyp_duration #undef ptyp_experimental #undef ptyp_feature #undef ptyp_poolparam diff --git a/bin/varnishd/mgt/mgt_param.h b/bin/varnishd/mgt/mgt_param.h index 35c9c2076..83a497945 100644 --- a/bin/varnishd/mgt/mgt_param.h +++ b/bin/varnishd/mgt/mgt_param.h @@ -74,6 +74,7 @@ tweak_t tweak_boolean; tweak_t tweak_bytes; tweak_t tweak_bytes_u; tweak_t tweak_double; +tweak_t tweak_duration; tweak_t tweak_debug; tweak_t tweak_experimental; tweak_t tweak_feature; diff --git a/bin/varnishd/mgt/mgt_param_tweak.c b/bin/varnishd/mgt/mgt_param_tweak.c index e80054244..8ad63d821 100644 --- a/bin/varnishd/mgt/mgt_param_tweak.c +++ b/bin/varnishd/mgt/mgt_param_tweak.c @@ -142,6 +142,13 @@ tweak_timeout(struct vsb *vsb, const struct parspec *par, const char *arg) return (tweak_generic_double(vsb, arg, par, parse_duration, "%.3f")); } +int v_matchproto_(tweak_t) +tweak_duration(struct vsb *vsb, const struct parspec *par, const char *arg) +{ + + return (tweak_generic_double(vsb, arg, par, parse_duration, "%.3f")); +} + /*--------------------------------------------------------------------*/ int v_matchproto_(tweak_t) diff --git a/include/tbl/params.h b/include/tbl/params.h index d8f485c71..27127e15b 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -97,7 +97,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ acceptor_sleep_incr, - /* type */ timeout, + /* type */ duration, /* min */ "0", /* max */ "1", /* def */ "0", @@ -112,7 +112,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ acceptor_sleep_max, - /* type */ timeout, + /* type */ duration, /* min */ "0", /* max */ "10", /* def */ "0.05", @@ -182,7 +182,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ ban_lurker_age, - /* type */ timeout, + /* type */ duration, /* min */ "0", /* max */ NULL, /* def */ "60", @@ -211,7 +211,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ ban_lurker_sleep, - /* type */ timeout, + /* type */ duration, /* min */ "0", /* max */ NULL, /* def */ "0.010", @@ -225,7 +225,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ ban_lurker_holdoff, - /* type */ timeout, + /* type */ duration, /* min */ "0", /* max */ NULL, /* def */ "0.010", @@ -267,7 +267,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ backend_idle_timeout, - /* type */ timeout, + /* type */ duration, /* min */ "1", /* max */ NULL, /* def */ "60", @@ -278,7 +278,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ backend_local_error_holddown, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "10.000", @@ -296,7 +296,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ backend_remote_error_holddown, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "0.250", @@ -361,7 +361,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ clock_step, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "1.000", @@ -387,7 +387,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ critbit_cooloff, - /* type */ timeout, + /* type */ duration, /* min */ "60.000", /* max */ "254.000", /* def */ "180.000", @@ -400,7 +400,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ default_grace, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "10s", @@ -417,7 +417,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ default_keep, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "0s", @@ -435,7 +435,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ default_ttl, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "2m", @@ -670,7 +670,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ lru_interval, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "2.000", @@ -836,7 +836,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ shortlived, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "10.000", @@ -895,7 +895,7 @@ PARAM_SIMPLE( #endif PARAM_SIMPLE( /* name */ tcp_keepalive_intvl, - /* type */ timeout, + /* type */ duration, /* min */ "1", /* max */ "100", /* def */ NULL, @@ -928,7 +928,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ tcp_keepalive_time, - /* type */ timeout, + /* type */ duration, /* min */ "1", /* max */ "7200", /* def */ NULL, @@ -1017,7 +1017,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ vcl_cooldown, - /* type */ timeout, + /* type */ duration, /* min */ "1.000", /* max */ NULL, /* def */ "600.000", @@ -1055,7 +1055,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ vsm_free_cooldown, - /* type */ timeout, + /* type */ duration, /* min */ "10.000", /* max */ "600.000", /* def */ "60.000", @@ -1275,7 +1275,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ h2_rapid_reset, - /* typ */ timeout, + /* typ */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "1.000", @@ -1305,7 +1305,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ h2_rapid_reset_period, - /* typ */ timeout, + /* typ */ duration, /* min */ "1.000", /* max */ NULL, /* def */ "60.000", @@ -1458,7 +1458,7 @@ PARAM_THREAD( PARAM_THREAD( /* name */ thread_pool_timeout, /* field */ timeout, - /* type */ timeout, + /* type */ duration, /* min */ "10", /* max */ NULL, /* def */ "300", @@ -1474,7 +1474,7 @@ PARAM_THREAD( PARAM_THREAD( /* name */ thread_pool_watchdog, /* field */ watchdog, - /* type */ timeout, + /* type */ duration, /* min */ "0.1", /* max */ NULL, /* def */ "60", @@ -1490,7 +1490,7 @@ PARAM_THREAD( PARAM_THREAD( /* name */ thread_pool_destroy_delay, /* field */ destroy_delay, - /* type */ timeout, + /* type */ duration, /* min */ "0.01", /* max */ NULL, /* def */ "1", @@ -1505,7 +1505,7 @@ PARAM_THREAD( PARAM_THREAD( /* name */ thread_pool_add_delay, /* field */ add_delay, - /* type */ timeout, + /* type */ duration, /* min */ "0", /* max */ NULL, /* def */ "0", @@ -1525,7 +1525,7 @@ PARAM_THREAD( PARAM_THREAD( /* name */ thread_pool_fail_delay, /* field */ fail_delay, - /* type */ timeout, + /* type */ duration, /* min */ ".01", /* max */ NULL, /* def */ "0.2", From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:08 +0000 (UTC) Subject: [master] 36087a87d param: Tweak timeouts with the special value "never" Message-ID: <20240305085308.34D7B655C1@lists.varnish-cache.org> commit 36087a87d00d4309096303d01afcf013222772be Author: Dridi Boukelmoune Date: Mon Feb 26 19:10:09 2024 +0100 param: Tweak timeouts with the special value "never" diff --git a/bin/varnishd/mgt/mgt_param_tweak.c b/bin/varnishd/mgt/mgt_param_tweak.c index 8ad63d821..be0af0b62 100644 --- a/bin/varnishd/mgt/mgt_param_tweak.c +++ b/bin/varnishd/mgt/mgt_param_tweak.c @@ -138,6 +138,22 @@ parse_duration(const char *p, const char **err) int v_matchproto_(tweak_t) tweak_timeout(struct vsb *vsb, const struct parspec *par, const char *arg) { + volatile double *dest = par->priv; + + if (arg != NULL && !strcmp(arg, "never")) { + *dest = INFINITY; + return (0); + } + + if (*dest == INFINITY && arg == NULL) { + VSB_cat(vsb, "never"); + return (0); + } + + if (*dest == INFINITY && arg == JSON_FMT) { + VSB_cat(vsb, "\"never\""); + return (0); + } return (tweak_generic_double(vsb, arg, par, parse_duration, "%.3f")); } From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:08 +0000 (UTC) Subject: [master] 6e4d4b3b5 param: Document timeout "never" with a pseudo-flag Message-ID: <20240305085308.5AD3E655C6@lists.varnish-cache.org> commit 6e4d4b3b5f9dc782431a48e4c3e27d0e9396a86a Author: Dridi Boukelmoune Date: Mon Feb 26 19:11:12 2024 +0100 param: Document timeout "never" with a pseudo-flag The timeout type is the authority from which both the tweak and flag are derived. diff --git a/bin/varnishd/mgt/mgt_param.c b/bin/varnishd/mgt/mgt_param.c index d305a1006..009ad7618 100644 --- a/bin/varnishd/mgt/mgt_param.c +++ b/bin/varnishd/mgt/mgt_param.c @@ -62,6 +62,10 @@ static const int tab0 = 3; /*--------------------------------------------------------------------*/ +static const char TYPE_TIMEOUT_TEXT[] = + "\n\n" + "NB: This parameter can be disabled with the value \"never\"."; + static const char OBJ_STICKY_TEXT[] = "\n\n" "NB: This parameter is evaluated only when objects are created. " @@ -337,6 +341,8 @@ mcf_param_show(struct cli *cli, const char * const *av, void *priv) margin1, "", pp->max); VCLI_Out(cli, "\n"); mcf_wrap(cli, pp->descr); + if (pp->func == tweak_timeout) + mcf_wrap(cli, TYPE_TIMEOUT_TEXT); if (pp->flags & OBJ_STICKY) mcf_wrap(cli, OBJ_STICKY_TEXT); if (pp->flags & DELAYED_EFFECT) @@ -825,6 +831,7 @@ MCF_DumpRstParam(void) struct plist *pl; const struct parspec *pp; const char *p, *q, *t1, *t2; + unsigned flags; size_t z; printf("\n.. The following is the autogenerated " @@ -857,35 +864,42 @@ MCF_DumpRstParam(void) MCF_DYN_REASON(Minimum, min); MCF_DYN_REASON(Maximum, max); #undef MCF_DYN_REASON - if (pp->flags & ~DOCS_FLAGS) { + flags = pp->flags & ~DOCS_FLAGS; + if (pp->func == tweak_timeout) + flags |= TYPE_TIMEOUT; + if (flags) { printf("\t* Flags: "); q = ""; - if (pp->flags & DELAYED_EFFECT) { + if (flags & TYPE_TIMEOUT) { + printf("%stimeout", q); + q = ", "; + } + if (flags & DELAYED_EFFECT) { printf("%sdelayed", q); q = ", "; } - if (pp->flags & MUST_RESTART) { + if (flags & MUST_RESTART) { printf("%smust_restart", q); q = ", "; } - if (pp->flags & MUST_RELOAD) { + if (flags & MUST_RELOAD) { printf("%smust_reload", q); q = ", "; } - if (pp->flags & EXPERIMENTAL) { + if (flags & EXPERIMENTAL) { printf("%sexperimental", q); q = ", "; } - if (pp->flags & WIZARD) { + if (flags & WIZARD) { printf("%swizard", q); q = ", "; } - if (pp->flags & ONLY_ROOT) { + if (flags & ONLY_ROOT) { printf("%sonly_root", q); q = ", "; } - if (pp->flags & OBJ_STICKY) { + if (flags & OBJ_STICKY) { printf("%sobj_sticky", q); q = ", "; } diff --git a/bin/varnishd/mgt/mgt_param.h b/bin/varnishd/mgt/mgt_param.h index 83a497945..c88aef212 100644 --- a/bin/varnishd/mgt/mgt_param.h +++ b/bin/varnishd/mgt/mgt_param.h @@ -58,6 +58,7 @@ struct parspec { #define NOT_IMPLEMENTED (1<<8) #define PLATFORM_DEPENDENT (1<<9) #define BUILD_OPTIONS (1<<10) +#define TYPE_TIMEOUT (1<<11) #define DOCS_FLAGS (NOT_IMPLEMENTED|PLATFORM_DEPENDENT|BUILD_OPTIONS) diff --git a/doc/sphinx/reference/varnishd.rst b/doc/sphinx/reference/varnishd.rst index 002de7d73..3f7dfcb1b 100644 --- a/doc/sphinx/reference/varnishd.rst +++ b/doc/sphinx/reference/varnishd.rst @@ -590,7 +590,7 @@ A duration parameter may accept the following units suffixes: - ``w`` (weeks) - ``y`` (years) -If the parameter is a timeout or a deadline, a value of zero (when allowed) +If the parameter is a timeout or a deadline, a value of "never" (when allowed) disables the effect of the parameter. Run Time Parameter Flags From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:08 +0000 (UTC) Subject: [master] 1a49e049d vcl: Session timeouts can now be unset Message-ID: <20240305085308.8B749655CB@lists.varnish-cache.org> commit 1a49e049d787005deab2afd1bd143404402f5a09 Author: Dridi Boukelmoune Date: Wed Feb 28 17:01:56 2024 +0100 vcl: Session timeouts can now be unset They were already relying on NAN to fall back to parameters. diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c index 9a14519b8..e509aea4b 100644 --- a/bin/varnishd/cache/cache_vrt_var.c +++ b/bin/varnishd/cache/cache_vrt_var.c @@ -1135,7 +1135,7 @@ set_idle_send_timeout(const struct sess *sp, VCL_DURATION d) #define SESS_VAR_DUR(x, setter) \ VCL_VOID \ -VRT_l_sess_##x(VRT_CTX, VCL_DURATION d) \ +VRT_l_sess_##x(VRT_CTX, VCL_DURATION d) \ { \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \ @@ -1145,11 +1145,19 @@ VRT_l_sess_##x(VRT_CTX, VCL_DURATION d) \ } \ \ VCL_DURATION \ -VRT_r_sess_##x(VRT_CTX) \ +VRT_r_sess_##x(VRT_CTX) \ { \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \ return (SESS_TMO(ctx->sp, x)); \ +} \ + \ +VCL_VOID \ +VRT_u_sess_##x(VRT_CTX) \ +{ \ + CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ + CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \ + ctx->sp->x = NAN; \ } SESS_VAR_DUR(timeout_idle, ) diff --git a/bin/varnishtest/tests/v00069.vtc b/bin/varnishtest/tests/v00069.vtc new file mode 100644 index 000000000..03ffcfdaa --- /dev/null +++ b/bin/varnishtest/tests/v00069.vtc @@ -0,0 +1,61 @@ +varnishtest "Unset session timeouts" + +varnish v1 -cliok "param.set timeout_idle 42" +varnish v1 -cliok "param.set timeout_linger 42" +varnish v1 -cliok "param.set idle_send_timeout 42" +varnish v1 -cliok "param.set send_timeout 42" + +varnish v1 -vcl { + backend be none; + + sub vcl_recv { + return (synth(200)); + } + + sub vcl_synth { + set resp.http.def_timeout_idle = sess.timeout_idle; + set resp.http.def_timeout_linger = sess.timeout_linger; + set resp.http.def_idle_send_timeout = sess.idle_send_timeout; + set resp.http.def_send_timeout = sess.send_timeout; + + set sess.timeout_idle = 0s; + set sess.timeout_linger = 0s; + set sess.idle_send_timeout = 0s; + set sess.send_timeout = 0s; + + set resp.http.set_timeout_idle = sess.timeout_idle; + set resp.http.set_timeout_linger = sess.timeout_linger; + set resp.http.set_idle_send_timeout = sess.idle_send_timeout; + set resp.http.set_send_timeout = sess.send_timeout; + + unset sess.timeout_idle; + unset sess.timeout_linger; + unset sess.idle_send_timeout; + unset sess.send_timeout; + + set resp.http.unset_timeout_idle = sess.timeout_idle; + set resp.http.unset_timeout_linger = sess.timeout_linger; + set resp.http.unset_idle_send_timeout = sess.idle_send_timeout; + set resp.http.unset_send_timeout = sess.send_timeout; + } +} -start + +client c1 { + txreq + rxresp + + expect resp.http.def_timeout_idle == 42.000 + expect resp.http.def_timeout_linger == 42.000 + expect resp.http.def_idle_send_timeout == 42.000 + expect resp.http.def_send_timeout == 42.000 + + expect resp.http.set_timeout_idle == 0.000 + expect resp.http.set_timeout_linger == 0.000 + expect resp.http.set_idle_send_timeout == 0.000 + expect resp.http.set_send_timeout == 0.000 + + expect resp.http.unset_timeout_idle == 42.000 + expect resp.http.unset_timeout_linger == 42.000 + expect resp.http.unset_idle_send_timeout == 42.000 + expect resp.http.unset_send_timeout == 42.000 +} -run diff --git a/doc/sphinx/reference/vcl_var.rst b/doc/sphinx/reference/vcl_var.rst index 16bb9c8c7..3be25d54e 100644 --- a/doc/sphinx/reference/vcl_var.rst +++ b/doc/sphinx/reference/vcl_var.rst @@ -1781,6 +1781,8 @@ sess.idle_send_timeout Writable from: client + Unsetable from: client + Send timeout for individual pieces of data on client connections, defaults to the ``idle_send_timeout`` parameter, see :ref:`varnishd(1)` @@ -1796,6 +1798,8 @@ sess.send_timeout Writable from: client + Unsetable from: client + Total timeout for ordinary HTTP1 responses, defaults to the ``send_timeout`` parameter, see :ref:`varnishd(1)` @@ -1810,6 +1814,8 @@ sess.timeout_idle Writable from: client + Unsetable from: client + Idle timeout for this session, defaults to the ``timeout_idle`` parameter, see :ref:`varnishd(1)` @@ -1824,6 +1830,8 @@ sess.timeout_linger Writable from: client + Unsetable from: client + Linger timeout for this session, defaults to the ``timeout_linger`` parameter, see :ref:`varnishd(1)` diff --git a/include/vrt.h b/include/vrt.h index f5ea03bc5..8bbdf8186 100644 --- a/include/vrt.h +++ b/include/vrt.h @@ -60,6 +60,10 @@ * NEXT (2024-03-15) * [cache.h] (struct req).filter_list renamed to vdp_filter_list * order of vcl/vmod and director COLD events reversed to directors first + * VRT_u_sess_idle_send_timeout() added + * VRT_u_sess_send_timeout() added + * VRT_u_sess_timeout_idle() added + * VRT_u_sess_timeout_linger() added * 18.1 (2023-12-05) * vbf_objiterate() implementation changed #4013 * 18.0 (2023-09-15) From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:08 +0000 (UTC) Subject: [master] 119056c4d vcc_backend: Initialize undefined timeouts with -1 Message-ID: <20240305085308.B576B655CF@lists.varnish-cache.org> commit 119056c4d9319155c6c6c2148519d2e8d81d5f76 Author: Dridi Boukelmoune Date: Wed Feb 28 17:35:32 2024 +0100 vcc_backend: Initialize undefined timeouts with -1 We can't use NAN in VGC code today, so in order to convey the lack of timeout setting in a backend definition, only a negative value makes sense since zero will eventually mean zero instead of undefined. This is an implicit breakage of the VRT ABI for the meaning of struct vrt_backend. diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c index 7b273c5b7..02bb82996 100644 --- a/bin/varnishd/cache/cache_backend.c +++ b/bin/varnishd/cache/cache_backend.c @@ -99,7 +99,7 @@ VBE_Connect_Error(struct VSC_vbe *vsc, int err) do { \ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); \ dst = bo->tmx; \ - if (dst == 0.0) \ + if (dst == 0.0 && be->tmx >= 0.0) \ dst = be->tmx; \ if (dst == 0.0) \ dst = cache_param->tmx; \ diff --git a/include/vrt.h b/include/vrt.h index 8bbdf8186..a9c347aab 100644 --- a/include/vrt.h +++ b/include/vrt.h @@ -64,6 +64,8 @@ * VRT_u_sess_send_timeout() added * VRT_u_sess_timeout_idle() added * VRT_u_sess_timeout_linger() added + * (struct vrt_backend).*_timeout must be initialized to a negative value + * VRT_BACKEND_INIT() helper macro added * 18.1 (2023-12-05) * vbf_objiterate() implementation changed #4013 * 18.0 (2023-09-15) @@ -582,6 +584,14 @@ struct vrt_endpoint { unsigned max_connections; \ unsigned proxy_header; +#define VRT_BACKEND_INIT(be) \ + do { \ + INIT_OBJ(be, VRT_BACKEND_MAGIC); \ + (be)->connect_timeout = -1.0; \ + (be)->first_byte_timeout = -1.0; \ + (be)->between_bytes_timeout = -1.0; \ + } while(0) + #define VRT_BACKEND_HANDLE() \ do { \ DA(vcl_name); \ diff --git a/lib/libvcc/vcc_backend.c b/lib/libvcc/vcc_backend.c index c199e2d36..8d40c472f 100644 --- a/lib/libvcc/vcc_backend.c +++ b/lib/libvcc/vcc_backend.c @@ -32,6 +32,7 @@ #include "config.h" +#include #include #include #include @@ -381,9 +382,11 @@ vcc_ParseHostDef(struct vcc *tl, struct symbol *sym, struct inifin *ifp; struct vsb *vsb1; struct symbol *via = NULL; + vtim_dur connect_timeout = NAN; + vtim_dur first_byte_timeout = NAN; + vtim_dur between_bytes_timeout = NAN; char *p; unsigned u; - double t; if (tl->t->tok == ID && (vcc_IdIs(tl->t, "none") || vcc_IdIs(tl->t, "None"))) { @@ -480,21 +483,21 @@ vcc_ParseHostDef(struct vcc *tl, struct symbol *sym, SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "connect_timeout")) { Fb(tl, 0, "\t.connect_timeout = "); - vcc_Duration(tl, &t); + vcc_Duration(tl, &connect_timeout); ERRCHK(tl); - Fb(tl, 0, "%g,\n", t); + Fb(tl, 0, "%g,\n", connect_timeout); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "first_byte_timeout")) { Fb(tl, 0, "\t.first_byte_timeout = "); - vcc_Duration(tl, &t); + vcc_Duration(tl, &first_byte_timeout); ERRCHK(tl); - Fb(tl, 0, "%g,\n", t); + Fb(tl, 0, "%g,\n", first_byte_timeout); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "between_bytes_timeout")) { Fb(tl, 0, "\t.between_bytes_timeout = "); - vcc_Duration(tl, &t); + vcc_Duration(tl, &between_bytes_timeout); ERRCHK(tl); - Fb(tl, 0, "%g,\n", t); + Fb(tl, 0, "%g,\n", between_bytes_timeout); SkipToken(tl, ';'); } else if (vcc_IdIs(t_field, "max_connections")) { u = vcc_UintVal(tl); @@ -581,6 +584,13 @@ vcc_ParseHostDef(struct vcc *tl, struct symbol *sym, free(fs); ERRCHK(tl); + if (isnan(connect_timeout)) + Fb(tl, 0, "\t.connect_timeout = -1.0,\n"); + if (isnan(first_byte_timeout)) + Fb(tl, 0, "\t.first_byte_timeout = -1.0,\n"); + if (isnan(between_bytes_timeout)) + Fb(tl, 0, "\t.between_bytes_timeout = -1.0,\n"); + ExpectErr(tl, '}'); if (t_host == NULL && t_path == NULL) { diff --git a/vmod/vmod_debug_dyn.c b/vmod/vmod_debug_dyn.c index 4714c436b..6b83299e4 100644 --- a/vmod/vmod_debug_dyn.c +++ b/vmod/vmod_debug_dyn.c @@ -75,7 +75,7 @@ dyn_dir_init(VRT_CTX, struct xyzzy_debug_dyn *dyn, CHECK_OBJ_ORNULL(via, DIRECTOR_MAGIC); INIT_OBJ(&vep, VRT_ENDPOINT_MAGIC); - INIT_OBJ(&vrt, VRT_BACKEND_MAGIC); + VRT_BACKEND_INIT(&vrt); vrt.endpoint = &vep; vrt.vcl_name = dyn->vcl_name; vrt.hosthdr = addr; @@ -206,7 +206,7 @@ dyn_uds_init(VRT_CTX, struct xyzzy_debug_dyn_uds *uds, VCL_STRING path) } INIT_OBJ(&vep, VRT_ENDPOINT_MAGIC); - INIT_OBJ(&vrt, VRT_BACKEND_MAGIC); + VRT_BACKEND_INIT(&vrt); vrt.endpoint = &vep; vep.uds_path = path; vrt.vcl_name = uds->vcl_name; From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:08 +0000 (UTC) Subject: [master] 75ea7f62b vcl: All bereq timeouts can now be unset Message-ID: <20240305085308.EB16B655E0@lists.varnish-cache.org> commit 75ea7f62bcd5add6d0b934a85d33105e04e943c7 Author: Dridi Boukelmoune Date: Wed Feb 28 19:01:19 2024 +0100 vcl: All bereq timeouts can now be unset Unlike session timeouts, they were not falling back to their parameter counterparts from NAN. Since NAN is not allowed in VCL, they now behave like session timeouts, returning their value or falling back to the parameter when unset. diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h index 7d6b68457..10fab7e8d 100644 --- a/bin/varnishd/cache/cache.h +++ b/bin/varnishd/cache/cache.h @@ -446,6 +446,9 @@ struct busyobj { const char *client_identity; }; +#define BUSYOBJ_TMO(bo, pfx, tmo) \ + (isnan((bo)->tmo) ? cache_param->pfx##tmo : (bo)->tmo) + /*--------------------------------------------------------------------*/ diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c index 02bb82996..935527015 100644 --- a/bin/varnishd/cache/cache_backend.c +++ b/bin/varnishd/cache/cache_backend.c @@ -99,9 +99,9 @@ VBE_Connect_Error(struct VSC_vbe *vsc, int err) do { \ CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); \ dst = bo->tmx; \ - if (dst == 0.0 && be->tmx >= 0.0) \ + if (isnan(dst) && be->tmx >= 0.0) \ dst = be->tmx; \ - if (dst == 0.0) \ + if (isnan(dst)) \ dst = cache_param->tmx; \ } while (0) diff --git a/bin/varnishd/cache/cache_busyobj.c b/bin/varnishd/cache/cache_busyobj.c index 9a5fe36d1..593bdfe43 100644 --- a/bin/varnishd/cache/cache_busyobj.c +++ b/bin/varnishd/cache/cache_busyobj.c @@ -142,6 +142,9 @@ VBO_GetBusyObj(const struct worker *wrk, const struct req *req) VCL_Ref(bo->vcl); bo->t_first = bo->t_prev = NAN; + bo->connect_timeout = NAN; + bo->first_byte_timeout = NAN; + bo->between_bytes_timeout = NAN; memcpy(bo->digest, req->digest, sizeof bo->digest); diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c index f49de59cf..f37183582 100644 --- a/bin/varnishd/cache/cache_fetch.c +++ b/bin/varnishd/cache/cache_fetch.c @@ -332,6 +332,9 @@ vbf_stp_retry(struct worker *wrk, struct busyobj *bo) bo->was_304 = 0; bo->err_code = 0; bo->err_reason = NULL; + bo->connect_timeout = NAN; + bo->first_byte_timeout = NAN; + bo->between_bytes_timeout = NAN; if (bo->htc != NULL) bo->htc->doclose = SC_NULL; diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c index e509aea4b..5f5cc75fe 100644 --- a/bin/varnishd/cache/cache_vrt_var.c +++ b/bin/varnishd/cache/cache_vrt_var.c @@ -387,26 +387,14 @@ VRT_l_client_identity(VRT_CTX, const char *str, VCL_STRANDS s) /*--------------------------------------------------------------------*/ -#define BEREQ_TIMEOUT_UNSET0(which) - -#define BEREQ_TIMEOUT_UNSET1(which) \ -VCL_VOID \ -VRT_u_bereq_##which(VRT_CTX) \ -{ \ - \ - CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ - CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \ - ctx->bo->which = NAN; \ -} - -#define BEREQ_TIMEOUT(which, unset) \ +#define BEREQ_TIMEOUT(prefix, which) \ VCL_VOID \ VRT_l_bereq_##which(VRT_CTX, VCL_DURATION num) \ { \ \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \ - ctx->bo->which = (num > 0.0 ? num : 0.0); \ + ctx->bo->which = num; \ } \ \ VCL_DURATION \ @@ -415,15 +403,22 @@ VRT_r_bereq_##which(VRT_CTX) \ \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \ - return (ctx->bo->which); \ + return (BUSYOBJ_TMO(ctx->bo, prefix, which)); \ } \ \ -BEREQ_TIMEOUT_UNSET##unset(which) +VCL_VOID \ +VRT_u_bereq_##which(VRT_CTX) \ +{ \ + \ + CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ + CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \ + ctx->bo->which = NAN; \ +} -BEREQ_TIMEOUT(connect_timeout, 0) -BEREQ_TIMEOUT(first_byte_timeout, 0) -BEREQ_TIMEOUT(between_bytes_timeout, 0) -BEREQ_TIMEOUT(task_deadline, 1) +BEREQ_TIMEOUT(, connect_timeout) +BEREQ_TIMEOUT(, first_byte_timeout) +BEREQ_TIMEOUT(, between_bytes_timeout) +BEREQ_TIMEOUT(pipe_, task_deadline) /*--------------------------------------------------------------------*/ diff --git a/bin/varnishtest/tests/v00070.vtc b/bin/varnishtest/tests/v00070.vtc new file mode 100644 index 000000000..57aa2c235 --- /dev/null +++ b/bin/varnishtest/tests/v00070.vtc @@ -0,0 +1,52 @@ +varnishtest "Unset bereq timeouts" + +varnish v1 -cliok "param.set connect_timeout 42" +varnish v1 -cliok "param.set first_byte_timeout 42" +varnish v1 -cliok "param.set between_bytes_timeout 42" + +varnish v1 -vcl { + backend be none; + + sub vcl_backend_fetch { + return (error(200)); + } + + sub vcl_backend_error { + set beresp.http.def_connect_timeout = bereq.connect_timeout; + set beresp.http.def_first_byte_timeout = bereq.first_byte_timeout; + set beresp.http.def_between_bytes_timeout = bereq.between_bytes_timeout; + + set bereq.connect_timeout = 0s; + set bereq.first_byte_timeout = 0s; + set bereq.between_bytes_timeout = 0s; + + set beresp.http.set_connect_timeout = bereq.connect_timeout; + set beresp.http.set_first_byte_timeout = bereq.first_byte_timeout; + set beresp.http.set_between_bytes_timeout = bereq.between_bytes_timeout; + + unset bereq.connect_timeout; + unset bereq.first_byte_timeout; + unset bereq.between_bytes_timeout; + + set beresp.http.unset_connect_timeout = bereq.connect_timeout; + set beresp.http.unset_first_byte_timeout = bereq.first_byte_timeout; + set beresp.http.unset_between_bytes_timeout = bereq.between_bytes_timeout; + } +} -start + +client c1 { + txreq + rxresp + + expect resp.http.def_connect_timeout == 42.000 + expect resp.http.def_first_byte_timeout == 42.000 + expect resp.http.def_between_bytes_timeout == 42.000 + + expect resp.http.set_connect_timeout == 0.000 + expect resp.http.set_first_byte_timeout == 0.000 + expect resp.http.set_between_bytes_timeout == 0.000 + + expect resp.http.unset_connect_timeout == 42.000 + expect resp.http.unset_first_byte_timeout == 42.000 + expect resp.http.unset_between_bytes_timeout == 42.000 +} -run diff --git a/doc/sphinx/reference/vcl_var.rst b/doc/sphinx/reference/vcl_var.rst index 3be25d54e..469721164 100644 --- a/doc/sphinx/reference/vcl_var.rst +++ b/doc/sphinx/reference/vcl_var.rst @@ -652,6 +652,8 @@ bereq.between_bytes_timeout Writable from: backend + Unsetable from: vcl_pipe, backend + Default: ``.between_bytes_timeout`` attribute from the :ref:`backend_definition`, which defaults to the ``between_bytes_timeout`` parameter, see :ref:`varnishd(1)`. @@ -682,6 +684,8 @@ bereq.connect_timeout Writable from: vcl_pipe, backend + Unsetable from: vcl_pipe, backend + Default: ``.connect_timeout`` attribute from the :ref:`backend_definition`, which defaults to the ``connect_timeout`` parameter, see :ref:`varnishd(1)`. @@ -700,6 +704,8 @@ bereq.first_byte_timeout Writable from: backend + Unsetable from: vcl_pipe, backend + Default: ``.first_byte_timeout`` attribute from the :ref:`backend_definition`, which defaults to the ``first_byte_timeout`` parameter, see :ref:`varnishd(1)`. diff --git a/include/vrt.h b/include/vrt.h index a9c347aab..5599ac7c9 100644 --- a/include/vrt.h +++ b/include/vrt.h @@ -66,6 +66,12 @@ * VRT_u_sess_timeout_linger() added * (struct vrt_backend).*_timeout must be initialized to a negative value * VRT_BACKEND_INIT() helper macro added + * VRT_l_bereq_task_deadline() added + * VRT_r_bereq_task_deadline() added + * VRT_u_bereq_task_deadline() added + * VRT_u_bereq_between_bytes_timeout() added + * VRT_u_bereq_connect_timeout() added + * VRT_u_bereq_first_byte_timeout() added * 18.1 (2023-12-05) * vbf_objiterate() implementation changed #4013 * 18.0 (2023-09-15) From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:09 +0000 (UTC) Subject: [master] d2cbad5e2 backend_probe: Use a VTIM duration Message-ID: <20240305085309.18245655EC@lists.varnish-cache.org> commit d2cbad5e2e9cfdbd2f733b4e8e140155bea2725e Author: Dridi Boukelmoune Date: Thu Feb 29 11:58:41 2024 +0100 backend_probe: Use a VTIM duration diff --git a/bin/varnishd/cache/cache_backend_probe.c b/bin/varnishd/cache/cache_backend_probe.c index 96101fa13..6de4eeb89 100644 --- a/bin/varnishd/cache/cache_backend_probe.c +++ b/bin/varnishd/cache/cache_backend_probe.c @@ -273,8 +273,9 @@ vbp_write_proxy_v1(struct vbp_target *vt, int *sock) static void vbp_poke(struct vbp_target *vt) { - int s, tmo, i, proxy_header, err; + int s, i, proxy_header, err; vtim_real t_start, t_now, t_end; + vtim_dur tmo; unsigned rlen, resp; char buf[8192], *p; struct pollfd pfda[1], *pfd = pfda; @@ -304,11 +305,11 @@ vbp_poke(struct vbp_target *vt) WRONG("Wrong probe protocol family"); t_now = VTIM_real(); - tmo = (int)round((t_end - t_now) * 1e3); + tmo = t_end - t_now; if (tmo <= 0) { bprintf(vt->resp_buf, "Open timeout %.3fs exceeded by %.3fs", - vt->timeout, t_now - t_end); + vt->timeout, -tmo); VTCP_close(&s); return; } @@ -347,15 +348,15 @@ vbp_poke(struct vbp_target *vt) pfd->events = POLLIN; pfd->revents = 0; t_now = VTIM_real(); - tmo = (int)round((t_end - t_now) * 1e3); + tmo = t_end - t_now; if (tmo <= 0) { bprintf(vt->resp_buf, "Poll timeout %.3fs exceeded by %.3fs", - vt->timeout, t_now - t_end); + vt->timeout, -tmo); i = -1; break; } - i = poll(pfd, 1, tmo); + i = poll(pfd, 1, VTIM_poll_tmo(tmo)); if (i <= 0) { if (!i) { if (!vt->exp_close) From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:09 +0000 (UTC) Subject: [master] 809426564 vtim: VTIM_timeval() for socket timeouts Message-ID: <20240305085309.3A4F4655FC@lists.varnish-cache.org> commit 80942656483b7b4b183ea5787f45d7f9f6586116 Author: Dridi Boukelmoune Date: Thu Feb 29 12:30:09 2024 +0100 vtim: VTIM_timeval() for socket timeouts diff --git a/include/vtim.h b/include/vtim.h index 042feedb1..9652238c0 100644 --- a/include/vtim.h +++ b/include/vtim.h @@ -40,4 +40,5 @@ vtim_real VTIM_real(void); void VTIM_sleep(vtim_dur t); struct timespec VTIM_timespec(vtim_dur t); struct timeval VTIM_timeval(vtim_dur t); +struct timeval VTIM_timeval_sock(vtim_dur t); int VTIM_poll_tmo(vtim_dur); diff --git a/lib/libvarnish/vtim.c b/lib/libvarnish/vtim.c index 33907432a..7485acb2e 100644 --- a/lib/libvarnish/vtim.c +++ b/lib/libvarnish/vtim.c @@ -454,6 +454,13 @@ VTIM_timespec(vtim_dur t) return (tv); } +struct timeval +VTIM_timeval_sock(vtim_dur t) +{ + + return (VTIM_timeval(isinf(t) ? 0. : vmax(t, 1e-3))); +} + int VTIM_poll_tmo(vtim_dur tmo) { From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:09 +0000 (UTC) Subject: [master] b4a094787 vca: Apply "never" socket timeouts Message-ID: <20240305085309.56CC365600@lists.varnish-cache.org> commit b4a094787b25b0d3571dc50829610cafe6b33129 Author: Dridi Boukelmoune Date: Thu Feb 29 12:30:35 2024 +0100 vca: Apply "never" socket timeouts diff --git a/bin/varnishd/cache/cache_acceptor.c b/bin/varnishd/cache/cache_acceptor.c index e229c7db4..ece80e3b6 100644 --- a/bin/varnishd/cache/cache_acceptor.c +++ b/bin/varnishd/cache/cache_acceptor.c @@ -204,9 +204,9 @@ vca_sock_opt_init(void) SET_VAL(SO_LINGER, so, lg, disable_so_linger); SET_VAL(SO_KEEPALIVE, so, i, enable_so_keepalive); NEW_VAL(SO_SNDTIMEO, so, tv, - VTIM_timeval(cache_param->idle_send_timeout)); + VTIM_timeval_sock(cache_param->idle_send_timeout)); NEW_VAL(SO_RCVTIMEO, so, tv, - VTIM_timeval(cache_param->timeout_idle)); + VTIM_timeval_sock(cache_param->timeout_idle)); SET_VAL(TCP_NODELAY, so, i, enable_tcp_nodelay); #if defined(HAVE_TCP_KEEP) NEW_VAL(TCP_KEEPIDLE, so, i, From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:09 +0000 (UTC) Subject: [master] 38ad554a5 vtcp: Apply "never" socket timeouts Message-ID: <20240305085309.7AC8D65613@lists.varnish-cache.org> commit 38ad554a5ba6d457f0fb7af232b7d375b6fb0560 Author: Dridi Boukelmoune Date: Thu Feb 29 12:31:32 2024 +0100 vtcp: Apply "never" socket timeouts diff --git a/lib/libvarnish/vtcp.c b/lib/libvarnish/vtcp.c index c15dfdedf..207b8f80d 100644 --- a/lib/libvarnish/vtcp.c +++ b/lib/libvarnish/vtcp.c @@ -349,7 +349,7 @@ VTCP_close(int *s) void VTCP_set_read_timeout(int s, vtim_dur seconds) { - struct timeval timeout = VTIM_timeval(seconds); + struct timeval timeout = VTIM_timeval_sock(seconds); /* * Solaris bug (present at least in snv_151 and older): If this fails From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:09 +0000 (UTC) Subject: [master] cd3c9f8e0 vrt_var: Apply "never" socket timeouts Message-ID: <20240305085309.9278365632@lists.varnish-cache.org> commit cd3c9f8e06a2deb7a5af2529443079a99d666afa Author: Dridi Boukelmoune Date: Thu Feb 29 12:31:16 2024 +0100 vrt_var: Apply "never" socket timeouts diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c index 5f5cc75fe..be84f1c0c 100644 --- a/bin/varnishd/cache/cache_vrt_var.c +++ b/bin/varnishd/cache/cache_vrt_var.c @@ -1123,7 +1123,7 @@ HTTP_VAR(beresp) static inline void set_idle_send_timeout(const struct sess *sp, VCL_DURATION d) { - struct timeval tv = VTIM_timeval(d); + struct timeval tv = VTIM_timeval_sock(d); VTCP_Assert(setsockopt(sp->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv)); } From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:09 +0000 (UTC) Subject: [master] 757e71956 vrt_var: Return VRT_DECIMAL_MAX for "never" timeouts Message-ID: <20240305085309.B56A46563C@lists.varnish-cache.org> commit 757e7195664149abcc034b109c28023cc95ba879 Author: Dridi Boukelmoune Date: Thu Feb 29 12:32:12 2024 +0100 vrt_var: Return VRT_DECIMAL_MAX for "never" timeouts diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c index be84f1c0c..a7e018713 100644 --- a/bin/varnishd/cache/cache_vrt_var.c +++ b/bin/varnishd/cache/cache_vrt_var.c @@ -45,6 +45,8 @@ #include "vrt_obj.h" +#define VRT_TMO(tmo) (isinf(tmo) ? VRT_DECIMAL_MAX : tmo) + static char vrt_hostname[255] = ""; /*-------------------------------------------------------------------- @@ -403,7 +405,7 @@ VRT_r_bereq_##which(VRT_CTX) \ \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \ - return (BUSYOBJ_TMO(ctx->bo, prefix, which)); \ + return (VRT_TMO(BUSYOBJ_TMO(ctx->bo, prefix, which))); \ } \ \ VCL_VOID \ @@ -1144,7 +1146,7 @@ VRT_r_sess_##x(VRT_CTX) \ { \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \ - return (SESS_TMO(ctx->sp, x)); \ + return (VRT_TMO(SESS_TMO(ctx->sp, x))); \ } \ \ VCL_VOID \ diff --git a/bin/varnishtest/tests/v00071.vtc b/bin/varnishtest/tests/v00071.vtc new file mode 100644 index 000000000..ef073e877 --- /dev/null +++ b/bin/varnishtest/tests/v00071.vtc @@ -0,0 +1,19 @@ +varnishtest "Disabled timeout in VCL" + +varnish v1 -cliok "param.set idle_send_timeout never" + +varnish v1 -vcl { + backend be none; + sub vcl_recv { + return (synth(200)); + } + sub vcl_synth { + set resp.http.idle_send_timeout = sess.idle_send_timeout; + } +} -start + +client c1 { + txreq + rxresp + expect resp.http.idle_send_timeout == 999999999999.999 +} -run From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:09 +0000 (UTC) Subject: [master] fe3f7e9f2 vcli_proto: Use VTIM_poll_tmo() Message-ID: <20240305085309.D8F6C6564F@lists.varnish-cache.org> commit fe3f7e9f2ee74a3ae4bb0b919f18146196adbe41 Author: Dridi Boukelmoune Date: Thu Feb 29 18:09:25 2024 +0100 vcli_proto: Use VTIM_poll_tmo() diff --git a/lib/libvarnish/vcli_proto.c b/lib/libvarnish/vcli_proto.c index e0fca5cec..90a1b0b4f 100644 --- a/lib/libvarnish/vcli_proto.c +++ b/lib/libvarnish/vcli_proto.c @@ -45,6 +45,7 @@ #include "vas.h" // XXX Flexelint "not used" - but req'ed for assert() #include "vcli.h" #include "vsha256.h" +#include "vtim.h" void VCLI_AuthResponse(int S_fd, const char *challenge, @@ -110,17 +111,13 @@ VCLI_WriteResult(int fd, unsigned status, const char *result) static int read_tmo(int fd, char *ptr, unsigned len, double tmo) { - int i, j, to; + int i, j; struct pollfd pfd; - if (tmo > 0) - to = (int)(tmo * 1e3); - else - to = -1; pfd.fd = fd; pfd.events = POLLIN; for (j = 0; len > 0; ) { - i = poll(&pfd, 1, to); + i = poll(&pfd, 1, VTIM_poll_tmo(tmo)); if (i < 0) { errno = EINTR; return (-1); From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:10 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:10 +0000 (UTC) Subject: [master] a26123f31 lck: Apply "never" timeouts to cond waits Message-ID: <20240305085310.0E94065664@lists.varnish-cache.org> commit a26123f31c9171ba01a8243d9ffa64334090c0b8 Author: Dridi Boukelmoune Date: Fri Mar 1 10:41:29 2024 +0100 lck: Apply "never" timeouts to cond waits The vtim_real in Lck_CondWaitUntil() is not meant to be INFINITY, and it should only apply to the vtim_dur passed to Lck_CondWaitTimeout(). In practice it does since the latter calls the former. It could be enforced by extracting a static function from Lck_CondWaitUntil(). This accommodates a few timeout parameters that are used for cond waits. diff --git a/bin/varnishd/cache/cache_lck.c b/bin/varnishd/cache/cache_lck.c index 8f33dee8c..5c7ab42ce 100644 --- a/bin/varnishd/cache/cache_lck.c +++ b/bin/varnishd/cache/cache_lck.c @@ -209,19 +209,20 @@ Lck__Owned(const struct lock *lck) int v_matchproto_() Lck_CondWait(pthread_cond_t *cond, struct lock *lck) { - return (Lck_CondWaitUntil(cond, lck, 0)); + return (Lck_CondWaitUntil(cond, lck, INFINITY)); } int v_matchproto_() Lck_CondWaitTimeout(pthread_cond_t *cond, struct lock *lck, vtim_dur timeout) { - assert(timeout >= 0); - assert(timeout < 3600); - if (timeout == 0) - return (Lck_CondWaitUntil(cond, lck, 0)); - else - return (Lck_CondWaitUntil(cond, lck, VTIM_real() + timeout)); + if (isinf(timeout)) + return (Lck_CondWaitUntil(cond, lck, INFINITY)); + + assert(timeout >= 0); + assert(timeout <= 3600); + timeout = vmax(timeout, 1e-3); + return (Lck_CondWaitUntil(cond, lck, VTIM_real() + timeout)); } int v_matchproto_() @@ -235,7 +236,7 @@ Lck_CondWaitUntil(pthread_cond_t *cond, struct lock *lck, vtim_real when) AN(ilck->held); assert(pthread_equal(ilck->owner, pthread_self())); ilck->held = 0; - if (when == 0) { + if (isinf(when)) { errno = pthread_cond_wait(cond, &ilck->mtx); AZ(errno); } else { diff --git a/bin/varnishd/cache/cache_wrk.c b/bin/varnishd/cache/cache_wrk.c index 8803b5048..971904337 100644 --- a/bin/varnishd/cache/cache_wrk.c +++ b/bin/varnishd/cache/cache_wrk.c @@ -443,7 +443,7 @@ Pool_Work_Thread(struct pool *pp, struct worker *wrk) * chance to push stats. */ tmo = now + 1.; else if (wrk->wpriv->vcl == NULL) - tmo = 0; + tmo = INFINITY; else if (DO_DEBUG(DBG_VTC_MODE)) tmo = now + 1.; else From dridi.boukelmoune at gmail.com Tue Mar 5 08:53:10 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 08:53:10 +0000 (UTC) Subject: [master] 460b9ceaa params: Restrict some session timeouts Message-ID: <20240305085310.259E26566D@lists.varnish-cache.org> commit 460b9ceaa4f75c6b92c3f49b0f24b86044cd40ce Author: Dridi Boukelmoune Date: Fri Mar 1 10:52:26 2024 +0100 params: Restrict some session timeouts The timeout_* parameters are used in duration arithmetics and the simplest is to not grant them the ability to be disabled. Both timeout_idle and idle_send_timeout appear in a CondWait context. For this reason both need to be capped to 1h, matching the implicit limit in Lck_CondWaitTimeout(). diff --git a/include/tbl/params.h b/include/tbl/params.h index 27127e15b..5f4359594 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -643,9 +643,9 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ idle_send_timeout, /* type */ timeout, - /* min */ "0.000", - /* max */ NULL, - /* def */ "60.000", + /* min */ "0s", + /* max */ "1h", + /* def */ "60s", /* units */ "seconds", /* descr */ "Send timeout for individual pieces of data on client connections." @@ -946,10 +946,10 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ timeout_idle, - /* type */ timeout, - /* min */ "0.000", - /* max */ NULL, - /* def */ "5.000", + /* type */ duration, + /* min */ "0s", + /* max */ "1h", + /* def */ "5s", /* units */ "seconds", /* descr */ "Idle timeout for client connections.\n\n" @@ -962,7 +962,7 @@ PARAM_SIMPLE( PARAM_SIMPLE( /* name */ timeout_linger, - /* type */ timeout, + /* type */ duration, /* min */ "0.000", /* max */ NULL, /* def */ "0.050", From dridi.boukelmoune at gmail.com Tue Mar 5 09:33:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 09:33:05 +0000 (UTC) Subject: [master] 92bd45b8c vrt_var: Avoid repeated side effects in VRT_TMO() Message-ID: <20240305093305.B235C101397@lists.varnish-cache.org> commit 92bd45b8c7348f3e18dedf606c7282dd43110aab Author: Dridi Boukelmoune Date: Tue Mar 5 10:30:46 2024 +0100 vrt_var: Avoid repeated side effects in VRT_TMO() Warning 666: Expression with side effects passed to repeated parameter 1 in macro 'VRT_TMO' Spotted by Flexelint. diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c index a7e018713..60409beca 100644 --- a/bin/varnishd/cache/cache_vrt_var.c +++ b/bin/varnishd/cache/cache_vrt_var.c @@ -402,10 +402,12 @@ VRT_l_bereq_##which(VRT_CTX, VCL_DURATION num) \ VCL_DURATION \ VRT_r_bereq_##which(VRT_CTX) \ { \ + vtim_dur res; \ \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); \ - return (VRT_TMO(BUSYOBJ_TMO(ctx->bo, prefix, which))); \ + res = BUSYOBJ_TMO(ctx->bo, prefix, which); \ + return (VRT_TMO(res)); \ } \ \ VCL_VOID \ @@ -1144,9 +1146,12 @@ VRT_l_sess_##x(VRT_CTX, VCL_DURATION d) \ VCL_DURATION \ VRT_r_sess_##x(VRT_CTX) \ { \ + vtim_dur res; \ + \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx->sp, SESS_MAGIC); \ - return (VRT_TMO(SESS_TMO(ctx->sp, x))); \ + res = SESS_TMO(ctx->sp, x); \ + return (VRT_TMO(res)); \ } \ \ VCL_VOID \ From nils.goroll at uplex.de Tue Mar 5 09:48:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Tue, 5 Mar 2024 09:48:05 +0000 (UTC) Subject: [master] a95a8208a Silence flexelint complaning about BSD's isinf() implementation Message-ID: <20240305094805.E1A6E101CB3@lists.varnish-cache.org> commit a95a8208a1721d58c27c240a65f54ea7184e6c64 Author: Nils Goroll Date: Tue Mar 5 10:43:55 2024 +0100 Silence flexelint complaning about BSD's isinf() implementation diff --git a/flint.lnt b/flint.lnt index aade0a8a2..214aac5ee 100644 --- a/flint.lnt +++ b/flint.lnt @@ -135,6 +135,8 @@ // System/Posix/Iso-C library related -emacro(747, isnan) // significant coercion +-emacro(506, isinf) // Constant value Boolean +-emacro(866, isinf) // Unusual use of '?' in argument to sizeof // ignore retval -esym(534, printf) From nils.goroll at uplex.de Tue Mar 5 09:48:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Tue, 5 Mar 2024 09:48:05 +0000 (UTC) Subject: [master] fd9341dfc Flexelinting Message-ID: <20240305094806.064EE101CB6@lists.varnish-cache.org> commit fd9341dfc682b1a43b5975bb536711bea542c4f1 Author: Nils Goroll Date: Tue Mar 5 10:45:57 2024 +0100 Flexelinting diff --git a/bin/varnishd/cache/cache_esi_deliver.c b/bin/varnishd/cache/cache_esi_deliver.c index 43c9c660f..33d1a22ad 100644 --- a/bin/varnishd/cache/cache_esi_deliver.c +++ b/bin/varnishd/cache/cache_esi_deliver.c @@ -944,5 +944,5 @@ ved_deliver(struct req *req, struct boc *boc, int wantbody) if (i && req->doclose == SC_NULL) req->doclose = SC_REM_CLOSE; - ved_close(req, boc, i && ecx->abrt); + ved_close(req, boc, i && ecx->abrt ? 1 : 0); } From nils.goroll at uplex.de Tue Mar 5 10:17:05 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Tue, 5 Mar 2024 10:17:05 +0000 (UTC) Subject: [master] 882f73ab3 Silence flexelint complaning about BSD's isinf() implementation Message-ID: <20240305101705.DA80C102DDA@lists.varnish-cache.org> commit 882f73ab3c59b4921dba247df7a8372f7896abe1 Author: Nils Goroll Date: Tue Mar 5 11:15:53 2024 +0100 Silence flexelint complaning about BSD's isinf() implementation diff --git a/flint.lnt b/flint.lnt index 214aac5ee..d338254b0 100644 --- a/flint.lnt +++ b/flint.lnt @@ -137,6 +137,7 @@ -emacro(747, isnan) // significant coercion -emacro(506, isinf) // Constant value Boolean -emacro(866, isinf) // Unusual use of '?' in argument to sizeof +-emacro(736, isinf) // Loss of precision // ignore retval -esym(534, printf) From dridi.boukelmoune at gmail.com Tue Mar 5 13:15:07 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 13:15:07 +0000 (UTC) Subject: [master] 5aa2601ff vtc: Disable ASLR in p7 Message-ID: <20240305131507.8A907108A90@lists.varnish-cache.org> commit 5aa2601ff7869251adbb2e80e978b71a7b354a80 Author: Dridi Boukelmoune Date: Tue Mar 5 14:10:14 2024 +0100 vtc: Disable ASLR in p7 Fixes #4074 diff --git a/bin/varnishtest/tests/p00007.vtc b/bin/varnishtest/tests/p00007.vtc index 67d00444e..4b0e5cbcb 100644 --- a/bin/varnishtest/tests/p00007.vtc +++ b/bin/varnishtest/tests/p00007.vtc @@ -1,6 +1,7 @@ varnishtest "test reload of object spanning incomplete segment" feature persistent_storage +feature disable_aslr barrier b1 cond 2 barrier b2 cond 2 From dridi.boukelmoune at gmail.com Tue Mar 5 13:15:07 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 13:15:07 +0000 (UTC) Subject: [master] 6fa6a3513 vtc.7: Document feature disable_aslr Message-ID: <20240305131507.A1945108A93@lists.varnish-cache.org> commit 6fa6a3513fb6bc55404b6d29bb5b9c9c780ec546 Author: Dridi Boukelmoune Date: Tue Mar 5 14:13:35 2024 +0100 vtc.7: Document feature disable_aslr diff --git a/bin/varnishtest/vtc_misc.c b/bin/varnishtest/vtc_misc.c index 95d4387ee..d4c894bd8 100644 --- a/bin/varnishtest/vtc_misc.c +++ b/bin/varnishtest/vtc_misc.c @@ -516,7 +516,9 @@ abstract_uds_works(void) * workspace_emulator * Varnish was built with its workspace emulator. * abstract_uds - * Creation of an abstract unix domain socket succeeded + * Creation of an abstract unix domain socket succeeded. + * disable_aslr + * ASLR can be disabnled. * * A feature name can be prefixed with an exclamation mark (!) to skip a * test if the feature is present. From dridi.boukelmoune at gmail.com Tue Mar 5 13:36:04 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 13:36:04 +0000 (UTC) Subject: [master] e3eba97a7 vtc.7: Fix spelling accident Message-ID: <20240305133604.C79CD109819@lists.varnish-cache.org> commit e3eba97a78c076a9bbf08f5241318ba141943a4f Author: Dridi Boukelmoune Date: Tue Mar 5 14:35:13 2024 +0100 vtc.7: Fix spelling accident Soptted by St?phane Cance. diff --git a/bin/varnishtest/vtc_misc.c b/bin/varnishtest/vtc_misc.c index d4c894bd8..64d7b506d 100644 --- a/bin/varnishtest/vtc_misc.c +++ b/bin/varnishtest/vtc_misc.c @@ -518,7 +518,7 @@ abstract_uds_works(void) * abstract_uds * Creation of an abstract unix domain socket succeeded. * disable_aslr - * ASLR can be disabnled. + * ASLR can be disabled. * * A feature name can be prefixed with an exclamation mark (!) to skip a * test if the feature is present. From dridi at varni.sh Tue Mar 5 15:30:14 2024 From: dridi at varni.sh (Dridi Boukelmoune) Date: Tue, 5 Mar 2024 15:30:14 +0000 Subject: [master] ca9829339 Fix mode for JAIL_FIXFD_FILE in the unix jail In-Reply-To: <20240301112808.AC0FE929A@lists.varnish-cache.org> References: <20240301112808.AC0FE929A@lists.varnish-cache.org> Message-ID: On Fri, Mar 1, 2024 at 11:28?AM Nils Goroll wrote: > > > commit ca98293398db21f9392cce0c762afde37872badb > Author: Nils Goroll > Date: Fri Mar 1 12:24:44 2024 +0100 > > Fix mode for JAIL_FIXFD_FILE in the unix jail > > Very much looks like copy-pasta in ede8c3dbe84b131d7e1240f28f2eb16c2818c309 > > JAIL_FIXFD_VSMMGT and JAIL_FIXFD_VSMWRK work on directories but, > as the name implies, JAIL_FIXFD_FILE not. > > diff --git a/bin/varnishd/mgt/mgt_jail_unix.c b/bin/varnishd/mgt/mgt_jail_unix.c > index d979c00f0..f84d63c2e 100644 > --- a/bin/varnishd/mgt/mgt_jail_unix.c > +++ b/bin/varnishd/mgt/mgt_jail_unix.c > @@ -296,7 +296,7 @@ vju_fixfd(int fd, enum jail_fixfd_e what) > > switch (what) { > case JAIL_FIXFD_FILE: > - AZ(fchmod(fd, 0750)); > + AZ(fchmod(fd, 0600)); Spotted by St?phane Cance on our end, why 600 and not 640? > AZ(fchown(fd, vju_wrkuid, vju_wrkgid)); > break; > case JAIL_FIXFD_VSMMGT: > _______________________________________________ > varnish-commit mailing list > varnish-commit at varnish-cache.org > https://www.varnish-cache.org/lists/mailman/listinfo/varnish-commit From nils.goroll at uplex.de Tue Mar 5 18:01:10 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Tue, 5 Mar 2024 19:01:10 +0100 Subject: [master] ca9829339 Fix mode for JAIL_FIXFD_FILE in the unix jail In-Reply-To: References: <20240301112808.AC0FE929A@lists.varnish-cache.org> Message-ID: On 05.03.24 16:30, Dridi Boukelmoune wrote: > Spotted by St?phane Cance on our end, why 600 and not 640? The use cases in the v-c tree are for the file and deprecated persistent storage engines (via STV_GetFile()). For storage engines, group permissions make no sense. Also, the code before ede8c3dbe84b131d7e1240f28f2eb16c2818c309 used 0600. If there are other use cases, we should introduce another JAIL_FIXFD_* type. Nils -- Nils Goroll (he/him) ** * * UPLEX - Nils Goroll Systemoptimierung Scheffelstra?e 32 22301 Hamburg tel +49 40 28805731 mob +49 170 2723133 fax +49 40 42949753 xmpp://slink at jabber.int.uplex.de/ http://uplex.de/ From dridi at varni.sh Wed Mar 6 08:50:14 2024 From: dridi at varni.sh (Dridi Boukelmoune) Date: Wed, 6 Mar 2024 08:50:14 +0000 Subject: [master] ca9829339 Fix mode for JAIL_FIXFD_FILE in the unix jail In-Reply-To: References: <20240301112808.AC0FE929A@lists.varnish-cache.org> Message-ID: On Tue, Mar 5, 2024 at 6:01?PM Nils Goroll wrote: > > On 05.03.24 16:30, Dridi Boukelmoune wrote: > > Spotted by St?phane Cance on our end, why 600 and not 640? > > The use cases in the v-c tree are for the file and deprecated persistent storage > engines (via STV_GetFile()). For storage engines, group permissions make no sense. > > Also, the code before ede8c3dbe84b131d7e1240f28f2eb16c2818c309 used 0600. > > If there are other use cases, we should introduce another JAIL_FIXFD_* type. I should have looked harder, thanks! From dridi.boukelmoune at gmail.com Wed Mar 6 11:46:12 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Wed, 6 Mar 2024 11:46:12 +0000 (UTC) Subject: [master] b37617df2 Start skeleton release notes for the next version. Message-ID: <20240306114612.2183A1144B6@lists.varnish-cache.org> commit b37617df2c6480e807d7787f2154eb641cca81be Author: Geoff Simmons Date: Tue Sep 25 16:31:17 2018 +0200 Start skeleton release notes for the next version. Restructured so that: * 'Upgrading' is limited to work that has to be done to upgrade from a current deployment to the new version. * 'Changes' is a comprehensive, user-level description of changes and new features. Conflicts: doc/sphinx/whats-new/changes-trunk.rst doc/sphinx/whats-new/index.rst doc/sphinx/whats-new/upgrading-trunk.rst diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst new file mode 100644 index 000000000..2070fadd5 --- /dev/null +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -0,0 +1,69 @@ +.. _whatsnew_changes_CURRENT: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Changes in Varnish **${NEXT_RELEASE}** +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +For information about updating your current Varnish deployment to the +new version, see :ref:`whatsnew_upgrading_CURRENT`. + +A more detailed and technical account of changes in Varnish, with +links to issues that have been fixed and pull requests that have been +merged, may be found in the `change log`_. + +.. _change log: https://github.com/varnishcache/varnish-cache/blob/master/doc/changes.rst + +varnishd +======== + +Parameters +~~~~~~~~~~ + +**XXX changes in -p parameters** + +Other changes in varnishd +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Changes to VCL +============== + +VCL variables +~~~~~~~~~~~~~ + +**XXX new, deprecated or removed variables, or changed semantics** + +Other changes to VCL +~~~~~~~~~~~~~~~~~~~~ + +VMODs +===== + +**XXX changes in the bundled VMODs** + +varnishlog +========== + +**XXX changes concerning varnishlog(1) and/or vsl(7)** + +varnishadm +========== + +**XXX changes concerning varnishadm(1) and/or varnish-cli(7)** + +varnishstat +=========== + +**XXX changes concerning varnishstat(1) and/or varnish-counters(7)** + +varnishtest +=========== + +**XXX changes concerning varnishtest(1) and/or vtc(7)** + +Changes for developers and VMOD authors +======================================= + +**XXX changes concerning VRT, the public APIs, source code organization, +builds etc.** + +*eof* diff --git a/doc/sphinx/whats-new/index.rst b/doc/sphinx/whats-new/index.rst index f3c199b4c..8b4225c98 100644 --- a/doc/sphinx/whats-new/index.rst +++ b/doc/sphinx/whats-new/index.rst @@ -13,6 +13,19 @@ This section describes the changes and improvements between different versions of Varnish, and what upgrading between the different versions entail. +Varnish **$NEXT_RELEASE** +------------------------- + +**Note: These are working documents for a future release, with running +updates for changes in the development branch. For changes in the +released versions of Varnish, see the chapters listed below.** + +.. toctree:: + :maxdepth: 2 + + changes-trunk + upgrading-trunk + Varnish 7.4 ----------- diff --git a/doc/sphinx/whats-new/upgrading-trunk.rst b/doc/sphinx/whats-new/upgrading-trunk.rst new file mode 100644 index 000000000..6143fde99 --- /dev/null +++ b/doc/sphinx/whats-new/upgrading-trunk.rst @@ -0,0 +1,33 @@ +**Note: This is a working document for a future release, with running +updates for changes in the development branch. For changes in the +released versions of Varnish, see:** :ref:`whats-new-index` + +.. _whatsnew_upgrading_CURRENT: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Upgrading to Varnish **$NEXT_RELEASE** +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +**XXX: how to upgrade from previous deployments to this +version. Limited to work that has to be done for an upgrade, new +features are listed in "Changes". Explicitly mention what does *not* +have to be changed, especially in VCL. May include, but is not limited +to:** + +* Elements of VCL that have been removed or are deprecated, or whose + semantics have changed. + +* -p parameters that have been removed or are deprecated, or whose + semantics have changed. + +* Changes in the CLI. + +* Changes in the output or interpretation of stats or the log, including + changes affecting varnishncsa/-hist/-top. + +* Changes that may be necessary in VTCs or in the use of varnishtest. + +* Changes in public APIs that may require changes in VMODs or VAPI/VUT + clients. + +*eof* From dridi.boukelmoune at gmail.com Wed Mar 6 11:46:12 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Wed, 6 Mar 2024 11:46:12 +0000 (UTC) Subject: [master] 2c58698b5 whats-new: First pass on changes since 7.4.0 Message-ID: <20240306114612.38B661144BA@lists.varnish-cache.org> commit 2c58698b5c3dd5a5ad85b27b4dc3200c38b90eec Author: Dridi Boukelmoune Date: Tue Mar 5 18:40:12 2024 +0100 whats-new: First pass on changes since 7.4.0 Please note the large TODO regarding the rapid reset attack mitigation. diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index 2070fadd5..e15a7e3cd 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -21,9 +21,78 @@ Parameters **XXX changes in -p parameters** +The default value of ``cli_limit`` increased to avoid truncating the +``param.show -j`` output. + +The ``vsl_mask`` parameter accepts a new special value "all" that enables +logging of all VSL tags, the counterpart of "none". + +All bits parameters can be set atomically to an absolute value:: + + param.set vsl_mask all,-Debug,-ExpKill + +The ``param.show`` output prints them with an absolute value. This enables +operations to atomically set a value, relative or absolute, and collect the +absolute value, for bits parameters:: + + param.set -j feature +http2 + +The ``param.set`` command in JSON mode prints the ``param.show`` JSON output +after successfully updating a parameter. The ``param.reset`` command now +shares the same behavior. + +The special value "default" for bits parameters was deprecated in favor of the +generic ``param.reset`` command. It will be removed in a future release. + +A new ``pipe_task_deadline`` specifies the maximum duration of a pipe +transaction. The default value is the special value "never" to align with the +former lack of such timeout:: + + # both equivalent for now + param.set pipe_task_deadline never + param.reset pipe_task_deadline + +All the timeout parameters that can be disabled accept the "never" value: + +- ``between_bytes_timeout`` +- ``cli_timeout`` +- ``connect_timeout`` +- ``first_byte_timeout`` +- ``idle_send_timeout`` +- ``pipe_task_deadline`` +- ``pipe_timeout`` +- ``send_timeout`` +- ``startup_timeout`` + +The :ref:`varnishd(1)` manual advertises the ``timeout`` flag for these +parameters. + Other changes in varnishd ~~~~~~~~~~~~~~~~~~~~~~~~~ +The CLI script specified with the ``-I`` option must end with a new line +character or ``varnishd`` will fail to start. Previously, an incomplete last +line would be ignored. + +TODO: Should we cover the rapid reset mitigation? It's new since 7.4.0 but not +quite new since "7.4" after the security releases. Should it get a dedicated +prominent headline? Or should it be dispatched in the various sections? Or a +little bit of both? + +List of rapid reset changes: + - param h2_rapid_reset + - param h2_rapid_reset_limit + - param h2_rapid_reset_period + - MAIN.sc_rapid_reset counter + - SessClose tag RAPID_RESET + - vmod_h2 (with per-h2_sess h2_rapid_* parameters) + +List of reset changes: + - param feature +vcl_req_reset + - MAIN.req_reset counter + - VSL Timestamp:Reset + - status 408 logged for reset streams + Changes to VCL ============== @@ -32,9 +101,53 @@ VCL variables **XXX new, deprecated or removed variables, or changed semantics** +A new ``bereq.task_deadline`` variable is available in ``vcl_pipe`` to +override the ``pipe_task_deadline`` parameter. + +All the timeouts that can be overridden in VCL can be unset as well: + +- ``bereq.between_bytes_timeout`` +- ``bereq.connect_timeout`` +- ``bereq.first_byte_timeout`` +- ``bereq.task_deadline`` +- ``sess.idle_send_timeout`` +- ``sess.send_timeout`` +- ``sess.timeout_idle`` +- ``sess.timeout_linger`` + +They are unset by default, and if they are read unset, the parameter value is +returned. If the timeout parameter was disabled with the "never" value, it is +capped in VCL to the maximum decimal number (999999999999.999). It is not +possible to disable a timeout in VCL. + +ESI +~~~ + +In the 7.3.0 release a new error condition was added to ESI fragments. A +fragment is considered valid only for the response status code 200 and 204. + +However, when introduced it also changed the default behavior of the feature +flag ``esi_include_onerror`` in an inconsistent way. + +The behavior is reverted to the traditional Varnish handling of ESI, and the +effect of the feature flag is clarified: + +- by default, fragments are always included, even errors +- the feature flag ``esi_include_onerror`` enable processing of the + ``onerror`` attribute of the ```` tag +- ``onerror="continue"`` allows a parent request to resume its delivery after + a sub-request failed +- when streaming is disabled for the sub-request, the ESI fragment is omitted + as mandated by the ESI specification + +See :ref:`users-guide-esi` for more information. + Other changes to VCL ~~~~~~~~~~~~~~~~~~~~ +The new ``+fold`` flag for ACLs merges adjacent subnets together and optimize +out subnets for which there exist another all-encompassing subnet. + VMODs ===== @@ -45,6 +158,30 @@ varnishlog **XXX changes concerning varnishlog(1) and/or vsl(7)** +When a ``BackendClose`` record includes a reason field, it now shows the +reason tag (for example ``RX_TIMEOUT``) instead of its description (Receive +timeout) to align with ``SessClose`` records. See :ref:`vsl(7)`. + +The ``ExpKill`` tag can be used to troubleshoot a cache policy. It is masked +by default because it is very verbose and requires a good understanding of +Varnish internals in the expiry vicinity. + +A new field with the number of hits is present in the ``EXP_Expired`` entry of +an object. Objects removed before they expired are now logged a new entry +``EXP_Removed``, removing a blind spot. Likewise, purged objects are no longer +logged as expired, but removed instead. The ``EXP_expire`` entry formerly +undocumented was renamed to ``EXP_Inspect`` for clarity and consistency. A new +``VBF_Superseded`` entry explains which object is evicting another one. + +varnishncsa +=========== + +A new custom format ``%{Varnish:default_format}x`` expands to the output +format when nothing is specified. This allows enhancing the default format +without having to repeat it:: + + varnishncsa -F ``%{Varnish:default_format}x %{Varnish:handling}x`` + varnishadm ========== @@ -55,15 +192,62 @@ varnishstat **XXX changes concerning varnishstat(1) and/or varnish-counters(7)** +A new counter ``MAIN.n_superseded`` adds visibility on how many objects are +inserted as the replacement of another object in the cache. This can give +insights regarding the nature of churn in a cache. + varnishtest =========== **XXX changes concerning varnishtest(1) and/or vtc(7)** +When an HTTP/2 stream number does not matter and the stream is handled in a +single block, the automatic ``next`` identifier can be used:: + + server s1 { + stream next { + rxreq + txresp + } -run + } -start + +It is now possible to include other VTC fragments:: + + include common-server.vtc common-varnish.vtc + +An include command takes at least one file name and expands it in place of the +include command itself. There are no guards against recursive includes. + Changes for developers and VMOD authors ======================================= **XXX changes concerning VRT, the public APIs, source code organization, builds etc.** +The ``VSB_tofile()`` function can work with VSBs larger than ``INT_MAX`` and +tolerate partial writes. + +The semantics for ``vtim_dur`` changed so that ``INFINITY`` is interpreted as +never timing out. A zero duration that was used in certain scenarios as never +timing out is now interpreted as non-blocking or when that is not possible, +rounded up to one millisecond. A negative value in this context is considered +an expired deadline as if zero was passed, giving a last chance for operations +to succeed before timing out. + +To support this use case, new functions convert ``vtim_dur`` to other values: + +- ``VTIM_poll_tmo()`` computes a timeout for ``poll(2)`` +- ``VTIM_timeval_sock()`` creates a ``struct timeval`` for ``setsockopt(2)`` + +The value ``NAN`` is used to represent unset timeouts in VCL with one notable +exception. The ``struct vrt_backend`` duration fields cannot be initialized to +``NAN`` and zero was the unset value, falling back to parameters. Zero will +disable a timeout in a backend definition (which can be overridden by VCL +variables) and a negative value will mean unset. + +This is an API breakage of ``struct vrt_backend`` and its consumers. + +Likewise, VMODs creating their own lock classes with ``Lck_CreateClass()`` +must stop using zero an indefinite ``Lck_CondWaitTimeout()``. + *eof* From dridi.boukelmoune at gmail.com Wed Mar 6 11:46:12 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Wed, 6 Mar 2024 11:46:12 +0000 (UTC) Subject: [master] e1fabeede varnishhist: Make like a tree, and leave Message-ID: <20240306114612.514091144BD@lists.varnish-cache.org> commit e1fabeede90fa262b962962bb729ac4b682a93e6 Author: Dridi Boukelmoune Date: Tue Mar 5 18:40:43 2024 +0100 varnishhist: Make like a tree, and leave diff --git a/bin/varnishhist/varnishhist.c b/bin/varnishhist/varnishhist.c index c8c5d9568..03251fce4 100644 --- a/bin/varnishhist/varnishhist.c +++ b/bin/varnishhist/varnishhist.c @@ -218,7 +218,7 @@ upd_vsl_ts(const char *p) } static void -deloran(void) +delorean(void) { int i; double t = VTIM_mono(); @@ -363,7 +363,7 @@ accumulate(struct VSL_data *vsl, struct VSL_transaction * const pt[], next_hist = 0; } if (vsl_ts >= vsl_to) - deloran(); + delorean(); PTOK(pthread_mutex_unlock(&mtx)); } return (0); From dridi.boukelmoune at gmail.com Wed Mar 6 11:46:12 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Wed, 6 Mar 2024 11:46:12 +0000 (UTC) Subject: [master] 18d07f34e vsl_tags: Fix spelling error Message-ID: <20240306114612.6AC011144C2@lists.varnish-cache.org> commit 18d07f34e0764367542c77508a6301eb9f2087e7 Author: Dridi Boukelmoune Date: Wed Mar 6 12:38:49 2024 +0100 vsl_tags: Fix spelling error diff --git a/include/tbl/vsl_tags.h b/include/tbl/vsl_tags.h index 858256f26..2c35404db 100644 --- a/include/tbl/vsl_tags.h +++ b/include/tbl/vsl_tags.h @@ -34,7 +34,7 @@ * REMEMBER to update the documentation (especially the varnishlog(1) man * page) whenever this list changes. * - * XXX: Please add new entries a the end to not break saved log-segments. + * XXX: Please add new entries at the end to not break saved log-segments. * * Arguments: * Tag-Name From dridi.boukelmoune at gmail.com Wed Mar 6 11:46:12 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Wed, 6 Mar 2024 11:46:12 +0000 (UTC) Subject: [master] 2de23ed87 varnish.m4: Bump varnish.m4 to reflect minor changes Message-ID: <20240306114612.864CA1144C5@lists.varnish-cache.org> commit 2de23ed87e0e5c3f671bf55ffa60a3c66d6c9185 Author: Dridi Boukelmoune Date: Wed Mar 6 12:39:06 2024 +0100 varnish.m4: Bump varnish.m4 to reflect minor changes diff --git a/varnish.m4 b/varnish.m4 index e7e596717..83d80f2c9 100644 --- a/varnish.m4 +++ b/varnish.m4 @@ -31,7 +31,7 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. # varnish.m4 - Macros to build against Varnish. -*- Autoconf -*- -# serial 11 (varnish-6.5.0) +# serial 12 (varnish-7.5.0) # # This collection of macros helps create VMODs or tools interacting with # Varnish Cache using the GNU build system (autotools). In order to work From nils.goroll at uplex.de Thu Mar 7 10:07:08 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Thu, 7 Mar 2024 10:07:08 +0000 (UTC) Subject: [master] 0c434255d Refer to vsl(7) from vsl_mask documentation Message-ID: <20240307100708.A98D211C2C4@lists.varnish-cache.org> commit 0c434255d514047f66343d7c4cf8b2c58ab2df1d Author: Nils Goroll Date: Thu Mar 7 11:05:58 2024 +0100 Refer to vsl(7) from vsl_mask documentation diff --git a/include/tbl/params.h b/include/tbl/params.h index 5f4359594..e96d75483 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -1899,7 +1899,7 @@ PARAM_BITS( "\tall\tEnable all tags\n" "\tdefault\tSet default value (deprecated: use param.reset)\n" "\nUse +/- prefix in front of VSL tag name to unmask/mask " - "individual VSL messages.") + "individual VSL messages. See vsl(7) for possible values.") PARAM_POST #undef PARAM_ALL From nils.goroll at uplex.de Thu Mar 7 10:14:04 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Thu, 7 Mar 2024 10:14:04 +0000 (UTC) Subject: [master] 3f69805f9 Release docs polish Message-ID: <20240307101404.C615C11C722@lists.varnish-cache.org> commit 3f69805f91ff70d55d2585214445abf267e4e26b Author: Nils Goroll Date: Thu Mar 7 11:11:49 2024 +0100 Release docs polish Mention the old/new cli_limit values Polish wordning of bits parameter change Add param.show example in place of what looks like an unmotivated param.set -j example diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index e15a7e3cd..f592518f7 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -21,28 +21,38 @@ Parameters **XXX changes in -p parameters** -The default value of ``cli_limit`` increased to avoid truncating the -``param.show -j`` output. +The default value of ``cli_limit`` has been increased from 48KB to +64KB to avoid truncating the ``param.show -j`` output for common use +cases. The ``vsl_mask`` parameter accepts a new special value "all" that enables logging of all VSL tags, the counterpart of "none". -All bits parameters can be set atomically to an absolute value:: +.. I am not sure if "absolute value" is the best name here. It is + "relative to all", but I do not have a better idea + +This allows all bits parameters to be set atomically to an absolute +value, as in:: param.set vsl_mask all,-Debug,-ExpKill -The ``param.show`` output prints them with an absolute value. This enables -operations to atomically set a value, relative or absolute, and collect the -absolute value, for bits parameters:: +The ``param.show`` output prints the absolute value. This enables +operations to atomically set a bits parameter, relative or absolute, +and collect the absolute value:: - param.set -j feature +http2 + param.show vsl_mask + 200 + vsl_mask + Value is: all,-Debug,-ExpKill + [...] -The ``param.set`` command in JSON mode prints the ``param.show`` JSON output -after successfully updating a parameter. The ``param.reset`` command now -shares the same behavior. +The ``param.set`` command in JSON mode (``-j argument``) prints the +``param.show`` JSON output after successfully updating a +parameter. The ``param.reset`` command now shares the same behavior. -The special value "default" for bits parameters was deprecated in favor of the -generic ``param.reset`` command. It will be removed in a future release. +The special value ``default`` for bits parameters was deprecated in +favor of the generic ``param.reset`` command. It will be removed in a +future release. A new ``pipe_task_deadline`` specifies the maximum duration of a pipe transaction. The default value is the special value "never" to align with the From dridi at varni.sh Thu Mar 7 11:18:22 2024 From: dridi at varni.sh (Dridi Boukelmoune) Date: Thu, 7 Mar 2024 11:18:22 +0000 Subject: [master] 3f69805f9 Release docs polish In-Reply-To: <20240307101404.C615C11C722@lists.varnish-cache.org> References: <20240307101404.C615C11C722@lists.varnish-cache.org> Message-ID: > Add param.show example in place of what looks like an unmotivated > param.set -j example Please revert that part, it was meant to be a param.set -j and not an accident. I'll try to find a better wording but basically for this: param.set -j bits +wanted,-part_of_defaults_but_not_wanted It means that in the JSON output I will get the absolute value, for example: "none,+wanted,+part_of_defaults" So in one atomic param.set command I can both make a partial update of a bits parameter and collect an absolute value for future consistency checks (if I were to implement such checks with the likes of ansible for example). The main use case is not having to care about the default values, and making sure that specific bits are raised or cleared without interfering with changes to default values when upgrading. Dridi From dridi.boukelmoune at gmail.com Thu Mar 7 13:05:07 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Thu, 7 Mar 2024 13:05:07 +0000 (UTC) Subject: [master] 9ddd9d471 varnishd: polish Message-ID: <20240307130507.246C8121C6A@lists.varnish-cache.org> commit 9ddd9d4717fbf3732815d687c776d1009334f65c Author: Asad Sajjad Ahmed Date: Thu Mar 7 13:27:55 2024 +0100 varnishd: polish Signed-off-by: Asad Sajjad Ahmed diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h index a73ff7170..d759f95e7 100644 --- a/bin/varnishd/cache/cache_varnishd.h +++ b/bin/varnishd/cache/cache_varnishd.h @@ -163,8 +163,6 @@ void VCA_Shutdown(void); /* cache_backend_cfg.c */ void VBE_InitCfg(void); -void VBP_Init(void); - /* cache_ban.c */ /* for stevedoes resurrecting bans */ @@ -464,7 +462,8 @@ struct conn_pool; void VCP_Init(void); void VCP_Panic(struct vsb *, struct conn_pool *); -/* cache_backend_poll.c */ +/* cache_backend_probe.c */ +void VBP_Init(void); /* cache_vary.c */ int VRY_Create(struct busyobj *bo, struct vsb **psb); From nils.goroll at uplex.de Thu Mar 7 17:17:50 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Thu, 7 Mar 2024 18:17:50 +0100 Subject: [master] 3f69805f9 Release docs polish In-Reply-To: References: <20240307101404.C615C11C722@lists.varnish-cache.org> Message-ID: On 07.03.24 12:18, Dridi Boukelmoune wrote: > Please revert that part, it was meant to be a param.set -j and not an accident. Before I try to make it so to follow your plan, just change it however you want it. -- Nils Goroll (he/him) ** * * UPLEX - Nils Goroll Systemoptimierung Scheffelstra?e 32 22301 Hamburg tel +49 40 28805731 mob +49 170 2723133 fax +49 40 42949753 xmpp://slink at jabber.int.uplex.de/ http://uplex.de/ From nils.goroll at uplex.de Thu Mar 7 19:55:08 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Thu, 7 Mar 2024 19:55:08 +0000 (UTC) Subject: [master] 333d5a5ed Improve test Message-ID: <20240307195508.4438E108039@lists.varnish-cache.org> commit 333d5a5edaddd4a5a729823e9eb59ae3c6046201 Author: Nils Goroll Date: Thu Mar 7 20:50:30 2024 +0100 Improve test weird behavior was observed while working on a new feature: This test would terminate s1 after the delay before varnish could finish reading all of the chunked body, which would leave an unfinished backend request in varnishd when it terminated. diff --git a/bin/varnishtest/tests/r03189.vtc b/bin/varnishtest/tests/r03189.vtc index cf3d466c9..18fc46b36 100644 --- a/bin/varnishtest/tests/r03189.vtc +++ b/bin/varnishtest/tests/r03189.vtc @@ -26,3 +26,5 @@ client c1 { barrier b sync expect_close } -run + +server s1 -wait From dridi.boukelmoune at gmail.com Thu Mar 14 22:36:13 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Thu, 14 Mar 2024 22:36:13 +0000 (UTC) Subject: [master] f4068c8f2 whats-new: Clarify changes to bits parameters Message-ID: <20240314223613.4A1A01055F3@lists.varnish-cache.org> commit f4068c8f285f69475a11a231332730aeac7742f7 Author: Dridi Boukelmoune Date: Thu Mar 14 23:33:50 2024 +0100 whats-new: Clarify changes to bits parameters Quick attempt to address 3f69805f91ff70d55d2585214445abf267e4e26b. The remaining TODO in the changes needs to be addressed, and upgrade notes are empty. diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index f592518f7..714f44cee 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -19,41 +19,10 @@ varnishd Parameters ~~~~~~~~~~ -**XXX changes in -p parameters** - The default value of ``cli_limit`` has been increased from 48KB to 64KB to avoid truncating the ``param.show -j`` output for common use cases. -The ``vsl_mask`` parameter accepts a new special value "all" that enables -logging of all VSL tags, the counterpart of "none". - -.. I am not sure if "absolute value" is the best name here. It is - "relative to all", but I do not have a better idea - -This allows all bits parameters to be set atomically to an absolute -value, as in:: - - param.set vsl_mask all,-Debug,-ExpKill - -The ``param.show`` output prints the absolute value. This enables -operations to atomically set a bits parameter, relative or absolute, -and collect the absolute value:: - - param.show vsl_mask - 200 - vsl_mask - Value is: all,-Debug,-ExpKill - [...] - -The ``param.set`` command in JSON mode (``-j argument``) prints the -``param.show`` JSON output after successfully updating a -parameter. The ``param.reset`` command now shares the same behavior. - -The special value ``default`` for bits parameters was deprecated in -favor of the generic ``param.reset`` command. It will be removed in a -future release. - A new ``pipe_task_deadline`` specifies the maximum duration of a pipe transaction. The default value is the special value "never" to align with the former lack of such timeout:: @@ -77,6 +46,65 @@ All the timeout parameters that can be disabled accept the "never" value: The :ref:`varnishd(1)` manual advertises the ``timeout`` flag for these parameters. +Bits parameters +~~~~~~~~~~~~~~~ + +In Varnish 7.1.0 the ``param.set`` command grew a new ``-j`` option that +displays the same output as ``param.show -j`` for the parameter that is +successfully updated. + +The goal was to atomically change a value and communicate how a subsequent +``param.show`` would render it. This could be used for consistency checks, +to ensure that a parameter was not changed by a different party. Collecting +how the parameter is displayed can be important for example for floating-point +numbers parameters that could be displayed with different resolutions, or +parameters that can take units and have multiple representations. + +Here is a concrete example:: + + $ varnishadm param.set -j workspace_client 16384 | jq '.[3].value' + 16384 + $ varnishadm param.set -j workspace_client 128k | jq '.[3].value' + 131072 + +However, this could not work with bits parameters:: + + $ varnishadm param.set -j feature +http2 | jq -r '.[3].value' + +http2,+validate_headers + +If the ``feature`` parameter is changed, reusing the output of ``param.set`` +cannot guarantee the restoration that exact value:: + + $ varnishadm param.set -j feature +http2,+validate_headers | jq -r '.[3].value' + +http2,+no_coredump,+validate_headers + +To fill this gap, bits parameters are now displayed as absolute values, +relative to none of the bits being set. A list of bits can start with the +special value ``none`` to clear all the bits, followed by specific bits to +raise:: + + $ varnishadm param.set -j feature +http2 | jq -r '.[3].value' + none,+http2,+validate_headers + $ varnishadm param.set -j feature none,+http2,+validate_headers | jq -r '.[3].value' + none,+http2,+validate_headers + +The output of ``param.show`` and ``param.set`` is now idempotent for bits +parameters, and can be used by a consistency check system to restore a +parameter to its desired value. + +Almost all bits parameters are displayed as bits set relative to a ``none`` +value. The notable exception is ``vsl_mask`` that is expressed with bits +cleared. For this purpose the ``vsl_mask`` parameter is now displayed as +bits cleared relative to an ``all`` value:: + + + $ varnishadm param.set -j vsl_mask all,-Debug | jq -r '.[3].value' + all,-Debug + +The special value ``default`` for bits parameters was deprecated in +favor of the generic ``param.reset`` command. It might be removed in a +future release. + Other changes in varnishd ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -109,8 +137,6 @@ Changes to VCL VCL variables ~~~~~~~~~~~~~ -**XXX new, deprecated or removed variables, or changed semantics** - A new ``bereq.task_deadline`` variable is available in ``vcl_pipe`` to override the ``pipe_task_deadline`` parameter. @@ -158,16 +184,9 @@ Other changes to VCL The new ``+fold`` flag for ACLs merges adjacent subnets together and optimize out subnets for which there exist another all-encompassing subnet. -VMODs -===== - -**XXX changes in the bundled VMODs** - varnishlog ========== -**XXX changes concerning varnishlog(1) and/or vsl(7)** - When a ``BackendClose`` record includes a reason field, it now shows the reason tag (for example ``RX_TIMEOUT``) instead of its description (Receive timeout) to align with ``SessClose`` records. See :ref:`vsl(7)`. @@ -192,16 +211,9 @@ without having to repeat it:: varnishncsa -F ``%{Varnish:default_format}x %{Varnish:handling}x`` -varnishadm -========== - -**XXX changes concerning varnishadm(1) and/or varnish-cli(7)** - varnishstat =========== -**XXX changes concerning varnishstat(1) and/or varnish-counters(7)** - A new counter ``MAIN.n_superseded`` adds visibility on how many objects are inserted as the replacement of another object in the cache. This can give insights regarding the nature of churn in a cache. @@ -209,8 +221,6 @@ insights regarding the nature of churn in a cache. varnishtest =========== -**XXX changes concerning varnishtest(1) and/or vtc(7)** - When an HTTP/2 stream number does not matter and the stream is handled in a single block, the automatic ``next`` identifier can be used:: @@ -231,9 +241,6 @@ include command itself. There are no guards against recursive includes. Changes for developers and VMOD authors ======================================= -**XXX changes concerning VRT, the public APIs, source code organization, -builds etc.** - The ``VSB_tofile()`` function can work with VSBs larger than ``INT_MAX`` and tolerate partial writes. From dridi.boukelmoune at gmail.com Fri Mar 15 09:19:11 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 09:19:11 +0000 (UTC) Subject: [master] a60746e1a whats-new: Give HTTP/2 Rapid Reset a headline Message-ID: <20240315091911.16F7511CBD6@lists.varnish-cache.org> commit a60746e1a2787212b79dd7a51b8dbbd11890bd35 Author: Dridi Boukelmoune Date: Fri Mar 15 10:17:45 2024 +0100 whats-new: Give HTTP/2 Rapid Reset a headline But spread the actual changes in their respective sections. diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index 714f44cee..d61a708bc 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -13,6 +13,20 @@ merged, may be found in the `change log`_. .. _change log: https://github.com/varnishcache/varnish-cache/blob/master/doc/changes.rst +Security +======== + +CVE-2023-44487 +~~~~~~~~~~~~~~ + +Also known as the HTTP/2 Rapid Reset Attack, or `VSV 13`_, this vulnerability +is addressed with two mitigations introducing several changes since the 7.4.0 +release of Varnish Cache. The first one detects and stops Rapid Reset attacks +and the second one interrupts the processing of HTTP/2 requests that are no +longer open (stream reset, client disconnected etc). + +.. _VSV 13: https://varnish-cache.org/security/VSV00013.html + varnishd ======== @@ -46,6 +60,18 @@ All the timeout parameters that can be disabled accept the "never" value: The :ref:`varnishd(1)` manual advertises the ``timeout`` flag for these parameters. +The following parameters address the HTTP/2 Rapid Reset attach: + +- ``h2_rapid_reset`` (duration below which a reset is considered rapid) +- ``h2_rapid_reset_limit`` (maximum number of rapid resets per period) +- ``h2_rapid_reset_period`` (the sliding period to track rapid resets) + +A new bit flag ``vcl_req_reset`` for the ``feature`` parameter interrupts +client request tasks during VCL transitions when an HTTP/2 stream is no longer +open. The result is equivalent to a ``return (fail);`` statement and can save +significant server resources. It can also break setups expecting requests to +always be fully processed, even when they are not delivered. + Bits parameters ~~~~~~~~~~~~~~~ @@ -117,20 +143,6 @@ quite new since "7.4" after the security releases. Should it get a dedicated prominent headline? Or should it be dispatched in the various sections? Or a little bit of both? -List of rapid reset changes: - - param h2_rapid_reset - - param h2_rapid_reset_limit - - param h2_rapid_reset_period - - MAIN.sc_rapid_reset counter - - SessClose tag RAPID_RESET - - vmod_h2 (with per-h2_sess h2_rapid_* parameters) - -List of reset changes: - - param feature +vcl_req_reset - - MAIN.req_reset counter - - VSL Timestamp:Reset - - status 408 logged for reset streams - Changes to VCL ============== @@ -184,9 +196,21 @@ Other changes to VCL The new ``+fold`` flag for ACLs merges adjacent subnets together and optimize out subnets for which there exist another all-encompassing subnet. +VMODs +===== + +A new :ref:`vmod_h2(3)` can override the ``h2_rapid_reset*`` parameters on a +per-session basis. + varnishlog ========== +The ``SessClose`` record may contain the ``RAPID_RESET`` reason. This can be +used to monitor attacks successfully mitigated or detect false positives. + +When the ``feature`` flag ``vcl_req_reset`` is raised, an interrupted client +logs a ``Reset`` timestamps, and the response status code 408 is logged. + When a ``BackendClose`` record includes a reason field, it now shows the reason tag (for example ``RX_TIMEOUT``) instead of its description (Receive timeout) to align with ``SessClose`` records. See :ref:`vsl(7)`. @@ -214,6 +238,14 @@ without having to repeat it:: varnishstat =========== +A new ``MAIN.sc_rapid_reset`` counter counts the number of HTTP/2 connections +closed because the number of rapid resets exceed the limit over the configured +period. + +Its ``MAIN.req_reset`` counterpart counts the number of time a client task was +prematurely failed because the HTTP/2 stream it was processing was no longer +open and the feature flag ``vcl_req_reset`` was raised. + A new counter ``MAIN.n_superseded`` adds visibility on how many objects are inserted as the replacement of another object in the cache. This can give insights regarding the nature of churn in a cache. From dridi.boukelmoune at gmail.com Fri Mar 15 09:24:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 09:24:05 +0000 (UTC) Subject: [master] d67bf4025 whats-new: Remove HTTP/2 Rapid Reset TODO Message-ID: <20240315092405.6E59A11CF61@lists.varnish-cache.org> commit d67bf4025bbb4f19fef794efecc076334652e83c Author: Dridi Boukelmoune Date: Fri Mar 15 10:22:48 2024 +0100 whats-new: Remove HTTP/2 Rapid Reset TODO See previous commit. diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index d61a708bc..333553369 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -138,11 +138,6 @@ The CLI script specified with the ``-I`` option must end with a new line character or ``varnishd`` will fail to start. Previously, an incomplete last line would be ignored. -TODO: Should we cover the rapid reset mitigation? It's new since 7.4.0 but not -quite new since "7.4" after the security releases. Should it get a dedicated -prominent headline? Or should it be dispatched in the various sections? Or a -little bit of both? - Changes to VCL ============== From dridi.boukelmoune at gmail.com Fri Mar 15 09:53:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 09:53:06 +0000 (UTC) Subject: [master] 2a84483ff whats-new: Add upgrade notes Message-ID: <20240315095306.BEA3811DE1D@lists.varnish-cache.org> commit 2a84483ffbfc48f11f28e05c453a29eb0e1f5e81 Author: Dridi Boukelmoune Date: Fri Mar 15 10:51:35 2024 +0100 whats-new: Add upgrade notes diff --git a/doc/sphinx/whats-new/upgrading-trunk.rst b/doc/sphinx/whats-new/upgrading-trunk.rst index 6143fde99..706966391 100644 --- a/doc/sphinx/whats-new/upgrading-trunk.rst +++ b/doc/sphinx/whats-new/upgrading-trunk.rst @@ -1,33 +1,69 @@ -**Note: This is a working document for a future release, with running -updates for changes in the development branch. For changes in the -released versions of Varnish, see:** :ref:`whats-new-index` - .. _whatsnew_upgrading_CURRENT: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Upgrading to Varnish **$NEXT_RELEASE** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -**XXX: how to upgrade from previous deployments to this -version. Limited to work that has to be done for an upgrade, new -features are listed in "Changes". Explicitly mention what does *not* -have to be changed, especially in VCL. May include, but is not limited -to:** +Logs +==== + +The optional reason field of ``BackendClose`` records changed from a +description (for example "Receive timeout") to a reason tag (for example +``RX_TIMEOUT``). This will break VSL queries based on the reason field. + +Using a tag should however make queries more reliable:: + + # before + varnishlog -q 'BackendClose ~ "Receive timeout"' + + # after + varnishlog -q 'BackendClose[4] eq RX_TIMEOUT' + +Such queries would no longer break when a description is changed. + +Timeouts +======== + +The value zero for timeouts could mean either timing out immediately, never +timing out, or not having a value and falling back to another. The semantic +changed so zero always means non-blocking, timing out either immediately after +checking whether progress is possible, or after a millisecond in parts where +this can't practically be done in a non-blocking fashion. + +In order to disable a timeout, that is to say never time out, the value +``INFINITY`` is used (or tested with ``isinf()``). + +In the places where a timeout setting may fall back to another value, like +VCL variables falling back to parameters, ``NAN`` is used to convey the lack +of timeout setting. + +VCL +~~~ + +All the timeouts backed by parameters can now be unset, meaning that setting +the value zero no longer falls back to parameters. + +Parameters +~~~~~~~~~~ -* Elements of VCL that have been removed or are deprecated, or whose - semantics have changed. +All the timeout parameters that can be disabled are now documented with the +``timeout`` flag, meaning that they can take the special value ``never`` for +that purpose:: -* -p parameters that have been removed or are deprecated, or whose - semantics have changed. + varnishadm param.set pipe_timeout never -* Changes in the CLI. +VRT +~~~ -* Changes in the output or interpretation of stats or the log, including - changes affecting varnishncsa/-hist/-top. +For VMOD authors, it means that the ``vtim_dur`` type expects ``INFINITY`` to +never time out or ``NAN`` to not set a timeout. -* Changes that may be necessary in VTCs or in the use of varnishtest. +For VMOD authors managing backends, there is one exception where a timeout +fallback did not change from zero to ``NAN`` in ``struct vrt_backend``. The +``vtim_dur`` fields must take a negative value in order to fall back to the +respective parameters due to a limitation in how VCL is compiled. -* Changes in public APIs that may require changes in VMODs or VAPI/VUT - clients. +As a convenience, a new macro ``VRT_BACKEND_INIT()`` behaves like ``INIT_OBJ`` +but initializes timeouts to a negative value. *eof* From dridi.boukelmoune at gmail.com Fri Mar 15 10:05:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 10:05:05 +0000 (UTC) Subject: [master] 025f1a61f fetch: Log bgfetch_no_thread event Message-ID: <20240315100506.0FF0D11E561@lists.varnish-cache.org> commit 025f1a61f10187f3a4ce9723253d49e6baf1ac06 Author: AlveElde Date: Mon Mar 11 18:30:48 2024 +0100 fetch: Log bgfetch_no_thread event diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c index f37183582..0f86d0305 100644 --- a/bin/varnishd/cache/cache_fetch.c +++ b/bin/varnishd/cache/cache_fetch.c @@ -1222,6 +1222,8 @@ VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc, if (Pool_Task(wrk->pool, bo->fetch_task, prio)) { wrk->stats->bgfetch_no_thread++; + VSLb(bo->vsl, SLT_FetchError, + "No thread available for bgfetch"); (void)vbf_stp_fail(req->wrk, bo); if (bo->stale_oc != NULL) (void)HSH_DerefObjCore(wrk, &bo->stale_oc, 0); diff --git a/bin/varnishtest/tests/c00120.vtc b/bin/varnishtest/tests/c00120.vtc index b340a48a9..ff9e41a1c 100644 --- a/bin/varnishtest/tests/c00120.vtc +++ b/bin/varnishtest/tests/c00120.vtc @@ -15,6 +15,10 @@ varnish v1 -vcl+backend { } } -start +logexpect l1 -v v1 { + expect * * FetchError "No thread available for bgfetch" +} -start + client c1 { txreq rxresp @@ -29,4 +33,6 @@ client c1 { expect resp.status == 200 } -start +logexpect l1 -wait + varnish v1 -expect MAIN.bgfetch_no_thread == 1 From dridi.boukelmoune at gmail.com Fri Mar 15 10:08:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 10:08:05 +0000 (UTC) Subject: [master] ba242f765 Run docker without seccomp rules. Message-ID: <20240315100805.8FFE511E7FA@lists.varnish-cache.org> commit ba242f765cab3a31a94cff40c8de97e4741ea362 Author: Simon Stridsberg Date: Fri Mar 15 08:08:31 2024 +0100 Run docker without seccomp rules. Ubuntu noble tries to use `fchmodat2` (new syscall) and gets permission denied instead of ENOSYS. This is a small security risk but it's running inside of circleci containers anyway so i think its acceptable. diff --git a/.circleci/config.yml b/.circleci/config.yml index 9ade65a8b..06d3240d2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -186,6 +186,7 @@ jobs: docker run \ --rm \ -it \ + --security-opt seccomp=unconfined \ -e PARAM_DIST=$(echo "<< parameters.platform >>" | cut -d: -f1) \ -e PARAM_RELEASE=$(echo "<< parameters.platform >>" | cut -d: -f2) \ -v$(pwd):/varnish-cache \ From dridi.boukelmoune at gmail.com Fri Mar 15 13:43:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 13:43:09 +0000 (UTC) Subject: [master] cb900f2e2 build: Copy vmod_h2.rst into sphinx tree Message-ID: <20240315134309.3B12C61262@lists.varnish-cache.org> commit cb900f2e2f404c1ea17f67de59054e6217d8853c Author: Dridi Boukelmoune Date: Fri Mar 15 14:35:18 2024 +0100 build: Copy vmod_h2.rst into sphinx tree diff --git a/doc/sphinx/Makefile.am b/doc/sphinx/Makefile.am index af4bc85c4..b5d34fb8d 100644 --- a/doc/sphinx/Makefile.am +++ b/doc/sphinx/Makefile.am @@ -186,6 +186,10 @@ include/vmod_cookie.generated.rst: $(top_builddir)/vmod/vmod_cookie.rst cp $(top_builddir)/vmod/vmod_cookie.rst $@ BUILT_SOURCES += include/vmod_cookie.generated.rst +include/vmod_h2.generated.rst: $(top_builddir)/vmod/vmod_h2.rst + cp $(top_builddir)/vmod/vmod_h2.rst $@ +BUILT_SOURCES += include/vmod_h2.generated.rst + include/vmod_unix.generated.rst: $(top_builddir)/vmod/vmod_unix.rst cp $(top_builddir)/vmod/vmod_unix.rst $@ BUILT_SOURCES += include/vmod_unix.generated.rst From dridi.boukelmoune at gmail.com Fri Mar 15 13:43:09 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 13:43:09 +0000 (UTC) Subject: [master] 30fdf3753 doc: Add vmod_h2 to our sphinx documentation Message-ID: <20240315134309.7954761265@lists.varnish-cache.org> commit 30fdf3753dc88f65a4e519cb605e6776bbdfdc65 Author: Dridi Boukelmoune Date: Fri Mar 15 14:41:52 2024 +0100 doc: Add vmod_h2 to our sphinx documentation diff --git a/doc/sphinx/reference/index.rst b/doc/sphinx/reference/index.rst index 8eec67414..0d5dc0657 100644 --- a/doc/sphinx/reference/index.rst +++ b/doc/sphinx/reference/index.rst @@ -36,6 +36,7 @@ Bundled VMODs vmod_blob.rst vmod_cookie.rst vmod_directors.rst + vmod_h2.rst vmod_proxy.rst vmod_purge.rst vmod_std.rst diff --git a/doc/sphinx/reference/vmod_h2.rst b/doc/sphinx/reference/vmod_h2.rst new file mode 100644 index 000000000..61c1560a7 --- /dev/null +++ b/doc/sphinx/reference/vmod_h2.rst @@ -0,0 +1,7 @@ +.. + Copyright (c) 2024 Varnish Software AS + SPDX-License-Identifier: BSD-2-Clause + See LICENSE file for full text of license + + +.. include:: ../include/vmod_h2.generated.rst From dridi.boukelmoune at gmail.com Fri Mar 15 13:59:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 13:59:05 +0000 (UTC) Subject: [master] e2171ae44 whats-new: Clarify bits restoration example Message-ID: <20240315135905.1925C61EC3@lists.varnish-cache.org> commit e2171ae44efbb1c7286dd47e4be8163eb45a133c Author: Dridi Boukelmoune Date: Fri Mar 15 14:57:58 2024 +0100 whats-new: Clarify bits restoration example diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index 333553369..706b37868 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -101,6 +101,10 @@ However, this could not work with bits parameters:: If the ``feature`` parameter is changed, reusing the output of ``param.set`` cannot guarantee the restoration that exact value:: + # third party intervention + $ varnishadm param.set feature +no_coredump | jq -r '.[3].value' + + # attempt at restoring the captured value $ varnishadm param.set -j feature +http2,+validate_headers | jq -r '.[3].value' +http2,+no_coredump,+validate_headers From dridi.boukelmoune at gmail.com Fri Mar 15 14:10:06 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Fri, 15 Mar 2024 14:10:06 +0000 (UTC) Subject: [master] 1ae702957 whats-new: Keep consistent bits examples Message-ID: <20240315141006.9A80665759@lists.varnish-cache.org> commit 1ae7029575c727a6b37135da4ba474027161f46b Author: Dridi Boukelmoune Date: Fri Mar 15 15:07:54 2024 +0100 whats-new: Keep consistent bits examples diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index 706b37868..2a6b36474 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -113,8 +113,14 @@ relative to none of the bits being set. A list of bits can start with the special value ``none`` to clear all the bits, followed by specific bits to raise:: + # atomically update and capture feature flags $ varnishadm param.set -j feature +http2 | jq -r '.[3].value' none,+http2,+validate_headers + + # very insistent systems administrator + $ varnishadm param.set feature +no_coredump | jq -r '.[3].value' + + # successful attempt at restoring the captured value $ varnishadm param.set -j feature none,+http2,+validate_headers | jq -r '.[3].value' none,+http2,+validate_headers From dridi.boukelmoune at gmail.com Mon Mar 18 16:13:00 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 18 Mar 2024 16:13:00 +0000 (UTC) Subject: [master] 8e8e7896b hash: Apply OC_F_DYING to purged objects Message-ID: <20240318161301.91DF1425E@lists.varnish-cache.org> commit 8e8e7896b24cedb834a7e37f71f531c702f26c84 Author: Dridi Boukelmoune Date: Tue Mar 12 17:39:43 2024 +0100 hash: Apply OC_F_DYING to purged objects All paths to EXP_Remove() raise the OC_F_DYING flag to dismiss the objcore in HSH_Lookup(). A regular purge used to EXP_Rearm() an oc for immediate (yet delayed) expiry, leaving it to the expiry thread to apply this flag and call EXP_Remove(). When the regular purge went from EXP_Rearm() to EXP_Remove() in order to avoid counting purged objects as expired, the OC_F_DYING flag was overlooked. Refs 709f71ab731298fa4d30d4c8b2b61dae04002ea6 diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c index ce31aecf0..8627c7a95 100644 --- a/bin/varnishd/cache/cache_hash.c +++ b/bin/varnishd/cache/cache_hash.c @@ -718,6 +718,8 @@ HSH_Purge(struct worker *wrk, struct objhead *oh, vtim_real ttl_now, } if (oc->flags & OC_F_DYING) continue; + if (is_purge) + oc->flags |= OC_F_DYING; oc->refcnt++; ocp[n++] = oc; } From nils.goroll at uplex.de Mon Mar 18 16:13:01 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Mon, 18 Mar 2024 16:13:01 +0000 (UTC) Subject: [master] 958a98cf1 Last minute changelog TLC Message-ID: <20240318161301.97B31425F@lists.varnish-cache.org> commit 958a98cf111333725658967d1c33f6de233c7c9b Author: Nils Goroll Date: Mon Mar 18 12:47:59 2024 +0100 Last minute changelog TLC diff --git a/doc/changes.rst b/doc/changes.rst index 33d9ab3f4..1c500aaec 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -41,6 +41,132 @@ Varnish Cache NEXT (2024-03-15) .. PLEASE keep this roughly in commit order as shown by git-log / tig (new to old) +* The parameters ``idle_send_timeout`` and ``timeout_idle`` are now + limited to a maximum of 1 hour. + +* The VCL variables ``bereq.connect_timeout``, + ``bereq.first_byte_timeout``, ``bereq.between_bytes_timeout``, + ``bereq.task_deadline``, ``sess.timeout_idle``, + ``sess.timeout_linger``, ``sess.idle_send_timeout`` and + ``sess.send_timeout`` can now be ``unset`` to use their default + values from parameters. + +* Timeout and deadline parameters and VCL variables can now be set to + the special value ``never`` to not apply an infinitely long + timeout. Parameters which used to be of type ``timeout`` but do not + accept ``never`` have been moved to the new type ``duration``. + +* The implementation of the feature flag ``esi_include_onerror`` added + in 7.3.0 has been reverted to more closely match the behavior of + Varnish-Cache before 7.3.0: By default, fragments are included + again, even errors. When ``esi_include_onerror`` is enabled and + errors are encountered while processing ESI fragment, processing + only continues if the ``onerror`` attribute of the ```` + tag is present. + + Any response status other than ``200`` or ``204`` counts as an error + as well as any fetch error. + + Streaming responses may continue to be partially delivered. + + Error behavior has been fixed to be consistent also for zero length + fragments. + +* The new VSC ``n_superseded`` gets incremented every time an object + is superseded by a new one, for example when the grace and/or keep + timers kept it in cache for longer than the TTL and a fresh copy is + fetched. + + Cache evictions of superseded objects are logged as ``ExpKill`` + messages starting with ``VBF_Superseded``. + + .. _Varnish-Modules #222: https://github.com/varnish/varnish-modules/issues/222 + +* The implementation of ``PRIV_TASK`` and ``PRIV_TOP`` VMOD + function/method arguments has been fixed to also work with + ``std.rollback()`` (`Varnish-Modules #222`_) + +* Transports are now responsible for calling ``VDP_Close()`` in all + cases. + +* The format of ``BackendClose`` VSL records has been changed to use + the short reason name for consistence with ``SessClose``. + +* During ``varnishd`` shutdown, pooled backend connections are now + closed bi-directionally. + +* Mode bits of files opened via the unix jail as ``JAIL_FIXFD_FILE`` + are now correctly set as ``0600``. + +* The ``busy_stats_rate`` feature now also works for HTTP/2. + +* The ``BUILD_VMOD_$NAME`` m4 macro for VMOD Makefiles has been fixed + to properly support custom ``CFLAGS``. + +* Storage engines are now responsible for deciding which + ``fetch_chunksize`` to use. When Varnish-Cache does not know the + expected object size, it calls the ``objgetspace`` with a zero + ``sz`` argument. + +* The ``Timestamp`` SLT with ``Process`` prefix is not emitted any + more when processing continues as for restarts. + +* The ``FetchError`` SLT with ``HTC`` prefix now contains a verbose + explanation. + +* Varnish Test Cases (VTCs) now support an ``include`` statement. + +* ``varnishncsa`` now supports the ``%{Varnish:default_format}x`` + format to use the default format with additions. + +* A deadlock in ``VRT_AddDirector()`` is now avoided with dynamic + backends when the VCL goes cold. + +* A new variable ``bereq.task_deadline``, available in ``sub vcl_pipe + {}`` only for now, allows to limit the total duration of pipe + transactions. Its default comes from the ``pipe_task_deadline`` + parameter, which itself defaults to ``never``. + +* The VSC counters ``n_expired``, ``n_purges`` and ``n_obj_purged`` + have been fixed for purged objects. + +* The ``ExpKill`` SLT prefix ``EXP_expire`` has been renamed to + ``EXP_Inspect``. + +* New VSL records of the ``ExpKill`` SLT with ``EXP_Removed`` are now + created to uniformly log all "object removed from cache" events. + +* VSL records of the ``ExpKill`` SLT with ``EXP_Expired`` prefix now + contain the number of hits on the removed object. + +* A bug has been fixed in ``varnishstat`` where the description of the + last VSC was not shown. + +* VCL COLD events have been fixed for directors vs. VMODs: VDI COLD + now comes before VMOD COLD. + +* The ``file`` storage engine now fails properly if the file size is + too small. + +* The ``.happy`` stevedore type method now returns ``true`` if not + implemented instead of panicking ``varnishd`` (`4036`_) + +* Use of ``objiterate_f`` on request bodies has been fixed to + correctly post ``OBJ_ITER_END``. + +* Use of ``STV_NewObject()`` has been fixed to correctly request zero + bytes for attributes where only a body is to be stored. + +* ``(struct req).filter_list`` has been renamed to ``vdp_filter_list``. + +* 304 object copying has been optimized to make optimal use of storage + engines' allocations. + +* Use of the ``trimstore`` storage engine function has been fixed for + 304 responses. + +* A missing ``:scheme`` for HTTP/2 requests is now properly handled. + * The ``fold`` flag has been added to Access Control Lists (ACLs) in VCL. When it is activated with ``acl ... +fold {}``, ACL entries get optimized in that subnets contained in other entries are skipped @@ -144,6 +270,7 @@ Varnish Cache NEXT (2024-03-15) .. _CVE-2023-44487: https://nvd.nist.gov/vuln/detail/CVE-2023-44487 +.. _4036: https://github.com/varnishcache/varnish-cache/issues/4036 .. _3984: https://github.com/varnishcache/varnish-cache/issues/3984 .. _3995: https://github.com/varnishcache/varnish-cache/issues/3995 .. _3996: https://github.com/varnishcache/varnish-cache/issues/3996 From nils.goroll at uplex.de Mon Mar 18 16:13:01 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Mon, 18 Mar 2024 16:13:01 +0000 (UTC) Subject: [master] f44b1814b Changelog polish Message-ID: <20240318161301.A69534263@lists.varnish-cache.org> commit f44b1814b4dccc56bf5e0df213464907b14fe32b Author: Nils Goroll Date: Mon Mar 18 12:58:02 2024 +0100 Changelog polish - before coffee + after coffee diff --git a/doc/changes.rst b/doc/changes.rst index 1c500aaec..9cc3357eb 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -52,15 +52,15 @@ Varnish Cache NEXT (2024-03-15) values from parameters. * Timeout and deadline parameters and VCL variables can now be set to - the special value ``never`` to not apply an infinitely long + the special value ``never`` to apply an infinitely long timeout. Parameters which used to be of type ``timeout`` but do not accept ``never`` have been moved to the new type ``duration``. * The implementation of the feature flag ``esi_include_onerror`` added - in 7.3.0 has been reverted to more closely match the behavior of - Varnish-Cache before 7.3.0: By default, fragments are included + in Varnish-Cache 7.3.0 has been reverted to more closely match the + behavior before that release: By default, fragments are included again, even errors. When ``esi_include_onerror`` is enabled and - errors are encountered while processing ESI fragment, processing + errors are encountered while retrieving an ESI fragment, processing only continues if the ``onerror`` attribute of the ```` tag is present. @@ -90,12 +90,12 @@ Varnish Cache NEXT (2024-03-15) cases. * The format of ``BackendClose`` VSL records has been changed to use - the short reason name for consistence with ``SessClose``. + the short reason name for consistency with ``SessClose``. * During ``varnishd`` shutdown, pooled backend connections are now closed bi-directionally. -* Mode bits of files opened via the unix jail as ``JAIL_FIXFD_FILE`` +* Mode bits of files opened via the UNIX jail as ``JAIL_FIXFD_FILE`` are now correctly set as ``0600``. * The ``busy_stats_rate`` feature now also works for HTTP/2. @@ -105,8 +105,8 @@ Varnish Cache NEXT (2024-03-15) * Storage engines are now responsible for deciding which ``fetch_chunksize`` to use. When Varnish-Cache does not know the - expected object size, it calls the ``objgetspace`` with a zero - ``sz`` argument. + expected object size, it calls the ``objgetspace`` stevedore + function with a zero ``sz`` argument. * The ``Timestamp`` SLT with ``Process`` prefix is not emitted any more when processing continues as for restarts. @@ -134,7 +134,7 @@ Varnish Cache NEXT (2024-03-15) ``EXP_Inspect``. * New VSL records of the ``ExpKill`` SLT with ``EXP_Removed`` are now - created to uniformly log all "object removed from cache" events. + emitted to uniformly log all "object removed from cache" events. * VSL records of the ``ExpKill`` SLT with ``EXP_Expired`` prefix now contain the number of hits on the removed object. From dridi.boukelmoune at gmail.com Mon Mar 18 16:13:01 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 18 Mar 2024 16:13:01 +0000 (UTC) Subject: [master] a8add6e4d whats-new: Remove useless pipe Message-ID: <20240318161301.A09504262@lists.varnish-cache.org> commit a8add6e4d05bd63281675881878576fd9be179df Author: Dridi Boukelmoune Date: Mon Mar 18 11:36:01 2024 +0100 whats-new: Remove useless pipe Spotted by Nils. diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index 2a6b36474..4bef696c0 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -118,7 +118,7 @@ raise:: none,+http2,+validate_headers # very insistent systems administrator - $ varnishadm param.set feature +no_coredump | jq -r '.[3].value' + $ varnishadm param.set feature +no_coredump # successful attempt at restoring the captured value $ varnishadm param.set -j feature none,+http2,+validate_headers | jq -r '.[3].value' From nils.goroll at uplex.de Mon Mar 18 16:13:01 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Mon, 18 Mar 2024 16:13:01 +0000 (UTC) Subject: [master] 662874435 Additions to release docs Message-ID: <20240318161301.AB8384264@lists.varnish-cache.org> commit 662874435af3a62af965ee030f74f25bebf37d61 Author: Nils Goroll Date: Mon Mar 18 13:15:52 2024 +0100 Additions to release docs diff --git a/doc/sphinx/whats-new/upgrading-trunk.rst b/doc/sphinx/whats-new/upgrading-trunk.rst index 706966391..cc0605775 100644 --- a/doc/sphinx/whats-new/upgrading-trunk.rst +++ b/doc/sphinx/whats-new/upgrading-trunk.rst @@ -52,6 +52,9 @@ that purpose:: varnishadm param.set pipe_timeout never +The parameters ``idle_send_timeout`` and ``timeout_idle`` are now +limited to a maximum of 1 hour. + VRT ~~~ @@ -66,4 +69,20 @@ respective parameters due to a limitation in how VCL is compiled. As a convenience, a new macro ``VRT_BACKEND_INIT()`` behaves like ``INIT_OBJ`` but initializes timeouts to a negative value. +VCL COLD events have been fixed for directors vs. VMODs: VDI COLD now +comes before VMOD COLD. + +Other changes relevant for VMOD / VEXT authors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Transports are now responsible for calling ``VDP_Close()`` in all +cases. + +Storage engines are now responsible for deciding which +``fetch_chunksize`` to use. When Varnish-Cache does not know the +expected object size, it calls the ``objgetspace`` stevedore function +with a zero ``sz`` argument. + +``(struct req).filter_list`` has been renamed to ``vdp_filter_list``. + *eof* From dridi.boukelmoune at gmail.com Mon Mar 18 16:13:01 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 18 Mar 2024 16:13:01 +0000 (UTC) Subject: [master] ac9830e9c changes: Split a strands of hair Message-ID: <20240318161301.CB0334267@lists.varnish-cache.org> commit ac9830e9c72eca7194c5cb60c292e6d0f1f6b1a8 Author: Dridi Boukelmoune Date: Mon Mar 18 14:00:56 2024 +0100 changes: Split a strands of hair Reverting "retrieving" to "processing" is motivated by the fact that we process ESI on the client side and we don't know whether we are in fact retrieving an object from a backend, or just reusing one from the cache. Even if the word "processing" appears again in the sentence, I think it is more accurate here. Better diff with the --word-diff option. diff --git a/doc/changes.rst b/doc/changes.rst index 9cc3357eb..3aa1b6d36 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -51,16 +51,16 @@ Varnish Cache NEXT (2024-03-15) ``sess.send_timeout`` can now be ``unset`` to use their default values from parameters. -* Timeout and deadline parameters and VCL variables can now be set to - the special value ``never`` to apply an infinitely long - timeout. Parameters which used to be of type ``timeout`` but do not - accept ``never`` have been moved to the new type ``duration``. +* Timeout and deadline parameters can now be set to a new special value + ``never`` to apply an infinitely long timeout. Parameters which used to + be of type ``timeout`` but do not accept ``never`` have been moved to + the new type ``duration``. VCL variables cannot be set to ``never``. -* The implementation of the feature flag ``esi_include_onerror`` added +* The implementation of the feature flag ``esi_include_onerror`` changed in Varnish-Cache 7.3.0 has been reverted to more closely match the behavior before that release: By default, fragments are included again, even errors. When ``esi_include_onerror`` is enabled and - errors are encountered while retrieving an ESI fragment, processing + errors are encountered while processing an ESI fragment, processing only continues if the ``onerror`` attribute of the ```` tag is present. @@ -109,7 +109,8 @@ Varnish Cache NEXT (2024-03-15) function with a zero ``sz`` argument. * The ``Timestamp`` SLT with ``Process`` prefix is not emitted any - more when processing continues as for restarts. + more when processing continues as for restarts, or when ``vcl_deliver`` + transitions to ``vcl_synth``. * The ``FetchError`` SLT with ``HTC`` prefix now contains a verbose explanation. From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:04 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:04 +0000 (UTC) Subject: [6.0] 2b75ddaea vtc_http2: Automatic stream identifier Message-ID: <20240318182004.3AE4F6EDB9@lists.varnish-cache.org> commit 2b75ddaea6553bbf36f132621bc1f058ce172845 Author: Dridi Boukelmoune Date: Fri Oct 20 18:53:26 2023 +0200 vtc_http2: Automatic stream identifier diff --git a/bin/varnishtest/tests/a02028.vtc b/bin/varnishtest/tests/a02028.vtc new file mode 100644 index 000000000..4ba8986ed --- /dev/null +++ b/bin/varnishtest/tests/a02028.vtc @@ -0,0 +1,24 @@ +varnishtest "Automatic stream numbers" + +server s1 { + loop 4 { + stream next { + rxreq + txresp + } -run + } +} -start + +client c1 -connect ${s1_sock} { + loop 3 { + stream next { + txreq + rxresp + } -run + } + + stream 7 { + txreq + rxresp + } -run +} -run diff --git a/bin/varnishtest/vtc_http.h b/bin/varnishtest/vtc_http.h index 5cd079890..0d542a2d3 100644 --- a/bin/varnishtest/vtc_http.h +++ b/bin/varnishtest/vtc_http.h @@ -63,6 +63,7 @@ struct http { pthread_t tp; VTAILQ_HEAD(, stream) streams; + unsigned last_stream; pthread_mutex_t mtx; pthread_cond_t cond; struct hpk_ctx *encctx; diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index d4d0443a2..0bc3d3362 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -2510,9 +2510,17 @@ stream_thread(void *priv) static struct stream * stream_new(const char *name, struct http *h) { - char *p; + char *p, buf[20]; struct stream *s; + if (!strcmp("next", name)) { + if (h->last_stream > 0) + bprintf(buf, "%d", h->last_stream + 2); + else + bprintf(buf, "%d", 1); + name = buf; + } + ALLOC_OBJ(s, STREAM_MAGIC); AN(s); AZ(pthread_cond_init(&s->cond, NULL)); @@ -2531,6 +2539,7 @@ stream_new(const char *name, struct http *h) CHECK_OBJ_NOTNULL(h, HTTP_MAGIC); s->hp = h; + h->last_stream = s->id; //bprintf(s->connect, "%s", "${v1_sock}"); AZ(pthread_mutex_lock(&h->mtx)); @@ -2623,7 +2632,8 @@ stream_run(struct stream *s) * stream ID [SPEC] [ACTION] * * ID is the HTTP/2 stream number, while SPEC describes what will be - * done in that stream. + * done in that stream. If ID has the value ``next``, the actual stream + * number is computed based on the last one. * * Note that, when parsing a stream action, if the entity isn't operating * in HTTP/2 mode, these spec is ran before:: @@ -2693,7 +2703,7 @@ cmd_stream(CMD_ARGS) continue; } if (**av == '-') - vtc_fatal(vl, "Unknown client argument: %s", *av); + vtc_fatal(vl, "Unknown stream argument: %s", *av); REPLACE(s->spec, *av); } } From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:04 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:04 +0000 (UTC) Subject: [6.0] 2b05b9ed2 http2_proto: Proper null checks for h2 errors Message-ID: <20240318182004.6BF246EDBC@lists.varnish-cache.org> commit 2b05b9ed29cd6743f7b21f059f03c18480cac646 Author: Dridi Boukelmoune Date: Mon Oct 23 11:34:31 2023 +0200 http2_proto: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index afa9f03ef..8ef3b9a90 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -832,11 +832,11 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) Lck_Lock(&h2->sess->mtx); CHECK_OBJ_ORNULL(r2->rxbuf, H2_RXBUF_MAGIC); - if (h2->error || r2->error) { + if (h2->error != NULL || r2->error != NULL) { if (r2->cond) AZ(pthread_cond_signal(r2->cond)); Lck_Unlock(&h2->sess->mtx); - return (h2->error ? h2->error : r2->error); + return (h2->error != NULL ? h2->error : r2->error); } /* Check padding if present */ @@ -1072,7 +1072,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp) } else l = 0; - if (h2->error || r2->error) + if (h2->error != NULL || r2->error != NULL) retval = VFP_ERROR; else if (r2->state >= H2_S_CLOS_REM && l <= *lp) retval = VFP_END; @@ -1274,15 +1274,15 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); - if (h2e == 0) - return (0); + if (h2e == NULL) + return (NULL); if (h2->rxf_stream == 0 || h2e->connection) return (h2e); // Connection errors one level up H2_Send_Get(wrk, h2, h2->req0); H2_Send_RST(wrk, h2, h2->req0, h2->rxf_stream, h2e); H2_Send_Rel(h2, h2->req0); - return (0); + return (NULL); } int @@ -1482,7 +1482,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) } h2e = h2_procframe(wrk, h2, h2f); - if (h2->error == 0 && h2e) { + if (h2->error == NULL && h2e != NULL) { h2->error = h2e; vbe32enc(b, h2->highest_stream); vbe32enc(b + 4, h2e->val); @@ -1490,5 +1490,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); H2_Send_Rel(h2, h2->req0); } - return (h2->error ? 0 : 1); + + return (h2->error != NULL ? 0 : 1); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:04 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:04 +0000 (UTC) Subject: [6.0] ca7682baf http2_send: Proper null checks for h2 errors Message-ID: <20240318182004.90D136EDC0@lists.varnish-cache.org> commit ca7682bafc2184583b58dc04a51053f44007b535 Author: Dridi Boukelmoune Date: Mon Oct 23 11:36:57 2023 +0200 http2_send: Proper null checks for h2 errors Conflicts: bin/varnishd/http2/cache_http2_send.c diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index f0a8b96cd..ddb00baad 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -239,11 +239,11 @@ h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - if (r2->error) + if (r2->error != NULL) return (r2->error); - if (h2->error && r2->stream > h2->goaway_last_stream) + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) return (h2->error); - return (0); + return (NULL); } static int64_t @@ -263,25 +263,25 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, if (r2->t_window <= 0 || h2->req0->t_window <= 0) { r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); - while (r2->t_window <= 0 && h2_errcheck(r2, h2) == 0) { + + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); r2->cond = NULL; } - while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == 0) + + while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == NULL) (void)h2_cond_wait(h2->winupd_cond, h2, r2); - if (h2_errcheck(r2, h2) == 0) { - w = h2_win_limit(r2, h2); - if (w > wanted) - w = wanted; + if (h2_errcheck(r2, h2) == NULL) { + w = vmin_t(int64_t, h2_win_limit(r2, h2), wanted); h2_win_charge(r2, h2, w); assert (w > 0); } h2_send_get_locked(wrk, h2, r2); } - if (w == 0 && h2_errcheck(r2, h2) == 0) { + if (w == 0 && h2_errcheck(r2, h2) == NULL) { assert(r2->t_window > 0); assert(h2->req0->t_window > 0); w = h2_win_limit(r2, h2); @@ -318,7 +318,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, AN(H2_SEND_HELD(h2, r2)); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(ftyp); @@ -343,7 +343,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } else @@ -363,8 +363,8 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, tf = mfs; if (ftyp->respect_window && p != ptr) { tf = h2_do_window(wrk, r2, h2, - (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + (len > mfs) ? mfs : len); + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } @@ -385,7 +385,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, ftyp = ftyp->continuation; flags &= ftyp->flags; final_flags &= ftyp->flags; - } while (!h2->error && len > 0); + } while (h2->error == NULL && len > 0); } } @@ -398,6 +398,7 @@ H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2, CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); AN(H2_SEND_HELD(h2, r2)); + AN(h2e); Lck_Lock(&h2->sess->mtx); VSLb(h2->vsl, SLT_Debug, "H2: stream %u: %s", stream, h2e->txt); From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:04 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:04 +0000 (UTC) Subject: [6.0] e006849e6 http2_proto: Make h2_stream_tmo() return an error Message-ID: <20240318182004.AA72D6EDC4@lists.varnish-cache.org> commit e006849e694633767ccc8ad427c673bd3b294794 Author: Dridi Boukelmoune Date: Thu Nov 16 13:16:15 2023 +0100 http2_proto: Make h2_stream_tmo() return an error Conflicts: bin/varnishd/http2/cache_http2.h bin/varnishd/http2/cache_http2_proto.c diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 4020b2887..e5cf6a224 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -257,7 +257,7 @@ void H2_Send(struct worker *, struct h2_req *, h2_frame type, uint8_t flags, /* cache_http2_proto.c */ struct h2_req * h2_new_req(const struct worker *, struct h2_sess *, unsigned stream, struct req *); -int h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); +h2_error h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); void h2_del_req(struct worker *, struct h2_req *); void h2_kill_req(struct worker *, struct h2_sess *, struct h2_req *, h2_error); int h2_rxframe(struct worker *, struct h2_sess *); diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 8ef3b9a90..1372074cb 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1285,10 +1285,10 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (NULL); } -int +h2_error h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) { - int r = 0; + h2_error h2e = NULL; CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); @@ -1301,36 +1301,36 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) AN(r2->t_winupd); if (r2->t_winupd == 0 && r2->t_send == 0) - return (0); + return (NULL); if (isnan(now) || (r2->t_winupd != 0 && now - r2->t_winupd > cache_param->idle_send_timeout)) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - if (r == 0 && r2->t_send != 0 && + if (h2e == NULL && r2->t_send != 0 && now - r2->t_send > cache_param->send_timeout) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit send_timeout", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - return (r); + return (h2e); } -static int +static h2_error h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) { - int r; + h2_error h2e; Lck_Lock(&h2->sess->mtx); - r = h2_stream_tmo(h2, r2, h2->sess->t_idle); + h2e = h2_stream_tmo(h2, r2, h2->sess->t_idle); Lck_Unlock(&h2->sess->mtx); - return (r); + return (h2e); } /* From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:04 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:04 +0000 (UTC) Subject: [6.0] 5ffa8a76c http2_send: Collect the timeout error Message-ID: <20240318182004.C674B6EDCA@lists.varnish-cache.org> commit 5ffa8a76cd55b5fae909924086b897bdf1949a49 Author: Dridi Boukelmoune Date: Thu Nov 16 13:23:18 2023 +0100 http2_send: Collect the timeout error Conflicts: bin/varnishd/http2/cache_http2_send.c diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ddb00baad..b78c95713 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -46,6 +46,7 @@ static int h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { vtim_real now, when = 0.; + h2_error h2e; int r; AN(cond); @@ -70,18 +71,16 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) * that the stream reached the idle_send_timeout via the lock and * force it to log it. */ - if (h2_stream_tmo(h2, r2, now)) - r = ETIMEDOUT; - else if (r == ETIMEDOUT) - AN(h2_stream_tmo(h2, r2, NAN)); - - if (r == ETIMEDOUT) { - if (r2->error == NULL) - r2->error = H2SE_CANCEL; - return (-1); + h2e = h2_stream_tmo(h2, r2, now); + if (h2e == NULL && r == ETIMEDOUT) { + h2e = h2_stream_tmo(h2, r2, NAN); + AN(h2e); } - return (0); + if (r2->error == NULL) + r2->error = h2e; + + return (h2e != NULL ? -1 : 0); } static void From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:04 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:04 +0000 (UTC) Subject: [6.0] cd48ced78 h2: Send GOAWAY frames in a dedicated function Message-ID: <20240318182005.0F9646EDD2@lists.varnish-cache.org> commit cd48ced78d5363171913cf7882b855ad3c40ddcd Author: Dridi Boukelmoune Date: Tue Jan 18 10:08:33 2022 +0100 h2: Send GOAWAY frames in a dedicated function And after issuing or receiving a goaway, stop processing frames when there are no streams left. Initially submitted as part of listen sockets management. Refs #3959 Conflicts: bin/varnishd/http2/cache_http2_proto.c diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index e5cf6a224..d0dbb4e35 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -163,6 +163,7 @@ struct h2_sess { struct sess *sess; int refcnt; uint32_t highest_stream; + int goaway; int bogosity; int do_sweep; diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 1372074cb..ccce69f0e 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -381,6 +381,7 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); assert(r2 == h2->req0); + h2->goaway = 1; h2->goaway_last_stream = vbe32dec(h2->rxf_data); h2->error = h2_connectionerror(vbe32dec(h2->rxf_data + 4)); Lck_Lock(&h2->sess->mtx); @@ -389,6 +390,25 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) return (h2->error); } +static void +h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) +{ + char b[8]; + + ASSERT_RXTHR(h2); + AN(h2e); + + if (h2->goaway) + return; + + h2->goaway = 1; + vbe32enc(b, h2->highest_stream); + vbe32enc(b + 4, h2e->val); + H2_Send_Get(wrk, h2, h2->req0); + H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); + H2_Send_Rel(h2, h2->req0); +} + /********************************************************************** */ @@ -1410,9 +1430,12 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) enum htc_status_e hs; h2_frame h2f; h2_error h2e; - char b[8]; ASSERT_RXTHR(h2); + + if (h2->goaway && h2->open_streams == 0) + return (0); + VTCP_blocking(*h2->htc->rfd); h2->sess->t_idle = VTIM_real(); hs = HTC_RxStuff(h2->htc, h2_frame_complete, @@ -1484,11 +1507,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2e = h2_procframe(wrk, h2, h2f); if (h2->error == NULL && h2e != NULL) { h2->error = h2e; - vbe32enc(b, h2->highest_stream); - vbe32enc(b + 4, h2e->val); - H2_Send_Get(wrk, h2, h2->req0); - H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); - H2_Send_Rel(h2, h2->req0); + h2_tx_goaway(wrk, h2, h2e); } return (h2->error != NULL ? 0 : 1); From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:05 +0000 (UTC) Subject: [6.0] ee7930ed1 http2_proto: Enforce session timeouts in h2_sweep() Message-ID: <20240318182005.3612F6EDDC@lists.varnish-cache.org> commit ee7930ed171f740845ee4e15b8afbead22a11a41 Author: Dridi Boukelmoune Date: Thu Nov 16 14:52:49 2023 +0100 http2_proto: Enforce session timeouts in h2_sweep() The new meaning for h2->sess->t_idle is now the time since the last complete frame, except before the first frame where it corresponds to the creation of the session. Conflicts: bin/varnishd/http2/cache_http2_proto.c diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index ccce69f0e..0b1167f8c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1357,14 +1357,20 @@ h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) * This is the janitorial task of cleaning up any closed & refused * streams, and checking if the session is timed out. */ -static int +static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { - int tmo = 0; struct h2_req *r2, *r22; + h2_error h2e = NULL, tmo; + vtim_real now; ASSERT_RXTHR(h2); + now = VTIM_real(); + if (h2e == NULL && h2->open_streams == 0 && + h2->sess->t_idle + cache_param->timeout_idle < now) + h2e = H2CE_NO_ERROR; + h2->do_sweep = 0; VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) { if (r2 == h2->req0) { @@ -1388,10 +1394,9 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) /* FALLTHROUGH */ case H2_S_CLOS_LOC: case H2_S_OPEN: - if (h2_stream_tmo_unlocked(h2, r2)) { - tmo = 1; - continue; - } + tmo = h2_stream_tmo_unlocked(h2, r2); + if (h2e == NULL) + h2e = tmo; break; case H2_S_IDLE: /* Current code make this unreachable: h2_new_req is @@ -1403,9 +1408,7 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) break; } } - if (tmo) - return (0); - return (h2->refcnt > 1); + return (h2e); } @@ -1437,30 +1440,30 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) return (0); VTCP_blocking(*h2->htc->rfd); - h2->sess->t_idle = VTIM_real(); - hs = HTC_RxStuff(h2->htc, h2_frame_complete, - NULL, NULL, NAN, - h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle), - NAN, h2->local_settings.max_frame_size + 9); + hs = HTC_RxStuff(h2->htc, h2_frame_complete, NULL, NULL, NAN, + VTIM_real() + 0.5, NAN, h2->local_settings.max_frame_size + 9); + + h2e = NULL; switch (hs) { case HTC_S_COMPLETE: + h2->sess->t_idle = VTIM_real(); + if (h2->do_sweep) + h2e = h2_sweep(wrk, h2); break; case HTC_S_TIMEOUT: - if (h2_sweep(wrk, h2)) - return (1); - - /* FALLTHROUGH */ + h2e = h2_sweep(wrk, h2); + break; default: - /* XXX: HTC_S_OVERFLOW / FRAME_SIZE_ERROR handling */ - Lck_Lock(&h2->sess->mtx); - VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%d)", hs); - h2->error = H2CE_NO_ERROR; - Lck_Unlock(&h2->sess->mtx); + h2e = H2CE_ENHANCE_YOUR_CALM; + } + + if (h2e != NULL && h2e->connection) { + h2->error = h2e; return (0); } - if (h2->do_sweep) - (void)h2_sweep(wrk, h2); + if (hs != HTC_S_COMPLETE) + return (1); h2->rxf_len = vbe32dec(h2->htc->rxbuf_b) >> 8; h2->rxf_type = h2->htc->rxbuf_b[3]; From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:05 +0000 (UTC) Subject: [6.0] ec6a1e1dd http2_proto: Introduce a custom BROKE_WINDOW error Message-ID: <20240318182005.646126EDF1@lists.varnish-cache.org> commit ec6a1e1ddbb84004c0f0ad06344f67b954b572ac Author: Dridi Boukelmoune Date: Thu Nov 16 16:03:42 2023 +0100 http2_proto: Introduce a custom BROKE_WINDOW error Conflicts: bin/varnishd/http2/cache_http2_send.c include/tbl/h2_error.h diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 0b1167f8c..c141d464c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1328,7 +1328,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - h2e = H2SE_CANCEL; + h2e = H2SE_BROKE_WINDOW; } if (h2e == NULL && r2->t_send != 0 && diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index b78c95713..b3396a6f1 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -412,12 +412,14 @@ H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, uint32_t len, const void *ptr, uint64_t *counter) { uint64_t dummy_counter; + h2_error h2e; if (counter == NULL) counter = &dummy_counter; h2_send(wrk, r2, ftyp, flags, len, ptr, counter); - if (h2_errcheck(r2, r2->h2sess) == H2SE_CANCEL) - H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, H2SE_CANCEL); + h2e = h2_errcheck(r2, r2->h2sess); + if (h2e != NULL && h2e->val == H2SE_CANCEL->val) + H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, h2e); } diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 8f3485c24..1664eb99a 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -154,6 +154,13 @@ H2_ERROR( /* descr */ "http/2 rapid reset detected" ) +H2_ERROR( + /* name */ BROKE_WINDOW, + /* val */ 8, /* CANCEL */ + /* types */ 2, + /* reason */ SC_NULL, + /* descr */ "http/2 stream out of window credits" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:05 +0000 (UTC) Subject: [6.0] 9572267c9 param: New h2_window_timeout parameter Message-ID: <20240318182005.802716EDFC@lists.varnish-cache.org> commit 9572267c95e66fe7244aedb3bc357e1ba428e921 Author: Dridi Boukelmoune Date: Mon Oct 23 11:49:23 2023 +0200 param: New h2_window_timeout parameter This parameter needs to be somewhat high because web browsers may for example only credit streams for image resources just enough to parse metadata like width and height of a picture in order to perform layout computations and fetch resources more sensitive to latency before the effective image payloads. Conflicts: include/tbl/params.h diff --git a/include/tbl/params.h b/include/tbl/params.h index 665303db4..f99bb6ad4 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -1800,6 +1800,22 @@ PARAM( /* func */ NULL ) +PARAM( + /* name */ h2_window_timeout, + /* typ */ timeout, + /* min */ "0", + /* max */ NULL, + /* def */ "5", + /* units */ "seconds", + /* flags */ WIZARD, + /* s-text */ + "HTTP2 time limit without window credits. How long a stream may " + "wait for the client to credit the window and allow for more DATA " + "frames to be sent.", + /* l-text */ "", + /* func */ NULL +) + PARAM( /* name */ h2_header_table_size, /* typ */ bytes_u, From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:05 +0000 (UTC) Subject: [6.0] d4baf2fae http2_send: Move h2_errcheck() at the top Message-ID: <20240318182005.BD2216EE0A@lists.varnish-cache.org> commit d4baf2faea1b37859742928cd2aa98080a0f9552 Author: Dridi Boukelmoune Date: Mon Oct 23 16:40:26 2023 +0200 http2_send: Move h2_errcheck() at the top diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index b3396a6f1..565f373f0 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -42,6 +42,19 @@ #define H2_SEND_HELD(h2, r2) (VTAILQ_FIRST(&(h2)->txqueue) == (r2)) +static h2_error +h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) +{ + CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); + CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); + + if (r2->error != NULL) + return (r2->error); + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) + return (h2->error); + return (NULL); +} + static int h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { @@ -232,19 +245,6 @@ h2_win_charge(struct h2_req *r2, const struct h2_sess *h2, uint32_t w) h2->req0->t_window -= w; } -static h2_error -h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) -{ - CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); - CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - - if (r2->error != NULL) - return (r2->error); - if (h2->error != NULL && r2->stream > h2->goaway_last_stream) - return (h2->error); - return (NULL); -} - static int64_t h2_do_window(struct worker *wrk, struct h2_req *r2, struct h2_sess *h2, int64_t wanted) From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:05 +0000 (UTC) Subject: [6.0] 9dfb893d3 http2_send: Apply h2_window_timeout Message-ID: <20240318182005.E36906EE1C@lists.varnish-cache.org> commit 9dfb893d36d256f02d55c0e18b7ecf6e81b0857d Author: Dridi Boukelmoune Date: Mon Oct 23 13:15:45 2023 +0200 http2_send: Apply h2_window_timeout It replaces idle_send_timeout when the stream is waiting for window credits before sending more DATA frames. The idle_send_timeout will still apply to individual writes to the socket, but triggering it is considered a failure condition (this was already the case). The two loops are merged into a single one to better deal with the lack of ordering guarantees of request vs connection stream control flow window crediting. Refs #2980 Conflicts: bin/varnishd/http2/cache_http2_proto.c bin/varnishd/http2/cache_http2_send.c diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index c141d464c..b24473251 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1314,7 +1314,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); Lck_AssertHeld(&h2->sess->mtx); - /* NB: when now is NAN, it means that idle_send_timeout was hit + /* NB: when now is NAN, it means that h2_window_timeout was hit * on a lock condwait operation. */ if (isnan(now)) @@ -1324,10 +1324,9 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) return (NULL); if (isnan(now) || (r2->t_winupd != 0 && - now - r2->t_winupd > cache_param->idle_send_timeout)) { + now - r2->t_winupd > cache_param->h2_window_timeout)) { VSLb(h2->vsl, SLT_Debug, - "H2: stream %u: Hit idle_send_timeout waiting for" - " WINDOW_UPDATE", r2->stream); + "H2: stream %u: Hit h2_window_timeout", r2->stream); h2e = H2SE_BROKE_WINDOW; } diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 565f373f0..cdb77c643 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -69,19 +69,20 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) Lck_AssertHeld(&h2->sess->mtx); now = VTIM_real(); - if (cache_param->idle_send_timeout > 0.) - when = now + cache_param->idle_send_timeout; + if (cache_param->h2_window_timeout > 0.) + when = now + cache_param->h2_window_timeout; r = Lck_CondWait(cond, &h2->sess->mtx, when); assert(r == 0 || r == ETIMEDOUT); now = VTIM_real(); - /* NB: when we grab idle_send_timeout before acquiring the session + + /* NB: when we grab h2_window_timeout before acquiring the session * lock we may time out, but once we wake up both send_timeout and - * idle_send_timeout may have changed meanwhile. For this reason + * h2_window_timeout may have changed meanwhile. For this reason * h2_stream_tmo() may not log what timed out and we need to call * again with a magic NAN "now" that indicates to h2_stream_tmo() - * that the stream reached the idle_send_timeout via the lock and + * that the stream reached the h2_window_timeout via the lock and * force it to log it. */ h2e = h2_stream_tmo(h2, r2, now); @@ -204,6 +205,10 @@ H2_Send_Frame(struct worker *wrk, struct h2_sess *h2, iov[1].iov_len = len; s = writev(h2->sess->fd, iov, len == 0 ? 1 : 2); if (s != sizeof hdr + len) { + if (errno == EWOULDBLOCK) { + VSLb(h2->vsl, SLT_Debug, + "H2: stream %u: Hit idle_send_timeout", stream); + } /* * There is no point in being nice here, we will be unable * to send a GOAWAY once the code unrolls, so go directly diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index 29ffea354..d2f5dcca8 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -44,13 +44,13 @@ client c1 { logexpect l1 -wait -# coverage for idle_send_timeout with c2 +# coverage for h2_window_timeout with c2 -varnish v1 -cliok "param.set idle_send_timeout 1" +varnish v1 -cliok "param.set h2_window_timeout 1" varnish v1 -cliok "param.reset send_timeout" logexpect l2 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c2 { @@ -79,12 +79,12 @@ client c2 { logexpect l2 -wait -# coverage for idle_send_timeout change with c3 +# coverage for h2_window_timeout change with c3 barrier b3 cond 2 logexpect l3 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c3 { @@ -113,7 +113,7 @@ client c3 { } -start barrier b3 sync -varnish v1 -cliok "param.reset idle_send_timeout" +varnish v1 -cliok "param.reset h2_window_timeout" client c3 -wait logexpect l3 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] 88963bb2e http2_send: Track bankrupt streams Message-ID: <20240318182006.109BD6EE2B@lists.varnish-cache.org> commit 88963bb2e3dcf0ee5710ca367543156ce6347a42 Author: Dridi Boukelmoune Date: Mon Oct 23 17:15:20 2023 +0200 http2_send: Track bankrupt streams Conflicts: bin/varnishd/http2/cache_http2.h diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index d0dbb4e35..3c30d17e9 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -162,6 +162,8 @@ struct h2_sess { struct sess *sess; int refcnt; + int open_streams; + int winup_streams; uint32_t highest_stream; int goaway; int bogosity; @@ -193,7 +195,6 @@ struct h2_sess { VTAILQ_HEAD(,h2_req) txqueue; h2_error error; - int open_streams; // rst rate limit parameters, copied from h2_* parameters vtim_dur rapid_reset; diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index cdb77c643..eb6d0170c 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -268,6 +268,9 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); + assert(h2->winup_streams >= 0); + h2->winup_streams++; + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); @@ -282,6 +285,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_win_charge(r2, h2, w); assert (w > 0); } + + assert(h2->winup_streams > 0); + h2->winup_streams--; + h2_send_get_locked(wrk, h2, r2); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] 0e4286c94 vsc: New MAIN.sc_bankrupt counter Message-ID: <20240318182006.328C26EE58@lists.varnish-cache.org> commit 0e4286c94007591e4b32857e991b729e331a7757 Author: Dridi Boukelmoune Date: Thu Nov 16 16:58:55 2023 +0100 vsc: New MAIN.sc_bankrupt counter diff --git a/bin/varnishd/VSC_main.vsc b/bin/varnishd/VSC_main.vsc index 4bb4697bf..b38594bd0 100644 --- a/bin/varnishd/VSC_main.vsc +++ b/bin/varnishd/VSC_main.vsc @@ -609,6 +609,14 @@ configured limits for the number of permitted rapid stream resets. +.. varnish_vsc:: sc_bankrupt + :level: diag + :oneliner: Session Err BANKRUPT + + Number of times we failed an http/2 session because all the streams + were waiting for their windows to be credited when h2_window_timeout + triggered. + .. varnish_vsc:: client_resp_500 :level: diag :group: wrk diff --git a/include/tbl/sess_close.h b/include/tbl/sess_close.h index de130aa87..81b6f41f8 100644 --- a/include/tbl/sess_close.h +++ b/include/tbl/sess_close.h @@ -48,6 +48,7 @@ SESS_CLOSE(RANGE_SHORT, range_short, 1, "Insufficient data for range") SESS_CLOSE(REQ_HTTP20, req_http20, 1, "HTTP2 not accepted") SESS_CLOSE(VCL_FAILURE, vcl_failure, 1, "VCL failure") SESS_CLOSE(RAPID_RESET, rapid_reset, 1, "HTTP2 rapid reset") +SESS_CLOSE(BANKRUPT, bankrupt, 1, "HTTP2 credit bankruptcy") #undef SESS_CLOSE /*lint -restore */ From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] 57efc3b27 http2_send: Promote global BROKE_WINDOW to BANKRUPT Message-ID: <20240318182006.55BC76EE6F@lists.varnish-cache.org> commit 57efc3b27cb18284ecef36932c10b45264a881e2 Author: Dridi Boukelmoune Date: Thu Nov 16 17:02:35 2023 +0100 http2_send: Promote global BROKE_WINDOW to BANKRUPT When a stream times out waiting for window credits, and all the other streams are broke, declare the whole connection bankrupt. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index b24473251..fa8e94928 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1360,11 +1360,12 @@ static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { struct h2_req *r2, *r22; - h2_error h2e = NULL, tmo; + h2_error h2e, tmo; vtim_real now; ASSERT_RXTHR(h2); + h2e = h2->error; now = VTIM_real(); if (h2e == NULL && h2->open_streams == 0 && h2->sess->t_idle + cache_param->timeout_idle < now) diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index eb6d0170c..ca6151fb2 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -286,6 +286,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + if (r2->error == H2SE_BROKE_WINDOW && + h2->open_streams <= h2->winup_streams) + h2->error = r2->error = H2CE_BANKRUPT; + assert(h2->winup_streams > 0); h2->winup_streams--; diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index d2f5dcca8..1e5a7dc8a 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -6,7 +6,13 @@ server s1 { } -start varnish v1 -cliok "param.set feature +http2" -varnish v1 -vcl+backend "" -start +varnish v1 -vcl+backend { + sub vcl_recv { + if (req.url ~ "synth") { + return (synth(200)); + } + } +} -start # coverage for send_timeout with c1 @@ -66,6 +72,10 @@ client c2 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -75,6 +85,9 @@ client c2 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -run logexpect l2 -wait @@ -100,6 +113,10 @@ client c3 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -110,6 +127,9 @@ client c3 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -start barrier b3 sync diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 1664eb99a..d0030d27f 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -161,6 +161,14 @@ H2_ERROR( /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) + +H2_ERROR( + /* name */ BANKRUPT, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* reason */ SC_BANKRUPT, + /* descr */ "http/2 bankrupt connection" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] 71666a00e http2: New send_goaway flag for errors Message-ID: <20240318182006.73E606EE7F@lists.varnish-cache.org> commit 71666a00e95798017614a1554765d5e6b6719811 Author: Dridi Boukelmoune Date: Thu Nov 16 17:27:11 2023 +0100 http2: New send_goaway flag for errors diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 3c30d17e9..201875409 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -42,16 +42,18 @@ struct h2_error_s { uint32_t val; int stream; int connection; + int send_goaway; enum sess_close reason; }; typedef const struct h2_error_s *h2_error; #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) extern const struct h2_error_s H2CE_##U[1]; -#define H2EC2(U,v,r,d) extern const struct h2_error_s H2SE_##U[1]; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) extern const struct h2_error_s H2CE_##U[1]; +#define H2EC2(U,v,g,r,d) extern const struct h2_error_s H2SE_##U[1]; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index fa8e94928..36ccb895e 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -46,10 +46,13 @@ #include "vtim.h" #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,r}}; -#define H2EC2(U,v,r,d) const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,r}}; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) \ + const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,g,r}}; +#define H2EC2(U,v,g,r,d) \ + const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,g,r}}; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -61,6 +64,7 @@ static const struct h2_error_s H2NN_ERROR[1] = {{ 0xffffffff, 1, 1, + 0, SC_RX_JUNK }}; @@ -88,10 +92,11 @@ h2_framename(enum h2frame h2f) */ static const h2_error stream_errors[] = { -#define H2EC1(U,v,r,d) -#define H2EC2(U,v,r,d) [v] = H2SE_##U, -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) +#define H2EC2(U,v,g,r,d) [v] = H2SE_##U, +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -113,10 +118,11 @@ h2_streamerror(uint32_t u) */ static const h2_error conn_errors[] = { -#define H2EC1(U,v,r,d) [v] = H2CE_##U, -#define H2EC2(U,v,r,d) -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) [v] = H2CE_##U, +#define H2EC2(U,v,g,r,d) +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -1320,6 +1326,10 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) if (isnan(now)) AN(r2->t_winupd); + if (h2->error != NULL && h2->error->connection && + !h2->error->send_goaway) + return (h2->error); + if (r2->t_winupd == 0 && r2->t_send == 0) return (NULL); diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index 0bc3d3362..491a1d072 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -51,7 +51,7 @@ #define BUF_SIZE (1024*2048) static const char *const h2_errs[] = { -#define H2_ERROR(n,v,sc,r,t) [v] = #n, +#define H2_ERROR(n,v,sc,g,r,t) [v] = #n, #include NULL }; @@ -1213,7 +1213,7 @@ cmd_var_resolve(const struct stream *s, const char *spec, char *buf) else return (NULL); } -#define H2_ERROR(U,v,sc,r,t) \ +#define H2_ERROR(U,v,sc,g,r,t) \ if (!strcmp(spec, #U)) { return (#v); } #include "tbl/h2_error.h" return (spec); diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index d0030d27f..6c14a909b 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -37,6 +37,7 @@ H2_ERROR( /* name */ NO_ERROR, /* val */ 0, /* types */ 3, + /* goaway */ 1, /* reason */ SC_REM_CLOSE, /* descr */ "Graceful shutdown" ) @@ -45,6 +46,7 @@ H2_ERROR( /* name */ PROTOCOL_ERROR, /* val */ 1, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Protocol error detected" ) @@ -53,6 +55,7 @@ H2_ERROR( /* name */ INTERNAL_ERROR, /* val */ 2, /* types */ 3, + /* goaway */ 1, /* reason */ SC_VCL_FAILURE, /* descr */ "Implementation fault" ) @@ -61,6 +64,7 @@ H2_ERROR( /* name */ FLOW_CONTROL_ERROR, /* val */ 3, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Flow-control limits exceeded" ) @@ -69,6 +73,7 @@ H2_ERROR( /* name */ SETTINGS_TIMEOUT, /* val */ 4, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_TIMEOUT, /* descr */ "Settings not acknowledged" ) @@ -77,6 +82,7 @@ H2_ERROR( /* name */ STREAM_CLOSED, /* val */ 5, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Frame received for closed stream" ) @@ -85,6 +91,7 @@ H2_ERROR( /* name */ FRAME_SIZE_ERROR, /* val */ 6, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Frame size incorrect" ) @@ -93,6 +100,7 @@ H2_ERROR( /* name */ REFUSED_STREAM, /* val */ 7, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream not processed" ) @@ -101,6 +109,7 @@ H2_ERROR( /* name */ CANCEL, /* val */ 8, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream cancelled" ) @@ -109,6 +118,7 @@ H2_ERROR( /* name */ COMPRESSION_ERROR, /* val */ 9, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Compression state not updated" ) @@ -117,6 +127,7 @@ H2_ERROR( /* name */ CONNECT_ERROR, /* val */ 10, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "TCP connection error for CONNECT method" ) @@ -125,6 +136,7 @@ H2_ERROR( /* name */ ENHANCE_YOUR_CALM, /* val */ 11, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Processing capacity exceeded" ) @@ -133,6 +145,7 @@ H2_ERROR( /* name */ INADEQUATE_SECURITY, /* val */ 12, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Negotiated TLS parameters not acceptable" ) @@ -141,23 +154,26 @@ H2_ERROR( /* name */ HTTP_1_1_REQUIRED, /* val */ 13, /* types */ 1, + /* goaway */ 1, /* reason */ SC_REQ_HTTP20, /* descr */ "Use HTTP/1.1 for the request" ) #ifdef H2_CUSTOM_ERRORS H2_ERROR( - /* name */ RAPID_RESET, - /* val */ 11, /* ENHANCE_YOUR_CALM */ - /* types */ 1, - /* reason */ SC_RAPID_RESET, - /* descr */ "http/2 rapid reset detected" + /* name */ RAPID_RESET, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* goaway */ 1, + /* reason */ SC_RAPID_RESET, + /* descr */ "http/2 rapid reset detected" ) H2_ERROR( /* name */ BROKE_WINDOW, /* val */ 8, /* CANCEL */ /* types */ 2, + /* goaway */ 0, /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) @@ -166,6 +182,7 @@ H2_ERROR( /* name */ BANKRUPT, /* val */ 11, /* ENHANCE_YOUR_CALM */ /* types */ 1, + /* goaway */ 0, /* reason */ SC_BANKRUPT, /* descr */ "http/2 bankrupt connection" ) From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] 2719cba1c http2_proto: Send GOAWAY before leaving the rx loop Message-ID: <20240318182006.96F306EE8C@lists.varnish-cache.org> commit 2719cba1cb222d2006600b85e9c25c85be1c4507 Author: Dridi Boukelmoune Date: Thu Nov 16 17:30:17 2023 +0100 http2_proto: Send GOAWAY before leaving the rx loop Conflicts: bin/varnishtest/tests/t02005.vtc diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 36ccb895e..4dae3e19b 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -404,7 +404,7 @@ h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) ASSERT_RXTHR(h2); AN(h2e); - if (h2->goaway) + if (h2->goaway || !h2e->send_goaway) return; h2->goaway = 1; @@ -1469,6 +1469,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) if (h2e != NULL && h2e->connection) { h2->error = h2e; + h2_tx_goaway(wrk, h2, h2e); return (0); } diff --git a/bin/varnishtest/tests/t02003.vtc b/bin/varnishtest/tests/t02003.vtc index 1d62ac986..fe30e8243 100644 --- a/bin/varnishtest/tests/t02003.vtc +++ b/bin/varnishtest/tests/t02003.vtc @@ -233,17 +233,28 @@ client c1 { } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 3 + } -start stream 1 { - txreq -nohdrend + txreq -nostrend txrst -err 2 } -run stream 3 { - txreq -nohdrend + txreq -nostrend txrst -err 0x666 } -run + stream 0 -wait } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq rxresp @@ -252,6 +263,7 @@ client c1 { # RST_STREAM on closed stream txrst } -run + stream 0 -wait } -run diff --git a/bin/varnishtest/tests/t02005.vtc b/bin/varnishtest/tests/t02005.vtc index 03c9a85ae..9aff481c9 100644 --- a/bin/varnishtest/tests/t02005.vtc +++ b/bin/varnishtest/tests/t02005.vtc @@ -27,7 +27,7 @@ varnish v1 -cliok "param.set debug +syncvsl" logexpect l1 -v v1 -g raw { expect * 1001 ReqAcct "80 7 87 106 8 114" - expect * 1000 ReqAcct "45 8 53 54 20 74" + expect * 1000 ReqAcct "45 8 53 63 28 91" } -start client c1 { diff --git a/bin/varnishtest/tests/t02025.vtc b/bin/varnishtest/tests/t02025.vtc index 4b83fe95b..39f987a06 100644 --- a/bin/varnishtest/tests/t02025.vtc +++ b/bin/varnishtest/tests/t02025.vtc @@ -25,12 +25,17 @@ logexpect l1 -v v1 -g raw -i Debug { } -start client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq barrier b1 sync txrst } -run - expect_close + stream 0 -wait } -start logexpect l1 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] f349948a9 http2_proto: Simplify CONTINUATION expectation check Message-ID: <20240318182006.B10E56EE9B@lists.varnish-cache.org> commit f349948a905f7f8393adc965af8886d5ec0307b5 Author: Dridi Boukelmoune Date: Mon Sep 11 17:52:00 2023 +0200 http2_proto: Simplify CONTINUATION expectation check Before the h2 frame dispatch we only need to check that coming from a HEADERS frame the very next frame is a CONTINUATION, when the HPACK block didn't fit in the former. The CONTINUATION dispatch will then make the stream consistency check. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 4dae3e19b..cc0335144 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1295,8 +1295,7 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) if (r2->stream == h2->rxf_stream) break; - if (h2->new_req != NULL && - !(r2 && h2->new_req == r2->req && h2f == H2_F_CONTINUATION)) + if (h2->new_req != NULL && h2f != H2_F_CONTINUATION) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] 162dee04a changes.rst: 6.0.13 edits Message-ID: <20240318182006.D13656EEA5@lists.varnish-cache.org> commit 162dee04ac06d9f65672264af35cf00ed6a34ac8 Author: Simon Stridsberg Date: Mon Mar 18 11:30:01 2024 +0100 changes.rst: 6.0.13 edits diff --git a/doc/changes.rst b/doc/changes.rst index 6c747fade..fd7818264 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -27,13 +27,17 @@ individual releases. These documents are updated as part of the release process. ================================= -Varnish Cache 6.0.13 (unreleased) +Varnish Cache 6.0.13 (2024-03-18) ================================= +* Add ``h2_window_timeout`` paramater to mitigate CVE-2023-43622 (VSV00014_). + * The ``Process`` timestamp for ``vcl_synth {}`` was wrongly issued before the VCL callback, now it gets emitted after VCL returns for consistency with ``vcl_deliver {}`` +.. _VSV00014: https://varnish-cache.org/security/VSV00014.html + ================================= Varnish Cache 6.0.12 (2023-11-13) ================================= From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:06 +0000 (UTC) Subject: [6.0] d6fedac35 http2_send: Explain the winup-open discrepancy Message-ID: <20240318182006.EB7736EEAD@lists.varnish-cache.org> commit d6fedac352a618123d3bd75c57528da16d8ff6c7 Author: Dridi Boukelmoune Date: Mon Jan 29 10:59:22 2024 +0100 http2_send: Explain the winup-open discrepancy diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ca6151fb2..c1e03a5dc 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -286,6 +286,18 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + /* If all streams ran out of control flow window credits + * upon triggering h2_window_timeout, declare bankruptcy + * for the entire connection. + * + * But streams may be closed from the h2_sess thread while + * waiting for a window update. So the open_streams counter + * may be decremented in a different critical section than + * winup_streams, right before signalling the stream thread. + * So there may be more streams awaiting a window updates + * than streams officially open, hence the "lower-equal" + * comparison. + */ if (r2->error == H2SE_BROKE_WINDOW && h2->open_streams <= h2->winup_streams) h2->error = r2->error = H2CE_BANKRUPT; From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:07 +0000 (UTC) Subject: [6.0] f27717690 Bump cli_limit to fit param.show -j with more parameters coming Message-ID: <20240318182007.13EA66EEB6@lists.varnish-cache.org> commit f27717690bf2fc9b9e87ed9fa19ce09ebc4295d5 Author: Nils Goroll Date: Mon Oct 16 19:14:56 2023 +0200 Bump cli_limit to fit param.show -j with more parameters coming diff --git a/include/tbl/params.h b/include/tbl/params.h index f99bb6ad4..455a79ec1 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -329,7 +329,7 @@ PARAM( /* typ */ bytes_u, /* min */ "128b", /* max */ "99999999b", - /* default */ "48k", + /* def */ "64k", /* units */ "bytes", /* flags */ 0, /* s-text */ From simon.stridsberg at varnish-software.com Mon Mar 18 18:20:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:20:07 +0000 (UTC) Subject: [6.0] a395739fa Prepare for 6.0.13 Message-ID: <20240318182007.3CFF26EEC3@lists.varnish-cache.org> commit a395739fa63cddec305142eabefec0a4fd5339e7 Author: Simon Stridsberg Date: Mon Mar 18 11:30:20 2024 +0100 Prepare for 6.0.13 diff --git a/configure.ac b/configure.ac index 6a86b27a4..1fc8d677c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ(2.59) AC_COPYRIGHT([Copyright (c) 2006 Verdens Gang AS -Copyright (c) 2006-2023 Varnish Software]) +Copyright (c) 2006-2024 Varnish Software]) AC_REVISION([$Id$]) -AC_INIT([Varnish], [6.0.12], [varnish-dev at varnish-cache.org]) +AC_INIT([Varnish], [6.0.13], [varnish-dev at varnish-cache.org]) AC_CONFIG_SRCDIR(include/miniobj.h) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 7e0d27619..20f52da85 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -37,7 +37,7 @@ Longer listings like example command output and VCL look like this:: $ /opt/varnish/sbin/varnishd -V varnishd (varnish-6.0.x revision 1234567) Copyright (c) 2006 Verdens Gang AS - Copyright (c) 2006-2022 Varnish Software AS + Copyright (c) 2006-2024 Varnish Software AS .. For maintainers: diff --git a/lib/libvarnish/version.c b/lib/libvarnish/version.c index f8124581a..1361c3b2a 100644 --- a/lib/libvarnish/version.c +++ b/lib/libvarnish/version.c @@ -44,5 +44,5 @@ VCS_Message(const char *progname) { fprintf(stderr, "%s (%s)\n", progname, VCS_version); fprintf(stderr, "Copyright (c) 2006 Verdens Gang AS\n"); - fprintf(stderr, "Copyright (c) 2006-2023 Varnish Software\n"); + fprintf(stderr, "Copyright (c) 2006-2024 Varnish Software\n"); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:05 +0000 (UTC) Subject: [7.3] 7d5a519fc vtc_http2: Automatic stream identifier Message-ID: <20240318182305.9A1E11019AF@lists.varnish-cache.org> commit 7d5a519fc608eec76a735d68100b2dab274e854d Author: Dridi Boukelmoune Date: Fri Oct 20 18:53:26 2023 +0200 vtc_http2: Automatic stream identifier diff --git a/bin/varnishtest/tests/a02028.vtc b/bin/varnishtest/tests/a02028.vtc new file mode 100644 index 000000000..4ba8986ed --- /dev/null +++ b/bin/varnishtest/tests/a02028.vtc @@ -0,0 +1,24 @@ +varnishtest "Automatic stream numbers" + +server s1 { + loop 4 { + stream next { + rxreq + txresp + } -run + } +} -start + +client c1 -connect ${s1_sock} { + loop 3 { + stream next { + txreq + rxresp + } -run + } + + stream 7 { + txreq + rxresp + } -run +} -run diff --git a/bin/varnishtest/vtc_http.h b/bin/varnishtest/vtc_http.h index a5d43001e..c213eae17 100644 --- a/bin/varnishtest/vtc_http.h +++ b/bin/varnishtest/vtc_http.h @@ -86,6 +86,7 @@ struct http { pthread_t tp; VTAILQ_HEAD(, stream) streams; + unsigned last_stream; pthread_mutex_t mtx; pthread_cond_t cond; struct hpk_ctx *encctx; diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index 42410e45f..ecd1ea326 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -2639,9 +2639,17 @@ stream_thread(void *priv) static struct stream * stream_new(const char *name, struct http *h) { - char *p; + char *p, buf[20]; struct stream *s; + if (!strcmp("next", name)) { + if (h->last_stream > 0) + bprintf(buf, "%d", h->last_stream + 2); + else + bprintf(buf, "%d", 1); + name = buf; + } + ALLOC_OBJ(s, STREAM_MAGIC); AN(s); AZ(pthread_cond_init(&s->cond, NULL)); @@ -2663,6 +2671,7 @@ stream_new(const char *name, struct http *h) CHECK_OBJ_NOTNULL(h, HTTP_MAGIC); s->hp = h; + h->last_stream = s->id; //bprintf(s->connect, "%s", "${v1_sock}"); AZ(pthread_mutex_lock(&h->mtx)); @@ -2768,7 +2777,8 @@ stream_run(struct stream *s) * stream ID [SPEC] [ACTION] * * ID is the HTTP/2 stream number, while SPEC describes what will be - * done in that stream. + * done in that stream. If ID has the value ``next``, the actual stream + * number is computed based on the last one. * * Note that, when parsing a stream action, if the entity isn't operating * in HTTP/2 mode, these spec is ran before:: @@ -2837,7 +2847,7 @@ cmd_stream(CMD_ARGS) continue; } if (**av == '-') - vtc_fatal(vl, "Unknown client argument: %s", *av); + vtc_fatal(vl, "Unknown stream argument: %s", *av); REPLACE(s->spec, *av); } } From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:05 +0000 (UTC) Subject: [7.3] 86a60ec57 http2_proto: Proper null checks for h2 errors Message-ID: <20240318182305.B2C501019B5@lists.varnish-cache.org> commit 86a60ec57791429dc0844dab5a4adccfbd99a1b7 Author: Dridi Boukelmoune Date: Mon Oct 23 11:34:31 2023 +0200 http2_proto: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index fddec7dbf..46a4aca08 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -834,11 +834,11 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) Lck_Lock(&h2->sess->mtx); CHECK_OBJ_ORNULL(r2->rxbuf, H2_RXBUF_MAGIC); - if (h2->error || r2->error) { + if (h2->error != NULL || r2->error != NULL) { if (r2->cond) AZ(pthread_cond_signal(r2->cond)); Lck_Unlock(&h2->sess->mtx); - return (h2->error ? h2->error : r2->error); + return (h2->error != NULL ? h2->error : r2->error); } /* Check padding if present */ @@ -1075,7 +1075,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp) } else l = 0; - if (h2->error || r2->error) + if (h2->error != NULL || r2->error != NULL) retval = VFP_ERROR; else if (r2->state >= H2_S_CLOS_REM && l <= *lp) retval = VFP_END; @@ -1271,15 +1271,15 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); - if (h2e == 0) - return (0); + if (h2e == NULL) + return (NULL); if (h2->rxf_stream == 0 || h2e->connection) return (h2e); // Connection errors one level up H2_Send_Get(wrk, h2, h2->req0); H2_Send_RST(wrk, h2, h2->req0, h2->rxf_stream, h2e); H2_Send_Rel(h2, h2->req0); - return (0); + return (NULL); } int @@ -1486,7 +1486,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) } h2e = h2_procframe(wrk, h2, h2f); - if (h2->error == 0 && h2e) { + if (h2->error == NULL && h2e != NULL) { h2->error = h2e; vbe32enc(b, h2->highest_stream); vbe32enc(b + 4, h2e->val); @@ -1494,5 +1494,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); H2_Send_Rel(h2, h2->req0); } - return (h2->error ? 0 : 1); + + return (h2->error != NULL ? 0 : 1); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:05 +0000 (UTC) Subject: [7.3] c1ceaa342 http2_send: Proper null checks for h2 errors Message-ID: <20240318182305.CDEA11019BC@lists.varnish-cache.org> commit c1ceaa34286d2d480d1c23c4d27b147a86006f8b Author: Dridi Boukelmoune Date: Mon Oct 23 11:36:57 2023 +0200 http2_send: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 791cfcbe2..ffcbe66bd 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -239,11 +239,11 @@ h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - if (r2->error) + if (r2->error != NULL) return (r2->error); - if (h2->error && r2->stream > h2->goaway_last_stream) + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) return (h2->error); - return (0); + return (NULL); } static int64_t @@ -263,15 +263,17 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, if (r2->t_window <= 0 || h2->req0->t_window <= 0) { r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); - while (r2->t_window <= 0 && h2_errcheck(r2, h2) == 0) { + + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); r2->cond = NULL; } - while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == 0) + + while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == NULL) (void)h2_cond_wait(h2->winupd_cond, h2, r2); - if (h2_errcheck(r2, h2) == 0) { + if (h2_errcheck(r2, h2) == NULL) { w = vmin_t(int64_t, h2_win_limit(r2, h2), wanted); h2_win_charge(r2, h2, w); assert (w > 0); @@ -279,7 +281,7 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_send_get_locked(wrk, h2, r2); } - if (w == 0 && h2_errcheck(r2, h2) == 0) { + if (w == 0 && h2_errcheck(r2, h2) == NULL) { assert(r2->t_window > 0); assert(h2->req0->t_window > 0); w = h2_win_limit(r2, h2); @@ -316,7 +318,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, AN(H2_SEND_HELD(h2, r2)); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(ftyp); @@ -341,7 +343,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } else @@ -362,7 +364,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window && p != ptr) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } @@ -383,7 +385,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, ftyp = ftyp->continuation; flags &= ftyp->flags; final_flags &= ftyp->flags; - } while (!h2->error && len > 0); + } while (h2->error == NULL && len > 0); } } @@ -396,6 +398,7 @@ H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2, CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); AN(H2_SEND_HELD(h2, r2)); + AN(h2e); Lck_Lock(&h2->sess->mtx); VSLb(h2->vsl, SLT_Debug, "H2: stream %u: %s", stream, h2e->txt); From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:05 +0000 (UTC) Subject: [7.3] c82abeaf7 http2_proto: Make h2_stream_tmo() return an error Message-ID: <20240318182305.E9B951019C9@lists.varnish-cache.org> commit c82abeaf7451b25d4768cd4982fe30383c3697c7 Author: Dridi Boukelmoune Date: Thu Nov 16 13:16:15 2023 +0100 http2_proto: Make h2_stream_tmo() return an error diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index ca2e65993..d5a890401 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -254,7 +254,7 @@ void H2_Send(struct worker *, struct h2_req *, h2_frame type, uint8_t flags, /* cache_http2_proto.c */ struct h2_req * h2_new_req(struct h2_sess *, unsigned stream, struct req *); -int h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); +h2_error h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); void h2_del_req(struct worker *, struct h2_req *); void h2_kill_req(struct worker *, struct h2_sess *, struct h2_req *, h2_error); int h2_rxframe(struct worker *, struct h2_sess *); diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 46a4aca08..e08fe9a49 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1282,10 +1282,10 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (NULL); } -int +h2_error h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) { - int r = 0; + h2_error h2e = NULL; CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); @@ -1298,36 +1298,36 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) AN(r2->t_winupd); if (r2->t_winupd == 0 && r2->t_send == 0) - return (0); + return (NULL); if (isnan(now) || (r2->t_winupd != 0 && now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - if (r == 0 && r2->t_send != 0 && + if (h2e == NULL && r2->t_send != 0 && now - r2->t_send > SESS_TMO(h2->sess, send_timeout)) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit send_timeout", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - return (r); + return (h2e); } -static int +static h2_error h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) { - int r; + h2_error h2e; Lck_Lock(&h2->sess->mtx); - r = h2_stream_tmo(h2, r2, h2->sess->t_idle); + h2e = h2_stream_tmo(h2, r2, h2->sess->t_idle); Lck_Unlock(&h2->sess->mtx); - return (r); + return (h2e); } /* From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] d952008a3 http2_send: Collect the timeout error Message-ID: <20240318182306.0F6771019D2@lists.varnish-cache.org> commit d952008a368ae22caae371fc18f8338f4fefe6fa Author: Dridi Boukelmoune Date: Thu Nov 16 13:23:18 2023 +0100 http2_send: Collect the timeout error diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ffcbe66bd..0aab8924c 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -48,6 +48,7 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { vtim_dur tmo = 0.; vtim_real now; + h2_error h2e; int r; AN(cond); @@ -72,18 +73,16 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) * that the stream reached the idle_send_timeout via the lock and * force it to log it. */ - if (h2_stream_tmo(h2, r2, now)) - r = ETIMEDOUT; - else if (r == ETIMEDOUT) - AN(h2_stream_tmo(h2, r2, NAN)); - - if (r == ETIMEDOUT) { - if (r2->error == NULL) - r2->error = H2SE_CANCEL; - return (-1); + h2e = h2_stream_tmo(h2, r2, now); + if (h2e == NULL && r == ETIMEDOUT) { + h2e = h2_stream_tmo(h2, r2, NAN); + AN(h2e); } - return (0); + if (r2->error == NULL) + r2->error = h2e; + + return (h2e != NULL ? -1 : 0); } static void From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] 7586b700f h2: Send GOAWAY frames in a dedicated function Message-ID: <20240318182306.2B2081019DF@lists.varnish-cache.org> commit 7586b700f04a268bca3e3ee43e37cdb8c772f711 Author: Dridi Boukelmoune Date: Tue Jan 18 10:08:33 2022 +0100 h2: Send GOAWAY frames in a dedicated function And after issuing or receiving a goaway, stop processing frames when there are no streams left. Initially submitted as part of listen sockets management. Refs #3959 diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index d5a890401..1f5a48148 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -165,6 +165,7 @@ struct h2_sess { int refcnt; unsigned open_streams; uint32_t highest_stream; + int goaway; int bogosity; int do_sweep; diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index e08fe9a49..b0bc38138 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -388,6 +388,7 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); assert(r2 == h2->req0); + h2->goaway = 1; h2->goaway_last_stream = vbe32dec(h2->rxf_data); h2->error = h2_connectionerror(vbe32dec(h2->rxf_data + 4)); Lck_Lock(&h2->sess->mtx); @@ -396,6 +397,25 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) return (h2->error); } +static void +h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) +{ + char b[8]; + + ASSERT_RXTHR(h2); + AN(h2e); + + if (h2->goaway) + return; + + h2->goaway = 1; + vbe32enc(b, h2->highest_stream); + vbe32enc(b + 4, h2e->val); + H2_Send_Get(wrk, h2, h2->req0); + H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); + H2_Send_Rel(h2, h2->req0); +} + /********************************************************************** */ @@ -1408,9 +1428,12 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2_frame h2f; h2_error h2e; const char *s = NULL; - char b[8]; ASSERT_RXTHR(h2); + + if (h2->goaway && h2->open_streams == 0) + return (0); + VTCP_blocking(*h2->htc->rfd); h2->sess->t_idle = VTIM_real(); hs = HTC_RxStuff(h2->htc, h2_frame_complete, @@ -1488,11 +1511,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2e = h2_procframe(wrk, h2, h2f); if (h2->error == NULL && h2e != NULL) { h2->error = h2e; - vbe32enc(b, h2->highest_stream); - vbe32enc(b + 4, h2e->val); - H2_Send_Get(wrk, h2, h2->req0); - H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); - H2_Send_Rel(h2, h2->req0); + h2_tx_goaway(wrk, h2, h2e); } return (h2->error != NULL ? 0 : 1); From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] 376799e66 http2_proto: Enforce session timeouts in h2_sweep() Message-ID: <20240318182306.49E211019E3@lists.varnish-cache.org> commit 376799e66ef4096e5700cf955d18b28d0e0c43cd Author: Dridi Boukelmoune Date: Thu Nov 16 14:52:49 2023 +0100 http2_proto: Enforce session timeouts in h2_sweep() The new meaning for h2->sess->t_idle is now the time since the last complete frame, except before the first frame where it corresponds to the creation of the session. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index b0bc38138..e11d056e1 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1354,14 +1354,20 @@ h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) * This is the janitorial task of cleaning up any closed & refused * streams, and checking if the session is timed out. */ -static int +static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { - int tmo = 0; struct h2_req *r2, *r22; + h2_error h2e = NULL, tmo; + vtim_real now; ASSERT_RXTHR(h2); + now = VTIM_real(); + if (h2e == NULL && h2->open_streams == 0 && + h2->sess->t_idle + cache_param->timeout_idle < now) + h2e = H2CE_NO_ERROR; + h2->do_sweep = 0; VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) { if (r2 == h2->req0) { @@ -1385,10 +1391,9 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) /* FALLTHROUGH */ case H2_S_CLOS_LOC: case H2_S_OPEN: - if (h2_stream_tmo_unlocked(h2, r2)) { - tmo = 1; - continue; - } + tmo = h2_stream_tmo_unlocked(h2, r2); + if (h2e == NULL) + h2e = tmo; break; case H2_S_IDLE: /* Current code make this unreachable: h2_new_req is @@ -1400,9 +1405,7 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) break; } } - if (tmo) - return (0); - return (h2->refcnt > 1); + return (h2e); } @@ -1427,7 +1430,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) enum htc_status_e hs; h2_frame h2f; h2_error h2e; - const char *s = NULL; ASSERT_RXTHR(h2); @@ -1435,36 +1437,30 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) return (0); VTCP_blocking(*h2->htc->rfd); - h2->sess->t_idle = VTIM_real(); - hs = HTC_RxStuff(h2->htc, h2_frame_complete, - NULL, NULL, NAN, - h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle), - NAN, h2->local_settings.max_frame_size + 9); + hs = HTC_RxStuff(h2->htc, h2_frame_complete, NULL, NULL, NAN, + VTIM_real() + 0.5, NAN, h2->local_settings.max_frame_size + 9); + + h2e = NULL; switch (hs) { case HTC_S_COMPLETE: + h2->sess->t_idle = VTIM_real(); + if (h2->do_sweep) + h2e = h2_sweep(wrk, h2); break; case HTC_S_TIMEOUT: - if (h2_sweep(wrk, h2)) - return (1); - - /* FALLTHROUGH */ + h2e = h2_sweep(wrk, h2); + break; default: - /* XXX: HTC_S_OVERFLOW / FRAME_SIZE_ERROR handling */ -#define HTC_STATUS(e, n, d, l) \ - do { \ - if (hs == HTC_S_ ## e) \ - s = #e; \ - } while (0); -#include "tbl/htc.h" - Lck_Lock(&h2->sess->mtx); - VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%s)", s); - h2->error = H2CE_NO_ERROR; - Lck_Unlock(&h2->sess->mtx); + h2e = H2CE_ENHANCE_YOUR_CALM; + } + + if (h2e != NULL && h2e->connection) { + h2->error = h2e; return (0); } - if (h2->do_sweep) - (void)h2_sweep(wrk, h2); + if (hs != HTC_S_COMPLETE) + return (1); h2->rxf_len = vbe32dec(h2->htc->rxbuf_b) >> 8; h2->rxf_type = h2->htc->rxbuf_b[3]; From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] 0ad5b82f4 http2_proto: Introduce a custom BROKE_WINDOW error Message-ID: <20240318182306.65E3A1019ED@lists.varnish-cache.org> commit 0ad5b82f4d95f5859dec13f94f5e67e920c66d7b Author: Dridi Boukelmoune Date: Thu Nov 16 16:03:42 2023 +0100 http2_proto: Introduce a custom BROKE_WINDOW error Conflicts: include/tbl/h2_error.h diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index e11d056e1..c43711f01 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1325,7 +1325,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - h2e = H2SE_CANCEL; + h2e = H2SE_BROKE_WINDOW; } if (h2e == NULL && r2->t_send != 0 && diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 0aab8924c..a8d2d5b36 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -412,12 +412,14 @@ H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, uint32_t len, const void *ptr, uint64_t *counter) { uint64_t dummy_counter = 0; + h2_error h2e; if (counter == NULL) counter = &dummy_counter; h2_send(wrk, r2, ftyp, flags, len, ptr, counter); - if (h2_errcheck(r2, r2->h2sess) == H2SE_CANCEL) - H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, H2SE_CANCEL); + h2e = h2_errcheck(r2, r2->h2sess); + if (h2e != NULL && h2e->val == H2SE_CANCEL->val) + H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, h2e); } diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index c6c6bed89..27260c797 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -156,6 +156,13 @@ H2_ERROR( /* descr */ "http/2 rapid reset detected" ) +H2_ERROR( + /* name */ BROKE_WINDOW, + /* val */ 8, /* CANCEL */ + /* types */ 2, + /* reason */ SC_NULL, + /* descr */ "http/2 stream out of window credits" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] 7e48cbad9 param: New h2_window_timeout parameter Message-ID: <20240318182306.87414101A05@lists.varnish-cache.org> commit 7e48cbad9d1ba68fab738c08cf41478a1f21f1a5 Author: Dridi Boukelmoune Date: Mon Oct 23 11:49:23 2023 +0200 param: New h2_window_timeout parameter This parameter needs to be somewhat high because web browsers may for example only credit streams for image resources just enough to parse metadata like width and height of a picture in order to perform layout computations and fetch resources more sensitive to latency before the effective image payloads. diff --git a/include/tbl/params.h b/include/tbl/params.h index 4ee8d01e1..fb8ded96a 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -1179,6 +1179,20 @@ PARAM_SIMPLE( /* flags */ WIZARD ) +PARAM_SIMPLE( + /* name */ h2_window_timeout, + /* type */ timeout, + /* min */ "0", + /* max */ NULL, + /* def */ "5", + /* units */ "seconds", + /* descr */ + "HTTP2 time limit without window credits. How long a stream may " + "wait for the client to credit the window and allow for more DATA " + "frames to be sent.", + /* flags */ WIZARD +) + PARAM_SIMPLE( /* name */ h2_header_table_size, /* type */ bytes_u, From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] f946bd160 http2_send: Move h2_errcheck() at the top Message-ID: <20240318182306.A3308101A1A@lists.varnish-cache.org> commit f946bd160f8342aa5229e2f9efde32762dcb545e Author: Dridi Boukelmoune Date: Mon Oct 23 16:40:26 2023 +0200 http2_send: Move h2_errcheck() at the top diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index a8d2d5b36..57c1b0f6f 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -43,6 +43,19 @@ #define H2_SEND_HELD(h2, r2) (VTAILQ_FIRST(&(h2)->txqueue) == (r2)) +static h2_error +h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) +{ + CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); + CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); + + if (r2->error != NULL) + return (r2->error); + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) + return (h2->error); + return (NULL); +} + static int h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { @@ -232,19 +245,6 @@ h2_win_charge(struct h2_req *r2, const struct h2_sess *h2, uint32_t w) h2->req0->t_window -= w; } -static h2_error -h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) -{ - CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); - CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - - if (r2->error != NULL) - return (r2->error); - if (h2->error != NULL && r2->stream > h2->goaway_last_stream) - return (h2->error); - return (NULL); -} - static int64_t h2_do_window(struct worker *wrk, struct h2_req *r2, struct h2_sess *h2, int64_t wanted) From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] 62b2d3064 http2_send: Apply h2_window_timeout Message-ID: <20240318182306.BFFB9101A3F@lists.varnish-cache.org> commit 62b2d3064ec39ef1d99eea8f02cf9c92b50c7cb9 Author: Dridi Boukelmoune Date: Mon Oct 23 13:15:45 2023 +0200 http2_send: Apply h2_window_timeout It replaces idle_send_timeout when the stream is waiting for window credits before sending more DATA frames. The idle_send_timeout will still apply to individual writes to the socket, but triggering it is considered a failure condition (this was already the case). The two loops are merged into a single one to better deal with the lack of ordering guarantees of request vs connection stream control flow window crediting. Refs #2980 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index c43711f01..dbc196e76 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1311,7 +1311,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); Lck_AssertHeld(&h2->sess->mtx); - /* NB: when now is NAN, it means that idle_send_timeout was hit + /* NB: when now is NAN, it means that h2_window_timeout was hit * on a lock condwait operation. */ if (isnan(now)) @@ -1321,10 +1321,9 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) return (NULL); if (isnan(now) || (r2->t_winupd != 0 && - now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { + now - r2->t_winupd > cache_param->h2_window_timeout)) { VSLb(h2->vsl, SLT_Debug, - "H2: stream %u: Hit idle_send_timeout waiting for" - " WINDOW_UPDATE", r2->stream); + "H2: stream %u: Hit h2_window_timeout", r2->stream); h2e = H2SE_BROKE_WINDOW; } diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 57c1b0f6f..35720806f 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -70,20 +70,20 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) Lck_AssertHeld(&h2->sess->mtx); - if (cache_param->idle_send_timeout > 0.) - tmo = cache_param->idle_send_timeout; + if (cache_param->h2_window_timeout > 0.) + tmo = cache_param->h2_window_timeout; r = Lck_CondWaitTimeout(cond, &h2->sess->mtx, tmo); assert(r == 0 || r == ETIMEDOUT); now = VTIM_real(); - /* NB: when we grab idle_send_timeout before acquiring the session + /* NB: when we grab h2_window_timeout before acquiring the session * lock we may time out, but once we wake up both send_timeout and - * idle_send_timeout may have changed meanwhile. For this reason + * h2_window_timeout may have changed meanwhile. For this reason * h2_stream_tmo() may not log what timed out and we need to call * again with a magic NAN "now" that indicates to h2_stream_tmo() - * that the stream reached the idle_send_timeout via the lock and + * that the stream reached the h2_window_timeout via the lock and * force it to log it. */ h2e = h2_stream_tmo(h2, r2, now); @@ -208,6 +208,10 @@ H2_Send_Frame(struct worker *wrk, struct h2_sess *h2, iov[1].iov_len = len; s = writev(h2->sess->fd, iov, len == 0 ? 1 : 2); if (s != sizeof hdr + len) { + if (errno == EWOULDBLOCK) { + VSLb(h2->vsl, SLT_Debug, + "H2: stream %u: Hit idle_send_timeout", stream); + } /* * There is no point in being nice here, we will be unable * to send a GOAWAY once the code unrolls, so go directly diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index 29ffea354..d2f5dcca8 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -44,13 +44,13 @@ client c1 { logexpect l1 -wait -# coverage for idle_send_timeout with c2 +# coverage for h2_window_timeout with c2 -varnish v1 -cliok "param.set idle_send_timeout 1" +varnish v1 -cliok "param.set h2_window_timeout 1" varnish v1 -cliok "param.reset send_timeout" logexpect l2 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c2 { @@ -79,12 +79,12 @@ client c2 { logexpect l2 -wait -# coverage for idle_send_timeout change with c3 +# coverage for h2_window_timeout change with c3 barrier b3 cond 2 logexpect l3 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c3 { @@ -113,7 +113,7 @@ client c3 { } -start barrier b3 sync -varnish v1 -cliok "param.reset idle_send_timeout" +varnish v1 -cliok "param.reset h2_window_timeout" client c3 -wait logexpect l3 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:06 +0000 (UTC) Subject: [7.3] 5f14905a8 http2_send: Track bankrupt streams Message-ID: <20240318182306.D7958101A4D@lists.varnish-cache.org> commit 5f14905a82af66bb63ac4fa61508874fe4dbcaeb Author: Dridi Boukelmoune Date: Mon Oct 23 17:15:20 2023 +0200 http2_send: Track bankrupt streams diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 1f5a48148..8d78276e3 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -163,7 +163,8 @@ struct h2_sess { struct sess *sess; int refcnt; - unsigned open_streams; + int open_streams; + int winup_streams; uint32_t highest_stream; int goaway; int bogosity; diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 35720806f..6fc913c5b 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -267,6 +267,9 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); + assert(h2->winup_streams >= 0); + h2->winup_streams++; + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); @@ -281,6 +284,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_win_charge(r2, h2, w); assert (w > 0); } + + assert(h2->winup_streams > 0); + h2->winup_streams--; + h2_send_get_locked(wrk, h2, r2); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:07 +0000 (UTC) Subject: [7.3] 67d5cbb66 vsc: New MAIN.sc_bankrupt counter Message-ID: <20240318182307.08FF1101A72@lists.varnish-cache.org> commit 67d5cbb66610d69901e2a22aed827caa8fa856d1 Author: Dridi Boukelmoune Date: Thu Nov 16 16:58:55 2023 +0100 vsc: New MAIN.sc_bankrupt counter diff --git a/include/tbl/sess_close.h b/include/tbl/sess_close.h index f15d34a64..1fc5b648e 100644 --- a/include/tbl/sess_close.h +++ b/include/tbl/sess_close.h @@ -51,6 +51,7 @@ SESS_CLOSE(RANGE_SHORT, range_short, 1, "Insufficient data for range") SESS_CLOSE(REQ_HTTP20, req_http20, 1, "HTTP2 not accepted") SESS_CLOSE(VCL_FAILURE, vcl_failure, 1, "VCL failure") SESS_CLOSE(RAPID_RESET, rapid_reset, 1, "HTTP2 rapid reset") +SESS_CLOSE(BANKRUPT, bankrupt, 1, "HTTP2 credit bankruptcy") #undef SESS_CLOSE /*lint -restore */ diff --git a/lib/libvsc/VSC_main.vsc b/lib/libvsc/VSC_main.vsc index aa2e36744..ae0a69976 100644 --- a/lib/libvsc/VSC_main.vsc +++ b/lib/libvsc/VSC_main.vsc @@ -648,6 +648,14 @@ configured limits for the number of permitted rapid stream resets. +.. varnish_vsc:: sc_bankrupt + :level: diag + :oneliner: Session Err BANKRUPT + + Number of times we failed an http/2 session because all the streams + were waiting for their windows to be credited when h2_window_timeout + triggered. + .. varnish_vsc:: client_resp_500 :level: diag :group: wrk From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:07 +0000 (UTC) Subject: [7.3] d85fdd923 http2_send: Promote global BROKE_WINDOW to BANKRUPT Message-ID: <20240318182307.23BA8101A8E@lists.varnish-cache.org> commit d85fdd923ddcb49a0bea47a9473e3d39f6998183 Author: Dridi Boukelmoune Date: Thu Nov 16 17:02:35 2023 +0100 http2_send: Promote global BROKE_WINDOW to BANKRUPT When a stream times out waiting for window credits, and all the other streams are broke, declare the whole connection bankrupt. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index dbc196e76..8f6ba5cfe 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1357,11 +1357,12 @@ static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { struct h2_req *r2, *r22; - h2_error h2e = NULL, tmo; + h2_error h2e, tmo; vtim_real now; ASSERT_RXTHR(h2); + h2e = h2->error; now = VTIM_real(); if (h2e == NULL && h2->open_streams == 0 && h2->sess->t_idle + cache_param->timeout_idle < now) diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 6fc913c5b..3a68ad6d5 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -285,6 +285,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + if (r2->error == H2SE_BROKE_WINDOW && + h2->open_streams <= h2->winup_streams) + h2->error = r2->error = H2CE_BANKRUPT; + assert(h2->winup_streams > 0); h2->winup_streams--; diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index d2f5dcca8..1e5a7dc8a 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -6,7 +6,13 @@ server s1 { } -start varnish v1 -cliok "param.set feature +http2" -varnish v1 -vcl+backend "" -start +varnish v1 -vcl+backend { + sub vcl_recv { + if (req.url ~ "synth") { + return (synth(200)); + } + } +} -start # coverage for send_timeout with c1 @@ -66,6 +72,10 @@ client c2 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -75,6 +85,9 @@ client c2 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -run logexpect l2 -wait @@ -100,6 +113,10 @@ client c3 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -110,6 +127,9 @@ client c3 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -start barrier b3 sync diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 27260c797..67ef403c8 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -163,6 +163,14 @@ H2_ERROR( /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) + +H2_ERROR( + /* name */ BANKRUPT, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* reason */ SC_BANKRUPT, + /* descr */ "http/2 bankrupt connection" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:07 +0000 (UTC) Subject: [7.3] 092a68216 http2: New send_goaway flag for errors Message-ID: <20240318182307.3DFA4101AAC@lists.varnish-cache.org> commit 092a68216dbf6a02cc0653dc5fa6b4fdafba8a92 Author: Dridi Boukelmoune Date: Thu Nov 16 17:27:11 2023 +0100 http2: New send_goaway flag for errors diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 8d78276e3..ac9e2c5a9 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -44,16 +44,18 @@ struct h2_error_s { uint32_t val; int stream; int connection; + int send_goaway; stream_close_t reason; }; typedef const struct h2_error_s *h2_error; #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) extern const struct h2_error_s H2CE_##U[1]; -#define H2EC2(U,v,r,d) extern const struct h2_error_s H2SE_##U[1]; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) extern const struct h2_error_s H2CE_##U[1]; +#define H2EC2(U,v,g,r,d) extern const struct h2_error_s H2SE_##U[1]; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 8f6ba5cfe..d4b9649fc 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -48,10 +48,13 @@ #include "vtim.h" #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,r}}; -#define H2EC2(U,v,r,d) const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,r}}; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) \ + const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,g,r}}; +#define H2EC2(U,v,g,r,d) \ + const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,g,r}}; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -63,6 +66,7 @@ static const struct h2_error_s H2NN_ERROR[1] = {{ 0xffffffff, 1, 1, + 0, SC_RX_JUNK }}; @@ -90,10 +94,11 @@ h2_framename(enum h2frame h2f) */ static const h2_error stream_errors[] = { -#define H2EC1(U,v,r,d) -#define H2EC2(U,v,r,d) [v] = H2SE_##U, -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) +#define H2EC2(U,v,g,r,d) [v] = H2SE_##U, +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -115,10 +120,11 @@ h2_streamerror(uint32_t u) */ static const h2_error conn_errors[] = { -#define H2EC1(U,v,r,d) [v] = H2CE_##U, -#define H2EC2(U,v,r,d) -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) [v] = H2CE_##U, +#define H2EC2(U,v,g,r,d) +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -1317,6 +1323,10 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) if (isnan(now)) AN(r2->t_winupd); + if (h2->error != NULL && h2->error->connection && + !h2->error->send_goaway) + return (h2->error); + if (r2->t_winupd == 0 && r2->t_send == 0) return (NULL); diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index ecd1ea326..9f9d3538e 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -52,7 +52,7 @@ #define BUF_SIZE (1024*2048) static const char *const h2_errs[] = { -#define H2_ERROR(n,v,sc,r,t) [v] = #n, +#define H2_ERROR(n,v,sc,g,r,t) [v] = #n, #include NULL }; @@ -1260,7 +1260,7 @@ cmd_var_resolve(const struct stream *s, const char *spec, char *buf) else return (NULL); } -#define H2_ERROR(U,v,sc,r,t) \ +#define H2_ERROR(U,v,sc,g,r,t) \ if (!strcmp(spec, #U)) { return (#v); } #include "tbl/h2_error.h" return (spec); diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 67ef403c8..ed72f6b00 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -39,6 +39,7 @@ H2_ERROR( /* name */ NO_ERROR, /* val */ 0, /* types */ 3, + /* goaway */ 1, /* reason */ SC_REM_CLOSE, /* descr */ "Graceful shutdown" ) @@ -47,6 +48,7 @@ H2_ERROR( /* name */ PROTOCOL_ERROR, /* val */ 1, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Protocol error detected" ) @@ -55,6 +57,7 @@ H2_ERROR( /* name */ INTERNAL_ERROR, /* val */ 2, /* types */ 3, + /* goaway */ 1, /* reason */ SC_VCL_FAILURE, /* descr */ "Implementation fault" ) @@ -63,6 +66,7 @@ H2_ERROR( /* name */ FLOW_CONTROL_ERROR, /* val */ 3, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Flow-control limits exceeded" ) @@ -71,6 +75,7 @@ H2_ERROR( /* name */ SETTINGS_TIMEOUT, /* val */ 4, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_TIMEOUT, /* descr */ "Settings not acknowledged" ) @@ -79,6 +84,7 @@ H2_ERROR( /* name */ STREAM_CLOSED, /* val */ 5, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Frame received for closed stream" ) @@ -87,6 +93,7 @@ H2_ERROR( /* name */ FRAME_SIZE_ERROR, /* val */ 6, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Frame size incorrect" ) @@ -95,6 +102,7 @@ H2_ERROR( /* name */ REFUSED_STREAM, /* val */ 7, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream not processed" ) @@ -103,6 +111,7 @@ H2_ERROR( /* name */ CANCEL, /* val */ 8, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream cancelled" ) @@ -111,6 +120,7 @@ H2_ERROR( /* name */ COMPRESSION_ERROR, /* val */ 9, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Compression state not updated" ) @@ -119,6 +129,7 @@ H2_ERROR( /* name */ CONNECT_ERROR, /* val */ 10, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "TCP connection error for CONNECT method" ) @@ -127,6 +138,7 @@ H2_ERROR( /* name */ ENHANCE_YOUR_CALM, /* val */ 11, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Processing capacity exceeded" ) @@ -135,6 +147,7 @@ H2_ERROR( /* name */ INADEQUATE_SECURITY, /* val */ 12, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Negotiated TLS parameters not acceptable" ) @@ -143,23 +156,26 @@ H2_ERROR( /* name */ HTTP_1_1_REQUIRED, /* val */ 13, /* types */ 1, + /* goaway */ 1, /* reason */ SC_REQ_HTTP20, /* descr */ "Use HTTP/1.1 for the request" ) #ifdef H2_CUSTOM_ERRORS H2_ERROR( - /* name */ RAPID_RESET, - /* val */ 11, /* ENHANCE_YOUR_CALM */ - /* types */ 1, - /* reason */ SC_RAPID_RESET, - /* descr */ "http/2 rapid reset detected" + /* name */ RAPID_RESET, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* goaway */ 1, + /* reason */ SC_RAPID_RESET, + /* descr */ "http/2 rapid reset detected" ) H2_ERROR( /* name */ BROKE_WINDOW, /* val */ 8, /* CANCEL */ /* types */ 2, + /* goaway */ 0, /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) @@ -168,6 +184,7 @@ H2_ERROR( /* name */ BANKRUPT, /* val */ 11, /* ENHANCE_YOUR_CALM */ /* types */ 1, + /* goaway */ 0, /* reason */ SC_BANKRUPT, /* descr */ "http/2 bankrupt connection" ) From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:07 +0000 (UTC) Subject: [7.3] 39713aa33 http2_proto: Send GOAWAY before leaving the rx loop Message-ID: <20240318182307.5CAFD101AC2@lists.varnish-cache.org> commit 39713aa33c0c7a51a793a2c35e6a87f6bad8b0f5 Author: Dridi Boukelmoune Date: Thu Nov 16 17:30:17 2023 +0100 http2_proto: Send GOAWAY before leaving the rx loop diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index d4b9649fc..20f6cfc1c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -411,7 +411,7 @@ h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) ASSERT_RXTHR(h2); AN(h2e); - if (h2->goaway) + if (h2->goaway || !h2e->send_goaway) return; h2->goaway = 1; @@ -1466,6 +1466,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) if (h2e != NULL && h2e->connection) { h2->error = h2e; + h2_tx_goaway(wrk, h2, h2e); return (0); } diff --git a/bin/varnishtest/tests/t02003.vtc b/bin/varnishtest/tests/t02003.vtc index 1d62ac986..fe30e8243 100644 --- a/bin/varnishtest/tests/t02003.vtc +++ b/bin/varnishtest/tests/t02003.vtc @@ -233,17 +233,28 @@ client c1 { } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 3 + } -start stream 1 { - txreq -nohdrend + txreq -nostrend txrst -err 2 } -run stream 3 { - txreq -nohdrend + txreq -nostrend txrst -err 0x666 } -run + stream 0 -wait } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq rxresp @@ -252,6 +263,7 @@ client c1 { # RST_STREAM on closed stream txrst } -run + stream 0 -wait } -run diff --git a/bin/varnishtest/tests/t02005.vtc b/bin/varnishtest/tests/t02005.vtc index 19f862ac9..2ceed2645 100644 --- a/bin/varnishtest/tests/t02005.vtc +++ b/bin/varnishtest/tests/t02005.vtc @@ -32,7 +32,7 @@ varnish v1 -cliok "param.set debug +syncvsl" logexpect l1 -v v1 -g raw { expect * 1001 ReqAcct "80 7 87 78 8 86" - expect * 1000 ReqAcct "45 8 53 54 20 74" + expect * 1000 ReqAcct "45 8 53 63 28 91" } -start client c1 { diff --git a/bin/varnishtest/tests/t02025.vtc b/bin/varnishtest/tests/t02025.vtc index 4b83fe95b..39f987a06 100644 --- a/bin/varnishtest/tests/t02025.vtc +++ b/bin/varnishtest/tests/t02025.vtc @@ -25,12 +25,17 @@ logexpect l1 -v v1 -g raw -i Debug { } -start client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq barrier b1 sync txrst } -run - expect_close + stream 0 -wait } -start logexpect l1 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:07 +0000 (UTC) Subject: [7.3] 1fd4086d3 http2_proto: Simplify CONTINUATION expectation check Message-ID: <20240318182307.755AE101AD4@lists.varnish-cache.org> commit 1fd4086d3744322078fd7590d309f11f79b7b058 Author: Dridi Boukelmoune Date: Mon Sep 11 17:52:00 2023 +0200 http2_proto: Simplify CONTINUATION expectation check Before the h2 frame dispatch we only need to check that coming from a HEADERS frame the very next frame is a CONTINUATION, when the HPACK block didn't fit in the former. The CONTINUATION dispatch will then make the stream consistency check. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 20f6cfc1c..38970ad7d 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1292,8 +1292,7 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) if (r2->stream == h2->rxf_stream) break; - if (h2->new_req != NULL && - !(r2 && h2->new_req == r2->req && h2f == H2_F_CONTINUATION)) + if (h2->new_req != NULL && h2f != H2_F_CONTINUATION) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:07 +0000 (UTC) Subject: [7.3] 1e6341e51 http2_send: Explain the winup-open discrepancy Message-ID: <20240318182307.8F86F101AE6@lists.varnish-cache.org> commit 1e6341e514bc613970360c47c8ef3325e4b6a0e0 Author: Dridi Boukelmoune Date: Mon Jan 29 10:59:22 2024 +0100 http2_send: Explain the winup-open discrepancy diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 3a68ad6d5..add519f57 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -285,6 +285,18 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + /* If all streams ran out of control flow window credits + * upon triggering h2_window_timeout, declare bankruptcy + * for the entire connection. + * + * But streams may be closed from the h2_sess thread while + * waiting for a window update. So the open_streams counter + * may be decremented in a different critical section than + * winup_streams, right before signalling the stream thread. + * So there may be more streams awaiting a window updates + * than streams officially open, hence the "lower-equal" + * comparison. + */ if (r2->error == H2SE_BROKE_WINDOW && h2->open_streams <= h2->winup_streams) h2->error = r2->error = H2CE_BANKRUPT; From simon.stridsberg at varnish-software.com Mon Mar 18 18:23:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:23:07 +0000 (UTC) Subject: [7.3] 68818d9cc Prepare for 7.3.2 Message-ID: <20240318182307.AC47B101AF1@lists.varnish-cache.org> commit 68818d9cc0e62df1b9c20daf7e8cb257c1869f0f Author: Simon Stridsberg Date: Mon Mar 18 13:05:04 2024 +0100 Prepare for 7.3.2 diff --git a/configure.ac b/configure.ac index d86cd4652..a6d483d35 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ AC_PREREQ(2.69) AC_COPYRIGHT([Copyright (c) 2006 Verdens Gang AS -Copyright (c) 2006-2023 Varnish Software]) +Copyright (c) 2006-2024 Varnish Software]) AC_REVISION([$Id$]) -AC_INIT([Varnish], [7.3.1], [varnish-dev at varnish-cache.org]) +AC_INIT([Varnish], [7.3.2], [varnish-dev at varnish-cache.org]) AC_CONFIG_SRCDIR(include/miniobj.h) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/changes.rst b/doc/changes.rst index d33618592..50d063d0d 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -31,6 +31,14 @@ http://varnish-cache.org/docs/trunk/whats-new/index.html and via individual releases. These documents are updated as part of the release process. +================================ +Varnish Cache 7.3.2 (2024-03-18) +================================ + +* Add ``h2_window_timeout`` paramater to mitigate CVE-2023-43622 (VSV00014_). + +.. _VSV00014: https://varnish-cache.org/security/VSV00014.html + ================================ Varnish Cache 7.3.1 (2023-11-13) ================================ diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 537c22209..706612917 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -42,7 +42,7 @@ Longer listings like example command output and VCL look like this:: $ /opt/varnish/sbin/varnishd -V varnishd (varnish-trunk revision 1234567) Copyright (c) 2006 Verdens Gang AS - Copyright (c) 2006-2023 Varnish Software + Copyright (c) 2006-2024 Varnish Software .. For maintainers: diff --git a/lib/libvarnish/version.c b/lib/libvarnish/version.c index 02c6fb90b..8c88fd9f4 100644 --- a/lib/libvarnish/version.c +++ b/lib/libvarnish/version.c @@ -76,7 +76,7 @@ VCS_String(const char *which) ")" "\n" "Copyright (c) 2006 Verdens Gang AS\n" - "Copyright (c) 2006-2023 Varnish Software\n" + "Copyright (c) 2006-2024 Varnish Software\n" ); default: WRONG("Wrong argument to VCS_String"); From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:06 +0000 (UTC) Subject: [7.4] 908fef9d6 vtc_http2: Automatic stream identifier Message-ID: <20240318182506.AE83B102DCE@lists.varnish-cache.org> commit 908fef9d6cb23f5c54dbae6ce1c4ceb0b0ca0e4b Author: Dridi Boukelmoune Date: Fri Oct 20 18:53:26 2023 +0200 vtc_http2: Automatic stream identifier diff --git a/bin/varnishtest/tests/a02028.vtc b/bin/varnishtest/tests/a02028.vtc new file mode 100644 index 000000000..4ba8986ed --- /dev/null +++ b/bin/varnishtest/tests/a02028.vtc @@ -0,0 +1,24 @@ +varnishtest "Automatic stream numbers" + +server s1 { + loop 4 { + stream next { + rxreq + txresp + } -run + } +} -start + +client c1 -connect ${s1_sock} { + loop 3 { + stream next { + txreq + rxresp + } -run + } + + stream 7 { + txreq + rxresp + } -run +} -run diff --git a/bin/varnishtest/vtc_http.h b/bin/varnishtest/vtc_http.h index 432c8bb02..7a86de8da 100644 --- a/bin/varnishtest/vtc_http.h +++ b/bin/varnishtest/vtc_http.h @@ -86,6 +86,7 @@ struct http { pthread_t tp; VTAILQ_HEAD(, stream) streams; + unsigned last_stream; pthread_mutex_t mtx; pthread_cond_t cond; struct hpk_ctx *encctx; diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index 025c22340..0361b9e1a 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -2632,9 +2632,17 @@ stream_thread(void *priv) static struct stream * stream_new(const char *name, struct http *h) { - char *p; + char *p, buf[20]; struct stream *s; + if (!strcmp("next", name)) { + if (h->last_stream > 0) + bprintf(buf, "%d", h->last_stream + 2); + else + bprintf(buf, "%d", 1); + name = buf; + } + ALLOC_OBJ(s, STREAM_MAGIC); AN(s); PTOK(pthread_cond_init(&s->cond, NULL)); @@ -2656,6 +2664,7 @@ stream_new(const char *name, struct http *h) CHECK_OBJ_NOTNULL(h, HTTP_MAGIC); s->hp = h; + h->last_stream = s->id; //bprintf(s->connect, "%s", "${v1_sock}"); PTOK(pthread_mutex_lock(&h->mtx)); @@ -2761,7 +2770,8 @@ stream_run(struct stream *s) * stream ID [SPEC] [ACTION] * * ID is the HTTP/2 stream number, while SPEC describes what will be - * done in that stream. + * done in that stream. If ID has the value ``next``, the actual stream + * number is computed based on the last one. * * Note that, when parsing a stream action, if the entity isn't operating * in HTTP/2 mode, these spec is ran before:: @@ -2830,7 +2840,7 @@ cmd_stream(CMD_ARGS) continue; } if (**av == '-') - vtc_fatal(vl, "Unknown client argument: %s", *av); + vtc_fatal(vl, "Unknown stream argument: %s", *av); REPLACE(s->spec, *av); } } From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:06 +0000 (UTC) Subject: [7.4] e3ba30649 http2_proto: Proper null checks for h2 errors Message-ID: <20240318182506.CED19102DD6@lists.varnish-cache.org> commit e3ba306496fff1d70cc02a2558115b2097e19b3d Author: Dridi Boukelmoune Date: Mon Oct 23 11:34:31 2023 +0200 http2_proto: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index edcc709d9..58172d3d1 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -833,11 +833,11 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) Lck_Lock(&h2->sess->mtx); CHECK_OBJ_ORNULL(r2->rxbuf, H2_RXBUF_MAGIC); - if (h2->error || r2->error) { + if (h2->error != NULL || r2->error != NULL) { if (r2->cond) PTOK(pthread_cond_signal(r2->cond)); Lck_Unlock(&h2->sess->mtx); - return (h2->error ? h2->error : r2->error); + return (h2->error != NULL ? h2->error : r2->error); } /* Check padding if present */ @@ -1074,7 +1074,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp) } else l = 0; - if (h2->error || r2->error) + if (h2->error != NULL || r2->error != NULL) retval = VFP_ERROR; else if (r2->state >= H2_S_CLOS_REM && l <= *lp) retval = VFP_END; @@ -1270,15 +1270,15 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); - if (h2e == 0) - return (0); + if (h2e == NULL) + return (NULL); if (h2->rxf_stream == 0 || h2e->connection) return (h2e); // Connection errors one level up H2_Send_Get(wrk, h2, h2->req0); H2_Send_RST(wrk, h2, h2->req0, h2->rxf_stream, h2e); H2_Send_Rel(h2, h2->req0); - return (0); + return (NULL); } int @@ -1485,7 +1485,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) } h2e = h2_procframe(wrk, h2, h2f); - if (h2->error == 0 && h2e) { + if (h2->error == NULL && h2e != NULL) { h2->error = h2e; vbe32enc(b, h2->highest_stream); vbe32enc(b + 4, h2e->val); @@ -1493,5 +1493,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); H2_Send_Rel(h2, h2->req0); } - return (h2->error ? 0 : 1); + + return (h2->error != NULL ? 0 : 1); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:06 +0000 (UTC) Subject: [7.4] a6aa36b55 http2_send: Proper null checks for h2 errors Message-ID: <20240318182507.03EE5102DDC@lists.varnish-cache.org> commit a6aa36b55b88ad7e2bb91f668547b806d1a15cad Author: Dridi Boukelmoune Date: Mon Oct 23 11:36:57 2023 +0200 http2_send: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index be3d6fd67..ac07d542c 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -239,11 +239,11 @@ h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - if (r2->error) + if (r2->error != NULL) return (r2->error); - if (h2->error && r2->stream > h2->goaway_last_stream) + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) return (h2->error); - return (0); + return (NULL); } static int64_t @@ -263,15 +263,17 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, if (r2->t_window <= 0 || h2->req0->t_window <= 0) { r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); - while (r2->t_window <= 0 && h2_errcheck(r2, h2) == 0) { + + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); r2->cond = NULL; } - while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == 0) + + while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == NULL) (void)h2_cond_wait(h2->winupd_cond, h2, r2); - if (h2_errcheck(r2, h2) == 0) { + if (h2_errcheck(r2, h2) == NULL) { w = vmin_t(int64_t, h2_win_limit(r2, h2), wanted); h2_win_charge(r2, h2, w); assert (w > 0); @@ -279,7 +281,7 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_send_get_locked(wrk, h2, r2); } - if (w == 0 && h2_errcheck(r2, h2) == 0) { + if (w == 0 && h2_errcheck(r2, h2) == NULL) { assert(r2->t_window > 0); assert(h2->req0->t_window > 0); w = h2_win_limit(r2, h2); @@ -316,7 +318,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, AN(H2_SEND_HELD(h2, r2)); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(ftyp); @@ -341,7 +343,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } else @@ -362,7 +364,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window && p != ptr) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } @@ -383,7 +385,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, ftyp = ftyp->continuation; flags &= ftyp->flags; final_flags &= ftyp->flags; - } while (!h2->error && len > 0); + } while (h2->error == NULL && len > 0); } } @@ -396,6 +398,7 @@ H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2, CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); AN(H2_SEND_HELD(h2, r2)); + AN(h2e); Lck_Lock(&h2->sess->mtx); VSLb(h2->vsl, SLT_Debug, "H2: stream %u: %s", stream, h2e->txt); From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:07 +0000 (UTC) Subject: [7.4] 25e3d2308 http2_proto: Make h2_stream_tmo() return an error Message-ID: <20240318182507.2687F102DE3@lists.varnish-cache.org> commit 25e3d2308573cd8bf1a3e21056394fdc9861fce1 Author: Dridi Boukelmoune Date: Thu Nov 16 13:16:15 2023 +0100 http2_proto: Make h2_stream_tmo() return an error diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index ca2e65993..d5a890401 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -254,7 +254,7 @@ void H2_Send(struct worker *, struct h2_req *, h2_frame type, uint8_t flags, /* cache_http2_proto.c */ struct h2_req * h2_new_req(struct h2_sess *, unsigned stream, struct req *); -int h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); +h2_error h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); void h2_del_req(struct worker *, struct h2_req *); void h2_kill_req(struct worker *, struct h2_sess *, struct h2_req *, h2_error); int h2_rxframe(struct worker *, struct h2_sess *); diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 58172d3d1..152c18000 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1281,10 +1281,10 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (NULL); } -int +h2_error h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) { - int r = 0; + h2_error h2e = NULL; CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); @@ -1297,36 +1297,36 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) AN(r2->t_winupd); if (r2->t_winupd == 0 && r2->t_send == 0) - return (0); + return (NULL); if (isnan(now) || (r2->t_winupd != 0 && now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - if (r == 0 && r2->t_send != 0 && + if (h2e == NULL && r2->t_send != 0 && now - r2->t_send > SESS_TMO(h2->sess, send_timeout)) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit send_timeout", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - return (r); + return (h2e); } -static int +static h2_error h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) { - int r; + h2_error h2e; Lck_Lock(&h2->sess->mtx); - r = h2_stream_tmo(h2, r2, h2->sess->t_idle); + h2e = h2_stream_tmo(h2, r2, h2->sess->t_idle); Lck_Unlock(&h2->sess->mtx); - return (r); + return (h2e); } /* From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:07 +0000 (UTC) Subject: [7.4] 0bbdb6ad7 http2_send: Collect the timeout error Message-ID: <20240318182507.4EF1D102DEE@lists.varnish-cache.org> commit 0bbdb6ad7e1c6ccecf1c6d2a0ba96eaef43533d3 Author: Dridi Boukelmoune Date: Thu Nov 16 13:23:18 2023 +0100 http2_send: Collect the timeout error diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ac07d542c..ac634e9ec 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -48,6 +48,7 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { vtim_dur tmo = 0.; vtim_real now; + h2_error h2e; int r; AN(cond); @@ -72,18 +73,16 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) * that the stream reached the idle_send_timeout via the lock and * force it to log it. */ - if (h2_stream_tmo(h2, r2, now)) - r = ETIMEDOUT; - else if (r == ETIMEDOUT) - AN(h2_stream_tmo(h2, r2, NAN)); - - if (r == ETIMEDOUT) { - if (r2->error == NULL) - r2->error = H2SE_CANCEL; - return (-1); + h2e = h2_stream_tmo(h2, r2, now); + if (h2e == NULL && r == ETIMEDOUT) { + h2e = h2_stream_tmo(h2, r2, NAN); + AN(h2e); } - return (0); + if (r2->error == NULL) + r2->error = h2e; + + return (h2e != NULL ? -1 : 0); } static void From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:07 +0000 (UTC) Subject: [7.4] 219366fc6 h2: Send GOAWAY frames in a dedicated function Message-ID: <20240318182507.6E21E102DF5@lists.varnish-cache.org> commit 219366fc6ea7f5df2820817b6e0d4d572f041651 Author: Dridi Boukelmoune Date: Tue Jan 18 10:08:33 2022 +0100 h2: Send GOAWAY frames in a dedicated function And after issuing or receiving a goaway, stop processing frames when there are no streams left. Initially submitted as part of listen sockets management. Refs #3959 diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index d5a890401..1f5a48148 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -165,6 +165,7 @@ struct h2_sess { int refcnt; unsigned open_streams; uint32_t highest_stream; + int goaway; int bogosity; int do_sweep; diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 152c18000..a138d5279 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -387,6 +387,7 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); assert(r2 == h2->req0); + h2->goaway = 1; h2->goaway_last_stream = vbe32dec(h2->rxf_data); h2->error = h2_connectionerror(vbe32dec(h2->rxf_data + 4)); Lck_Lock(&h2->sess->mtx); @@ -395,6 +396,25 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) return (h2->error); } +static void +h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) +{ + char b[8]; + + ASSERT_RXTHR(h2); + AN(h2e); + + if (h2->goaway) + return; + + h2->goaway = 1; + vbe32enc(b, h2->highest_stream); + vbe32enc(b + 4, h2e->val); + H2_Send_Get(wrk, h2, h2->req0); + H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); + H2_Send_Rel(h2, h2->req0); +} + /********************************************************************** */ @@ -1407,9 +1427,12 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2_frame h2f; h2_error h2e; const char *s = NULL; - char b[8]; ASSERT_RXTHR(h2); + + if (h2->goaway && h2->open_streams == 0) + return (0); + VTCP_blocking(*h2->htc->rfd); h2->sess->t_idle = VTIM_real(); hs = HTC_RxStuff(h2->htc, h2_frame_complete, @@ -1487,11 +1510,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2e = h2_procframe(wrk, h2, h2f); if (h2->error == NULL && h2e != NULL) { h2->error = h2e; - vbe32enc(b, h2->highest_stream); - vbe32enc(b + 4, h2e->val); - H2_Send_Get(wrk, h2, h2->req0); - H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); - H2_Send_Rel(h2, h2->req0); + h2_tx_goaway(wrk, h2, h2e); } return (h2->error != NULL ? 0 : 1); From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:07 +0000 (UTC) Subject: [7.4] e82c1936a http2_proto: Enforce session timeouts in h2_sweep() Message-ID: <20240318182507.8A243102E05@lists.varnish-cache.org> commit e82c1936a5a95ccf649090bd5743529628ee6619 Author: Dridi Boukelmoune Date: Thu Nov 16 14:52:49 2023 +0100 http2_proto: Enforce session timeouts in h2_sweep() The new meaning for h2->sess->t_idle is now the time since the last complete frame, except before the first frame where it corresponds to the creation of the session. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index a138d5279..44c589d56 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1353,14 +1353,20 @@ h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) * This is the janitorial task of cleaning up any closed & refused * streams, and checking if the session is timed out. */ -static int +static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { - int tmo = 0; struct h2_req *r2, *r22; + h2_error h2e = NULL, tmo; + vtim_real now; ASSERT_RXTHR(h2); + now = VTIM_real(); + if (h2e == NULL && h2->open_streams == 0 && + h2->sess->t_idle + cache_param->timeout_idle < now) + h2e = H2CE_NO_ERROR; + h2->do_sweep = 0; VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) { if (r2 == h2->req0) { @@ -1384,10 +1390,9 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) /* FALLTHROUGH */ case H2_S_CLOS_LOC: case H2_S_OPEN: - if (h2_stream_tmo_unlocked(h2, r2)) { - tmo = 1; - continue; - } + tmo = h2_stream_tmo_unlocked(h2, r2); + if (h2e == NULL) + h2e = tmo; break; case H2_S_IDLE: /* Current code make this unreachable: h2_new_req is @@ -1399,9 +1404,7 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) break; } } - if (tmo) - return (0); - return (h2->refcnt > 1); + return (h2e); } @@ -1426,7 +1429,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) enum htc_status_e hs; h2_frame h2f; h2_error h2e; - const char *s = NULL; ASSERT_RXTHR(h2); @@ -1434,36 +1436,30 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) return (0); VTCP_blocking(*h2->htc->rfd); - h2->sess->t_idle = VTIM_real(); - hs = HTC_RxStuff(h2->htc, h2_frame_complete, - NULL, NULL, NAN, - h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle), - NAN, h2->local_settings.max_frame_size + 9); + hs = HTC_RxStuff(h2->htc, h2_frame_complete, NULL, NULL, NAN, + VTIM_real() + 0.5, NAN, h2->local_settings.max_frame_size + 9); + + h2e = NULL; switch (hs) { case HTC_S_COMPLETE: + h2->sess->t_idle = VTIM_real(); + if (h2->do_sweep) + h2e = h2_sweep(wrk, h2); break; case HTC_S_TIMEOUT: - if (h2_sweep(wrk, h2)) - return (1); - - /* FALLTHROUGH */ + h2e = h2_sweep(wrk, h2); + break; default: - /* XXX: HTC_S_OVERFLOW / FRAME_SIZE_ERROR handling */ -#define HTC_STATUS(e, n, d, l) \ - do { \ - if (hs == HTC_S_ ## e) \ - s = #e; \ - } while (0); -#include "tbl/htc.h" - Lck_Lock(&h2->sess->mtx); - VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%s)", s); - h2->error = H2CE_NO_ERROR; - Lck_Unlock(&h2->sess->mtx); + h2e = H2CE_ENHANCE_YOUR_CALM; + } + + if (h2e != NULL && h2e->connection) { + h2->error = h2e; return (0); } - if (h2->do_sweep) - (void)h2_sweep(wrk, h2); + if (hs != HTC_S_COMPLETE) + return (1); h2->rxf_len = vbe32dec(h2->htc->rxbuf_b) >> 8; h2->rxf_type = h2->htc->rxbuf_b[3]; From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:07 +0000 (UTC) Subject: [7.4] 984e207dd http2_proto: Introduce a custom BROKE_WINDOW error Message-ID: <20240318182507.A4983102E13@lists.varnish-cache.org> commit 984e207dd1aaa7583232517c8289ed1559c1b853 Author: Dridi Boukelmoune Date: Thu Nov 16 16:03:42 2023 +0100 http2_proto: Introduce a custom BROKE_WINDOW error Conflicts: include/tbl/h2_error.h diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 44c589d56..e3ef54a24 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1324,7 +1324,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - h2e = H2SE_CANCEL; + h2e = H2SE_BROKE_WINDOW; } if (h2e == NULL && r2->t_send != 0 && diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ac634e9ec..a31d99248 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -412,12 +412,14 @@ H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, uint32_t len, const void *ptr, uint64_t *counter) { uint64_t dummy_counter = 0; + h2_error h2e; if (counter == NULL) counter = &dummy_counter; h2_send(wrk, r2, ftyp, flags, len, ptr, counter); - if (h2_errcheck(r2, r2->h2sess) == H2SE_CANCEL) - H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, H2SE_CANCEL); + h2e = h2_errcheck(r2, r2->h2sess); + if (h2e != NULL && h2e->val == H2SE_CANCEL->val) + H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, h2e); } diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index c6c6bed89..27260c797 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -156,6 +156,13 @@ H2_ERROR( /* descr */ "http/2 rapid reset detected" ) +H2_ERROR( + /* name */ BROKE_WINDOW, + /* val */ 8, /* CANCEL */ + /* types */ 2, + /* reason */ SC_NULL, + /* descr */ "http/2 stream out of window credits" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:07 +0000 (UTC) Subject: [7.4] 7c5660820 param: New h2_window_timeout parameter Message-ID: <20240318182507.C509C102E28@lists.varnish-cache.org> commit 7c5660820fb329eb3e8ca6a991b2ebf0defe4ddf Author: Dridi Boukelmoune Date: Mon Oct 23 11:49:23 2023 +0200 param: New h2_window_timeout parameter This parameter needs to be somewhat high because web browsers may for example only credit streams for image resources just enough to parse metadata like width and height of a picture in order to perform layout computations and fetch resources more sensitive to latency before the effective image payloads. diff --git a/include/tbl/params.h b/include/tbl/params.h index 073e5be3b..600bf6a55 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -1193,6 +1193,20 @@ PARAM_SIMPLE( /* flags */ WIZARD ) +PARAM_SIMPLE( + /* name */ h2_window_timeout, + /* type */ timeout, + /* min */ "0", + /* max */ NULL, + /* def */ "5", + /* units */ "seconds", + /* descr */ + "HTTP2 time limit without window credits. How long a stream may " + "wait for the client to credit the window and allow for more DATA " + "frames to be sent.", + /* flags */ WIZARD +) + PARAM_SIMPLE( /* name */ h2_header_table_size, /* type */ bytes_u, From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:07 +0000 (UTC) Subject: [7.4] ae53a693a http2_send: Move h2_errcheck() at the top Message-ID: <20240318182507.E0616102E38@lists.varnish-cache.org> commit ae53a693a8bb478607ecdf7e8008493e37c4e3cb Author: Dridi Boukelmoune Date: Mon Oct 23 16:40:26 2023 +0200 http2_send: Move h2_errcheck() at the top diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index a31d99248..de4f2850d 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -43,6 +43,19 @@ #define H2_SEND_HELD(h2, r2) (VTAILQ_FIRST(&(h2)->txqueue) == (r2)) +static h2_error +h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) +{ + CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); + CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); + + if (r2->error != NULL) + return (r2->error); + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) + return (h2->error); + return (NULL); +} + static int h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { @@ -232,19 +245,6 @@ h2_win_charge(struct h2_req *r2, const struct h2_sess *h2, uint32_t w) h2->req0->t_window -= w; } -static h2_error -h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) -{ - CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); - CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - - if (r2->error != NULL) - return (r2->error); - if (h2->error != NULL && r2->stream > h2->goaway_last_stream) - return (h2->error); - return (NULL); -} - static int64_t h2_do_window(struct worker *wrk, struct h2_req *r2, struct h2_sess *h2, int64_t wanted) From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] a512becd4 http2_send: Apply h2_window_timeout Message-ID: <20240318182508.0B843102E4A@lists.varnish-cache.org> commit a512becd418ef12c15ccaef9c0720d943f232aba Author: Dridi Boukelmoune Date: Mon Oct 23 13:15:45 2023 +0200 http2_send: Apply h2_window_timeout It replaces idle_send_timeout when the stream is waiting for window credits before sending more DATA frames. The idle_send_timeout will still apply to individual writes to the socket, but triggering it is considered a failure condition (this was already the case). The two loops are merged into a single one to better deal with the lack of ordering guarantees of request vs connection stream control flow window crediting. Refs #2980 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index e3ef54a24..116bf8550 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1310,7 +1310,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); Lck_AssertHeld(&h2->sess->mtx); - /* NB: when now is NAN, it means that idle_send_timeout was hit + /* NB: when now is NAN, it means that h2_window_timeout was hit * on a lock condwait operation. */ if (isnan(now)) @@ -1320,10 +1320,9 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) return (NULL); if (isnan(now) || (r2->t_winupd != 0 && - now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { + now - r2->t_winupd > cache_param->h2_window_timeout)) { VSLb(h2->vsl, SLT_Debug, - "H2: stream %u: Hit idle_send_timeout waiting for" - " WINDOW_UPDATE", r2->stream); + "H2: stream %u: Hit h2_window_timeout", r2->stream); h2e = H2SE_BROKE_WINDOW; } diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index de4f2850d..39ddcfafd 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -70,20 +70,20 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) Lck_AssertHeld(&h2->sess->mtx); - if (cache_param->idle_send_timeout > 0.) - tmo = cache_param->idle_send_timeout; + if (cache_param->h2_window_timeout > 0.) + tmo = cache_param->h2_window_timeout; r = Lck_CondWaitTimeout(cond, &h2->sess->mtx, tmo); assert(r == 0 || r == ETIMEDOUT); now = VTIM_real(); - /* NB: when we grab idle_send_timeout before acquiring the session + /* NB: when we grab h2_window_timeout before acquiring the session * lock we may time out, but once we wake up both send_timeout and - * idle_send_timeout may have changed meanwhile. For this reason + * h2_window_timeout may have changed meanwhile. For this reason * h2_stream_tmo() may not log what timed out and we need to call * again with a magic NAN "now" that indicates to h2_stream_tmo() - * that the stream reached the idle_send_timeout via the lock and + * that the stream reached the h2_window_timeout via the lock and * force it to log it. */ h2e = h2_stream_tmo(h2, r2, now); @@ -208,6 +208,10 @@ H2_Send_Frame(struct worker *wrk, struct h2_sess *h2, iov[1].iov_len = len; s = writev(h2->sess->fd, iov, len == 0 ? 1 : 2); if (s != sizeof hdr + len) { + if (errno == EWOULDBLOCK) { + VSLb(h2->vsl, SLT_Debug, + "H2: stream %u: Hit idle_send_timeout", stream); + } /* * There is no point in being nice here, we will be unable * to send a GOAWAY once the code unrolls, so go directly diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index 29ffea354..d2f5dcca8 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -44,13 +44,13 @@ client c1 { logexpect l1 -wait -# coverage for idle_send_timeout with c2 +# coverage for h2_window_timeout with c2 -varnish v1 -cliok "param.set idle_send_timeout 1" +varnish v1 -cliok "param.set h2_window_timeout 1" varnish v1 -cliok "param.reset send_timeout" logexpect l2 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c2 { @@ -79,12 +79,12 @@ client c2 { logexpect l2 -wait -# coverage for idle_send_timeout change with c3 +# coverage for h2_window_timeout change with c3 barrier b3 cond 2 logexpect l3 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c3 { @@ -113,7 +113,7 @@ client c3 { } -start barrier b3 sync -varnish v1 -cliok "param.reset idle_send_timeout" +varnish v1 -cliok "param.reset h2_window_timeout" client c3 -wait logexpect l3 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] 0115143e4 http2_send: Track bankrupt streams Message-ID: <20240318182508.28149102E70@lists.varnish-cache.org> commit 0115143e4753754e93b7be36f8a531566f9fb7d7 Author: Dridi Boukelmoune Date: Mon Oct 23 17:15:20 2023 +0200 http2_send: Track bankrupt streams diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 1f5a48148..8d78276e3 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -163,7 +163,8 @@ struct h2_sess { struct sess *sess; int refcnt; - unsigned open_streams; + int open_streams; + int winup_streams; uint32_t highest_stream; int goaway; int bogosity; diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 39ddcfafd..0d6b3a6e7 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -267,6 +267,9 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); + assert(h2->winup_streams >= 0); + h2->winup_streams++; + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); @@ -281,6 +284,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_win_charge(r2, h2, w); assert (w > 0); } + + assert(h2->winup_streams > 0); + h2->winup_streams--; + h2_send_get_locked(wrk, h2, r2); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] 76eb2d46b vsc: New MAIN.sc_bankrupt counter Message-ID: <20240318182508.40CBB102E82@lists.varnish-cache.org> commit 76eb2d46bc188031875e0807846a8b790bb588d5 Author: Dridi Boukelmoune Date: Thu Nov 16 16:58:55 2023 +0100 vsc: New MAIN.sc_bankrupt counter diff --git a/include/tbl/sess_close.h b/include/tbl/sess_close.h index f15d34a64..1fc5b648e 100644 --- a/include/tbl/sess_close.h +++ b/include/tbl/sess_close.h @@ -51,6 +51,7 @@ SESS_CLOSE(RANGE_SHORT, range_short, 1, "Insufficient data for range") SESS_CLOSE(REQ_HTTP20, req_http20, 1, "HTTP2 not accepted") SESS_CLOSE(VCL_FAILURE, vcl_failure, 1, "VCL failure") SESS_CLOSE(RAPID_RESET, rapid_reset, 1, "HTTP2 rapid reset") +SESS_CLOSE(BANKRUPT, bankrupt, 1, "HTTP2 credit bankruptcy") #undef SESS_CLOSE /*lint -restore */ diff --git a/lib/libvsc/VSC_main.vsc b/lib/libvsc/VSC_main.vsc index 14f3e266f..4a4a527a5 100644 --- a/lib/libvsc/VSC_main.vsc +++ b/lib/libvsc/VSC_main.vsc @@ -651,6 +651,14 @@ configured limits for the number of permitted rapid stream resets. +.. varnish_vsc:: sc_bankrupt + :level: diag + :oneliner: Session Err BANKRUPT + + Number of times we failed an http/2 session because all the streams + were waiting for their windows to be credited when h2_window_timeout + triggered. + .. varnish_vsc:: client_resp_500 :level: diag :group: wrk From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] 56cf48133 http2_send: Promote global BROKE_WINDOW to BANKRUPT Message-ID: <20240318182508.63440102E92@lists.varnish-cache.org> commit 56cf4813369e1a05bc6e4b68677327e2d0ad36fb Author: Dridi Boukelmoune Date: Thu Nov 16 17:02:35 2023 +0100 http2_send: Promote global BROKE_WINDOW to BANKRUPT When a stream times out waiting for window credits, and all the other streams are broke, declare the whole connection bankrupt. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 116bf8550..f52a609d5 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1356,11 +1356,12 @@ static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { struct h2_req *r2, *r22; - h2_error h2e = NULL, tmo; + h2_error h2e, tmo; vtim_real now; ASSERT_RXTHR(h2); + h2e = h2->error; now = VTIM_real(); if (h2e == NULL && h2->open_streams == 0 && h2->sess->t_idle + cache_param->timeout_idle < now) diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 0d6b3a6e7..316d13dc5 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -285,6 +285,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + if (r2->error == H2SE_BROKE_WINDOW && + h2->open_streams <= h2->winup_streams) + h2->error = r2->error = H2CE_BANKRUPT; + assert(h2->winup_streams > 0); h2->winup_streams--; diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index d2f5dcca8..1e5a7dc8a 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -6,7 +6,13 @@ server s1 { } -start varnish v1 -cliok "param.set feature +http2" -varnish v1 -vcl+backend "" -start +varnish v1 -vcl+backend { + sub vcl_recv { + if (req.url ~ "synth") { + return (synth(200)); + } + } +} -start # coverage for send_timeout with c1 @@ -66,6 +72,10 @@ client c2 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -75,6 +85,9 @@ client c2 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -run logexpect l2 -wait @@ -100,6 +113,10 @@ client c3 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -110,6 +127,9 @@ client c3 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -start barrier b3 sync diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 27260c797..67ef403c8 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -163,6 +163,14 @@ H2_ERROR( /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) + +H2_ERROR( + /* name */ BANKRUPT, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* reason */ SC_BANKRUPT, + /* descr */ "http/2 bankrupt connection" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] 7b02fd7e3 http2: New send_goaway flag for errors Message-ID: <20240318182508.853E7102EA9@lists.varnish-cache.org> commit 7b02fd7e3d79428baf204999eab5d4f438021536 Author: Dridi Boukelmoune Date: Thu Nov 16 17:27:11 2023 +0100 http2: New send_goaway flag for errors diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 8d78276e3..ac9e2c5a9 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -44,16 +44,18 @@ struct h2_error_s { uint32_t val; int stream; int connection; + int send_goaway; stream_close_t reason; }; typedef const struct h2_error_s *h2_error; #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) extern const struct h2_error_s H2CE_##U[1]; -#define H2EC2(U,v,r,d) extern const struct h2_error_s H2SE_##U[1]; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) extern const struct h2_error_s H2CE_##U[1]; +#define H2EC2(U,v,g,r,d) extern const struct h2_error_s H2SE_##U[1]; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index f52a609d5..42fd37484 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -47,10 +47,13 @@ #include "vtim.h" #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,r}}; -#define H2EC2(U,v,r,d) const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,r}}; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) \ + const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,g,r}}; +#define H2EC2(U,v,g,r,d) \ + const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,g,r}}; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -62,6 +65,7 @@ static const struct h2_error_s H2NN_ERROR[1] = {{ 0xffffffff, 1, 1, + 0, SC_RX_JUNK }}; @@ -89,10 +93,11 @@ h2_framename(enum h2frame h2f) */ static const h2_error stream_errors[] = { -#define H2EC1(U,v,r,d) -#define H2EC2(U,v,r,d) [v] = H2SE_##U, -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) +#define H2EC2(U,v,g,r,d) [v] = H2SE_##U, +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -114,10 +119,11 @@ h2_streamerror(uint32_t u) */ static const h2_error conn_errors[] = { -#define H2EC1(U,v,r,d) [v] = H2CE_##U, -#define H2EC2(U,v,r,d) -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) [v] = H2CE_##U, +#define H2EC2(U,v,g,r,d) +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -1316,6 +1322,10 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) if (isnan(now)) AN(r2->t_winupd); + if (h2->error != NULL && h2->error->connection && + !h2->error->send_goaway) + return (h2->error); + if (r2->t_winupd == 0 && r2->t_send == 0) return (NULL); diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index 0361b9e1a..93c7d6508 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -52,7 +52,7 @@ #define BUF_SIZE (1024*2048) static const char *const h2_errs[] = { -#define H2_ERROR(n,v,sc,r,t) [v] = #n, +#define H2_ERROR(n,v,sc,g,r,t) [v] = #n, #include NULL }; @@ -1260,7 +1260,7 @@ cmd_var_resolve(const struct stream *s, const char *spec, char *buf) else return (NULL); } -#define H2_ERROR(U,v,sc,r,t) \ +#define H2_ERROR(U,v,sc,g,r,t) \ if (!strcmp(spec, #U)) { return (#v); } #include "tbl/h2_error.h" return (spec); diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 67ef403c8..ed72f6b00 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -39,6 +39,7 @@ H2_ERROR( /* name */ NO_ERROR, /* val */ 0, /* types */ 3, + /* goaway */ 1, /* reason */ SC_REM_CLOSE, /* descr */ "Graceful shutdown" ) @@ -47,6 +48,7 @@ H2_ERROR( /* name */ PROTOCOL_ERROR, /* val */ 1, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Protocol error detected" ) @@ -55,6 +57,7 @@ H2_ERROR( /* name */ INTERNAL_ERROR, /* val */ 2, /* types */ 3, + /* goaway */ 1, /* reason */ SC_VCL_FAILURE, /* descr */ "Implementation fault" ) @@ -63,6 +66,7 @@ H2_ERROR( /* name */ FLOW_CONTROL_ERROR, /* val */ 3, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Flow-control limits exceeded" ) @@ -71,6 +75,7 @@ H2_ERROR( /* name */ SETTINGS_TIMEOUT, /* val */ 4, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_TIMEOUT, /* descr */ "Settings not acknowledged" ) @@ -79,6 +84,7 @@ H2_ERROR( /* name */ STREAM_CLOSED, /* val */ 5, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Frame received for closed stream" ) @@ -87,6 +93,7 @@ H2_ERROR( /* name */ FRAME_SIZE_ERROR, /* val */ 6, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Frame size incorrect" ) @@ -95,6 +102,7 @@ H2_ERROR( /* name */ REFUSED_STREAM, /* val */ 7, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream not processed" ) @@ -103,6 +111,7 @@ H2_ERROR( /* name */ CANCEL, /* val */ 8, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream cancelled" ) @@ -111,6 +120,7 @@ H2_ERROR( /* name */ COMPRESSION_ERROR, /* val */ 9, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Compression state not updated" ) @@ -119,6 +129,7 @@ H2_ERROR( /* name */ CONNECT_ERROR, /* val */ 10, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "TCP connection error for CONNECT method" ) @@ -127,6 +138,7 @@ H2_ERROR( /* name */ ENHANCE_YOUR_CALM, /* val */ 11, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Processing capacity exceeded" ) @@ -135,6 +147,7 @@ H2_ERROR( /* name */ INADEQUATE_SECURITY, /* val */ 12, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Negotiated TLS parameters not acceptable" ) @@ -143,23 +156,26 @@ H2_ERROR( /* name */ HTTP_1_1_REQUIRED, /* val */ 13, /* types */ 1, + /* goaway */ 1, /* reason */ SC_REQ_HTTP20, /* descr */ "Use HTTP/1.1 for the request" ) #ifdef H2_CUSTOM_ERRORS H2_ERROR( - /* name */ RAPID_RESET, - /* val */ 11, /* ENHANCE_YOUR_CALM */ - /* types */ 1, - /* reason */ SC_RAPID_RESET, - /* descr */ "http/2 rapid reset detected" + /* name */ RAPID_RESET, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* goaway */ 1, + /* reason */ SC_RAPID_RESET, + /* descr */ "http/2 rapid reset detected" ) H2_ERROR( /* name */ BROKE_WINDOW, /* val */ 8, /* CANCEL */ /* types */ 2, + /* goaway */ 0, /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) @@ -168,6 +184,7 @@ H2_ERROR( /* name */ BANKRUPT, /* val */ 11, /* ENHANCE_YOUR_CALM */ /* types */ 1, + /* goaway */ 0, /* reason */ SC_BANKRUPT, /* descr */ "http/2 bankrupt connection" ) From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] 976185106 http2_proto: Send GOAWAY before leaving the rx loop Message-ID: <20240318182508.A6C8D102EBA@lists.varnish-cache.org> commit 97618510697aa89ad28f11aed01d55b890351d3e Author: Dridi Boukelmoune Date: Thu Nov 16 17:30:17 2023 +0100 http2_proto: Send GOAWAY before leaving the rx loop diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 42fd37484..7fe14591a 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -410,7 +410,7 @@ h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) ASSERT_RXTHR(h2); AN(h2e); - if (h2->goaway) + if (h2->goaway || !h2e->send_goaway) return; h2->goaway = 1; @@ -1465,6 +1465,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) if (h2e != NULL && h2e->connection) { h2->error = h2e; + h2_tx_goaway(wrk, h2, h2e); return (0); } diff --git a/bin/varnishtest/tests/t02003.vtc b/bin/varnishtest/tests/t02003.vtc index 1d62ac986..fe30e8243 100644 --- a/bin/varnishtest/tests/t02003.vtc +++ b/bin/varnishtest/tests/t02003.vtc @@ -233,17 +233,28 @@ client c1 { } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 3 + } -start stream 1 { - txreq -nohdrend + txreq -nostrend txrst -err 2 } -run stream 3 { - txreq -nohdrend + txreq -nostrend txrst -err 0x666 } -run + stream 0 -wait } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq rxresp @@ -252,6 +263,7 @@ client c1 { # RST_STREAM on closed stream txrst } -run + stream 0 -wait } -run diff --git a/bin/varnishtest/tests/t02005.vtc b/bin/varnishtest/tests/t02005.vtc index 616e4c039..c5176f725 100644 --- a/bin/varnishtest/tests/t02005.vtc +++ b/bin/varnishtest/tests/t02005.vtc @@ -32,7 +32,7 @@ varnish v1 -cliok "param.set debug +syncvsl" logexpect l1 -v v1 -g raw { expect * 1001 ReqAcct "80 7 87 78 8 86" - expect * 1000 ReqAcct "45 8 53 54 20 74" + expect * 1000 ReqAcct "45 8 53 63 28 91" } -start client c1 { diff --git a/bin/varnishtest/tests/t02025.vtc b/bin/varnishtest/tests/t02025.vtc index 4b83fe95b..39f987a06 100644 --- a/bin/varnishtest/tests/t02025.vtc +++ b/bin/varnishtest/tests/t02025.vtc @@ -25,12 +25,17 @@ logexpect l1 -v v1 -g raw -i Debug { } -start client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq barrier b1 sync txrst } -run - expect_close + stream 0 -wait } -start logexpect l1 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] cc5f7e7aa http2_proto: Simplify CONTINUATION expectation check Message-ID: <20240318182508.C5BBC102ECA@lists.varnish-cache.org> commit cc5f7e7aa9c2c3addfa4f15f3b153153f3313ece Author: Dridi Boukelmoune Date: Mon Sep 11 17:52:00 2023 +0200 http2_proto: Simplify CONTINUATION expectation check Before the h2 frame dispatch we only need to check that coming from a HEADERS frame the very next frame is a CONTINUATION, when the HPACK block didn't fit in the former. The CONTINUATION dispatch will then make the stream consistency check. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 7fe14591a..5218ed8e5 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1291,8 +1291,7 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) if (r2->stream == h2->rxf_stream) break; - if (h2->new_req != NULL && - !(r2 && h2->new_req == r2->req && h2f == H2_F_CONTINUATION)) + if (h2->new_req != NULL && h2f != H2_F_CONTINUATION) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:08 +0000 (UTC) Subject: [7.4] cbf01b233 http2_send: Explain the winup-open discrepancy Message-ID: <20240318182508.E27F9102EF6@lists.varnish-cache.org> commit cbf01b2339a5beba911299298aa5422dc3ad1e3a Author: Dridi Boukelmoune Date: Mon Jan 29 10:59:22 2024 +0100 http2_send: Explain the winup-open discrepancy diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 316d13dc5..d642e31df 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -285,6 +285,18 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + /* If all streams ran out of control flow window credits + * upon triggering h2_window_timeout, declare bankruptcy + * for the entire connection. + * + * But streams may be closed from the h2_sess thread while + * waiting for a window update. So the open_streams counter + * may be decremented in a different critical section than + * winup_streams, right before signalling the stream thread. + * So there may be more streams awaiting a window updates + * than streams officially open, hence the "lower-equal" + * comparison. + */ if (r2->error == H2SE_BROKE_WINDOW && h2->open_streams <= h2->winup_streams) h2->error = r2->error = H2CE_BANKRUPT; From simon.stridsberg at varnish-software.com Mon Mar 18 18:25:09 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:25:09 +0000 (UTC) Subject: [7.4] b659b7ae6 Prepare for 7.4.3 Message-ID: <20240318182509.174ED102EFE@lists.varnish-cache.org> commit b659b7ae62b44c05888919c5c1cd03ba6eaec681 Author: Simon Stridsberg Date: Mon Mar 18 13:42:51 2024 +0100 Prepare for 7.4.3 diff --git a/configure.ac b/configure.ac index ce6f8dcf1..20e99408b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ AC_PREREQ(2.69) AC_COPYRIGHT([Copyright (c) 2006 Verdens Gang AS -Copyright (c) 2006-2023 Varnish Software -Copyright 2010-2023 UPLEX - Nils Goroll Systemoptimierung]) +Copyright (c) 2006-2024 Varnish Software +Copyright 2010-2024 UPLEX - Nils Goroll Systemoptimierung]) AC_REVISION([$Id$]) -AC_INIT([Varnish], [7.4.2], [varnish-dev at varnish-cache.org]) +AC_INIT([Varnish], [7.4.3], [varnish-dev at varnish-cache.org]) AC_CONFIG_SRCDIR(include/miniobj.h) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/changes.rst b/doc/changes.rst index 11ba00a14..91fcb6ab7 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -34,6 +34,14 @@ http://varnish-cache.org/docs/trunk/whats-new/index.html and via individual releases. These documents are updated as part of the release process. +================================ +Varnish Cache 7.4.3 (2024-03-18) +================================ + +* Add ``h2_window_timeout`` paramater to mitigate CVE-2023-43622 (VSV00014_). + +.. _VSV00014: https://varnish-cache.org/security/VSV00014.html + ================================ Varnish Cache 7.4.2 (2023-11-13) ================================ diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 537c22209..706612917 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -42,7 +42,7 @@ Longer listings like example command output and VCL look like this:: $ /opt/varnish/sbin/varnishd -V varnishd (varnish-trunk revision 1234567) Copyright (c) 2006 Verdens Gang AS - Copyright (c) 2006-2023 Varnish Software + Copyright (c) 2006-2024 Varnish Software .. For maintainers: diff --git a/lib/libvarnish/version.c b/lib/libvarnish/version.c index 0d09ab748..4f5983c0d 100644 --- a/lib/libvarnish/version.c +++ b/lib/libvarnish/version.c @@ -76,8 +76,8 @@ VCS_String(const char *which) ")" "\n" "Copyright (c) 2006 Verdens Gang AS\n" - "Copyright (c) 2006-2023 Varnish Software\n" - "Copyright 2010-2023 UPLEX - Nils Goroll Systemoptimierung\n" + "Copyright (c) 2006-2024 Varnish Software\n" + "Copyright 2010-2024 UPLEX - Nils Goroll Systemoptimierung\n" ); default: WRONG("Wrong argument to VCS_String"); From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:05 +0000 (UTC) Subject: [7.5] 7fb01bdfb http2_proto: Proper null checks for h2 errors Message-ID: <20240318182605.82A6D1039CE@lists.varnish-cache.org> commit 7fb01bdfbed10f4b8a1042d9578228385000d9cf Author: Dridi Boukelmoune Date: Mon Oct 23 11:34:31 2023 +0200 http2_proto: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 52a1c2121..58e67ecef 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -837,11 +837,11 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) Lck_Lock(&h2->sess->mtx); CHECK_OBJ_ORNULL(r2->rxbuf, H2_RXBUF_MAGIC); - if (h2->error || r2->error) { + if (h2->error != NULL || r2->error != NULL) { if (r2->cond) PTOK(pthread_cond_signal(r2->cond)); Lck_Unlock(&h2->sess->mtx); - return (h2->error ? h2->error : r2->error); + return (h2->error != NULL ? h2->error : r2->error); } /* Check padding if present */ @@ -1078,7 +1078,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp) } else l = 0; - if (h2->error || r2->error) + if (h2->error != NULL || r2->error != NULL) retval = VFP_ERROR; else if (r2->state >= H2_S_CLOS_REM && l <= *lp) retval = VFP_END; @@ -1274,15 +1274,15 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); - if (h2e == 0) - return (0); + if (h2e == NULL) + return (NULL); if (h2->rxf_stream == 0 || h2e->connection) return (h2e); // Connection errors one level up H2_Send_Get(wrk, h2, h2->req0); H2_Send_RST(wrk, h2, h2->req0, h2->rxf_stream, h2e); H2_Send_Rel(h2, h2->req0); - return (0); + return (NULL); } int @@ -1489,7 +1489,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) } h2e = h2_procframe(wrk, h2, h2f); - if (h2->error == 0 && h2e) { + if (h2->error == NULL && h2e != NULL) { h2->error = h2e; vbe32enc(b, h2->highest_stream); vbe32enc(b + 4, h2e->val); @@ -1497,5 +1497,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); H2_Send_Rel(h2, h2->req0); } - return (h2->error ? 0 : 1); + + return (h2->error != NULL ? 0 : 1); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:05 +0000 (UTC) Subject: [7.5] ec95d0499 http2_send: Proper null checks for h2 errors Message-ID: <20240318182605.9B0061039DB@lists.varnish-cache.org> commit ec95d0499777830425c890221e86ee216ea27024 Author: Dridi Boukelmoune Date: Mon Oct 23 11:36:57 2023 +0200 http2_send: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index be3d6fd67..ac07d542c 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -239,11 +239,11 @@ h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - if (r2->error) + if (r2->error != NULL) return (r2->error); - if (h2->error && r2->stream > h2->goaway_last_stream) + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) return (h2->error); - return (0); + return (NULL); } static int64_t @@ -263,15 +263,17 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, if (r2->t_window <= 0 || h2->req0->t_window <= 0) { r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); - while (r2->t_window <= 0 && h2_errcheck(r2, h2) == 0) { + + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); r2->cond = NULL; } - while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == 0) + + while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == NULL) (void)h2_cond_wait(h2->winupd_cond, h2, r2); - if (h2_errcheck(r2, h2) == 0) { + if (h2_errcheck(r2, h2) == NULL) { w = vmin_t(int64_t, h2_win_limit(r2, h2), wanted); h2_win_charge(r2, h2, w); assert (w > 0); @@ -279,7 +281,7 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_send_get_locked(wrk, h2, r2); } - if (w == 0 && h2_errcheck(r2, h2) == 0) { + if (w == 0 && h2_errcheck(r2, h2) == NULL) { assert(r2->t_window > 0); assert(h2->req0->t_window > 0); w = h2_win_limit(r2, h2); @@ -316,7 +318,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, AN(H2_SEND_HELD(h2, r2)); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(ftyp); @@ -341,7 +343,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } else @@ -362,7 +364,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window && p != ptr) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } @@ -383,7 +385,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, ftyp = ftyp->continuation; flags &= ftyp->flags; final_flags &= ftyp->flags; - } while (!h2->error && len > 0); + } while (h2->error == NULL && len > 0); } } @@ -396,6 +398,7 @@ H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2, CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); AN(H2_SEND_HELD(h2, r2)); + AN(h2e); Lck_Lock(&h2->sess->mtx); VSLb(h2->vsl, SLT_Debug, "H2: stream %u: %s", stream, h2e->txt); From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:05 +0000 (UTC) Subject: [7.5] 884f8b316 http2_proto: Make h2_stream_tmo() return an error Message-ID: <20240318182605.B71C71039E8@lists.varnish-cache.org> commit 884f8b3164a8b598cb7960f8379f5504c70b6c62 Author: Dridi Boukelmoune Date: Thu Nov 16 13:16:15 2023 +0100 http2_proto: Make h2_stream_tmo() return an error diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index f73b5657e..0ca9eeb78 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -255,7 +255,7 @@ void H2_Send(struct worker *, struct h2_req *, h2_frame type, uint8_t flags, /* cache_http2_proto.c */ struct h2_req * h2_new_req(struct h2_sess *, unsigned stream, struct req *); -int h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); +h2_error h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); void h2_del_req(struct worker *, struct h2_req *); void h2_kill_req(struct worker *, struct h2_sess *, struct h2_req *, h2_error); int h2_rxframe(struct worker *, struct h2_sess *); diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 58e67ecef..454a78cbe 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1285,10 +1285,10 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (NULL); } -int +h2_error h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) { - int r = 0; + h2_error h2e = NULL; CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); @@ -1301,36 +1301,36 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) AN(r2->t_winupd); if (r2->t_winupd == 0 && r2->t_send == 0) - return (0); + return (NULL); if (isnan(now) || (r2->t_winupd != 0 && now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - if (r == 0 && r2->t_send != 0 && + if (h2e == NULL && r2->t_send != 0 && now - r2->t_send > SESS_TMO(h2->sess, send_timeout)) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit send_timeout", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - return (r); + return (h2e); } -static int +static h2_error h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) { - int r; + h2_error h2e; Lck_Lock(&h2->sess->mtx); - r = h2_stream_tmo(h2, r2, h2->sess->t_idle); + h2e = h2_stream_tmo(h2, r2, h2->sess->t_idle); Lck_Unlock(&h2->sess->mtx); - return (r); + return (h2e); } /* From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:05 +0000 (UTC) Subject: [7.5] 7ce5f508f http2_send: Collect the timeout error Message-ID: <20240318182605.D30211039FC@lists.varnish-cache.org> commit 7ce5f508f55706709c7e42531d001d6e554c5f42 Author: Dridi Boukelmoune Date: Thu Nov 16 13:23:18 2023 +0100 http2_send: Collect the timeout error diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ac07d542c..ac634e9ec 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -48,6 +48,7 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { vtim_dur tmo = 0.; vtim_real now; + h2_error h2e; int r; AN(cond); @@ -72,18 +73,16 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) * that the stream reached the idle_send_timeout via the lock and * force it to log it. */ - if (h2_stream_tmo(h2, r2, now)) - r = ETIMEDOUT; - else if (r == ETIMEDOUT) - AN(h2_stream_tmo(h2, r2, NAN)); - - if (r == ETIMEDOUT) { - if (r2->error == NULL) - r2->error = H2SE_CANCEL; - return (-1); + h2e = h2_stream_tmo(h2, r2, now); + if (h2e == NULL && r == ETIMEDOUT) { + h2e = h2_stream_tmo(h2, r2, NAN); + AN(h2e); } - return (0); + if (r2->error == NULL) + r2->error = h2e; + + return (h2e != NULL ? -1 : 0); } static void From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:05 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:05 +0000 (UTC) Subject: [7.5] 64f609dbd h2: Send GOAWAY frames in a dedicated function Message-ID: <20240318182605.ED3A5103A0A@lists.varnish-cache.org> commit 64f609dbdaeb4d9f574424a374100b06f8f40398 Author: Dridi Boukelmoune Date: Tue Jan 18 10:08:33 2022 +0100 h2: Send GOAWAY frames in a dedicated function And after issuing or receiving a goaway, stop processing frames when there are no streams left. Initially submitted as part of listen sockets management. Refs #3959 diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 0ca9eeb78..11e957d49 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -165,6 +165,7 @@ struct h2_sess { int refcnt; unsigned open_streams; uint32_t highest_stream; + int goaway; int bogosity; int do_sweep; diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 454a78cbe..eaa6b1b7a 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -389,6 +389,7 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); assert(r2 == h2->req0); + h2->goaway = 1; h2->goaway_last_stream = vbe32dec(h2->rxf_data); h2->error = h2_connectionerror(vbe32dec(h2->rxf_data + 4)); Lck_Lock(&h2->sess->mtx); @@ -397,6 +398,25 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) return (h2->error); } +static void +h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) +{ + char b[8]; + + ASSERT_RXTHR(h2); + AN(h2e); + + if (h2->goaway) + return; + + h2->goaway = 1; + vbe32enc(b, h2->highest_stream); + vbe32enc(b + 4, h2e->val); + H2_Send_Get(wrk, h2, h2->req0); + H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); + H2_Send_Rel(h2, h2->req0); +} + /********************************************************************** */ @@ -1411,9 +1431,12 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2_frame h2f; h2_error h2e; const char *s = NULL; - char b[8]; ASSERT_RXTHR(h2); + + if (h2->goaway && h2->open_streams == 0) + return (0); + VTCP_blocking(*h2->htc->rfd); h2->sess->t_idle = VTIM_real(); hs = HTC_RxStuff(h2->htc, h2_frame_complete, @@ -1491,11 +1514,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2e = h2_procframe(wrk, h2, h2f); if (h2->error == NULL && h2e != NULL) { h2->error = h2e; - vbe32enc(b, h2->highest_stream); - vbe32enc(b + 4, h2e->val); - H2_Send_Get(wrk, h2, h2->req0); - H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); - H2_Send_Rel(h2, h2->req0); + h2_tx_goaway(wrk, h2, h2e); } return (h2->error != NULL ? 0 : 1); From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] 41ef373af http2_proto: Enforce session timeouts in h2_sweep() Message-ID: <20240318182606.157EC103A0F@lists.varnish-cache.org> commit 41ef373af53571a94ea8f73f0538322270799a84 Author: Dridi Boukelmoune Date: Thu Nov 16 14:52:49 2023 +0100 http2_proto: Enforce session timeouts in h2_sweep() The new meaning for h2->sess->t_idle is now the time since the last complete frame, except before the first frame where it corresponds to the creation of the session. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index eaa6b1b7a..364f2bf38 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1357,14 +1357,20 @@ h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) * This is the janitorial task of cleaning up any closed & refused * streams, and checking if the session is timed out. */ -static int +static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { - int tmo = 0; struct h2_req *r2, *r22; + h2_error h2e = NULL, tmo; + vtim_real now; ASSERT_RXTHR(h2); + now = VTIM_real(); + if (h2e == NULL && h2->open_streams == 0 && + h2->sess->t_idle + cache_param->timeout_idle < now) + h2e = H2CE_NO_ERROR; + h2->do_sweep = 0; VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) { if (r2 == h2->req0) { @@ -1388,10 +1394,9 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) /* FALLTHROUGH */ case H2_S_CLOS_LOC: case H2_S_OPEN: - if (h2_stream_tmo_unlocked(h2, r2)) { - tmo = 1; - continue; - } + tmo = h2_stream_tmo_unlocked(h2, r2); + if (h2e == NULL) + h2e = tmo; break; case H2_S_IDLE: /* Current code make this unreachable: h2_new_req is @@ -1403,9 +1408,7 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) break; } } - if (tmo) - return (0); - return (h2->refcnt > 1); + return (h2e); } @@ -1430,7 +1433,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) enum htc_status_e hs; h2_frame h2f; h2_error h2e; - const char *s = NULL; ASSERT_RXTHR(h2); @@ -1438,36 +1440,30 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) return (0); VTCP_blocking(*h2->htc->rfd); - h2->sess->t_idle = VTIM_real(); - hs = HTC_RxStuff(h2->htc, h2_frame_complete, - NULL, NULL, NAN, - h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle), - NAN, h2->local_settings.max_frame_size + 9); + hs = HTC_RxStuff(h2->htc, h2_frame_complete, NULL, NULL, NAN, + VTIM_real() + 0.5, NAN, h2->local_settings.max_frame_size + 9); + + h2e = NULL; switch (hs) { case HTC_S_COMPLETE: + h2->sess->t_idle = VTIM_real(); + if (h2->do_sweep) + h2e = h2_sweep(wrk, h2); break; case HTC_S_TIMEOUT: - if (h2_sweep(wrk, h2)) - return (1); - - /* FALLTHROUGH */ + h2e = h2_sweep(wrk, h2); + break; default: - /* XXX: HTC_S_OVERFLOW / FRAME_SIZE_ERROR handling */ -#define HTC_STATUS(e, n, d, l) \ - do { \ - if (hs == HTC_S_ ## e) \ - s = #e; \ - } while (0); -#include "tbl/htc.h" - Lck_Lock(&h2->sess->mtx); - VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%s)", s); - h2->error = H2CE_NO_ERROR; - Lck_Unlock(&h2->sess->mtx); + h2e = H2CE_ENHANCE_YOUR_CALM; + } + + if (h2e != NULL && h2e->connection) { + h2->error = h2e; return (0); } - if (h2->do_sweep) - (void)h2_sweep(wrk, h2); + if (hs != HTC_S_COMPLETE) + return (1); h2->rxf_len = vbe32dec(h2->htc->rxbuf_b) >> 8; h2->rxf_type = h2->htc->rxbuf_b[3]; From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] 4938f05b3 http2_proto: Introduce a custom BROKE_WINDOW error Message-ID: <20240318182606.30560103A15@lists.varnish-cache.org> commit 4938f05b318eb2daa2ccc89dafeed3126552c481 Author: Dridi Boukelmoune Date: Thu Nov 16 16:03:42 2023 +0100 http2_proto: Introduce a custom BROKE_WINDOW error diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 364f2bf38..a00112c5f 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1328,7 +1328,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - h2e = H2SE_CANCEL; + h2e = H2SE_BROKE_WINDOW; } if (h2e == NULL && r2->t_send != 0 && diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ac634e9ec..a31d99248 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -412,12 +412,14 @@ H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, uint32_t len, const void *ptr, uint64_t *counter) { uint64_t dummy_counter = 0; + h2_error h2e; if (counter == NULL) counter = &dummy_counter; h2_send(wrk, r2, ftyp, flags, len, ptr, counter); - if (h2_errcheck(r2, r2->h2sess) == H2SE_CANCEL) - H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, H2SE_CANCEL); + h2e = h2_errcheck(r2, r2->h2sess); + if (h2e != NULL && h2e->val == H2SE_CANCEL->val) + H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, h2e); } diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 345e1549b..045ddaa59 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -163,6 +163,14 @@ H2_ERROR( /* reason */ SC_NULL, /* descr */ "Missing :scheme pseudo-header" ) + +H2_ERROR( + /* name */ BROKE_WINDOW, + /* val */ 8, /* CANCEL */ + /* types */ 2, + /* reason */ SC_NULL, + /* descr */ "http/2 stream out of window credits" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] 0b82e0070 param: New h2_window_timeout parameter Message-ID: <20240318182606.4CCE9103A1F@lists.varnish-cache.org> commit 0b82e00708b88f696af5881b7a19caf2144d13f7 Author: Dridi Boukelmoune Date: Mon Oct 23 11:49:23 2023 +0200 param: New h2_window_timeout parameter This parameter needs to be somewhat high because web browsers may for example only credit streams for image resources just enough to parse metadata like width and height of a picture in order to perform layout computations and fetch resources more sensitive to latency before the effective image payloads. diff --git a/include/tbl/params.h b/include/tbl/params.h index e96d75483..42d72947b 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -1205,6 +1205,20 @@ PARAM_SIMPLE( /* flags */ WIZARD ) +PARAM_SIMPLE( + /* name */ h2_window_timeout, + /* type */ timeout, + /* min */ "0", + /* max */ NULL, + /* def */ "5", + /* units */ "seconds", + /* descr */ + "HTTP2 time limit without window credits. How long a stream may " + "wait for the client to credit the window and allow for more DATA " + "frames to be sent.", + /* flags */ WIZARD +) + PARAM_SIMPLE( /* name */ h2_header_table_size, /* type */ bytes_u, From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] 47e12f219 http2_send: Move h2_errcheck() at the top Message-ID: <20240318182606.6C11A103A24@lists.varnish-cache.org> commit 47e12f219108b011f41e4f6cd8c8c6262154045e Author: Dridi Boukelmoune Date: Mon Oct 23 16:40:26 2023 +0200 http2_send: Move h2_errcheck() at the top diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index a31d99248..de4f2850d 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -43,6 +43,19 @@ #define H2_SEND_HELD(h2, r2) (VTAILQ_FIRST(&(h2)->txqueue) == (r2)) +static h2_error +h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) +{ + CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); + CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); + + if (r2->error != NULL) + return (r2->error); + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) + return (h2->error); + return (NULL); +} + static int h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { @@ -232,19 +245,6 @@ h2_win_charge(struct h2_req *r2, const struct h2_sess *h2, uint32_t w) h2->req0->t_window -= w; } -static h2_error -h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) -{ - CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); - CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - - if (r2->error != NULL) - return (r2->error); - if (h2->error != NULL && r2->stream > h2->goaway_last_stream) - return (h2->error); - return (NULL); -} - static int64_t h2_do_window(struct worker *wrk, struct h2_req *r2, struct h2_sess *h2, int64_t wanted) From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] c0201724f http2_send: Apply h2_window_timeout Message-ID: <20240318182606.888D7103A33@lists.varnish-cache.org> commit c0201724f0280894ec714fe76fc26ba9831f0551 Author: Dridi Boukelmoune Date: Mon Oct 23 13:15:45 2023 +0200 http2_send: Apply h2_window_timeout It replaces idle_send_timeout when the stream is waiting for window credits before sending more DATA frames. The idle_send_timeout will still apply to individual writes to the socket, but triggering it is considered a failure condition (this was already the case). The two loops are merged into a single one to better deal with the lack of ordering guarantees of request vs connection stream control flow window crediting. Refs #2980 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index a00112c5f..b575b0f11 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1314,7 +1314,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); Lck_AssertHeld(&h2->sess->mtx); - /* NB: when now is NAN, it means that idle_send_timeout was hit + /* NB: when now is NAN, it means that h2_window_timeout was hit * on a lock condwait operation. */ if (isnan(now)) @@ -1324,10 +1324,9 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) return (NULL); if (isnan(now) || (r2->t_winupd != 0 && - now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { + now - r2->t_winupd > cache_param->h2_window_timeout)) { VSLb(h2->vsl, SLT_Debug, - "H2: stream %u: Hit idle_send_timeout waiting for" - " WINDOW_UPDATE", r2->stream); + "H2: stream %u: Hit h2_window_timeout", r2->stream); h2e = H2SE_BROKE_WINDOW; } diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index de4f2850d..39ddcfafd 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -70,20 +70,20 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) Lck_AssertHeld(&h2->sess->mtx); - if (cache_param->idle_send_timeout > 0.) - tmo = cache_param->idle_send_timeout; + if (cache_param->h2_window_timeout > 0.) + tmo = cache_param->h2_window_timeout; r = Lck_CondWaitTimeout(cond, &h2->sess->mtx, tmo); assert(r == 0 || r == ETIMEDOUT); now = VTIM_real(); - /* NB: when we grab idle_send_timeout before acquiring the session + /* NB: when we grab h2_window_timeout before acquiring the session * lock we may time out, but once we wake up both send_timeout and - * idle_send_timeout may have changed meanwhile. For this reason + * h2_window_timeout may have changed meanwhile. For this reason * h2_stream_tmo() may not log what timed out and we need to call * again with a magic NAN "now" that indicates to h2_stream_tmo() - * that the stream reached the idle_send_timeout via the lock and + * that the stream reached the h2_window_timeout via the lock and * force it to log it. */ h2e = h2_stream_tmo(h2, r2, now); @@ -208,6 +208,10 @@ H2_Send_Frame(struct worker *wrk, struct h2_sess *h2, iov[1].iov_len = len; s = writev(h2->sess->fd, iov, len == 0 ? 1 : 2); if (s != sizeof hdr + len) { + if (errno == EWOULDBLOCK) { + VSLb(h2->vsl, SLT_Debug, + "H2: stream %u: Hit idle_send_timeout", stream); + } /* * There is no point in being nice here, we will be unable * to send a GOAWAY once the code unrolls, so go directly diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index 29ffea354..d2f5dcca8 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -44,13 +44,13 @@ client c1 { logexpect l1 -wait -# coverage for idle_send_timeout with c2 +# coverage for h2_window_timeout with c2 -varnish v1 -cliok "param.set idle_send_timeout 1" +varnish v1 -cliok "param.set h2_window_timeout 1" varnish v1 -cliok "param.reset send_timeout" logexpect l2 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c2 { @@ -79,12 +79,12 @@ client c2 { logexpect l2 -wait -# coverage for idle_send_timeout change with c3 +# coverage for h2_window_timeout change with c3 barrier b3 cond 2 logexpect l3 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c3 { @@ -113,7 +113,7 @@ client c3 { } -start barrier b3 sync -varnish v1 -cliok "param.reset idle_send_timeout" +varnish v1 -cliok "param.reset h2_window_timeout" client c3 -wait logexpect l3 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] 727a5f803 http2_send: Track bankrupt streams Message-ID: <20240318182606.A734A103A38@lists.varnish-cache.org> commit 727a5f80347545b6fc7a6aa48f9fb74e90528f0c Author: Dridi Boukelmoune Date: Mon Oct 23 17:15:20 2023 +0200 http2_send: Track bankrupt streams diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 11e957d49..95550c080 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -163,7 +163,8 @@ struct h2_sess { struct sess *sess; int refcnt; - unsigned open_streams; + int open_streams; + int winup_streams; uint32_t highest_stream; int goaway; int bogosity; diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 39ddcfafd..0d6b3a6e7 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -267,6 +267,9 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); + assert(h2->winup_streams >= 0); + h2->winup_streams++; + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); @@ -281,6 +284,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_win_charge(r2, h2, w); assert (w > 0); } + + assert(h2->winup_streams > 0); + h2->winup_streams--; + h2_send_get_locked(wrk, h2, r2); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] 42a10e900 vsc: New MAIN.sc_bankrupt counter Message-ID: <20240318182606.C25A0103A40@lists.varnish-cache.org> commit 42a10e90015bd8a9cb1c7c2e0e313f8b5ae9ebe9 Author: Dridi Boukelmoune Date: Thu Nov 16 16:58:55 2023 +0100 vsc: New MAIN.sc_bankrupt counter diff --git a/include/tbl/sess_close.h b/include/tbl/sess_close.h index f15d34a64..1fc5b648e 100644 --- a/include/tbl/sess_close.h +++ b/include/tbl/sess_close.h @@ -51,6 +51,7 @@ SESS_CLOSE(RANGE_SHORT, range_short, 1, "Insufficient data for range") SESS_CLOSE(REQ_HTTP20, req_http20, 1, "HTTP2 not accepted") SESS_CLOSE(VCL_FAILURE, vcl_failure, 1, "VCL failure") SESS_CLOSE(RAPID_RESET, rapid_reset, 1, "HTTP2 rapid reset") +SESS_CLOSE(BANKRUPT, bankrupt, 1, "HTTP2 credit bankruptcy") #undef SESS_CLOSE /*lint -restore */ diff --git a/lib/libvsc/VSC_main.vsc b/lib/libvsc/VSC_main.vsc index 82542a4c5..f5ce2b62f 100644 --- a/lib/libvsc/VSC_main.vsc +++ b/lib/libvsc/VSC_main.vsc @@ -657,6 +657,14 @@ configured limits for the number of permitted rapid stream resets. +.. varnish_vsc:: sc_bankrupt + :level: diag + :oneliner: Session Err BANKRUPT + + Number of times we failed an http/2 session because all the streams + were waiting for their windows to be credited when h2_window_timeout + triggered. + .. varnish_vsc:: client_resp_500 :level: diag :group: wrk From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:06 +0000 (UTC) Subject: [7.5] eccb50837 http2_send: Promote global BROKE_WINDOW to BANKRUPT Message-ID: <20240318182606.DEFEE103A6E@lists.varnish-cache.org> commit eccb50837d61fcb5a6927eef94c570bd1d03c26d Author: Dridi Boukelmoune Date: Thu Nov 16 17:02:35 2023 +0100 http2_send: Promote global BROKE_WINDOW to BANKRUPT When a stream times out waiting for window credits, and all the other streams are broke, declare the whole connection bankrupt. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index b575b0f11..1568e76bc 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1360,11 +1360,12 @@ static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { struct h2_req *r2, *r22; - h2_error h2e = NULL, tmo; + h2_error h2e, tmo; vtim_real now; ASSERT_RXTHR(h2); + h2e = h2->error; now = VTIM_real(); if (h2e == NULL && h2->open_streams == 0 && h2->sess->t_idle + cache_param->timeout_idle < now) diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 0d6b3a6e7..316d13dc5 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -285,6 +285,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + if (r2->error == H2SE_BROKE_WINDOW && + h2->open_streams <= h2->winup_streams) + h2->error = r2->error = H2CE_BANKRUPT; + assert(h2->winup_streams > 0); h2->winup_streams--; diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index d2f5dcca8..1e5a7dc8a 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -6,7 +6,13 @@ server s1 { } -start varnish v1 -cliok "param.set feature +http2" -varnish v1 -vcl+backend "" -start +varnish v1 -vcl+backend { + sub vcl_recv { + if (req.url ~ "synth") { + return (synth(200)); + } + } +} -start # coverage for send_timeout with c1 @@ -66,6 +72,10 @@ client c2 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -75,6 +85,9 @@ client c2 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -run logexpect l2 -wait @@ -100,6 +113,10 @@ client c3 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -110,6 +127,9 @@ client c3 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -start barrier b3 sync diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 045ddaa59..564d78544 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -171,6 +171,14 @@ H2_ERROR( /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) + +H2_ERROR( + /* name */ BANKRUPT, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* reason */ SC_BANKRUPT, + /* descr */ "http/2 bankrupt connection" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:07 +0000 (UTC) Subject: [7.5] 05d91face http2: New send_goaway flag for errors Message-ID: <20240318182607.0564C103A84@lists.varnish-cache.org> commit 05d91face09ba76b5fc1cec9e13cbf2859cb7e3d Author: Dridi Boukelmoune Date: Thu Nov 16 17:27:11 2023 +0100 http2: New send_goaway flag for errors diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 95550c080..126a70d3a 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -44,16 +44,18 @@ struct h2_error_s { uint32_t val; int stream; int connection; + int send_goaway; stream_close_t reason; }; typedef const struct h2_error_s *h2_error; #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) extern const struct h2_error_s H2CE_##U[1]; -#define H2EC2(U,v,r,d) extern const struct h2_error_s H2SE_##U[1]; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) extern const struct h2_error_s H2CE_##U[1]; +#define H2EC2(U,v,g,r,d) extern const struct h2_error_s H2SE_##U[1]; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 1568e76bc..b9d03d47c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -47,10 +47,13 @@ #include "vtim.h" #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,r}}; -#define H2EC2(U,v,r,d) const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,r}}; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) \ + const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,g,r}}; +#define H2EC2(U,v,g,r,d) \ + const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,g,r}}; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -62,6 +65,7 @@ static const struct h2_error_s H2NN_ERROR[1] = {{ 0xffffffff, 1, 1, + 0, SC_RX_JUNK }}; @@ -89,10 +93,11 @@ h2_framename(enum h2frame h2f) */ static const h2_error stream_errors[] = { -#define H2EC1(U,v,r,d) -#define H2EC2(U,v,r,d) [v] = H2SE_##U, -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) +#define H2EC2(U,v,g,r,d) [v] = H2SE_##U, +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -114,10 +119,11 @@ h2_streamerror(uint32_t u) */ static const h2_error conn_errors[] = { -#define H2EC1(U,v,r,d) [v] = H2CE_##U, -#define H2EC2(U,v,r,d) -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) [v] = H2CE_##U, +#define H2EC2(U,v,g,r,d) +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -1320,6 +1326,10 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) if (isnan(now)) AN(r2->t_winupd); + if (h2->error != NULL && h2->error->connection && + !h2->error->send_goaway) + return (h2->error); + if (r2->t_winupd == 0 && r2->t_send == 0) return (NULL); diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index 0361b9e1a..93c7d6508 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -52,7 +52,7 @@ #define BUF_SIZE (1024*2048) static const char *const h2_errs[] = { -#define H2_ERROR(n,v,sc,r,t) [v] = #n, +#define H2_ERROR(n,v,sc,g,r,t) [v] = #n, #include NULL }; @@ -1260,7 +1260,7 @@ cmd_var_resolve(const struct stream *s, const char *spec, char *buf) else return (NULL); } -#define H2_ERROR(U,v,sc,r,t) \ +#define H2_ERROR(U,v,sc,g,r,t) \ if (!strcmp(spec, #U)) { return (#v); } #include "tbl/h2_error.h" return (spec); diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 564d78544..f4dc5ca2c 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -39,6 +39,7 @@ H2_ERROR( /* name */ NO_ERROR, /* val */ 0, /* types */ 3, + /* goaway */ 1, /* reason */ SC_REM_CLOSE, /* descr */ "Graceful shutdown" ) @@ -47,6 +48,7 @@ H2_ERROR( /* name */ PROTOCOL_ERROR, /* val */ 1, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Protocol error detected" ) @@ -55,6 +57,7 @@ H2_ERROR( /* name */ INTERNAL_ERROR, /* val */ 2, /* types */ 3, + /* goaway */ 1, /* reason */ SC_VCL_FAILURE, /* descr */ "Implementation fault" ) @@ -63,6 +66,7 @@ H2_ERROR( /* name */ FLOW_CONTROL_ERROR, /* val */ 3, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Flow-control limits exceeded" ) @@ -71,6 +75,7 @@ H2_ERROR( /* name */ SETTINGS_TIMEOUT, /* val */ 4, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_TIMEOUT, /* descr */ "Settings not acknowledged" ) @@ -79,6 +84,7 @@ H2_ERROR( /* name */ STREAM_CLOSED, /* val */ 5, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Frame received for closed stream" ) @@ -87,6 +93,7 @@ H2_ERROR( /* name */ FRAME_SIZE_ERROR, /* val */ 6, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Frame size incorrect" ) @@ -95,6 +102,7 @@ H2_ERROR( /* name */ REFUSED_STREAM, /* val */ 7, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream not processed" ) @@ -103,6 +111,7 @@ H2_ERROR( /* name */ CANCEL, /* val */ 8, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream cancelled" ) @@ -111,6 +120,7 @@ H2_ERROR( /* name */ COMPRESSION_ERROR, /* val */ 9, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Compression state not updated" ) @@ -119,6 +129,7 @@ H2_ERROR( /* name */ CONNECT_ERROR, /* val */ 10, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "TCP connection error for CONNECT method" ) @@ -127,6 +138,7 @@ H2_ERROR( /* name */ ENHANCE_YOUR_CALM, /* val */ 11, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Processing capacity exceeded" ) @@ -135,6 +147,7 @@ H2_ERROR( /* name */ INADEQUATE_SECURITY, /* val */ 12, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Negotiated TLS parameters not acceptable" ) @@ -143,31 +156,35 @@ H2_ERROR( /* name */ HTTP_1_1_REQUIRED, /* val */ 13, /* types */ 1, + /* goaway */ 1, /* reason */ SC_REQ_HTTP20, /* descr */ "Use HTTP/1.1 for the request" ) #ifdef H2_CUSTOM_ERRORS H2_ERROR( - /* name */ RAPID_RESET, - /* val */ 11, /* ENHANCE_YOUR_CALM */ - /* types */ 1, - /* reason */ SC_RAPID_RESET, - /* descr */ "http/2 rapid reset detected" + /* name */ RAPID_RESET, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* goaway */ 1, + /* reason */ SC_RAPID_RESET, + /* descr */ "http/2 rapid reset detected" ) H2_ERROR( - /* name */ MISSING_SCHEME, - /* val */ 1, /* PROTOCOL_ERROR */ - /* types */ 2, - /* reason */ SC_NULL, - /* descr */ "Missing :scheme pseudo-header" + /* name */ MISSING_SCHEME, + /* val */ 1, /* PROTOCOL_ERROR */ + /* types */ 2, + /* goaway */ 1, + /* reason */ SC_NULL, + /* descr */ "Missing :scheme pseudo-header" ) H2_ERROR( /* name */ BROKE_WINDOW, /* val */ 8, /* CANCEL */ /* types */ 2, + /* goaway */ 0, /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) @@ -176,6 +193,7 @@ H2_ERROR( /* name */ BANKRUPT, /* val */ 11, /* ENHANCE_YOUR_CALM */ /* types */ 1, + /* goaway */ 0, /* reason */ SC_BANKRUPT, /* descr */ "http/2 bankrupt connection" ) From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:07 +0000 (UTC) Subject: [7.5] 9aa45a9f2 http2_proto: Send GOAWAY before leaving the rx loop Message-ID: <20240318182607.21CD3103AA0@lists.varnish-cache.org> commit 9aa45a9f290b3e43c3939622c55017075862965f Author: Dridi Boukelmoune Date: Thu Nov 16 17:30:17 2023 +0100 http2_proto: Send GOAWAY before leaving the rx loop diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index b9d03d47c..1ae72410c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -412,7 +412,7 @@ h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) ASSERT_RXTHR(h2); AN(h2e); - if (h2->goaway) + if (h2->goaway || !h2e->send_goaway) return; h2->goaway = 1; @@ -1469,6 +1469,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) if (h2e != NULL && h2e->connection) { h2->error = h2e; + h2_tx_goaway(wrk, h2, h2e); return (0); } diff --git a/bin/varnishtest/tests/t02003.vtc b/bin/varnishtest/tests/t02003.vtc index 1d62ac986..fe30e8243 100644 --- a/bin/varnishtest/tests/t02003.vtc +++ b/bin/varnishtest/tests/t02003.vtc @@ -233,17 +233,28 @@ client c1 { } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 3 + } -start stream 1 { - txreq -nohdrend + txreq -nostrend txrst -err 2 } -run stream 3 { - txreq -nohdrend + txreq -nostrend txrst -err 0x666 } -run + stream 0 -wait } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq rxresp @@ -252,6 +263,7 @@ client c1 { # RST_STREAM on closed stream txrst } -run + stream 0 -wait } -run diff --git a/bin/varnishtest/tests/t02005.vtc b/bin/varnishtest/tests/t02005.vtc index 616e4c039..c5176f725 100644 --- a/bin/varnishtest/tests/t02005.vtc +++ b/bin/varnishtest/tests/t02005.vtc @@ -32,7 +32,7 @@ varnish v1 -cliok "param.set debug +syncvsl" logexpect l1 -v v1 -g raw { expect * 1001 ReqAcct "80 7 87 78 8 86" - expect * 1000 ReqAcct "45 8 53 54 20 74" + expect * 1000 ReqAcct "45 8 53 63 28 91" } -start client c1 { diff --git a/bin/varnishtest/tests/t02025.vtc b/bin/varnishtest/tests/t02025.vtc index 4b83fe95b..39f987a06 100644 --- a/bin/varnishtest/tests/t02025.vtc +++ b/bin/varnishtest/tests/t02025.vtc @@ -25,12 +25,17 @@ logexpect l1 -v v1 -g raw -i Debug { } -start client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq barrier b1 sync txrst } -run - expect_close + stream 0 -wait } -start logexpect l1 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:07 +0000 (UTC) Subject: [7.5] 9f6a7e3f9 http2_proto: Simplify CONTINUATION expectation check Message-ID: <20240318182607.39E0B103AB5@lists.varnish-cache.org> commit 9f6a7e3f90c50565ff2184592a66d1c0e711502c Author: Dridi Boukelmoune Date: Mon Sep 11 17:52:00 2023 +0200 http2_proto: Simplify CONTINUATION expectation check Before the h2 frame dispatch we only need to check that coming from a HEADERS frame the very next frame is a CONTINUATION, when the HPACK block didn't fit in the former. The CONTINUATION dispatch will then make the stream consistency check. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 1ae72410c..d9210ff3c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1295,8 +1295,7 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) if (r2->stream == h2->rxf_stream) break; - if (h2->new_req != NULL && - !(r2 && h2->new_req == r2->req && h2f == H2_F_CONTINUATION)) + if (h2->new_req != NULL && h2f != H2_F_CONTINUATION) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:07 +0000 (UTC) Subject: [7.5] 88f7f790d whats-new: Mention CVE-2023-43622 Message-ID: <20240318182607.52C38103ACA@lists.varnish-cache.org> commit 88f7f790d79941fb7592efd9b34068d1c7e0b7c2 Author: Dridi Boukelmoune Date: Fri Mar 15 16:03:13 2024 +0100 whats-new: Mention CVE-2023-43622 diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index 4bef696c0..1ed15bf75 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -27,6 +27,16 @@ longer open (stream reset, client disconnected etc). .. _VSV 13: https://varnish-cache.org/security/VSV00013.html +CVE-2023-43622 +~~~~~~~~~~~~~~ + +Another denial of service attack vector received a CVE number in the aftermath +of the Rapid Reset debacle. `VSV 14`_ is called the HTTP/2 Broke Window attack +and can be summarized as the ability for clients to hold a server still by not +crediting the control flow window of HTTP/2 streams. + +.. _VSV 14: https://varnish-cache.org/security/VSV00014.html + varnishd ======== @@ -66,6 +76,11 @@ The following parameters address the HTTP/2 Rapid Reset attach: - ``h2_rapid_reset_limit`` (maximum number of rapid resets per period) - ``h2_rapid_reset_period`` (the sliding period to track rapid resets) +The new ``h2_window_timeout`` parameter defines how long an HTTP/2 stream can +stall its delivery waiting for a control flow window update. A stream without +any credits is considered broke, and if all streams are broke when the new +timeout triggers the entire connection is considered bankrupt. + A new bit flag ``vcl_req_reset`` for the ``feature`` parameter interrupts client request tasks during VCL transitions when an HTTP/2 stream is no longer open. The result is equivalent to a ``return (fail);`` statement and can save @@ -247,9 +262,12 @@ A new ``MAIN.sc_rapid_reset`` counter counts the number of HTTP/2 connections closed because the number of rapid resets exceed the limit over the configured period. -Its ``MAIN.req_reset`` counterpart counts the number of time a client task was -prematurely failed because the HTTP/2 stream it was processing was no longer -open and the feature flag ``vcl_req_reset`` was raised. +Likewise, ``MAIN.sc_bankrupt`` counts the number of HTTP/2 connections closed +because all streams ran out of credits and ``h2_window_timeout`` triggered. + +Their ``MAIN.req_reset`` counterpart counts the number of time a client task +was prematurely failed because the HTTP/2 stream it was processing was no +longer open and the feature flag ``vcl_req_reset`` was raised. A new counter ``MAIN.n_superseded`` adds visibility on how many objects are inserted as the replacement of another object in the cache. This can give From simon.stridsberg at varnish-software.com Mon Mar 18 18:26:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:26:07 +0000 (UTC) Subject: [7.5] eef25264e Prepare for 7.5.0 Message-ID: <20240318182607.75CC7103AEC@lists.varnish-cache.org> commit eef25264e5ca5f96a77129308edb83ccf84cb1b1 Author: Simon Stridsberg Date: Mon Mar 18 14:45:32 2024 +0100 Prepare for 7.5.0 diff --git a/bin/varnishtest/tests/m00003.vtc b/bin/varnishtest/tests/m00003.vtc index 1b6a90faa..7130e90bb 100644 --- a/bin/varnishtest/tests/m00003.vtc +++ b/bin/varnishtest/tests/m00003.vtc @@ -96,7 +96,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so "\x03" varnish v1 -errvcl {VMOD wants ABI version 1.0} { import wrong; } ############################################################# -# NB: in the tests below "18" should track VRT_MAJOR_VERSION +# NB: in the tests below "19" should track VRT_MAJOR_VERSION filewrite ${tmpdir}/libvmod_wrong.so "VMOD_JSON_SPEC\x02" filewrite -a ${tmpdir}/libvmod_wrong.so { @@ -108,7 +108,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ "$FOOBAR" @@ -128,7 +128,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ] ] @@ -146,7 +146,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ "$CPROTO" @@ -168,7 +168,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_std_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ "$CPROTO", "/* blabla */" diff --git a/bin/varnishtest/tests/m00055.vtc b/bin/varnishtest/tests/m00055.vtc index f79182b8a..7d8f9afa9 100644 --- a/bin/varnishtest/tests/m00055.vtc +++ b/bin/varnishtest/tests/m00055.vtc @@ -21,7 +21,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ diff --git a/configure.ac b/configure.ac index adb25c713..f9e9666e6 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ AC_PREREQ([2.69]) AC_COPYRIGHT([Copyright (c) 2006 Verdens Gang AS -Copyright (c) 2006-2023 Varnish Software -Copyright 2010-2023 UPLEX - Nils Goroll Systemoptimierung]) +Copyright (c) 2006-2024 Varnish Software +Copyright 2010-2024 UPLEX - Nils Goroll Systemoptimierung]) AC_REVISION([$Id$]) -AC_INIT([Varnish],[trunk],[varnish-dev at varnish-cache.org]) +AC_INIT([Varnish],[7.5.0],[varnish-dev at varnish-cache.org]) AC_CONFIG_SRCDIR(include/miniobj.h) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/changes.rst b/doc/changes.rst index 3aa1b6d36..aeda844ff 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -34,13 +34,15 @@ http://varnish-cache.org/docs/trunk/whats-new/index.html and via individual releases. These documents are updated as part of the release process. -=============================== -Varnish Cache NEXT (2024-03-15) -=============================== +================================ +Varnish Cache 7.5.0 (2024-03-18) +================================ .. PLEASE keep this roughly in commit order as shown by git-log / tig (new to old) +* Add ``h2_window_timeout`` paramater to mitigate CVE-2023-43622 (VSV00014_). + * The parameters ``idle_send_timeout`` and ``timeout_idle`` are now limited to a maximum of 1 hour. @@ -280,6 +282,7 @@ Varnish Cache NEXT (2024-03-15) .. _3997: https://github.com/varnishcache/varnish-cache/pull/3997 .. _3998: https://github.com/varnishcache/varnish-cache/pull/3998 .. _3999: https://github.com/varnishcache/varnish-cache/pull/3999 +.. _VSV00014: https://varnish-cache.org/security/VSV00014.html ================================ Varnish Cache 7.4.0 (2023-09-15) diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 537c22209..489910406 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -40,9 +40,9 @@ Conventions used in this manual include: Longer listings like example command output and VCL look like this:: $ /opt/varnish/sbin/varnishd -V - varnishd (varnish-trunk revision 1234567) + varnishd (varnish-7.5.0 revision 1234567) Copyright (c) 2006 Verdens Gang AS - Copyright (c) 2006-2023 Varnish Software + Copyright (c) 2006-2024 Varnish Software .. For maintainers: diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-7.5.rst similarity index 99% rename from doc/sphinx/whats-new/changes-trunk.rst rename to doc/sphinx/whats-new/changes-7.5.rst index 1ed15bf75..3a36a1120 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-7.5.rst @@ -1,11 +1,11 @@ -.. _whatsnew_changes_CURRENT: +.. _whatsnew_changes_7.5: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Changes in Varnish **${NEXT_RELEASE}** +Changes in Varnish **7.5** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% For information about updating your current Varnish deployment to the -new version, see :ref:`whatsnew_upgrading_CURRENT`. +new version, see :ref:`whatsnew_upgrading_7.5`. A more detailed and technical account of changes in Varnish, with links to issues that have been fixed and pull requests that have been diff --git a/doc/sphinx/whats-new/index.rst b/doc/sphinx/whats-new/index.rst index 8b4225c98..51a6b97bd 100644 --- a/doc/sphinx/whats-new/index.rst +++ b/doc/sphinx/whats-new/index.rst @@ -13,7 +13,7 @@ This section describes the changes and improvements between different versions of Varnish, and what upgrading between the different versions entail. -Varnish **$NEXT_RELEASE** +Varnish **7.5** ------------------------- **Note: These are working documents for a future release, with running @@ -23,8 +23,8 @@ released versions of Varnish, see the chapters listed below.** .. toctree:: :maxdepth: 2 - changes-trunk - upgrading-trunk + changes-7.5 + upgrading-7.5 Varnish 7.4 ----------- diff --git a/doc/sphinx/whats-new/upgrading-trunk.rst b/doc/sphinx/whats-new/upgrading-7.5.rst similarity index 97% rename from doc/sphinx/whats-new/upgrading-trunk.rst rename to doc/sphinx/whats-new/upgrading-7.5.rst index cc0605775..ac068ec86 100644 --- a/doc/sphinx/whats-new/upgrading-trunk.rst +++ b/doc/sphinx/whats-new/upgrading-7.5.rst @@ -1,7 +1,7 @@ -.. _whatsnew_upgrading_CURRENT: +.. _whatsnew_upgrading_7.5: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Upgrading to Varnish **$NEXT_RELEASE** +Upgrading to Varnish **7.5** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Logs diff --git a/include/vrt.h b/include/vrt.h index 5599ac7c9..0f1df8984 100644 --- a/include/vrt.h +++ b/include/vrt.h @@ -46,9 +46,9 @@ # error "include vdef.h before vrt.h" #endif -#define VRT_MAJOR_VERSION 18U +#define VRT_MAJOR_VERSION 19U -#define VRT_MINOR_VERSION 1U +#define VRT_MINOR_VERSION 0U /*********************************************************************** * Major and minor VRT API versions. @@ -57,7 +57,7 @@ * Whenever something is deleted or changed in a way which is not * binary/load-time compatible, increment MAJOR version * - * NEXT (2024-03-15) + * 19.0 (2024-03-18) * [cache.h] (struct req).filter_list renamed to vdp_filter_list * order of vcl/vmod and director COLD events reversed to directors first * VRT_u_sess_idle_send_timeout() added diff --git a/lib/libvarnish/version.c b/lib/libvarnish/version.c index 0d09ab748..4f5983c0d 100644 --- a/lib/libvarnish/version.c +++ b/lib/libvarnish/version.c @@ -76,8 +76,8 @@ VCS_String(const char *which) ")" "\n" "Copyright (c) 2006 Verdens Gang AS\n" - "Copyright (c) 2006-2023 Varnish Software\n" - "Copyright 2010-2023 UPLEX - Nils Goroll Systemoptimierung\n" + "Copyright (c) 2006-2024 Varnish Software\n" + "Copyright 2010-2024 UPLEX - Nils Goroll Systemoptimierung\n" ); default: WRONG("Wrong argument to VCS_String"); From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 7fb01bdfb http2_proto: Proper null checks for h2 errors Message-ID: <20240318183206.0CC0C106DD6@lists.varnish-cache.org> commit 7fb01bdfbed10f4b8a1042d9578228385000d9cf Author: Dridi Boukelmoune Date: Mon Oct 23 11:34:31 2023 +0200 http2_proto: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 52a1c2121..58e67ecef 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -837,11 +837,11 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) Lck_Lock(&h2->sess->mtx); CHECK_OBJ_ORNULL(r2->rxbuf, H2_RXBUF_MAGIC); - if (h2->error || r2->error) { + if (h2->error != NULL || r2->error != NULL) { if (r2->cond) PTOK(pthread_cond_signal(r2->cond)); Lck_Unlock(&h2->sess->mtx); - return (h2->error ? h2->error : r2->error); + return (h2->error != NULL ? h2->error : r2->error); } /* Check padding if present */ @@ -1078,7 +1078,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp) } else l = 0; - if (h2->error || r2->error) + if (h2->error != NULL || r2->error != NULL) retval = VFP_ERROR; else if (r2->state >= H2_S_CLOS_REM && l <= *lp) retval = VFP_END; @@ -1274,15 +1274,15 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); - if (h2e == 0) - return (0); + if (h2e == NULL) + return (NULL); if (h2->rxf_stream == 0 || h2e->connection) return (h2e); // Connection errors one level up H2_Send_Get(wrk, h2, h2->req0); H2_Send_RST(wrk, h2, h2->req0, h2->rxf_stream, h2e); H2_Send_Rel(h2, h2->req0); - return (0); + return (NULL); } int @@ -1489,7 +1489,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) } h2e = h2_procframe(wrk, h2, h2f); - if (h2->error == 0 && h2e) { + if (h2->error == NULL && h2e != NULL) { h2->error = h2e; vbe32enc(b, h2->highest_stream); vbe32enc(b + 4, h2e->val); @@ -1497,5 +1497,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); H2_Send_Rel(h2, h2->req0); } - return (h2->error ? 0 : 1); + + return (h2->error != NULL ? 0 : 1); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] ec95d0499 http2_send: Proper null checks for h2 errors Message-ID: <20240318183206.273CF106DDB@lists.varnish-cache.org> commit ec95d0499777830425c890221e86ee216ea27024 Author: Dridi Boukelmoune Date: Mon Oct 23 11:36:57 2023 +0200 http2_send: Proper null checks for h2 errors diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index be3d6fd67..ac07d542c 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -239,11 +239,11 @@ h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - if (r2->error) + if (r2->error != NULL) return (r2->error); - if (h2->error && r2->stream > h2->goaway_last_stream) + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) return (h2->error); - return (0); + return (NULL); } static int64_t @@ -263,15 +263,17 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, if (r2->t_window <= 0 || h2->req0->t_window <= 0) { r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); - while (r2->t_window <= 0 && h2_errcheck(r2, h2) == 0) { + + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); r2->cond = NULL; } - while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == 0) + + while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == NULL) (void)h2_cond_wait(h2->winupd_cond, h2, r2); - if (h2_errcheck(r2, h2) == 0) { + if (h2_errcheck(r2, h2) == NULL) { w = vmin_t(int64_t, h2_win_limit(r2, h2), wanted); h2_win_charge(r2, h2, w); assert (w > 0); @@ -279,7 +281,7 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_send_get_locked(wrk, h2, r2); } - if (w == 0 && h2_errcheck(r2, h2) == 0) { + if (w == 0 && h2_errcheck(r2, h2) == NULL) { assert(r2->t_window > 0); assert(h2->req0->t_window > 0); w = h2_win_limit(r2, h2); @@ -316,7 +318,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, AN(H2_SEND_HELD(h2, r2)); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(ftyp); @@ -341,7 +343,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } else @@ -362,7 +364,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, if (ftyp->respect_window && p != ptr) { tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len); - if (h2_errcheck(r2, h2)) + if (h2_errcheck(r2, h2) != NULL) return; AN(H2_SEND_HELD(h2, r2)); } @@ -383,7 +385,7 @@ h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, ftyp = ftyp->continuation; flags &= ftyp->flags; final_flags &= ftyp->flags; - } while (!h2->error && len > 0); + } while (h2->error == NULL && len > 0); } } @@ -396,6 +398,7 @@ H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2, CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); AN(H2_SEND_HELD(h2, r2)); + AN(h2e); Lck_Lock(&h2->sess->mtx); VSLb(h2->vsl, SLT_Debug, "H2: stream %u: %s", stream, h2e->txt); From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 884f8b316 http2_proto: Make h2_stream_tmo() return an error Message-ID: <20240318183206.4275E106DE5@lists.varnish-cache.org> commit 884f8b3164a8b598cb7960f8379f5504c70b6c62 Author: Dridi Boukelmoune Date: Thu Nov 16 13:16:15 2023 +0100 http2_proto: Make h2_stream_tmo() return an error diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index f73b5657e..0ca9eeb78 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -255,7 +255,7 @@ void H2_Send(struct worker *, struct h2_req *, h2_frame type, uint8_t flags, /* cache_http2_proto.c */ struct h2_req * h2_new_req(struct h2_sess *, unsigned stream, struct req *); -int h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); +h2_error h2_stream_tmo(struct h2_sess *, const struct h2_req *, vtim_real); void h2_del_req(struct worker *, struct h2_req *); void h2_kill_req(struct worker *, struct h2_sess *, struct h2_req *, h2_error); int h2_rxframe(struct worker *, struct h2_sess *); diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 58e67ecef..454a78cbe 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1285,10 +1285,10 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) return (NULL); } -int +h2_error h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) { - int r = 0; + h2_error h2e = NULL; CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); @@ -1301,36 +1301,36 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) AN(r2->t_winupd); if (r2->t_winupd == 0 && r2->t_send == 0) - return (0); + return (NULL); if (isnan(now) || (r2->t_winupd != 0 && now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - if (r == 0 && r2->t_send != 0 && + if (h2e == NULL && r2->t_send != 0 && now - r2->t_send > SESS_TMO(h2->sess, send_timeout)) { VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit send_timeout", r2->stream); - r = 1; + h2e = H2SE_CANCEL; } - return (r); + return (h2e); } -static int +static h2_error h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) { - int r; + h2_error h2e; Lck_Lock(&h2->sess->mtx); - r = h2_stream_tmo(h2, r2, h2->sess->t_idle); + h2e = h2_stream_tmo(h2, r2, h2->sess->t_idle); Lck_Unlock(&h2->sess->mtx); - return (r); + return (h2e); } /* From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 7ce5f508f http2_send: Collect the timeout error Message-ID: <20240318183206.5DE61106DEA@lists.varnish-cache.org> commit 7ce5f508f55706709c7e42531d001d6e554c5f42 Author: Dridi Boukelmoune Date: Thu Nov 16 13:23:18 2023 +0100 http2_send: Collect the timeout error diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ac07d542c..ac634e9ec 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -48,6 +48,7 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { vtim_dur tmo = 0.; vtim_real now; + h2_error h2e; int r; AN(cond); @@ -72,18 +73,16 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) * that the stream reached the idle_send_timeout via the lock and * force it to log it. */ - if (h2_stream_tmo(h2, r2, now)) - r = ETIMEDOUT; - else if (r == ETIMEDOUT) - AN(h2_stream_tmo(h2, r2, NAN)); - - if (r == ETIMEDOUT) { - if (r2->error == NULL) - r2->error = H2SE_CANCEL; - return (-1); + h2e = h2_stream_tmo(h2, r2, now); + if (h2e == NULL && r == ETIMEDOUT) { + h2e = h2_stream_tmo(h2, r2, NAN); + AN(h2e); } - return (0); + if (r2->error == NULL) + r2->error = h2e; + + return (h2e != NULL ? -1 : 0); } static void From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 64f609dbd h2: Send GOAWAY frames in a dedicated function Message-ID: <20240318183206.79675106DF4@lists.varnish-cache.org> commit 64f609dbdaeb4d9f574424a374100b06f8f40398 Author: Dridi Boukelmoune Date: Tue Jan 18 10:08:33 2022 +0100 h2: Send GOAWAY frames in a dedicated function And after issuing or receiving a goaway, stop processing frames when there are no streams left. Initially submitted as part of listen sockets management. Refs #3959 diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 0ca9eeb78..11e957d49 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -165,6 +165,7 @@ struct h2_sess { int refcnt; unsigned open_streams; uint32_t highest_stream; + int goaway; int bogosity; int do_sweep; diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 454a78cbe..eaa6b1b7a 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -389,6 +389,7 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); assert(r2 == h2->req0); + h2->goaway = 1; h2->goaway_last_stream = vbe32dec(h2->rxf_data); h2->error = h2_connectionerror(vbe32dec(h2->rxf_data + 4)); Lck_Lock(&h2->sess->mtx); @@ -397,6 +398,25 @@ h2_rx_goaway(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) return (h2->error); } +static void +h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) +{ + char b[8]; + + ASSERT_RXTHR(h2); + AN(h2e); + + if (h2->goaway) + return; + + h2->goaway = 1; + vbe32enc(b, h2->highest_stream); + vbe32enc(b + 4, h2e->val); + H2_Send_Get(wrk, h2, h2->req0); + H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); + H2_Send_Rel(h2, h2->req0); +} + /********************************************************************** */ @@ -1411,9 +1431,12 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2_frame h2f; h2_error h2e; const char *s = NULL; - char b[8]; ASSERT_RXTHR(h2); + + if (h2->goaway && h2->open_streams == 0) + return (0); + VTCP_blocking(*h2->htc->rfd); h2->sess->t_idle = VTIM_real(); hs = HTC_RxStuff(h2->htc, h2_frame_complete, @@ -1491,11 +1514,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) h2e = h2_procframe(wrk, h2, h2f); if (h2->error == NULL && h2e != NULL) { h2->error = h2e; - vbe32enc(b, h2->highest_stream); - vbe32enc(b + 4, h2e->val); - H2_Send_Get(wrk, h2, h2->req0); - H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b); - H2_Send_Rel(h2, h2->req0); + h2_tx_goaway(wrk, h2, h2e); } return (h2->error != NULL ? 0 : 1); From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 41ef373af http2_proto: Enforce session timeouts in h2_sweep() Message-ID: <20240318183206.9617F106E00@lists.varnish-cache.org> commit 41ef373af53571a94ea8f73f0538322270799a84 Author: Dridi Boukelmoune Date: Thu Nov 16 14:52:49 2023 +0100 http2_proto: Enforce session timeouts in h2_sweep() The new meaning for h2->sess->t_idle is now the time since the last complete frame, except before the first frame where it corresponds to the creation of the session. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index eaa6b1b7a..364f2bf38 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1357,14 +1357,20 @@ h2_stream_tmo_unlocked(struct h2_sess *h2, const struct h2_req *r2) * This is the janitorial task of cleaning up any closed & refused * streams, and checking if the session is timed out. */ -static int +static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { - int tmo = 0; struct h2_req *r2, *r22; + h2_error h2e = NULL, tmo; + vtim_real now; ASSERT_RXTHR(h2); + now = VTIM_real(); + if (h2e == NULL && h2->open_streams == 0 && + h2->sess->t_idle + cache_param->timeout_idle < now) + h2e = H2CE_NO_ERROR; + h2->do_sweep = 0; VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) { if (r2 == h2->req0) { @@ -1388,10 +1394,9 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) /* FALLTHROUGH */ case H2_S_CLOS_LOC: case H2_S_OPEN: - if (h2_stream_tmo_unlocked(h2, r2)) { - tmo = 1; - continue; - } + tmo = h2_stream_tmo_unlocked(h2, r2); + if (h2e == NULL) + h2e = tmo; break; case H2_S_IDLE: /* Current code make this unreachable: h2_new_req is @@ -1403,9 +1408,7 @@ h2_sweep(struct worker *wrk, struct h2_sess *h2) break; } } - if (tmo) - return (0); - return (h2->refcnt > 1); + return (h2e); } @@ -1430,7 +1433,6 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) enum htc_status_e hs; h2_frame h2f; h2_error h2e; - const char *s = NULL; ASSERT_RXTHR(h2); @@ -1438,36 +1440,30 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) return (0); VTCP_blocking(*h2->htc->rfd); - h2->sess->t_idle = VTIM_real(); - hs = HTC_RxStuff(h2->htc, h2_frame_complete, - NULL, NULL, NAN, - h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle), - NAN, h2->local_settings.max_frame_size + 9); + hs = HTC_RxStuff(h2->htc, h2_frame_complete, NULL, NULL, NAN, + VTIM_real() + 0.5, NAN, h2->local_settings.max_frame_size + 9); + + h2e = NULL; switch (hs) { case HTC_S_COMPLETE: + h2->sess->t_idle = VTIM_real(); + if (h2->do_sweep) + h2e = h2_sweep(wrk, h2); break; case HTC_S_TIMEOUT: - if (h2_sweep(wrk, h2)) - return (1); - - /* FALLTHROUGH */ + h2e = h2_sweep(wrk, h2); + break; default: - /* XXX: HTC_S_OVERFLOW / FRAME_SIZE_ERROR handling */ -#define HTC_STATUS(e, n, d, l) \ - do { \ - if (hs == HTC_S_ ## e) \ - s = #e; \ - } while (0); -#include "tbl/htc.h" - Lck_Lock(&h2->sess->mtx); - VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%s)", s); - h2->error = H2CE_NO_ERROR; - Lck_Unlock(&h2->sess->mtx); + h2e = H2CE_ENHANCE_YOUR_CALM; + } + + if (h2e != NULL && h2e->connection) { + h2->error = h2e; return (0); } - if (h2->do_sweep) - (void)h2_sweep(wrk, h2); + if (hs != HTC_S_COMPLETE) + return (1); h2->rxf_len = vbe32dec(h2->htc->rxbuf_b) >> 8; h2->rxf_type = h2->htc->rxbuf_b[3]; From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 4938f05b3 http2_proto: Introduce a custom BROKE_WINDOW error Message-ID: <20240318183206.B2633106E0B@lists.varnish-cache.org> commit 4938f05b318eb2daa2ccc89dafeed3126552c481 Author: Dridi Boukelmoune Date: Thu Nov 16 16:03:42 2023 +0100 http2_proto: Introduce a custom BROKE_WINDOW error diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 364f2bf38..a00112c5f 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1328,7 +1328,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) VSLb(h2->vsl, SLT_Debug, "H2: stream %u: Hit idle_send_timeout waiting for" " WINDOW_UPDATE", r2->stream); - h2e = H2SE_CANCEL; + h2e = H2SE_BROKE_WINDOW; } if (h2e == NULL && r2->t_send != 0 && diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index ac634e9ec..a31d99248 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -412,12 +412,14 @@ H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags, uint32_t len, const void *ptr, uint64_t *counter) { uint64_t dummy_counter = 0; + h2_error h2e; if (counter == NULL) counter = &dummy_counter; h2_send(wrk, r2, ftyp, flags, len, ptr, counter); - if (h2_errcheck(r2, r2->h2sess) == H2SE_CANCEL) - H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, H2SE_CANCEL); + h2e = h2_errcheck(r2, r2->h2sess); + if (h2e != NULL && h2e->val == H2SE_CANCEL->val) + H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, h2e); } diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 345e1549b..045ddaa59 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -163,6 +163,14 @@ H2_ERROR( /* reason */ SC_NULL, /* descr */ "Missing :scheme pseudo-header" ) + +H2_ERROR( + /* name */ BROKE_WINDOW, + /* val */ 8, /* CANCEL */ + /* types */ 2, + /* reason */ SC_NULL, + /* descr */ "http/2 stream out of window credits" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 0b82e0070 param: New h2_window_timeout parameter Message-ID: <20240318183206.CBC2B106E1B@lists.varnish-cache.org> commit 0b82e00708b88f696af5881b7a19caf2144d13f7 Author: Dridi Boukelmoune Date: Mon Oct 23 11:49:23 2023 +0200 param: New h2_window_timeout parameter This parameter needs to be somewhat high because web browsers may for example only credit streams for image resources just enough to parse metadata like width and height of a picture in order to perform layout computations and fetch resources more sensitive to latency before the effective image payloads. diff --git a/include/tbl/params.h b/include/tbl/params.h index e96d75483..42d72947b 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -1205,6 +1205,20 @@ PARAM_SIMPLE( /* flags */ WIZARD ) +PARAM_SIMPLE( + /* name */ h2_window_timeout, + /* type */ timeout, + /* min */ "0", + /* max */ NULL, + /* def */ "5", + /* units */ "seconds", + /* descr */ + "HTTP2 time limit without window credits. How long a stream may " + "wait for the client to credit the window and allow for more DATA " + "frames to be sent.", + /* flags */ WIZARD +) + PARAM_SIMPLE( /* name */ h2_header_table_size, /* type */ bytes_u, From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:06 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:06 +0000 (UTC) Subject: [master] 47e12f219 http2_send: Move h2_errcheck() at the top Message-ID: <20240318183206.E5BA0106E2F@lists.varnish-cache.org> commit 47e12f219108b011f41e4f6cd8c8c6262154045e Author: Dridi Boukelmoune Date: Mon Oct 23 16:40:26 2023 +0200 http2_send: Move h2_errcheck() at the top diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index a31d99248..de4f2850d 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -43,6 +43,19 @@ #define H2_SEND_HELD(h2, r2) (VTAILQ_FIRST(&(h2)->txqueue) == (r2)) +static h2_error +h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) +{ + CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); + CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); + + if (r2->error != NULL) + return (r2->error); + if (h2->error != NULL && r2->stream > h2->goaway_last_stream) + return (h2->error); + return (NULL); +} + static int h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) { @@ -232,19 +245,6 @@ h2_win_charge(struct h2_req *r2, const struct h2_sess *h2, uint32_t w) h2->req0->t_window -= w; } -static h2_error -h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2) -{ - CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); - CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); - - if (r2->error != NULL) - return (r2->error); - if (h2->error != NULL && r2->stream > h2->goaway_last_stream) - return (h2->error); - return (NULL); -} - static int64_t h2_do_window(struct worker *wrk, struct h2_req *r2, struct h2_sess *h2, int64_t wanted) From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:07 +0000 (UTC) Subject: [master] c0201724f http2_send: Apply h2_window_timeout Message-ID: <20240318183207.42AB1106E44@lists.varnish-cache.org> commit c0201724f0280894ec714fe76fc26ba9831f0551 Author: Dridi Boukelmoune Date: Mon Oct 23 13:15:45 2023 +0200 http2_send: Apply h2_window_timeout It replaces idle_send_timeout when the stream is waiting for window credits before sending more DATA frames. The idle_send_timeout will still apply to individual writes to the socket, but triggering it is considered a failure condition (this was already the case). The two loops are merged into a single one to better deal with the lack of ordering guarantees of request vs connection stream control flow window crediting. Refs #2980 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index a00112c5f..b575b0f11 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1314,7 +1314,7 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC); Lck_AssertHeld(&h2->sess->mtx); - /* NB: when now is NAN, it means that idle_send_timeout was hit + /* NB: when now is NAN, it means that h2_window_timeout was hit * on a lock condwait operation. */ if (isnan(now)) @@ -1324,10 +1324,9 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) return (NULL); if (isnan(now) || (r2->t_winupd != 0 && - now - r2->t_winupd > SESS_TMO(h2->sess, idle_send_timeout))) { + now - r2->t_winupd > cache_param->h2_window_timeout)) { VSLb(h2->vsl, SLT_Debug, - "H2: stream %u: Hit idle_send_timeout waiting for" - " WINDOW_UPDATE", r2->stream); + "H2: stream %u: Hit h2_window_timeout", r2->stream); h2e = H2SE_BROKE_WINDOW; } diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index de4f2850d..39ddcfafd 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -70,20 +70,20 @@ h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2) Lck_AssertHeld(&h2->sess->mtx); - if (cache_param->idle_send_timeout > 0.) - tmo = cache_param->idle_send_timeout; + if (cache_param->h2_window_timeout > 0.) + tmo = cache_param->h2_window_timeout; r = Lck_CondWaitTimeout(cond, &h2->sess->mtx, tmo); assert(r == 0 || r == ETIMEDOUT); now = VTIM_real(); - /* NB: when we grab idle_send_timeout before acquiring the session + /* NB: when we grab h2_window_timeout before acquiring the session * lock we may time out, but once we wake up both send_timeout and - * idle_send_timeout may have changed meanwhile. For this reason + * h2_window_timeout may have changed meanwhile. For this reason * h2_stream_tmo() may not log what timed out and we need to call * again with a magic NAN "now" that indicates to h2_stream_tmo() - * that the stream reached the idle_send_timeout via the lock and + * that the stream reached the h2_window_timeout via the lock and * force it to log it. */ h2e = h2_stream_tmo(h2, r2, now); @@ -208,6 +208,10 @@ H2_Send_Frame(struct worker *wrk, struct h2_sess *h2, iov[1].iov_len = len; s = writev(h2->sess->fd, iov, len == 0 ? 1 : 2); if (s != sizeof hdr + len) { + if (errno == EWOULDBLOCK) { + VSLb(h2->vsl, SLT_Debug, + "H2: stream %u: Hit idle_send_timeout", stream); + } /* * There is no point in being nice here, we will be unable * to send a GOAWAY once the code unrolls, so go directly diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index 29ffea354..d2f5dcca8 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -44,13 +44,13 @@ client c1 { logexpect l1 -wait -# coverage for idle_send_timeout with c2 +# coverage for h2_window_timeout with c2 -varnish v1 -cliok "param.set idle_send_timeout 1" +varnish v1 -cliok "param.set h2_window_timeout 1" varnish v1 -cliok "param.reset send_timeout" logexpect l2 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c2 { @@ -79,12 +79,12 @@ client c2 { logexpect l2 -wait -# coverage for idle_send_timeout change with c3 +# coverage for h2_window_timeout change with c3 barrier b3 cond 2 logexpect l3 -v v1 { - expect * * Debug "Hit idle_send_timeout" + expect * * Debug "Hit h2_window_timeout" } -start client c3 { @@ -113,7 +113,7 @@ client c3 { } -start barrier b3 sync -varnish v1 -cliok "param.reset idle_send_timeout" +varnish v1 -cliok "param.reset h2_window_timeout" client c3 -wait logexpect l3 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:07 +0000 (UTC) Subject: [master] 727a5f803 http2_send: Track bankrupt streams Message-ID: <20240318183207.6B811106E56@lists.varnish-cache.org> commit 727a5f80347545b6fc7a6aa48f9fb74e90528f0c Author: Dridi Boukelmoune Date: Mon Oct 23 17:15:20 2023 +0200 http2_send: Track bankrupt streams diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 11e957d49..95550c080 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -163,7 +163,8 @@ struct h2_sess { struct sess *sess; int refcnt; - unsigned open_streams; + int open_streams; + int winup_streams; uint32_t highest_stream; int goaway; int bogosity; diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 39ddcfafd..0d6b3a6e7 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -267,6 +267,9 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, r2->t_winupd = VTIM_real(); h2_send_rel_locked(h2, r2); + assert(h2->winup_streams >= 0); + h2->winup_streams++; + while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) { r2->cond = &wrk->cond; (void)h2_cond_wait(r2->cond, h2, r2); @@ -281,6 +284,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, h2_win_charge(r2, h2, w); assert (w > 0); } + + assert(h2->winup_streams > 0); + h2->winup_streams--; + h2_send_get_locked(wrk, h2, r2); } From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:07 +0000 (UTC) Subject: [master] 42a10e900 vsc: New MAIN.sc_bankrupt counter Message-ID: <20240318183207.AEF0A106E6B@lists.varnish-cache.org> commit 42a10e90015bd8a9cb1c7c2e0e313f8b5ae9ebe9 Author: Dridi Boukelmoune Date: Thu Nov 16 16:58:55 2023 +0100 vsc: New MAIN.sc_bankrupt counter diff --git a/include/tbl/sess_close.h b/include/tbl/sess_close.h index f15d34a64..1fc5b648e 100644 --- a/include/tbl/sess_close.h +++ b/include/tbl/sess_close.h @@ -51,6 +51,7 @@ SESS_CLOSE(RANGE_SHORT, range_short, 1, "Insufficient data for range") SESS_CLOSE(REQ_HTTP20, req_http20, 1, "HTTP2 not accepted") SESS_CLOSE(VCL_FAILURE, vcl_failure, 1, "VCL failure") SESS_CLOSE(RAPID_RESET, rapid_reset, 1, "HTTP2 rapid reset") +SESS_CLOSE(BANKRUPT, bankrupt, 1, "HTTP2 credit bankruptcy") #undef SESS_CLOSE /*lint -restore */ diff --git a/lib/libvsc/VSC_main.vsc b/lib/libvsc/VSC_main.vsc index 82542a4c5..f5ce2b62f 100644 --- a/lib/libvsc/VSC_main.vsc +++ b/lib/libvsc/VSC_main.vsc @@ -657,6 +657,14 @@ configured limits for the number of permitted rapid stream resets. +.. varnish_vsc:: sc_bankrupt + :level: diag + :oneliner: Session Err BANKRUPT + + Number of times we failed an http/2 session because all the streams + were waiting for their windows to be credited when h2_window_timeout + triggered. + .. varnish_vsc:: client_resp_500 :level: diag :group: wrk From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:07 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:07 +0000 (UTC) Subject: [master] eccb50837 http2_send: Promote global BROKE_WINDOW to BANKRUPT Message-ID: <20240318183207.E4FC1106E7D@lists.varnish-cache.org> commit eccb50837d61fcb5a6927eef94c570bd1d03c26d Author: Dridi Boukelmoune Date: Thu Nov 16 17:02:35 2023 +0100 http2_send: Promote global BROKE_WINDOW to BANKRUPT When a stream times out waiting for window credits, and all the other streams are broke, declare the whole connection bankrupt. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index b575b0f11..1568e76bc 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1360,11 +1360,12 @@ static h2_error h2_sweep(struct worker *wrk, struct h2_sess *h2) { struct h2_req *r2, *r22; - h2_error h2e = NULL, tmo; + h2_error h2e, tmo; vtim_real now; ASSERT_RXTHR(h2); + h2e = h2->error; now = VTIM_real(); if (h2e == NULL && h2->open_streams == 0 && h2->sess->t_idle + cache_param->timeout_idle < now) diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c index 0d6b3a6e7..316d13dc5 100644 --- a/bin/varnishd/http2/cache_http2_send.c +++ b/bin/varnishd/http2/cache_http2_send.c @@ -285,6 +285,10 @@ h2_do_window(struct worker *wrk, struct h2_req *r2, assert (w > 0); } + if (r2->error == H2SE_BROKE_WINDOW && + h2->open_streams <= h2->winup_streams) + h2->error = r2->error = H2CE_BANKRUPT; + assert(h2->winup_streams > 0); h2->winup_streams--; diff --git a/bin/varnishtest/tests/t02016.vtc b/bin/varnishtest/tests/t02016.vtc index d2f5dcca8..1e5a7dc8a 100644 --- a/bin/varnishtest/tests/t02016.vtc +++ b/bin/varnishtest/tests/t02016.vtc @@ -6,7 +6,13 @@ server s1 { } -start varnish v1 -cliok "param.set feature +http2" -varnish v1 -vcl+backend "" -start +varnish v1 -vcl+backend { + sub vcl_recv { + if (req.url ~ "synth") { + return (synth(200)); + } + } +} -start # coverage for send_timeout with c1 @@ -66,6 +72,10 @@ client c2 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -75,6 +85,9 @@ client c2 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -run logexpect l2 -wait @@ -100,6 +113,10 @@ client c3 { } -run stream 1 { + txreq -nostrend -url "/synth" + } -run + + stream 3 { txreq rxhdrs rxdata @@ -110,6 +127,9 @@ client c3 { expect rst.err == CANCEL } -run + stream 1 { + txdata + } -run } -start barrier b3 sync diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 045ddaa59..564d78544 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -171,6 +171,14 @@ H2_ERROR( /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) + +H2_ERROR( + /* name */ BANKRUPT, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* reason */ SC_BANKRUPT, + /* descr */ "http/2 bankrupt connection" +) # undef H2_CUSTOM_ERRORS #endif From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:08 +0000 (UTC) Subject: [master] 05d91face http2: New send_goaway flag for errors Message-ID: <20240318183208.20644106E95@lists.varnish-cache.org> commit 05d91face09ba76b5fc1cec9e13cbf2859cb7e3d Author: Dridi Boukelmoune Date: Thu Nov 16 17:27:11 2023 +0100 http2: New send_goaway flag for errors diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h index 95550c080..126a70d3a 100644 --- a/bin/varnishd/http2/cache_http2.h +++ b/bin/varnishd/http2/cache_http2.h @@ -44,16 +44,18 @@ struct h2_error_s { uint32_t val; int stream; int connection; + int send_goaway; stream_close_t reason; }; typedef const struct h2_error_s *h2_error; #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) extern const struct h2_error_s H2CE_##U[1]; -#define H2EC2(U,v,r,d) extern const struct h2_error_s H2SE_##U[1]; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) extern const struct h2_error_s H2CE_##U[1]; +#define H2EC2(U,v,g,r,d) extern const struct h2_error_s H2SE_##U[1]; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 1568e76bc..b9d03d47c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -47,10 +47,13 @@ #include "vtim.h" #define H2_CUSTOM_ERRORS -#define H2EC1(U,v,r,d) const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,r}}; -#define H2EC2(U,v,r,d) const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,r}}; -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) \ + const struct h2_error_s H2CE_##U[1] = {{#U,d,v,0,1,g,r}}; +#define H2EC2(U,v,g,r,d) \ + const struct h2_error_s H2SE_##U[1] = {{#U,d,v,1,0,g,r}}; +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -62,6 +65,7 @@ static const struct h2_error_s H2NN_ERROR[1] = {{ 0xffffffff, 1, 1, + 0, SC_RX_JUNK }}; @@ -89,10 +93,11 @@ h2_framename(enum h2frame h2f) */ static const h2_error stream_errors[] = { -#define H2EC1(U,v,r,d) -#define H2EC2(U,v,r,d) [v] = H2SE_##U, -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) +#define H2EC2(U,v,g,r,d) [v] = H2SE_##U, +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -114,10 +119,11 @@ h2_streamerror(uint32_t u) */ static const h2_error conn_errors[] = { -#define H2EC1(U,v,r,d) [v] = H2CE_##U, -#define H2EC2(U,v,r,d) -#define H2EC3(U,v,r,d) H2EC1(U,v,r,d) H2EC2(U,v,r,d) -#define H2_ERROR(NAME, val, sc, reason, desc) H2EC##sc(NAME, val, reason, desc) +#define H2EC1(U,v,g,r,d) [v] = H2CE_##U, +#define H2EC2(U,v,g,r,d) +#define H2EC3(U,v,g,r,d) H2EC1(U,v,g,r,d) H2EC2(U,v,g,r,d) +#define H2_ERROR(NAME, val, sc, goaway, reason, desc) \ + H2EC##sc(NAME, val, goaway, reason, desc) #include "tbl/h2_error.h" #undef H2EC1 #undef H2EC2 @@ -1320,6 +1326,10 @@ h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2, vtim_real now) if (isnan(now)) AN(r2->t_winupd); + if (h2->error != NULL && h2->error->connection && + !h2->error->send_goaway) + return (h2->error); + if (r2->t_winupd == 0 && r2->t_send == 0) return (NULL); diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c index 0361b9e1a..93c7d6508 100644 --- a/bin/varnishtest/vtc_http2.c +++ b/bin/varnishtest/vtc_http2.c @@ -52,7 +52,7 @@ #define BUF_SIZE (1024*2048) static const char *const h2_errs[] = { -#define H2_ERROR(n,v,sc,r,t) [v] = #n, +#define H2_ERROR(n,v,sc,g,r,t) [v] = #n, #include NULL }; @@ -1260,7 +1260,7 @@ cmd_var_resolve(const struct stream *s, const char *spec, char *buf) else return (NULL); } -#define H2_ERROR(U,v,sc,r,t) \ +#define H2_ERROR(U,v,sc,g,r,t) \ if (!strcmp(spec, #U)) { return (#v); } #include "tbl/h2_error.h" return (spec); diff --git a/include/tbl/h2_error.h b/include/tbl/h2_error.h index 564d78544..f4dc5ca2c 100644 --- a/include/tbl/h2_error.h +++ b/include/tbl/h2_error.h @@ -39,6 +39,7 @@ H2_ERROR( /* name */ NO_ERROR, /* val */ 0, /* types */ 3, + /* goaway */ 1, /* reason */ SC_REM_CLOSE, /* descr */ "Graceful shutdown" ) @@ -47,6 +48,7 @@ H2_ERROR( /* name */ PROTOCOL_ERROR, /* val */ 1, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Protocol error detected" ) @@ -55,6 +57,7 @@ H2_ERROR( /* name */ INTERNAL_ERROR, /* val */ 2, /* types */ 3, + /* goaway */ 1, /* reason */ SC_VCL_FAILURE, /* descr */ "Implementation fault" ) @@ -63,6 +66,7 @@ H2_ERROR( /* name */ FLOW_CONTROL_ERROR, /* val */ 3, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Flow-control limits exceeded" ) @@ -71,6 +75,7 @@ H2_ERROR( /* name */ SETTINGS_TIMEOUT, /* val */ 4, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_TIMEOUT, /* descr */ "Settings not acknowledged" ) @@ -79,6 +84,7 @@ H2_ERROR( /* name */ STREAM_CLOSED, /* val */ 5, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Frame received for closed stream" ) @@ -87,6 +93,7 @@ H2_ERROR( /* name */ FRAME_SIZE_ERROR, /* val */ 6, /* types */ 3, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Frame size incorrect" ) @@ -95,6 +102,7 @@ H2_ERROR( /* name */ REFUSED_STREAM, /* val */ 7, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream not processed" ) @@ -103,6 +111,7 @@ H2_ERROR( /* name */ CANCEL, /* val */ 8, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "Stream cancelled" ) @@ -111,6 +120,7 @@ H2_ERROR( /* name */ COMPRESSION_ERROR, /* val */ 9, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Compression state not updated" ) @@ -119,6 +129,7 @@ H2_ERROR( /* name */ CONNECT_ERROR, /* val */ 10, /* types */ 2, + /* goaway */ 1, /* reason */ SC_NULL, /* descr */ "TCP connection error for CONNECT method" ) @@ -127,6 +138,7 @@ H2_ERROR( /* name */ ENHANCE_YOUR_CALM, /* val */ 11, /* types */ 3, + /* goaway */ 1, /* reason */ SC_OVERLOAD, /* descr */ "Processing capacity exceeded" ) @@ -135,6 +147,7 @@ H2_ERROR( /* name */ INADEQUATE_SECURITY, /* val */ 12, /* types */ 1, + /* goaway */ 1, /* reason */ SC_RX_JUNK, /* descr */ "Negotiated TLS parameters not acceptable" ) @@ -143,31 +156,35 @@ H2_ERROR( /* name */ HTTP_1_1_REQUIRED, /* val */ 13, /* types */ 1, + /* goaway */ 1, /* reason */ SC_REQ_HTTP20, /* descr */ "Use HTTP/1.1 for the request" ) #ifdef H2_CUSTOM_ERRORS H2_ERROR( - /* name */ RAPID_RESET, - /* val */ 11, /* ENHANCE_YOUR_CALM */ - /* types */ 1, - /* reason */ SC_RAPID_RESET, - /* descr */ "http/2 rapid reset detected" + /* name */ RAPID_RESET, + /* val */ 11, /* ENHANCE_YOUR_CALM */ + /* types */ 1, + /* goaway */ 1, + /* reason */ SC_RAPID_RESET, + /* descr */ "http/2 rapid reset detected" ) H2_ERROR( - /* name */ MISSING_SCHEME, - /* val */ 1, /* PROTOCOL_ERROR */ - /* types */ 2, - /* reason */ SC_NULL, - /* descr */ "Missing :scheme pseudo-header" + /* name */ MISSING_SCHEME, + /* val */ 1, /* PROTOCOL_ERROR */ + /* types */ 2, + /* goaway */ 1, + /* reason */ SC_NULL, + /* descr */ "Missing :scheme pseudo-header" ) H2_ERROR( /* name */ BROKE_WINDOW, /* val */ 8, /* CANCEL */ /* types */ 2, + /* goaway */ 0, /* reason */ SC_NULL, /* descr */ "http/2 stream out of window credits" ) @@ -176,6 +193,7 @@ H2_ERROR( /* name */ BANKRUPT, /* val */ 11, /* ENHANCE_YOUR_CALM */ /* types */ 1, + /* goaway */ 0, /* reason */ SC_BANKRUPT, /* descr */ "http/2 bankrupt connection" ) From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:08 +0000 (UTC) Subject: [master] 9aa45a9f2 http2_proto: Send GOAWAY before leaving the rx loop Message-ID: <20240318183208.3C9E4106E9C@lists.varnish-cache.org> commit 9aa45a9f290b3e43c3939622c55017075862965f Author: Dridi Boukelmoune Date: Thu Nov 16 17:30:17 2023 +0100 http2_proto: Send GOAWAY before leaving the rx loop diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index b9d03d47c..1ae72410c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -412,7 +412,7 @@ h2_tx_goaway(struct worker *wrk, struct h2_sess *h2, h2_error h2e) ASSERT_RXTHR(h2); AN(h2e); - if (h2->goaway) + if (h2->goaway || !h2e->send_goaway) return; h2->goaway = 1; @@ -1469,6 +1469,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) if (h2e != NULL && h2e->connection) { h2->error = h2e; + h2_tx_goaway(wrk, h2, h2e); return (0); } diff --git a/bin/varnishtest/tests/t02003.vtc b/bin/varnishtest/tests/t02003.vtc index 1d62ac986..fe30e8243 100644 --- a/bin/varnishtest/tests/t02003.vtc +++ b/bin/varnishtest/tests/t02003.vtc @@ -233,17 +233,28 @@ client c1 { } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 3 + } -start stream 1 { - txreq -nohdrend + txreq -nostrend txrst -err 2 } -run stream 3 { - txreq -nohdrend + txreq -nostrend txrst -err 0x666 } -run + stream 0 -wait } -run client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq rxresp @@ -252,6 +263,7 @@ client c1 { # RST_STREAM on closed stream txrst } -run + stream 0 -wait } -run diff --git a/bin/varnishtest/tests/t02005.vtc b/bin/varnishtest/tests/t02005.vtc index 616e4c039..c5176f725 100644 --- a/bin/varnishtest/tests/t02005.vtc +++ b/bin/varnishtest/tests/t02005.vtc @@ -32,7 +32,7 @@ varnish v1 -cliok "param.set debug +syncvsl" logexpect l1 -v v1 -g raw { expect * 1001 ReqAcct "80 7 87 78 8 86" - expect * 1000 ReqAcct "45 8 53 54 20 74" + expect * 1000 ReqAcct "45 8 53 63 28 91" } -start client c1 { diff --git a/bin/varnishtest/tests/t02025.vtc b/bin/varnishtest/tests/t02025.vtc index 4b83fe95b..39f987a06 100644 --- a/bin/varnishtest/tests/t02025.vtc +++ b/bin/varnishtest/tests/t02025.vtc @@ -25,12 +25,17 @@ logexpect l1 -v v1 -g raw -i Debug { } -start client c1 { + stream 0 { + rxgoaway + expect goaway.err == NO_ERROR + expect goaway.laststream == 1 + } -start stream 1 { txreq barrier b1 sync txrst } -run - expect_close + stream 0 -wait } -start logexpect l1 -wait From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:08 +0000 (UTC) Subject: [master] 9f6a7e3f9 http2_proto: Simplify CONTINUATION expectation check Message-ID: <20240318183208.76E08106EA4@lists.varnish-cache.org> commit 9f6a7e3f90c50565ff2184592a66d1c0e711502c Author: Dridi Boukelmoune Date: Mon Sep 11 17:52:00 2023 +0200 http2_proto: Simplify CONTINUATION expectation check Before the h2 frame dispatch we only need to check that coming from a HEADERS frame the very next frame is a CONTINUATION, when the HPACK block didn't fit in the former. The CONTINUATION dispatch will then make the stream consistency check. diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c index 1ae72410c..d9210ff3c 100644 --- a/bin/varnishd/http2/cache_http2_proto.c +++ b/bin/varnishd/http2/cache_http2_proto.c @@ -1295,8 +1295,7 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2, h2_frame h2f) if (r2->stream == h2->rxf_stream) break; - if (h2->new_req != NULL && - !(r2 && h2->new_req == r2->req && h2f == H2_F_CONTINUATION)) + if (h2->new_req != NULL && h2f != H2_F_CONTINUATION) return (H2CE_PROTOCOL_ERROR); // rfc7540,l,1859,1863 h2e = h2f->rxfunc(wrk, h2, r2); From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:08 +0000 (UTC) Subject: [master] 88f7f790d whats-new: Mention CVE-2023-43622 Message-ID: <20240318183208.8F4ED106EB3@lists.varnish-cache.org> commit 88f7f790d79941fb7592efd9b34068d1c7e0b7c2 Author: Dridi Boukelmoune Date: Fri Mar 15 16:03:13 2024 +0100 whats-new: Mention CVE-2023-43622 diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-trunk.rst index 4bef696c0..1ed15bf75 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-trunk.rst @@ -27,6 +27,16 @@ longer open (stream reset, client disconnected etc). .. _VSV 13: https://varnish-cache.org/security/VSV00013.html +CVE-2023-43622 +~~~~~~~~~~~~~~ + +Another denial of service attack vector received a CVE number in the aftermath +of the Rapid Reset debacle. `VSV 14`_ is called the HTTP/2 Broke Window attack +and can be summarized as the ability for clients to hold a server still by not +crediting the control flow window of HTTP/2 streams. + +.. _VSV 14: https://varnish-cache.org/security/VSV00014.html + varnishd ======== @@ -66,6 +76,11 @@ The following parameters address the HTTP/2 Rapid Reset attach: - ``h2_rapid_reset_limit`` (maximum number of rapid resets per period) - ``h2_rapid_reset_period`` (the sliding period to track rapid resets) +The new ``h2_window_timeout`` parameter defines how long an HTTP/2 stream can +stall its delivery waiting for a control flow window update. A stream without +any credits is considered broke, and if all streams are broke when the new +timeout triggers the entire connection is considered bankrupt. + A new bit flag ``vcl_req_reset`` for the ``feature`` parameter interrupts client request tasks during VCL transitions when an HTTP/2 stream is no longer open. The result is equivalent to a ``return (fail);`` statement and can save @@ -247,9 +262,12 @@ A new ``MAIN.sc_rapid_reset`` counter counts the number of HTTP/2 connections closed because the number of rapid resets exceed the limit over the configured period. -Its ``MAIN.req_reset`` counterpart counts the number of time a client task was -prematurely failed because the HTTP/2 stream it was processing was no longer -open and the feature flag ``vcl_req_reset`` was raised. +Likewise, ``MAIN.sc_bankrupt`` counts the number of HTTP/2 connections closed +because all streams ran out of credits and ``h2_window_timeout`` triggered. + +Their ``MAIN.req_reset`` counterpart counts the number of time a client task +was prematurely failed because the HTTP/2 stream it was processing was no +longer open and the feature flag ``vcl_req_reset`` was raised. A new counter ``MAIN.n_superseded`` adds visibility on how many objects are inserted as the replacement of another object in the cache. This can give From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:08 +0000 (UTC) Subject: [master] eef25264e Prepare for 7.5.0 Message-ID: <20240318183208.B40EC106EC2@lists.varnish-cache.org> commit eef25264e5ca5f96a77129308edb83ccf84cb1b1 Author: Simon Stridsberg Date: Mon Mar 18 14:45:32 2024 +0100 Prepare for 7.5.0 diff --git a/bin/varnishtest/tests/m00003.vtc b/bin/varnishtest/tests/m00003.vtc index 1b6a90faa..7130e90bb 100644 --- a/bin/varnishtest/tests/m00003.vtc +++ b/bin/varnishtest/tests/m00003.vtc @@ -96,7 +96,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so "\x03" varnish v1 -errvcl {VMOD wants ABI version 1.0} { import wrong; } ############################################################# -# NB: in the tests below "18" should track VRT_MAJOR_VERSION +# NB: in the tests below "19" should track VRT_MAJOR_VERSION filewrite ${tmpdir}/libvmod_wrong.so "VMOD_JSON_SPEC\x02" filewrite -a ${tmpdir}/libvmod_wrong.so { @@ -108,7 +108,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ "$FOOBAR" @@ -128,7 +128,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ] ] @@ -146,7 +146,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ "$CPROTO" @@ -168,7 +168,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_std_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ "$CPROTO", "/* blabla */" diff --git a/bin/varnishtest/tests/m00055.vtc b/bin/varnishtest/tests/m00055.vtc index f79182b8a..7d8f9afa9 100644 --- a/bin/varnishtest/tests/m00055.vtc +++ b/bin/varnishtest/tests/m00055.vtc @@ -21,7 +21,7 @@ filewrite -a ${tmpdir}/libvmod_wrong.so { "Vmod_vmod_wrong_Func", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", - "18", + "19", "0" ], [ diff --git a/configure.ac b/configure.ac index adb25c713..f9e9666e6 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ AC_PREREQ([2.69]) AC_COPYRIGHT([Copyright (c) 2006 Verdens Gang AS -Copyright (c) 2006-2023 Varnish Software -Copyright 2010-2023 UPLEX - Nils Goroll Systemoptimierung]) +Copyright (c) 2006-2024 Varnish Software +Copyright 2010-2024 UPLEX - Nils Goroll Systemoptimierung]) AC_REVISION([$Id$]) -AC_INIT([Varnish],[trunk],[varnish-dev at varnish-cache.org]) +AC_INIT([Varnish],[7.5.0],[varnish-dev at varnish-cache.org]) AC_CONFIG_SRCDIR(include/miniobj.h) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/changes.rst b/doc/changes.rst index 3aa1b6d36..aeda844ff 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -34,13 +34,15 @@ http://varnish-cache.org/docs/trunk/whats-new/index.html and via individual releases. These documents are updated as part of the release process. -=============================== -Varnish Cache NEXT (2024-03-15) -=============================== +================================ +Varnish Cache 7.5.0 (2024-03-18) +================================ .. PLEASE keep this roughly in commit order as shown by git-log / tig (new to old) +* Add ``h2_window_timeout`` paramater to mitigate CVE-2023-43622 (VSV00014_). + * The parameters ``idle_send_timeout`` and ``timeout_idle`` are now limited to a maximum of 1 hour. @@ -280,6 +282,7 @@ Varnish Cache NEXT (2024-03-15) .. _3997: https://github.com/varnishcache/varnish-cache/pull/3997 .. _3998: https://github.com/varnishcache/varnish-cache/pull/3998 .. _3999: https://github.com/varnishcache/varnish-cache/pull/3999 +.. _VSV00014: https://varnish-cache.org/security/VSV00014.html ================================ Varnish Cache 7.4.0 (2023-09-15) diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 537c22209..489910406 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -40,9 +40,9 @@ Conventions used in this manual include: Longer listings like example command output and VCL look like this:: $ /opt/varnish/sbin/varnishd -V - varnishd (varnish-trunk revision 1234567) + varnishd (varnish-7.5.0 revision 1234567) Copyright (c) 2006 Verdens Gang AS - Copyright (c) 2006-2023 Varnish Software + Copyright (c) 2006-2024 Varnish Software .. For maintainers: diff --git a/doc/sphinx/whats-new/changes-trunk.rst b/doc/sphinx/whats-new/changes-7.5.rst similarity index 99% rename from doc/sphinx/whats-new/changes-trunk.rst rename to doc/sphinx/whats-new/changes-7.5.rst index 1ed15bf75..3a36a1120 100644 --- a/doc/sphinx/whats-new/changes-trunk.rst +++ b/doc/sphinx/whats-new/changes-7.5.rst @@ -1,11 +1,11 @@ -.. _whatsnew_changes_CURRENT: +.. _whatsnew_changes_7.5: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Changes in Varnish **${NEXT_RELEASE}** +Changes in Varnish **7.5** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% For information about updating your current Varnish deployment to the -new version, see :ref:`whatsnew_upgrading_CURRENT`. +new version, see :ref:`whatsnew_upgrading_7.5`. A more detailed and technical account of changes in Varnish, with links to issues that have been fixed and pull requests that have been diff --git a/doc/sphinx/whats-new/index.rst b/doc/sphinx/whats-new/index.rst index 8b4225c98..51a6b97bd 100644 --- a/doc/sphinx/whats-new/index.rst +++ b/doc/sphinx/whats-new/index.rst @@ -13,7 +13,7 @@ This section describes the changes and improvements between different versions of Varnish, and what upgrading between the different versions entail. -Varnish **$NEXT_RELEASE** +Varnish **7.5** ------------------------- **Note: These are working documents for a future release, with running @@ -23,8 +23,8 @@ released versions of Varnish, see the chapters listed below.** .. toctree:: :maxdepth: 2 - changes-trunk - upgrading-trunk + changes-7.5 + upgrading-7.5 Varnish 7.4 ----------- diff --git a/doc/sphinx/whats-new/upgrading-trunk.rst b/doc/sphinx/whats-new/upgrading-7.5.rst similarity index 97% rename from doc/sphinx/whats-new/upgrading-trunk.rst rename to doc/sphinx/whats-new/upgrading-7.5.rst index cc0605775..ac068ec86 100644 --- a/doc/sphinx/whats-new/upgrading-trunk.rst +++ b/doc/sphinx/whats-new/upgrading-7.5.rst @@ -1,7 +1,7 @@ -.. _whatsnew_upgrading_CURRENT: +.. _whatsnew_upgrading_7.5: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -Upgrading to Varnish **$NEXT_RELEASE** +Upgrading to Varnish **7.5** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Logs diff --git a/include/vrt.h b/include/vrt.h index 5599ac7c9..0f1df8984 100644 --- a/include/vrt.h +++ b/include/vrt.h @@ -46,9 +46,9 @@ # error "include vdef.h before vrt.h" #endif -#define VRT_MAJOR_VERSION 18U +#define VRT_MAJOR_VERSION 19U -#define VRT_MINOR_VERSION 1U +#define VRT_MINOR_VERSION 0U /*********************************************************************** * Major and minor VRT API versions. @@ -57,7 +57,7 @@ * Whenever something is deleted or changed in a way which is not * binary/load-time compatible, increment MAJOR version * - * NEXT (2024-03-15) + * 19.0 (2024-03-18) * [cache.h] (struct req).filter_list renamed to vdp_filter_list * order of vcl/vmod and director COLD events reversed to directors first * VRT_u_sess_idle_send_timeout() added diff --git a/lib/libvarnish/version.c b/lib/libvarnish/version.c index 0d09ab748..4f5983c0d 100644 --- a/lib/libvarnish/version.c +++ b/lib/libvarnish/version.c @@ -76,8 +76,8 @@ VCS_String(const char *which) ")" "\n" "Copyright (c) 2006 Verdens Gang AS\n" - "Copyright (c) 2006-2023 Varnish Software\n" - "Copyright 2010-2023 UPLEX - Nils Goroll Systemoptimierung\n" + "Copyright (c) 2006-2024 Varnish Software\n" + "Copyright 2010-2024 UPLEX - Nils Goroll Systemoptimierung\n" ); default: WRONG("Wrong argument to VCS_String"); From simon.stridsberg at varnish-software.com Mon Mar 18 18:32:08 2024 From: simon.stridsberg at varnish-software.com (Simon Stridsberg) Date: Mon, 18 Mar 2024 18:32:08 +0000 (UTC) Subject: [master] 02cbe3166 Merge tag 'varnish-7.5.0' Message-ID: <20240318183208.D80D7106ECD@lists.varnish-cache.org> commit 02cbe31660f4416dc776c65f27b57b0d52e74f37 Merge: ac9830e9c eef25264e Author: Simon Stridsberg Date: Mon Mar 18 19:28:20 2024 +0100 Merge tag 'varnish-7.5.0' Releasing 7.5.0 From dridi.boukelmoune at gmail.com Mon Mar 18 19:33:05 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 18 Mar 2024 19:33:05 +0000 (UTC) Subject: [master] 3d597de62 build: Back to the future Message-ID: <20240318193305.C6FF2113304@lists.varnish-cache.org> commit 3d597de6275470155da5162e2566637acb32ecf1 Author: Dridi Boukelmoune Date: Mon Sep 18 07:19:46 2023 +0200 build: Back to the future diff --git a/configure.ac b/configure.ac index f9e9666e6..aa1e3f40c 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_COPYRIGHT([Copyright (c) 2006 Verdens Gang AS Copyright (c) 2006-2024 Varnish Software Copyright 2010-2024 UPLEX - Nils Goroll Systemoptimierung]) AC_REVISION([$Id$]) -AC_INIT([Varnish],[7.5.0],[varnish-dev at varnish-cache.org]) +AC_INIT([Varnish], [trunk], [varnish-dev at varnish-cache.org]) AC_CONFIG_SRCDIR(include/miniobj.h) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) From dridi.boukelmoune at gmail.com Tue Mar 19 09:21:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Tue, 19 Mar 2024 09:21:08 +0000 (UTC) Subject: [master] 23229ebdf circleci: Tolerate spaces in AC_INIT() Message-ID: <20240319092108.6E9A5105BF6@lists.varnish-cache.org> commit 23229ebdf2bf4a91bb0c806a7ac480c6cee2ca52 Author: Dridi Boukelmoune Date: Tue Mar 19 10:19:58 2024 +0100 circleci: Tolerate spaces in AC_INIT() Better diff with the --word-diff --word-diff-regex=. options. diff --git a/.circleci/config.yml b/.circleci/config.yml index 06d3240d2..171165f5c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -82,9 +82,9 @@ jobs: touch .is_weekly # If version is "trunk", override version to add date if grep 'AC_INIT.*trunk.*' ./configure.ac; then - sed -i -e "s/AC_INIT(\[\(.*\)\],\[\(.*\)\],\[\(.*\)\])/AC_INIT([\1],[$(date +%Y%m%d)],[\3])/" ./configure.ac + sed -i -e "s/AC_INIT(\[\(.*\)\],\s*\[\(.*\)\],\s*\[\(.*\)\])/AC_INIT([\1],[$(date +%Y%m%d)],[\3])/" ./configure.ac else - sed -i -e "s/AC_INIT(\[\(.*\)\],\[\(.*\)\],\[\(.*\)\])/AC_INIT([\1],[\2-$(date +%Y%m%d)],[\3])/" ./configure.ac + sed -i -e "s/AC_INIT(\[\(.*\)\],\s*\[\(.*\)\],\s*\[\(.*\)\])/AC_INIT([\1],[\2-$(date +%Y%m%d)],[\3])/" ./configure.ac fi ./autogen.des make dist -j 16 From dridi.boukelmoune at gmail.com Wed Mar 20 11:13:08 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Wed, 20 Mar 2024 11:13:08 +0000 (UTC) Subject: [master] 13fe897fa varnishncsa: Reduce CTX.gen overflow likelihood Message-ID: <20240320111308.5915F115111@lists.varnish-cache.org> commit 13fe897fa582661fe075af21aff0e53b3770fcfe Author: Walid Boudebouda Date: Fri Mar 15 09:39:32 2024 +0100 varnishncsa: Reduce CTX.gen overflow likelihood If a format never matches anything, the 4294967296th transaction proccessed by varnishncsa will wrap its generation around to zero, be considered a match, and let vsb_fcat() pass a null string to VSB_quote(). diff --git a/bin/varnishncsa/varnishncsa.c b/bin/varnishncsa/varnishncsa.c index 8789adbe7..94af83748 100644 --- a/bin/varnishncsa/varnishncsa.c +++ b/bin/varnishncsa/varnishncsa.c @@ -93,7 +93,7 @@ enum e_frag { }; struct fragment { - unsigned gen; + uint64_t gen; const char *b, *e; }; @@ -144,7 +144,7 @@ static struct ctx { FILE *fo; struct vsb *vsb; - unsigned gen; + uint64_t gen; VTAILQ_HEAD(,format) format; int quote_how; char *missing_string; From dridi.boukelmoune at gmail.com Mon Mar 25 09:16:12 2024 From: dridi.boukelmoune at gmail.com (Dridi Boukelmoune) Date: Mon, 25 Mar 2024 09:16:12 +0000 (UTC) Subject: [7.5] 13979d1dc whats-new: Use CVE-2024-30156 for the h2 broke window Message-ID: <20240325091612.2E4C311345D@lists.varnish-cache.org> commit 13979d1dc31eae68a4d66dd5d0de5724866b24f3 Author: Dridi Boukelmoune Date: Mon Mar 25 10:09:27 2024 +0100 whats-new: Use CVE-2024-30156 for the h2 broke window diff --git a/doc/sphinx/whats-new/changes-7.5.rst b/doc/sphinx/whats-new/changes-7.5.rst index 3a36a1120..e55acb1f9 100644 --- a/doc/sphinx/whats-new/changes-7.5.rst +++ b/doc/sphinx/whats-new/changes-7.5.rst @@ -27,7 +27,7 @@ longer open (stream reset, client disconnected etc). .. _VSV 13: https://varnish-cache.org/security/VSV00013.html -CVE-2023-43622 +CVE-2024-30156 ~~~~~~~~~~~~~~ Another denial of service attack vector received a CVE number in the aftermath From nils.goroll at uplex.de Mon Mar 25 14:56:07 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Mon, 25 Mar 2024 14:56:07 +0000 (UTC) Subject: [master] 9c0abf0c8 expire: Introduce EXP_Reduce() Message-ID: <20240325145607.B5B0C11DD46@lists.varnish-cache.org> commit 9c0abf0c8065c2dab42410475346e7dff2156bc7 Author: AlveElde Date: Fri Mar 22 11:21:46 2024 +0100 expire: Introduce EXP_Reduce() This commit introduces EXP_Reduce(), a function to reduce object timers. The goal is to provide a function better suited to soft-purging objects, as EXP_Rearm() has some non-obvious disadvantages when used or this purpose. When EXP_Rearm() is used to soft-purge an object by setting its TTL to 0, the expiry is effectively reset to the start of the objects grace period. This happens because the object TTL includes a time delta between object insertion time (oc->t_origin) and now. The result is that a soft-purge extends the lifetime of an already stale object, and repeated soft-purges can keep the object away from expiry indefinitely. The EXP_Reduce() function is better suited for soft-purging, as it only updates an objects TTL if it would reduce the objects lifetime. The function also has facilities for reducing grace and keep. diff --git a/bin/varnishd/cache/cache_expire.c b/bin/varnishd/cache/cache_expire.c index fb823e3cc..eb862bf49 100644 --- a/bin/varnishd/cache/cache_expire.c +++ b/bin/varnishd/cache/cache_expire.c @@ -219,6 +219,28 @@ EXP_Insert(struct worker *wrk, struct objcore *oc) } } +/*-------------------------------------------------------------------- + * Reduce object timers + */ + +void +EXP_Reduce(struct objcore *oc, vtim_real now, + vtim_dur ttl, vtim_dur grace, vtim_dur keep) +{ + + CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); + assert(oc->refcnt > 0); + + if (!isnan(ttl) && now + ttl - oc->t_origin >= oc->ttl) + ttl = NAN; + if (!isnan(grace) && grace >= oc->grace) + grace = NAN; + if (!isnan(keep) && keep >= oc->keep) + keep = NAN; + + EXP_Rearm(oc, now, ttl, grace, keep); +} + /*-------------------------------------------------------------------- * We have changed one or more of the object timers, tell the exp_thread * diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h index d759f95e7..61d3145c9 100644 --- a/bin/varnishd/cache/cache_varnishd.h +++ b/bin/varnishd/cache/cache_varnishd.h @@ -240,6 +240,8 @@ void EXP_Remove(struct objcore *, const struct objcore *); /* cache_exp.c */ void EXP_Rearm(struct objcore *oc, vtim_real now, vtim_dur ttl, vtim_dur grace, vtim_dur keep); +void EXP_Reduce(struct objcore *oc, vtim_real now, + vtim_dur ttl, vtim_dur grace, vtim_dur keep); /* From cache_main.c */ void BAN_Init(void); From nils.goroll at uplex.de Mon Mar 25 14:56:07 2024 From: nils.goroll at uplex.de (Nils Goroll) Date: Mon, 25 Mar 2024 14:56:07 +0000 (UTC) Subject: [master] e676f7793 purge: Use EXP_Reduce() instead of EXP_Rearm() Message-ID: <20240325145607.DF39F11DD49@lists.varnish-cache.org> commit e676f77939e7dbde851ee3aa58dfd36505f2b7e8 Author: AlveElde Date: Tue Mar 19 13:44:24 2024 +0100 purge: Use EXP_Reduce() instead of EXP_Rearm() When a stale object is soft-purged, the time until the object expires should not be reset, as repeated soft-purges could keep the object around indefinitely. diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c index 8627c7a95..32f9340c7 100644 --- a/bin/varnishd/cache/cache_hash.c +++ b/bin/varnishd/cache/cache_hash.c @@ -747,7 +747,7 @@ HSH_Purge(struct worker *wrk, struct objhead *oh, vtim_real ttl_now, if (is_purge) EXP_Remove(ocp[i], NULL); else - EXP_Rearm(ocp[i], ttl_now, ttl, grace, keep); + EXP_Reduce(ocp[i], ttl_now, ttl, grace, keep); (void)HSH_DerefObjCore(wrk, &ocp[i], 0); AZ(ocp[i]); total++; diff --git a/bin/varnishtest/tests/m00057.vtc b/bin/varnishtest/tests/m00057.vtc new file mode 100644 index 000000000..8f9c67d1f --- /dev/null +++ b/bin/varnishtest/tests/m00057.vtc @@ -0,0 +1,60 @@ +varnishtest "Softpurging a stale object" + +server s1 { + rxreq + txresp -hdr "version: 1" + + rxreq + txresp -hdr "version: 2" +} -start + +varnish v1 -vcl+backend { + import purge; + + sub vcl_hit { + if (req.http.purge) { + set req.http.npurged = purge.soft(); + return (synth(200)); + } + } + + sub vcl_backend_response { + set beresp.grace = 3s; + set beresp.keep = 10s; + } + + sub vcl_synth { + set resp.http.npurged = req.http.npurged; + } +} -start + +client c1 { + txreq + rxresp + expect resp.status == 200 + expect resp.http.version == "1" + + # Softpurge the object + txreq -hdr "purge: yes" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Wait for half the grace period + delay 1.5 + + # Softpurge the object again, this should not reset the expiry timer + txreq -hdr "purge: yes" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Wait for the object to enter keep + delay 1.5 + + # A grace hit should not be possible now + txreq + rxresp + expect resp.http.version == "2" + expect resp.status == 200 +} -run diff --git a/bin/varnishtest/tests/m00058.vtc b/bin/varnishtest/tests/m00058.vtc new file mode 100644 index 000000000..e339764ae --- /dev/null +++ b/bin/varnishtest/tests/m00058.vtc @@ -0,0 +1,86 @@ +varnishtest "Softpurging an object cannot increase grace or keep" + +server s1 { + rxreq + txresp -hdr "Last-Modified: Wed, 11 Sep 2013 13:36:55 GMT" -body "foo" + + rxreq + expect req.http.if-modified-since == "Wed, 11 Sep 2013 13:36:55 GMT" + txresp -body "bar" +} -start + +varnish v1 -arg "-p vsl_mask=+ExpKill" -vcl+backend { + import purge; + import std; + + sub vcl_hit { + if (req.http.purge) { + set req.http.npurged = purge.soft( + grace = std.duration(req.http.grace, -1s), + keep = std.duration(req.http.keep, -1s)); + return (synth(200)); + } + } + + sub vcl_backend_response { + set beresp.ttl = 1y; + set beresp.grace = 1y; + set beresp.keep = 1y; + } + + sub vcl_synth { + set resp.http.npurged = req.http.npurged; + } +} -start + +client c1 { + txreq + rxresp + expect resp.status == 200 + expect resp.body == "foo" + + # Reduce the objects grace + txreq -hdr "purge: yes" -hdr "grace: 10s" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Reduce the objects keep + txreq -hdr "purge: yes" -hdr "keep: 10s" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Reduce the objects grace and keep + txreq -hdr "purge: yes" -hdr "grace: 1s" -hdr "keep: 5s" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Increasing the objects grace is not possible + txreq -hdr "purge: yes" -hdr "grace: 15s" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Increasing the objects keep is not possible + txreq -hdr "purge: yes" -hdr "keep: 105" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Increasing the objects grace and keep is not possible + txreq -hdr "purge: yes" -hdr "grace: 15s" -hdr "keep: 15s" + rxresp + expect resp.status == 200 + expect resp.http.npurged == 1 + + # Wait for the obejct to enter keep + delay 1 + + # We don't get a grace hit, but the backend gets an IMS header + txreq + rxresp + expect resp.status == 200 + expect resp.body == "bar" +} -run diff --git a/vmod/vmod_purge.vcc b/vmod/vmod_purge.vcc index dc55a7f30..7fa7639da 100644 --- a/vmod/vmod_purge.vcc +++ b/vmod/vmod_purge.vcc @@ -98,12 +98,46 @@ $Restrict vcl_hit vcl_miss $Function INT soft(DURATION ttl = 0, DURATION grace = -1, DURATION keep = -1) -Sets the *ttl*, *grace* and *keep*. - -By default, *ttl* is set to 0 with *grace* and *keep* periods left -untouched. Setting a negative value for *grace* or *keep* periods -leaves them untouched. Setting all three parameters to ``0`` is -equivalent to a hard purge. It returns the number of soft-purged objects. +Sets the *ttl*, *grace* and *keep*. By default, *ttl* is set to ``0`` with +*grace* and *keep* periods left untouched. Setting *grace* or *keep* to a +negative value or to something higher than the objects current value leaves them +untouched. Setting all three parameters to ``0`` is equivalent to a hard purge. +Returns the number of soft-purged objects. + +A soft-purge can only decrease the lifetime of an object. Let's consider an +object in cache created with *ttl*, *grace*, and *keep* of 60 seconds each: + +``purge.soft(ttl = 0s, grace = -1s, keep = -1s);`` + +* If the object is **fresh**, the *ttl* is reduced to 0 seconds and the object + expires after 120 seconds. +* If the object is **stale**, the expiry time is not changed. + +``purge.soft(ttl = 0s, grace = 10s, keep = 10s);`` + +* If the object is **fresh**, the *ttl* is reduced to 0 seconds, *grace* and + *keep* are reduced to 10 seconds. The object expires after 20 seconds. +* If the object has been **stale** for 5 seconds, *grace* is reduced to 5 + seconds and *keep* is reduced to 10 seconds. The object expires after 15 + seconds. +* If the object has been **stale** for 15 seconds, *grace* is reduced to 0 + seconds and *keep* is reduced to 5 seconds. The object expires after 5 + seconds. +* If the object has been **stale** for 20 seconds or more, the object + immediately expires. + +``purge.soft(ttl = 10s, grace = -1s, keep = -1s);`` + +* If the object has been **fresh** for 5 seconds, the *ttl* is reduced to 10 + seconds. The object expires after 130 seconds. +* If the object has been **fresh** for 55 seconds, the *ttl* is not changed. The + object expires after 125 seconds. +* If the object is **stale**, the expiry time is not changed. + +When the expiry time of an object is reduced due to a softpurge, an +``EXP_Reduce`` entry is logged under the ``ExpKill`` VSL tag. If a softpurge +does not reduce the expiry time of an object, an ``EXP_Unchanged`` entry is +logged instead. $Restrict vcl_hit vcl_miss SEE ALSO