Commit b253bf9c authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

When a streaming delivery of a pass object is terminated prematurely,

we cannot just throw the storage away, we have to wait for the
fetch-thread to go away, possibly in response to a new "abandon"
signal.

Spotted first by:	scoof
Fixes	#1391
parent 781fb81d
......@@ -573,6 +573,7 @@ struct busyobj {
/* do_pass is our intent, uncacheable is the result */
unsigned do_pass;
unsigned uncacheable;
unsigned abandon;
/* Timeouts */
double connect_timeout;
......
......@@ -201,6 +201,19 @@ VFP_Fetch_Body(struct busyobj *bo, ssize_t est)
}
do {
if (bo->abandon) {
/*
* A pass object and delivery was terminted
* We don't fail the fetch, in order for hit-for-pass
* objects to be created.
*/
AN(bo->fetch_objcore->flags & OC_F_PASS);
VSLb(bo->vsl, SLT_FetchError,
"Pass delivery abandonned");
vfps = VFP_END;
bo->should_close = 1;
break;
}
assert(bo->state != BOS_FAILED);
if (st == NULL) {
st = VFP_GetStorage(bo, est);
......
......@@ -170,11 +170,13 @@ v1d_WriteDirObj(struct req *req)
while (1) {
ois = ObjIter(oi, &ptr, &len);
if (ois == OIS_DATA && !VDP_bytes(req, VDP_NULL, ptr, len))
continue;
if (ois == OIS_STREAM && !VDP_bytes(req, VDP_FLUSH, ptr, len))
continue;
break;
if (ois == OIS_DONE) {
AZ(len);
break;
}
if (VDP_bytes(req,
ois == OIS_DATA ? VDP_NULL : VDP_FLUSH, ptr, len))
break;
}
(void)VDP_bytes(req, VDP_FINISH, NULL, 0);
ObjIterEnd(&oi);
......
......@@ -126,8 +126,11 @@ ObjIterEnd(struct objiter **oi)
AN(oi);
CHECK_OBJ_NOTNULL((*oi), OBJITER_MAGIC);
CHECK_OBJ_NOTNULL((*oi)->obj, OBJECT_MAGIC);
if ((*oi)->bo != NULL)
if ((*oi)->bo != NULL) {
if ((*oi)->obj->objcore->flags & OC_F_PASS)
(*oi)->bo->abandon = 1;
VBO_DerefBusyObj((*oi)->wrk, &(*oi)->bo);
}
FREE_OBJ((*oi));
*oi = NULL;
}
......@@ -159,9 +159,16 @@ cnt_deliver(struct worker *wrk, struct req *req)
V1D_Deliver(req);
/* No point in saving the body if it is hit-for-pass */
if (req->obj->objcore->flags & OC_F_PASS)
if (req->obj->objcore->flags & OC_F_PASS) {
/*
* No point in saving the body if it is hit-for-pass,
* but we can't yank it until the fetching thread has
* finished/abandonned also.
*/
while (req->obj->objcore->busyobj != NULL)
(void)usleep(100000);
STV_Freestore(req->obj);
}
assert(WRW_IsReleased(wrk));
VSLb(req->vsl, SLT_Debug, "XXX REF %d", req->obj->objcore->refcnt);
......
varnishtest "client abandoning hit-for-pass"
server s1 {
rxreq
txresp -nolen -hdr "Transfer-Encoding: chunked" -hdr "Set-Cookie: foo=bar"
chunked "foo"
sema r1 sync 2
chunked "bar"
delay .1
chunkedlen 64
delay .1
chunkedlen 64
chunkedlen 0
} -start
varnish v1 -vcl+backend {
} -start
client c1 {
txreq
rxhdrs
rxchunk
sema r1 sync 2
} -run
delay 2
server s1 {
rxreq
txresp
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
} -run
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