diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c index 5f5ebb53579..48075d937f6 100644 --- a/bin/varnishd/cache/cache_backend.c +++ b/bin/varnishd/cache/cache_backend.c @@ -178,7 +178,8 @@ vbe_dir_finish(const struct director *d, struct worker *wrk, CAST_OBJ_NOTNULL(vtp, bo->htc->priv, VTP_MAGIC); bo->htc->priv = NULL; if (vtp->state != VTP_STATE_USED) - assert(bo->htc->doclose == SC_TX_PIPE); + assert(bo->htc->doclose == SC_TX_PIPE || + bo->htc->doclose == SC_RX_TIMEOUT); if (bo->htc->doclose != SC_NULL || bp->proxy_header != 0) { VSLb(bo->vsl, SLT_BackendClose, "%d %s", vtp->fd, bp->director->display_name); @@ -233,16 +234,24 @@ vbe_dir_gethdrs(const struct director *d, struct worker *wrk, i = V1F_SendReq(wrk, bo, &bo->acct.bereq_hdrbytes, 0); - if (vtp->state != VTP_STATE_USED) - VTP_Wait(wrk, vtp); - - assert(vtp->state == VTP_STATE_USED); + if (vtp->state != VTP_STATE_USED) { + if (VTP_Wait(wrk, vtp, VTIM_real() + + bo->htc->first_byte_timeout) != 0) { + bo->htc->doclose = SC_RX_TIMEOUT; + VSLb(bo->vsl, SLT_FetchError, + "Timed out reusing backend connection"); + extrachance = 0; + } + } - if (i == 0) - i = V1F_FetchRespHdr(bo); - if (i == 0) { - AN(bo->htc->priv); - return (0); + if (bo->htc->doclose == SC_NULL) { + assert(vtp->state == VTP_STATE_USED); + if (i == 0) + i = V1F_FetchRespHdr(bo); + if (i == 0) { + AN(bo->htc->priv); + return (0); + } } /* @@ -252,7 +261,7 @@ vbe_dir_gethdrs(const struct director *d, struct worker *wrk, */ vbe_dir_finish(d, wrk, bo); AZ(bo->htc); - if (i < 0) + if (i < 0 || extrachance == 0) break; if (bo->req != NULL && bo->req->req_body_status != REQ_BODY_NONE && diff --git a/bin/varnishd/cache/cache_tcp_pool.c b/bin/varnishd/cache/cache_tcp_pool.c index 855eb0c9235..18adad3a28e 100644 --- a/bin/varnishd/cache/cache_tcp_pool.c +++ b/bin/varnishd/cache/cache_tcp_pool.c @@ -31,6 +31,7 @@ #include "config.h" +#include #include #include "cache_varnishd.h" @@ -416,10 +417,11 @@ VTP_Get(struct tcp_pool *tp, double tmo, struct worker *wrk, /*-------------------------------------------------------------------- */ -void -VTP_Wait(struct worker *wrk, struct vtp *vtp) +int +VTP_Wait(struct worker *wrk, struct vtp *vtp, double tmo) { struct tcp_pool *tp; + int r; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(vtp, VTP_MAGIC); @@ -427,11 +429,21 @@ VTP_Wait(struct worker *wrk, struct vtp *vtp) CHECK_OBJ_NOTNULL(tp, TCP_POOL_MAGIC); assert(vtp->cond == &wrk->cond); Lck_Lock(&tp->mtx); - while (vtp->state == VTP_STATE_STOLEN) - AZ(Lck_CondWait(&wrk->cond, &tp->mtx, 0)); + while (vtp->state == VTP_STATE_STOLEN) { + r = Lck_CondWait(&wrk->cond, &tp->mtx, tmo); + if (r != 0) { + if (r == EINTR) + continue; + assert(r == ETIMEDOUT); + Lck_Unlock(&tp->mtx); + return (1); + } + } assert(vtp->state == VTP_STATE_USED); vtp->cond = NULL; Lck_Unlock(&tp->mtx); + + return (0); } /*--------------------------------------------------------------------*/ diff --git a/bin/varnishd/cache/cache_tcp_pool.h b/bin/varnishd/cache/cache_tcp_pool.h index 4dbc12f1e16..d9d3c545a2d 100644 --- a/bin/varnishd/cache/cache_tcp_pool.h +++ b/bin/varnishd/cache/cache_tcp_pool.h @@ -91,7 +91,7 @@ struct vtp *VTP_Get(struct tcp_pool *, double tmo, struct worker *, * Get a (possibly) recycled connection. */ -void VTP_Wait(struct worker *, struct vtp *); +int VTP_Wait(struct worker *, struct vtp *, double tmo); /* * If the connection was recycled (state != VTP_STATE_USED) call this * function before attempting to receive on the connection. diff --git a/bin/varnishtest/tests/r01772.vtc b/bin/varnishtest/tests/r01772.vtc new file mode 100644 index 00000000000..93c5e1b4b2d --- /dev/null +++ b/bin/varnishtest/tests/r01772.vtc @@ -0,0 +1,24 @@ +varnishtest "#1772: Honor first_byte_timeout on a recycled connection" + +server s1 { + rxreq + expect req.url == "/first" + txresp + + rxreq + expect req.url == "/second" + delay 2 + txresp +} -start + +varnish v1 -arg "-p first_byte_timeout=1" -vcl+backend {} -start + +client c1 { + txreq -url "/first" + rxresp + expect resp.status == 200 + + txreq -url "/second" + rxresp + expect resp.status == 503 +} -run