Commit 18f63d48 authored by Andrew Wiik's avatar Andrew Wiik Committed by Poul-Henning Kamp

Add "error" state to backend fetch and response

parent 4600cf98
...@@ -412,6 +412,9 @@ struct busyobj { ...@@ -412,6 +412,9 @@ struct busyobj {
struct http_conn *htc; struct http_conn *htc;
uint16_t err_code;
const char *err_reason;
struct pool_task fetch_task; struct pool_task fetch_task;
#define BO_FLAG(l, r, w, d) unsigned l:1; #define BO_FLAG(l, r, w, d) unsigned l:1;
......
...@@ -277,7 +277,7 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) ...@@ -277,7 +277,7 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo)
if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL) if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL)
return (F_STP_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); HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod);
...@@ -290,6 +290,9 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) ...@@ -290,6 +290,9 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo)
bo->vfc->resp = bo->beresp; bo->vfc->resp = bo->beresp;
bo->vfc->req = bo->bereq; bo->vfc->req = bo->bereq;
if (wrk->handling == VCL_RET_ERROR)
return (F_STP_ERROR);
i = VDI_GetHdr(bo); i = VDI_GetHdr(bo);
now = W_TIM_real(wrk); now = W_TIM_real(wrk);
...@@ -384,10 +387,14 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) ...@@ -384,10 +387,14 @@ vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo)
VCL_backend_response_method(bo->vcl, wrk, NULL, bo, NULL); 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; bo->htc->doclose = SC_RESP_CLOSE;
VDI_Finish(bo); VDI_Finish(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) { if (wrk->handling == VCL_RET_RETRY) {
...@@ -705,7 +712,8 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo) ...@@ -705,7 +712,8 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
AN(bo->fetch_objcore->flags & OC_F_BUSY); AN(bo->fetch_objcore->flags & OC_F_BUSY);
assert(bo->director_state == DIR_S_NULL); 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); now = W_TIM_real(wrk);
VSLb_ts_busyobj(bo, "Error", now); VSLb_ts_busyobj(bo, "Error", now);
...@@ -719,7 +727,11 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo) ...@@ -719,7 +727,11 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
// XXX: reset all beresp flags ? // XXX: reset all beresp flags ?
HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod); 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_TimeHeader(bo->beresp, "Date: ", now);
http_SetHeader(bo->beresp, "Server: Varnish"); http_SetHeader(bo->beresp, "Server: Varnish");
......
...@@ -55,9 +55,18 @@ VRT_synth(VRT_CTX, VCL_INT code, VCL_STRING reason) ...@@ -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, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); assert(ctx->req != NULL || ctx->bo != NULL);
if (code < 100 || code > 65535) if (code < 100 || code > 65535)
code = 503; 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_code = (uint16_t)code;
ctx->req->err_reason = reason ? reason ctx->req->err_reason = reason ? reason
: http_Status2Reason(ctx->req->err_code % 1000, NULL); : 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 { ...@@ -39,16 +39,18 @@ digraph cache_fetch {
/* vbf_stp_startfetch() */ /* vbf_stp_startfetch() */
v_b_f [ v_b_f [
shape=record 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_f:fetch:s -> v_b_hdrs [style=bold]
v_b_hdrs [ label="send bereq,\nread beresp (headers)"] v_b_hdrs [ label="send bereq,\nread beresp (headers)"]
v_b_hdrs -> v_b_r [style=bold] v_b_hdrs -> v_b_r [style=bold]
v_b_hdrs -> v_b_e v_b_hdrs -> v_b_e
v_b_r [ v_b_r [
shape=record 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:retry -> v_b_r_retry [color=purple]
v_b_r:max -> v_b_e v_b_r:max -> v_b_e
v_b_r:fetch_304:s -> vbf_stp_condfetch v_b_r:fetch_304:s -> vbf_stp_condfetch
...@@ -90,8 +92,8 @@ digraph cache_fetch { ...@@ -90,8 +92,8 @@ digraph cache_fetch {
] ]
vbf_stp_condfetch:ok:s -> vbf_stp_fetchend vbf_stp_condfetch:ok:s -> vbf_stp_fetchend
error [shape=plaintext] fail [shape=plaintext]
error -> FETCH_FAIL fail -> FETCH_FAIL
/* vbf_stp_error */ /* vbf_stp_error */
v_b_e [ v_b_e [
......
This diff is collapsed.
...@@ -356,6 +356,11 @@ The `vcl_backend_fetch` subroutine may terminate with calling ...@@ -356,6 +356,11 @@ The `vcl_backend_fetch` subroutine may terminate with calling
``fetch`` ``fetch``
Fetch the object from the backend. Fetch the object from the backend.
``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` Before calling `vcl_backend_fetch`, Varnish core prepares the `bereq`
backend request as follows: backend request as follows:
...@@ -417,6 +422,11 @@ The `vcl_backend_response` subroutine may terminate with calling ...@@ -417,6 +422,11 @@ The `vcl_backend_response` subroutine may terminate with calling
lookups hitting this object will be turned into passed transactions, lookups hitting this object will be turned into passed transactions,
as if ``vcl_recv`` had returned ``pass``. 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 304 handling
~~~~~~~~~~~~ ~~~~~~~~~~~~
......
...@@ -129,11 +129,11 @@ returns = ( ...@@ -129,11 +129,11 @@ returns = (
('backend_fetch', ('backend_fetch',
"B", "B",
('fail', 'fetch', 'abandon') ('fail', 'fetch', 'abandon', 'error')
), ),
('backend_response', ('backend_response',
"B", "B",
('fail', 'deliver', 'retry', 'abandon', 'pass') ('fail', 'deliver', 'retry', 'abandon', 'pass', 'error')
), ),
('backend_error', ('backend_error',
"B", "B",
......
...@@ -335,7 +335,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym) ...@@ -335,7 +335,7 @@ vcc_act_return(struct vcc *tl, struct token *t, struct symbol *sym)
vcc_ProcAction(tl->curproc, hand, tl->t); vcc_ProcAction(tl->curproc, hand, tl->t);
vcc_NextToken(tl); vcc_NextToken(tl);
if (tl->t->tok == '(') { if (tl->t->tok == '(') {
if (hand == VCL_RET_SYNTH) if (hand == VCL_RET_SYNTH || hand == VCL_RET_ERROR)
vcc_act_return_synth(tl); vcc_act_return_synth(tl);
else if (hand == VCL_RET_VCL) else if (hand == VCL_RET_VCL)
vcc_act_return_vcl(tl); 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