Commit a8606b8e authored by Andrew Wiik's avatar Andrew Wiik Committed by Reza Naghibi

Add "error" state to backend fetch and response

parent 8bf63a88
......@@ -407,6 +407,9 @@ struct busyobj {
struct http_conn *htc;
uint16_t err_code;
const char *err_reason;
struct pool_task fetch_task;
#define BO_FLAG(l, r, w, d) unsigned l:1;
......
......@@ -277,7 +277,7 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo)
if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL)
return (F_STP_FAIL);
assert (wrk->handling == VCL_RET_FETCH);
assert (wrk->handling == VCL_RET_FETCH || wrk->handling == VCL_RET_ERROR);
HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod);
......@@ -290,6 +290,9 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo)
bo->vfc->resp = bo->beresp;
bo->vfc->req = bo->bereq;
if (wrk->handling == VCL_RET_ERROR)
return (F_STP_ERROR);
i = VDI_GetHdr(wrk, bo);
now = W_TIM_real(wrk);
......@@ -383,10 +386,15 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo)
VCL_backend_response_method(bo->vcl, wrk, NULL, bo, NULL);
if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL) {
if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL ||
wrk->handling == VCL_RET_ERROR) {
bo->htc->doclose = SC_RESP_CLOSE;
VDI_Finish(bo->wrk, bo);
return (F_STP_FAIL);
if (wrk->handling == VCL_RET_ERROR)
return (F_STP_ERROR);
else
return (F_STP_FAIL);
}
if (wrk->handling == VCL_RET_RETRY) {
......@@ -756,7 +764,8 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
AN(bo->fetch_objcore->flags & OC_F_BUSY);
assert(bo->director_state == DIR_S_NULL);
wrk->stats->fetch_failed++;
if (wrk->handling != VCL_RET_ERROR)
wrk->stats->fetch_failed++;
now = W_TIM_real(wrk);
VSLb_ts_busyobj(bo, "Error", now);
......@@ -770,7 +779,11 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
// XXX: reset all beresp flags ?
HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod);
http_PutResponse(bo->beresp, "HTTP/1.1", 503, "Backend fetch failed");
if (bo->err_code > 0)
http_PutResponse(bo->beresp, "HTTP/1.1", bo->err_code, bo->err_reason);
else
http_PutResponse(bo->beresp, "HTTP/1.1", 503, "Backend fetch failed");
http_TimeHeader(bo->beresp, "Date: ", now);
http_SetHeader(bo->beresp, "Server: Varnish");
......
......@@ -55,9 +55,18 @@ VRT_synth(VRT_CTX, VCL_INT code, VCL_STRING reason)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
assert(ctx->req != NULL || ctx->bo != NULL);
if (code < 100 || code > 65535)
code = 503;
if (ctx->req == NULL) {
CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
ctx->bo->err_code = (uint16_t)code;
ctx->bo->err_reason = reason ? reason
: http_Status2Reason(ctx->bo->err_code % 1000, NULL);
return;
}
ctx->req->err_code = (uint16_t)code;
ctx->req->err_reason = reason ? reason
: http_Status2Reason(ctx->req->err_code % 1000, NULL);
......
varnishtest "backend_(fetch|response) error state with custom status/reason"
server s1 -repeat 3 {
rxreq
txresp
} -start
varnish v1 -vcl+backend {
sub vcl_backend_fetch {
if (bereq.url == "/errorsynth") {
return (error(403));
}
if (bereq.url == "/errorsynthbody") {
return (error(403, "Steven has no cookies"));
}
if (bereq.url == "/error") {
return (error);
}
}
sub vcl_backend_response {
if (bereq.url == "/resperrorsynth") {
return (error(403));
}
if (bereq.url == "/resperrorsynthbody") {
return (error(403, "Steven has no cookies"));
}
if (bereq.url == "/resperror") {
return (error);
}
}
sub vcl_backend_error {
set beresp.http.error = "visited";
}
} -start
client c1 {
txreq -url /error
rxresp
expect resp.status == 503
expect resp.http.error == visited
txreq -url /errorsynth
rxresp
expect resp.status == 403
expect resp.http.error == visited
txreq -url /errorsynthbody
rxresp
expect resp.status == 403
expect resp.reason == "Steven has no cookies"
expect resp.http.error == visited
txreq -url /resperror
rxresp
expect resp.status == 503
expect resp.http.error == visited
txreq -url /resperrorsynth
rxresp
expect resp.status == 403
expect resp.http.error == visited
txreq -url /resperrorsynthbody
rxresp
expect resp.status == 403
expect resp.reason == "Steven has no cookies"
expect resp.http.error == visited
} -run
# Make sure we don't increment the failed fetch counter
varnish v1 -expect fetch_failed == 0
......@@ -39,16 +39,18 @@ digraph cache_fetch {
/* vbf_stp_startfetch() */
v_b_f [
shape=record
label="{vbf_stp_startfetch:|{vcl_backend_fetch\{\}|bereq.*}|{fail|abandon|<fetch>fetch}}"
label="{vbf_stp_startfetch:|{vcl_backend_fetch\{\}|bereq.*}|{<error>error|fail|abandon|<fetch>fetch}}"
]
v_b_f:error:s -> v_b_e
v_b_f:fetch:s -> v_b_hdrs [style=bold]
v_b_hdrs [ label="send bereq,\nread beresp (headers)"]
v_b_hdrs -> v_b_r [style=bold]
v_b_hdrs -> v_b_e
v_b_r [
shape=record
label="{vbf_stp_startfetch:|{vcl_backend_response\{\}|{bereq.*|beresp.*}}|{fail|{retry|{<max>max?|<retry>ok?}}|abandon|{deliver or pass|{<fetch_304>304?|<non_304>other?}}}}"
label="{vbf_stp_startfetch:|{vcl_backend_response\{\}|{bereq.*|beresp.*}}|{<error>error|fail|{retry|{<max>max?|<retry>ok?}}|abandon|{deliver or pass|{<fetch_304>304?|<non_304>other?}}}}"
]
v_b_r:error:s -> v_b_e
v_b_r:retry -> v_b_r_retry [color=purple]
v_b_r:max -> v_b_e
v_b_r:fetch_304:s -> vbf_stp_condfetch
......@@ -90,8 +92,8 @@ digraph cache_fetch {
]
vbf_stp_condfetch:ok:s -> vbf_stp_fetchend
error [shape=plaintext]
error -> FETCH_FAIL
fail [shape=plaintext]
fail -> FETCH_FAIL
/* vbf_stp_error */
v_b_e [
......
This diff is collapsed.
......@@ -345,7 +345,12 @@ The `vcl_backend_fetch` subroutine may terminate with calling
background fetch, control is passed to :ref:`vcl_synth` on the
client side with ``resp.status`` preset to 503.
Before calling `vcl_backend_fetch`, varnish core prepares the `bereq`
``error(status code, reason)``
Transition to :ref:`vcl_backend_error` with ``beresp.status`` and
``beresp.reason`` being preset to the arguments of ``error()`` if
arguments are provided.
Before calling `vcl_backend_fetch`, Varnish core prepares the `bereq`
backend request as follows:
* Unless the request is a `pass`,
......@@ -408,6 +413,11 @@ The `vcl_backend_response` subroutine may terminate with calling
lookups hitting this object will be turned into passed transactions,
as if ``vcl_recv`` had returned ``pass``.
``error(status code, reason)``
Transition to :ref:`vcl_backend_error` with ``beresp.status`` and
``beresp.reason`` being preset to the arguments of ``error()`` if
arguments are provided.
304 handling
~~~~~~~~~~~~
......
......@@ -131,11 +131,11 @@ returns = (
('backend_fetch',
"B",
('fail', 'fetch', 'abandon')
('fail', 'fetch', 'abandon', 'error')
),
('backend_response',
"B",
('fail', 'deliver', 'retry', 'abandon', 'pass')
('fail', 'deliver', 'retry', 'abandon', 'pass', 'error')
),
('backend_error',
"B",
......
......@@ -331,7 +331,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
vcc_ProcAction(tl->curproc, hand, tl->t);
vcc_NextToken(tl);
if (tl->t->tok == '(') {
if (hand == VCL_RET_SYNTH)
if (hand == VCL_RET_SYNTH || hand == VCL_RET_ERROR)
vcc_act_return_synth(tl);
else if (hand == VCL_RET_VCL)
vcc_act_return_vcl(tl);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment