Skip to content
This repository was archived by the owner on Feb 16, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/varnishd/cache/cache_req_fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ cnt_synth(struct worker *wrk, struct req *req)

VSLb_ts_req(req, "Process", W_TIM_real(wrk));

while (wrk->vpi->handling == VCL_RET_FAIL) {
while (req->req_reset || wrk->vpi->handling == VCL_RET_FAIL) {
if (req->esi_level > 0) {
wrk->vpi->handling = VCL_RET_DELIVER;
break;
Expand Down
21 changes: 14 additions & 7 deletions bin/varnishd/cache/cache_vrt_vcl.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,13 +560,16 @@ req_poll(struct worker *wrk, struct req *req)
{
struct req *top;

/* NB: Since a fail transition leads to vcl_synth, the request may be
* short-circuited twice.
/* If the req_reset flag was raised without taking the emulated
* return(fail) transition, there must be a good reason for that.
* One is that sub vcl_recv is always followed by a call to sub
* vcl_hash to always compute a cache key. The other one is that
* we always want to run sub vcl_synth for return(fail) even if
* we won't deliver the response, and maybe sub vcl_synth needs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand this. The only place where req_reset is set, VCL_RET_FAIL handling is signaled. Why does this pivot around req_reset and not VCL_RET_FAIL as already seems to be the case?

Also, is vcl_synth{} still the right place for this? Do we need some place to handle VCL_RET_FAIL, where it is clear that we do not emit headers?

I do not want to say that this is wrong, but could you please at least explain more?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The req_poll() function is a short-circuit to circumvent VCL execution once a request is "reset". For now, that is limited to aborted h2 connections or h2 streams being reset (and again, #3835 and more on the enterprise side).

The goal is to ensure that this short circuit either emulates a return (fail) that normally leads to vcl_synth (via R_STP_VCLFAIL) but does not prevent vcl_synth from being executed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand how your response would answer my questions.

  • why does this (need to) look at req_reset and not just at VCL_RET_FAIL?

  • Would it not be cleaner to have a vcl sub to handle VCL_RET_FAIL rather than invoking vcl_synth {}, but without the intended effect? The existing code path in vcl_synth {} is to handle a return(fail) from vcl_synth {} itself, but now entering vcl_synth {} for fail paths and not executing the expected delivery seems plain wrong to me.

Side note: We should base our design decisions on what we have in our code base. What is in your private fork should not guide us.

* the cache key. There may be other good reasons to proceed.
*/
if (req->req_reset) {
wrk->vpi->handling = VCL_RET_FAIL;
return (-1);
}
if (req->req_reset)
return (0);

top = req->top->topreq;
CHECK_OBJ_NOTNULL(top, REQ_MAGIC);
Expand All @@ -581,8 +584,12 @@ req_poll(struct worker *wrk, struct req *req)

VSLb_ts_req(req, "Reset", W_TIM_real(wrk));
wrk->stats->req_reset++;
wrk->vpi->handling = VCL_RET_FAIL;
req->req_reset = 1;

if (req->req_step == R_STP_SYNTH)
return (0);

wrk->vpi->handling = VCL_RET_FAIL;
return (-1);
}

Expand Down
11 changes: 9 additions & 2 deletions bin/varnishtest/tests/t02025.vtc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ varnish v1 -vcl {
sub vcl_miss {
vtc.panic("unreachable");
}

sub vcl_synth {
if (resp.status == 408) {
set resp.http.gone = "bye";
}
}
} -start

logexpect l1 -v v1 -g raw -i Debug {
Expand Down Expand Up @@ -51,7 +57,8 @@ varnish v1 -expect req_reset == 1
# is interpreted as before a second elapsed. Session VXIDs showing up
# numerous times become increasingly more suspicious. The format can of
# course be extended to add anything else useful for data mining.
shell -expect "1000 ${localhost} 408" {
shell -expect "1000 ${localhost} 408 bye" {
varnishncsa -n ${v1_name} -d \
-q 'Timestamp:Reset[2] < 1.0' -F '%{VSL:Begin[2]}x %h %s'
-q 'Timestamp:Reset[2] < 1.0' \
-F '%{VSL:Begin[2]}x %h %s %{gone}o'
}