vfp_nop_begin(struct busyobj *bo, size_t estimate)
{

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	if (estimate > 0)
		(void)VFP_GetStorage(bo, estimate);
}
Esempio n. 2
0
int
VGZ_ObufStorage(struct busyobj *bo, struct vgz *vg)
{
	struct storage *st;

	st = VFP_GetStorage(bo, 0);
	if (st == NULL)
		return (-1);

	VGZ_Obuf(vg, st->ptr + st->len, st->space - st->len);

	return (0);
}
Esempio n. 3
0
static ssize_t
vfp_vep_callback(struct vfp_ctx *vc, void *priv, ssize_t l, enum vgz_flag flg)
{
	struct vef_priv *vef;
	ssize_t dl;
	const void *dp;
	uint8_t *ptr;
	int i;

	CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
	CAST_OBJ_NOTNULL(vef, priv, VEF_MAGIC);
	assert(l >= 0);

	if (vef->error) {
		vef->tot += l;
		return (vef->tot);
	}

	/*
	 * l == 0 is valid when 'flg' calls for action, but in the
	 * normal case we can just ignore a l==0 request.
	 * (It would cause Z_BUF_ERROR anyway)
	 */
	if (l == 0 && flg == VGZ_NORMAL)
		return (vef->tot);

	CHECK_OBJ_NOTNULL(vc->bo, BUSYOBJ_MAGIC);
	VGZ_Ibuf(vef->vgz, vef->ibuf_o, l);
	do {
		dl = 0;
		if (VFP_GetStorage(vc, &dl, &ptr) != VFP_OK) {
			vef->error = ENOMEM;
			vef->tot += l;
			return (vef->tot);
		}
		VGZ_Obuf(vef->vgz, ptr, dl);
		i = VGZ_Gzip(vef->vgz, &dp, &dl, flg);
		VGZ_UpdateObj(vc, vef->vgz, VUA_UPDATE);
		if (dl > 0) {
			vef->tot += dl;
			VFP_Extend(vc, dl);
		}
	} while (i != VGZ_ERROR &&
	    (!VGZ_IbufEmpty(vef->vgz) || VGZ_ObufFull(vef->vgz)));
	assert(i == VGZ_ERROR || VGZ_IbufEmpty(vef->vgz));
	vef->ibuf_o += l;
	return (vef->tot);
}
Esempio n. 4
0
static ssize_t
vfp_vep_callback(struct busyobj *bo, void *priv, ssize_t l, enum vgz_flag flg)
{
    struct vef_priv *vef;
    size_t dl;
    const void *dp;
    struct storage *st;
    int i;

    CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
    CAST_OBJ_NOTNULL(vef, priv, VEF_MAGIC);
    assert(l >= 0);

    if (vef->error) {
        vef->tot += l;
        return (vef->tot);
    }

    /*
     * l == 0 is valid when 'flg' calls for action, but in the
     * normal case we can just ignore a l==0 request.
     * (It would cause Z_BUF_ERROR anyway)
     */
    if (l == 0 && flg == VGZ_NORMAL)
        return (vef->tot);

    VGZ_Ibuf(vef->vgz, vef->ibuf_o, l);
    do {
        st = VFP_GetStorage(bo, 0);
        if (st == NULL) {
            vef->error = ENOMEM;
            vef->tot += l;
            return (vef->tot);
        }
        VGZ_Obuf(vef->vgz, st->ptr + st->len, st->space - st->len);
        i = VGZ_Gzip(vef->vgz, &dp, &dl, flg);
        vef->tot += dl;
        VBO_extend(bo, dl);
    } while (i != VGZ_ERROR &&
             (!VGZ_IbufEmpty(vef->vgz) || VGZ_ObufFull(vef->vgz)));
    assert(i == VGZ_ERROR || VGZ_IbufEmpty(vef->vgz));
    vef->ibuf_o += l;
    return (vef->tot);
}
Esempio n. 5
0
vfp_testgzip_bytes(struct busyobj *bo, struct http_conn *htc, ssize_t bytes)
{
	struct vgz *vg;
	ssize_t l, wl;
	int i = -100;
	size_t dl;
	const void *dp;
	struct storage *st;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	vg = bo->vgz_rx;
	CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
	AZ(vg->vz.avail_in);
	while (bytes > 0) {
		st = VFP_GetStorage(bo, 0);
		if (st == NULL)
			return(-1);
		l = st->space - st->len;
		if (l > bytes)
			l = bytes;
		wl = htc->read(htc, st->ptr + st->len, l);
		if (wl <= 0)
			return (wl);
		bytes -= wl;
		VGZ_Ibuf(vg, st->ptr + st->len, wl);
		VBO_extend(bo, wl);

		while (!VGZ_IbufEmpty(vg)) {
			VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
			i = VGZ_Gunzip(vg, &dp, &dl);
			if (i == VGZ_END && !VGZ_IbufEmpty(vg))
				return(VFP_Error(bo, "Junk after gzip data"));
			if (i != VGZ_OK && i != VGZ_END)
				return(VFP_Error2(bo,
				    "Invalid Gzip data", vg->vz.msg));
		}
	}
	assert(i == VGZ_OK || i == VGZ_END);
	return (1);
}
vfp_nop_bytes(struct busyobj *bo, struct http_conn *htc, ssize_t bytes)
{
	ssize_t l, wl;
	struct storage *st;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	while (bytes > 0) {
		st = VFP_GetStorage(bo, 0);
		if (st == NULL)
			return(-1);
		l = st->space - st->len;
		if (l > bytes)
			l = bytes;
		wl = HTTP1_Read(htc, st->ptr + st->len, l);
		if (wl <= 0)
			return (wl);
		st->len += wl;
		VBO_extend(bo, wl);
		bytes -= wl;
	}
	return (1);
}
Esempio n. 7
0
static int
vfp_esi_bytes_uu(struct busyobj *bo, const struct vef_priv *vef,
    struct http_conn *htc, ssize_t bytes)
{
	ssize_t wl;
	struct storage *st;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	CHECK_OBJ_NOTNULL(vef, VEF_MAGIC);

	while (bytes > 0) {
		st = VFP_GetStorage(bo, 0);
		if (st == NULL)
			return (-1);
		wl = vef_read(htc,
		    st->ptr + st->len, st->space - st->len, bytes);
		if (wl <= 0)
			return (wl);
		VEP_Parse(bo, (const char *)st->ptr + st->len, wl);
		VBO_extend(bo, wl);
		bytes -= wl;
	}
	return (1);
}
Esempio n. 8
0
static int
vbf_objiterator(void *priv, int flush, const void *ptr, ssize_t len)
{
	struct busyobj *bo;
	ssize_t l;
	const uint8_t *ps = ptr;
	uint8_t *pd;

	(void)flush;
	CAST_OBJ_NOTNULL(bo, priv, BUSYOBJ_MAGIC);

	while (len > 0) {
		l = len;
		if (VFP_GetStorage(bo->vfc, &l, &pd) != VFP_OK)
			return (1);
		if (len < l)
			l = len;
		memcpy(pd, ps, l);
		VFP_Extend(bo->vfc, l);
		ps += l;
		len -= l;
	}
	return (0);
}
Esempio n. 9
0
static enum fetch_step
vbf_stp_error(struct worker *wrk, struct busyobj *bo)
{
	ssize_t l, ll, o;
	double now;
	uint8_t *ptr;
	struct vsb *synth_body;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	CHECK_OBJ_NOTNULL(bo->fetch_objcore, OBJCORE_MAGIC);
	AN(bo->fetch_objcore->flags & OC_F_BUSY);
	assert(bo->director_state == DIR_S_NULL);

	wrk->stats->fetch_failed++;

	now = W_TIM_real(wrk);
	VSLb_ts_busyobj(bo, "Error", now);

	if (bo->fetch_objcore->stobj->stevedore != NULL)
		ObjFreeObj(bo->wrk, bo->fetch_objcore);

	if (bo->storage == NULL)
		bo->storage = STV_next();

	// 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");
	http_TimeHeader(bo->beresp, "Date: ", now);
	http_SetHeader(bo->beresp, "Server: Varnish");

	bo->fetch_objcore->t_origin = now;
	if (!VTAILQ_EMPTY(&bo->fetch_objcore->objhead->waitinglist)) {
		/*
		 * If there is a waitinglist, it means that there is no
		 * grace-able object, so cache the error return for a
		 * short time, so the waiting list can drain, rather than
		 * each objcore on the waiting list sequentially attempt
		 * to fetch from the backend.
		 */
		bo->fetch_objcore->ttl = 1;
		bo->fetch_objcore->grace = 5;
		bo->fetch_objcore->keep = 5;
	} else {
		bo->fetch_objcore->ttl = 0;
		bo->fetch_objcore->grace = 0;
		bo->fetch_objcore->keep = 0;
	}

	synth_body = VSB_new_auto();
	AN(synth_body);

	VCL_backend_error_method(bo->vcl, wrk, NULL, bo, synth_body);

	AZ(VSB_finish(synth_body));

	if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL) {
		VSB_destroy(&synth_body);
		return (F_STP_FAIL);
	}

	if (wrk->handling == VCL_RET_RETRY) {
		VSB_destroy(&synth_body);
		if (bo->retries++ < cache_param->max_retries)
			return (F_STP_RETRY);
		VSLb(bo->vsl, SLT_VCL_Error, "Too many retries, failing");
		return (F_STP_FAIL);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	assert(bo->vfc->wrk == bo->wrk);
	assert(bo->vfc->oc == bo->fetch_objcore);
	assert(bo->vfc->resp == bo->beresp);
	assert(bo->vfc->req == bo->bereq);

	if (vbf_beresp2obj(bo)) {
		(void)VFP_Error(bo->vfc, "Could not get storage");
		VSB_destroy(&synth_body);
		return (F_STP_FAIL);
	}

	ll = VSB_len(synth_body);
	o = 0;
	while (ll > 0) {
		l = ll;
		if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK)
			break;
		if (l > ll)
			l = ll;
		memcpy(ptr, VSB_data(synth_body) + o, l);
		VFP_Extend(bo->vfc, l);
		ll -= l;
		o += l;
	}
	AZ(ObjSetU64(wrk, bo->fetch_objcore, OA_LEN, o));
	VSB_destroy(&synth_body);
	HSH_Unbusy(wrk, bo->fetch_objcore);
	ObjSetState(wrk, bo->fetch_objcore, BOS_FINISHED);
	return (F_STP_DONE);
}
Esempio n. 10
0
static enum fetch_step
vbf_stp_fetchbody(struct worker *wrk, struct busyobj *bo)
{
	ssize_t l;
	uint8_t *ptr;
	enum vfp_status vfps = VFP_ERROR;
	ssize_t est;
	struct vfp_ctx *vfc;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	vfc = bo->vfc;
	CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);

	AN(vfc->vfp_nxt);

	est = bo->htc->content_length;
	if (est < 0)
		est = 0;

	do {
		if (vfc->oc->flags & OC_F_ABANDON) {
			/*
			 * A pass object and delivery was terminated
			 * We don't fail the fetch, in order for hit-for-pass
			 * objects to be created.
			 */
			AN(vfc->oc->flags & OC_F_PASS);
			VSLb(wrk->vsl, SLT_Debug,
			    "Fetch: Pass delivery abandoned");
			bo->htc->doclose = SC_RX_BODY;
			break;
		}
		AZ(vfc->failed);
		l = est;
		assert(l >= 0);
		if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK) {
			bo->htc->doclose = SC_RX_BODY;
			break;
		}

		AZ(vfc->failed);
		vfps = VFP_Suck(vfc, ptr, &l);
		if (l > 0 && vfps != VFP_ERROR) {
			bo->acct.beresp_bodybytes += l;
			VFP_Extend(vfc, l);
			if (est >= l)
				est -= l;
			else
				est = 0;
		}
	} while (vfps == VFP_OK);

	if (vfc->failed) {
		(void)VFP_Error(vfc, "Fetch pipeline failed to process");
		bo->htc->doclose = SC_RX_BODY;
		VFP_Close(vfc);
		VDI_Finish(wrk, bo);
		if (!bo->do_stream) {
			assert(bo->fetch_objcore->boc->state < BOS_STREAM);
			// XXX: doclose = ?
			return (F_STP_ERROR);
		} else {
			wrk->stats->fetch_failed++;
			return (F_STP_FAIL);
		}
	}

	ObjTrimStore(wrk, vfc->oc);
	return (F_STP_FETCHEND);
}
Esempio n. 11
0
static enum fetch_step
vbf_stp_error(struct worker *wrk, struct busyobj *bo)
{
	ssize_t l, ll, o;
	double now;
	uint8_t *ptr;
	struct vsb *synth_body;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	CHECK_OBJ_NOTNULL(bo->fetch_objcore, OBJCORE_MAGIC);
	assert(bo->director_state == DIR_S_NULL);

	if(bo->fetch_objcore->stobj->stevedore != NULL)
		ObjFreeObj(bo->wrk, bo->fetch_objcore);

	now = W_TIM_real(wrk);
	VSLb_ts_busyobj(bo, "Error", now);

	AN(bo->fetch_objcore->flags & OC_F_BUSY);

	synth_body = VSB_new_auto();
	AN(synth_body);

	// 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");
	http_TimeHeader(bo->beresp, "Date: ", now);
	http_SetHeader(bo->beresp, "Server: Varnish");

	EXP_Clr(&bo->fetch_objcore->exp);
	bo->fetch_objcore->exp.t_origin = bo->t_prev;

	VCL_backend_error_method(bo->vcl, wrk, NULL, bo, synth_body);

	AZ(VSB_finish(synth_body));

	if (wrk->handling == VCL_RET_RETRY ||
	    wrk->handling == VCL_RET_ABANDON) {
		VSB_delete(synth_body);

		if (bo->director_state != DIR_S_NULL) {
			bo->htc->doclose = SC_RESP_CLOSE;
			VDI_Finish(bo->wrk, bo);
		}

		if (wrk->handling == VCL_RET_RETRY) {
			if (bo->retries++ < cache_param->max_retries)
				return (F_STP_RETRY);
			VSLb(bo->vsl, SLT_VCL_Error,
			    "Too many retries, delivering 503");
		}

		return (F_STP_FAIL);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	bo->vfc->bo = bo;
	bo->vfc->wrk = bo->wrk;
	bo->vfc->oc = bo->fetch_objcore;
	bo->vfc->http = bo->beresp;
	bo->vfc->esi_req = bo->bereq;

	if (vbf_beresp2obj(bo)) {
		VSB_delete(synth_body);
		return (F_STP_FAIL);
	}

	ll = VSB_len(synth_body);
	o = 0;
	while (ll > 0) {
		l = ll;
		if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK)
			break;
		memcpy(ptr, VSB_data(synth_body) + o, l);
		VBO_extend(bo, l);
		ll -= l;
		o += l;
	}
	VSB_delete(synth_body);

	HSH_Unbusy(wrk, bo->fetch_objcore);
	VBO_setstate(bo, BOS_FINISHED);
	return (F_STP_DONE);
}
Esempio n. 12
0
static enum fetch_step
vbf_stp_condfetch(struct worker *wrk, struct busyobj *bo)
{
	void *oi;
	void *sp;
	ssize_t sl, al, l;
	uint8_t *ptr;
	enum objiter_status ois;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	AZ(vbf_beresp2obj(bo));

	if (ObjGetattr(bo->wrk, bo->stale_oc, OA_ESIDATA, NULL) != NULL)
		AZ(ObjCopyAttr(bo->wrk, bo->fetch_objcore, bo->stale_oc,
		    OA_ESIDATA));

	AZ(ObjCopyAttr(bo->wrk, bo->fetch_objcore, bo->stale_oc, OA_FLAGS));
	AZ(ObjCopyAttr(bo->wrk, bo->fetch_objcore, bo->stale_oc, OA_GZIPBITS));

	if (bo->do_stream) {
		HSH_Unbusy(wrk, bo->fetch_objcore);
		VBO_setstate(bo, BOS_STREAM);
	}

	al = 0;
	oi = ObjIterBegin(wrk, bo->stale_oc);
	do {
		ois = ObjIter(bo->stale_oc, oi, &sp, &sl);
		if (ois == OIS_ERROR)
			(void)VFP_Error(bo->vfc, "Template object failed");
		while (sl > 0) {
			l = ObjGetLen(bo->wrk, bo->stale_oc) - al;
			assert(l > 0);
			if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK)
				break;
			if (sl < l)
				l = sl;
			memcpy(ptr, sp, l);
			VBO_extend(bo, l);
			al += l;
			sp = (char *)sp + l;
			sl -= l;
		}
	} while (!bo->vfc->failed && (ois == OIS_DATA || ois == OIS_STREAM));
	ObjIterEnd(bo->stale_oc, &oi);
	if (bo->stale_oc->flags & OC_F_FAILED)
		(void)VFP_Error(bo->vfc, "Template object failed");
	if (bo->vfc->failed) {
		VDI_Finish(bo->wrk, bo);
		return (F_STP_FAIL);
	}

	if (!bo->do_stream)
		HSH_Unbusy(wrk, bo->fetch_objcore);

	assert(ObjGetLen(bo->wrk, bo->fetch_objcore) == al);
	EXP_Rearm(bo->stale_oc, bo->stale_oc->exp.t_origin, 0, 0, 0);

	/* Recycle the backend connection before setting BOS_FINISHED to
	   give predictable backend reuse behavior for varnishtest */
	VDI_Finish(bo->wrk, bo);

	VBO_setstate(bo, BOS_FINISHED);
	VSLb_ts_busyobj(bo, "BerespBody", W_TIM_real(wrk));
	return (F_STP_DONE);
}
Esempio n. 13
0
static void
vbf_fetch_body_helper(struct busyobj *bo)
{
	ssize_t l;
	uint8_t *ptr;
	enum vfp_status vfps = VFP_ERROR;
	ssize_t est;
	struct vfp_ctx *vfc;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	vfc = bo->vfc;
	CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC);

	AN(vfc->vfp_nxt);

	est = bo->htc->content_length;
	if (est < 0)
		est = 0;

	do {
		if (bo->abandon) {
			/*
			 * A pass object and delivery was terminated
			 * We don't fail the fetch, in order for hit-for-pass
			 * objects to be created.
			 */
			AN(vfc->oc->flags & OC_F_PASS);
			VSLb(vfc->wrk->vsl, SLT_FetchError,
			    "Pass delivery abandoned");
			vfps = VFP_END;
			bo->htc->doclose = SC_RX_BODY;
			break;
		}
		AZ(vfc->failed);
		l = est;
		assert(l >= 0);
		if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK) {
			bo->htc->doclose = SC_RX_BODY;
			break;
		}

		AZ(vfc->failed);
		vfps = VFP_Suck(vfc, ptr, &l);
		if (l > 0 && vfps != VFP_ERROR) {
			bo->acct.beresp_bodybytes += l;
			VBO_extend(bo, l);
			if (est >= l)
				est -= l;
			else
				est = 0;
		}
	} while (vfps == VFP_OK);

	VFP_Close(vfc);

	if (vfps == VFP_ERROR) {
		AN(vfc->failed);
		(void)VFP_Error(vfc, "Fetch pipeline failed to process");
		bo->htc->doclose = SC_RX_BODY;
	}

	if (!bo->do_stream)
		ObjTrimStore(bo->wrk, vfc->oc);
}
Esempio n. 14
0
void
VFP_Fetch_Body(struct busyobj *bo, ssize_t est)
{
	ssize_t l;
	enum vfp_status vfps = VFP_ERROR;
	struct storage *st = NULL;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	AN(bo->vfp_nxt);

	if (est < 0)
		est = 0;

	if (vfp_suck_init(bo) != VFP_OK) {
		(void)VFP_Error(bo, "Fetch Pipeline failed to initialize");
		bo->should_close = 1;
		return;
	}

	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 abandoned");
			vfps = VFP_END;
			bo->should_close = 1;
			break;
		}
		AZ(bo->failed);
		if (st == NULL) {
			st = VFP_GetStorage(bo, est);
			est = 0;
		}
		if (st == NULL) {
			bo->should_close = 1;
			(void)VFP_Error(bo, "Out of storage");
			break;
		}

		CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
		assert(st == VTAILQ_LAST(&bo->fetch_obj->store, storagehead));
		l = st->space - st->len;
		AZ(bo->failed);
		vfps = VFP_Suck(bo, st->ptr + st->len, &l);
		if (l > 0 && vfps != VFP_ERROR) {
			AZ(VTAILQ_EMPTY(&bo->fetch_obj->store));
			VBO_extend(bo, l);
		}
		if (st->len == st->space)
			st = NULL;
	} while (vfps == VFP_OK);

	if (vfps == VFP_ERROR) {
		AN(bo->failed);
		(void)VFP_Error(bo, "Fetch Pipeline failed to process");
		bo->should_close = 1;
	}

	vfp_suck_fini(bo);

	/*
	 * Trim or delete the last segment, if any
	 */

	st = VTAILQ_LAST(&bo->fetch_obj->store, storagehead);
	/* XXX: Temporary:  Only trim if we are not streaming */
	if (st != NULL && !bo->do_stream) {
		/* None of this this is safe under streaming */
		if (st->len == 0) {
			VTAILQ_REMOVE(&bo->fetch_obj->store, st, list);
			STV_free(st);
		} else if (st->len < st->space) {
			STV_trim(st, st->len, 1);
		}
	}
}
Esempio n. 15
0
static enum fetch_step
vbf_stp_error(struct worker *wrk, struct busyobj *bo)
{
	ssize_t l, ll, o;
	double now;
	uint8_t *ptr;
	char time_str[VTIM_FORMAT_SIZE];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	assert(bo->director_state == DIR_S_NULL);

	now = W_TIM_real(wrk);
	VSLb_ts_busyobj(bo, "Error", now);

	AN(bo->fetch_objcore->flags & OC_F_BUSY);

	AZ(bo->synth_body);
	bo->synth_body = VSB_new_auto();
	AN(bo->synth_body);

	// 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");
	VTIM_format(now, time_str);
	http_PrintfHeader(bo->beresp, "Date: %s", time_str);
	http_SetHeader(bo->beresp, "Server: Varnish");

	bo->fetch_objcore->exp.t_origin = bo->t_prev;
	bo->fetch_objcore->exp.ttl = 0;
	bo->fetch_objcore->exp.grace = 0;
	bo->fetch_objcore->exp.keep = 0;

	VCL_backend_error_method(bo->vcl, wrk, NULL, bo, bo->bereq->ws);

	AZ(VSB_finish(bo->synth_body));

	if (wrk->handling == VCL_RET_RETRY) {
		VSB_delete(bo->synth_body);
		bo->synth_body = NULL;
		if (bo->retries++ < cache_param->max_retries)
			return (F_STP_RETRY);
		return (F_STP_FAIL);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	VFP_Setup(bo->vfc);
	bo->vfc->bo = bo;
	bo->vfc->wrk = bo->wrk;
	bo->vfc->oc = bo->fetch_objcore;
	bo->vfc->http = bo->beresp;
	bo->vfc->esi_req = bo->bereq;

	if (vbf_beresp2obj(bo))
		return (F_STP_FAIL);

	ll = VSB_len(bo->synth_body);
	o = 0;
	while (ll > 0) {
		l = ll;
		if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK)
			break;
		memcpy(ptr, VSB_data(bo->synth_body) + o, l);
		VBO_extend(bo, l);
		ll -= l;
		o += l;
	}
	VSB_delete(bo->synth_body);
	bo->synth_body = NULL;

	HSH_Unbusy(wrk, bo->fetch_objcore);
	VBO_setstate(bo, BOS_FINISHED);
	return (F_STP_DONE);
}
Esempio n. 16
0
ssize_t
VRB_Cache(struct req *req, ssize_t maxsize)
{
	ssize_t l, yet;
	struct vfp_ctx *vfc;
	uint8_t *ptr;
	enum vfp_status vfps = VFP_ERROR;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

	assert (req->req_step == R_STP_RECV);
	switch(req->req_body_status) {
	case REQ_BODY_CACHED:
		return (req->req_bodybytes);
	case REQ_BODY_FAIL:
		return (-1);
	case REQ_BODY_NONE:
		return (0);
	case REQ_BODY_WITHOUT_LEN:
	case REQ_BODY_WITH_LEN:
		break;
	default:
		WRONG("Wrong req_body_status in VRB_Cache()");
	}

	CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC);
	vfc = req->htc->vfc;
	VFP_Setup(vfc);
	vfc->wrk = req->wrk;

	if (req->htc->content_length > maxsize) {
		req->req_body_status = REQ_BODY_FAIL;
		(void)VFP_Error(vfc, "Request body too big to cache");
		return (-1);
	}

	req->body_oc = HSH_Private(req->wrk);
	AN(req->body_oc);
	XXXAN(STV_NewObject(req->wrk, req->body_oc, TRANSIENT_STORAGE, 8));

	vfc->http = req->http;
	vfc->oc = req->body_oc;
	V1F_Setup_Fetch(vfc, req->htc);

	if (VFP_Open(vfc) < 0) {
		req->req_body_status = REQ_BODY_FAIL;
		return (-1);
	}

	AZ(req->req_bodybytes);
	AN(req->htc);
	yet = req->htc->content_length;
	if (yet < 0)
		yet = 0;
	do {
		AZ(vfc->failed);
		if (req->req_bodybytes > maxsize) {
			req->req_body_status = REQ_BODY_FAIL;
			(void)VFP_Error(vfc, "Request body too big to cache");
			VFP_Close(vfc);
			return(-1);
		}
		l = yet;
		if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK)
			break;
		AZ(vfc->failed);
		AN(ptr);
		AN(l);
		vfps = VFP_Suck(vfc, ptr, &l);
		if (l > 0 && vfps != VFP_ERROR) {
			req->req_bodybytes += l;
			req->acct.req_bodybytes += l;
			if (yet >= l)
				yet -= l;
			ObjExtend(req->wrk, req->body_oc, l);
		}

	} while (vfps == VFP_OK);
	VFP_Close(vfc);
	ObjTrimStore(req->wrk, req->body_oc);

	/* XXX: check missing:
	    if (req->htc->content_length >= 0)
		MUSTBE (req->req_bodybytes == req->htc->content_length);
	*/

	if (vfps == VFP_END) {
		assert(req->req_bodybytes >= 0);
		if (req->req_bodybytes != req->htc->content_length) {
			/* We must update also the "pristine" req.* copy */
			http_Unset(req->http0, H_Content_Length);
			http_Unset(req->http0, H_Transfer_Encoding);
			http_PrintfHeader(req->http0, "Content-Length: %ju",
			    (uintmax_t)req->req_bodybytes);

			http_Unset(req->http, H_Content_Length);
			http_Unset(req->http, H_Transfer_Encoding);
			http_PrintfHeader(req->http, "Content-Length: %ju",
			    (uintmax_t)req->req_bodybytes);
		}

		req->req_body_status = REQ_BODY_CACHED;
	} else {
		req->req_body_status = REQ_BODY_FAIL;
	}
	VSLb_ts_req(req, "ReqBody", VTIM_real());
	return (vfps == VFP_END ? req->req_bodybytes : -1);
}
Esempio n. 17
0
static enum fetch_step
vbf_stp_condfetch(struct worker *wrk, struct busyobj *bo)
{
	unsigned l;
	uint16_t nhttp;
	struct object *obj;
	struct objiter *oi;
	void *sp;
	ssize_t sl, al, tl, vl;
	struct storage *st;
	enum objiter_status ois;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	l = 0;
	if (bo->ims_obj->vary != NULL) {
		vl = VRY_Validate(bo->ims_obj->vary);
		l += vl;
	} else
		vl = 0;
	l += http_EstimateWS(bo->ims_obj->http, 0, &nhttp);

	bo->stats = &wrk->stats;
	obj = STV_NewObject(bo, bo->storage_hint, l, nhttp);
	if (obj == NULL) {
		(void)VFP_Error(bo, "Could not get storage");
		VDI_CloseFd(&bo->vbc);
		return (F_STP_DONE);
	}

	AZ(bo->fetch_obj);
	bo->fetch_obj = obj;

	obj->gziped = bo->ims_obj->gziped;
	obj->gzip_start = bo->ims_obj->gzip_start;
	obj->gzip_last = bo->ims_obj->gzip_last;
	obj->gzip_stop = bo->ims_obj->gzip_stop;

	/* XXX: ESI */

	if (bo->ims_obj->vary != NULL) {
		obj->vary = (void *)WS_Copy(obj->http->ws,
		    bo->ims_obj->vary, vl);
		assert(vl == VRY_Validate(obj->vary));
	}

	obj->vxid = bo->vsl->wid;

	obj->http->logtag = HTTP_Obj;
	/* XXX: we should have our own HTTP_A_CONDFETCH */
	http_FilterResp(bo->ims_obj->http, obj->http, HTTPH_A_INS);
	http_CopyHome(obj->http);


	AZ(WS_Overflowed(bo->ws_o));
	VBO_setstate(bo, BOS_FETCHING);
	HSH_Unbusy(&wrk->stats, obj->objcore);

	if (!(obj->objcore->flags & OC_F_PRIVATE)) {
		EXP_Insert(obj->objcore);
		AN(obj->objcore->ban);
	}

	st = NULL;
	al = 0;

	oi = ObjIterBegin(wrk, bo->ims_obj);
	do {
		ois = ObjIter(oi, &sp, &sl);
		while (sl > 0) {
			if (st == NULL) {
				st = VFP_GetStorage(bo, bo->ims_obj->len - al);
				XXXAN(st);
			}
			tl = sl;
			if (tl > st->space - st->len)
				tl = st->space - st->len;
			memcpy(st->ptr + st->len, sp, tl);
			al += tl;
			sp = (char *)sp + tl;
			sl -= tl;
			VBO_extend(bo, al);
			if (st->len == st->space)
				st = NULL;
		}
	} while (ois == OIS_DATA || ois == OIS_STREAM);
	ObjIterEnd(&oi);
	bo->stats = NULL;
	assert(al == bo->ims_obj->len);
	assert(obj->len == al);
	if (bo->state != BOS_FAILED)
		VBO_setstate(bo, BOS_FINISHED);
	HSH_Complete(obj->objcore);
	return (F_STP_DONE);
}
Esempio n. 18
0
static enum fetch_step
vbf_stp_error(struct worker *wrk, struct busyobj *bo)
{
	struct storage *st;
	ssize_t l;
	double now;
	char time_str[VTIM_FORMAT_SIZE];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	now = W_TIM_real(wrk);
	VSLb_ts_busyobj(bo, "Error", now);

	AN(bo->fetch_objcore->flags & OC_F_BUSY);

	AZ(bo->synth_body);
	bo->synth_body = VSB_new_auto();
	AN(bo->synth_body);

	// 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");
	VTIM_format(now, time_str);
	http_PrintfHeader(bo->beresp, "Date: %s", time_str);
	http_SetHeader(bo->beresp, "Server: Varnish");

	bo->fetch_objcore->exp.t_origin = bo->t_prev;
	bo->fetch_objcore->exp.ttl = 0;
	bo->fetch_objcore->exp.grace = 0;
	bo->fetch_objcore->exp.keep = 0;

	VCL_backend_error_method(bo->vcl, wrk, NULL, bo, bo->bereq->ws);

	AZ(VSB_finish(bo->synth_body));

	if (wrk->handling == VCL_RET_RETRY) {
		VSB_delete(bo->synth_body);
		bo->synth_body = NULL;
		if (bo->retries++ < cache_param->max_retries)
			return (F_STP_RETRY);
		bo->synth_body = NULL;
		return (F_STP_FAIL);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	VFP_Setup(bo->vfc);
	bo->vfc->bo = bo;
	bo->vfc->http = bo->beresp;
	bo->vfc->vsl = bo->vsl;

	if (vbf_beresp2obj(bo))
		return (F_STP_FAIL);

	bo->vfc->body = bo->fetch_obj->body;

	l = VSB_len(bo->synth_body);
	if (l > 0) {
		st = VFP_GetStorage(bo->vfc, l);
		if (st != NULL) {
			if (st->space < l) {
				VSLb(bo->vsl, SLT_Error,
				    "No space for %zd bytes of synth body", l);
			} else {
				memcpy(st->ptr, VSB_data(bo->synth_body), l);
				VBO_extend(bo, l);
			}
		}
	}
	VSB_delete(bo->synth_body);
	bo->synth_body = NULL;

	HSH_Unbusy(&wrk->stats, bo->fetch_objcore);
	VBO_setstate(bo, BOS_FINISHED);
	return (F_STP_DONE);
}
Esempio n. 19
0
static enum fetch_step
vbf_stp_condfetch(struct worker *wrk, struct busyobj *bo)
{
	struct object *obj;
	struct objiter *oi;
	void *sp;
	ssize_t sl, al, tl;
	struct storage *st;
	enum objiter_status ois;
	char *p;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	if (bo->ims_obj->changed_gzip) {
		/*
		 * If we modified the gzip status of the IMS object, that
		 * must control the C-E header, if any.
		 */
		http_Unset(bo->beresp, H_Content_Encoding);
		if (http_GetHdr(bo->ims_obj->http, H_Content_Encoding, &p))
			http_PrintfHeader(bo->beresp,
			    "Content-Encoding: %s", p);
	}

	AZ(vbf_beresp2obj(bo));
	obj = bo->fetch_obj;
	bo->vfc->body = obj->body;

	if (bo->ims_obj->esidata != NULL) {
		sl = bo->ims_obj->esidata->len;
		obj->esidata = STV_alloc(bo->vfc, sl);
		if (obj->esidata == NULL || obj->esidata->space < sl) {
			VSLb(bo->vsl, SLT_Error,
			    "No space for %zd bytes of ESI data", sl);
			return (F_STP_FAIL);
		}
		memcpy(obj->esidata->ptr, bo->ims_obj->esidata->ptr, sl);
		obj->esidata->len = sl;
	}

	obj->gziped = bo->ims_obj->gziped;
	obj->gzip_start = bo->ims_obj->gzip_start;
	obj->gzip_last = bo->ims_obj->gzip_last;
	obj->gzip_stop = bo->ims_obj->gzip_stop;

	AZ(WS_Overflowed(bo->ws_o));
	if (bo->do_stream) {
		HSH_Unbusy(&wrk->stats, obj->objcore);
		VBO_setstate(bo, BOS_STREAM);
	}

	st = NULL;
	al = 0;

	oi = ObjIterBegin(wrk, bo->ims_obj);
	do {
		ois = ObjIter(oi, &sp, &sl);
		while (sl > 0) {
			if (st == NULL)
				st = VFP_GetStorage(bo->vfc,
				    bo->ims_obj->len - al);
			if (st == NULL)
				break;
			tl = sl;
			if (tl > st->space - st->len)
				tl = st->space - st->len;
			memcpy(st->ptr + st->len, sp, tl);
			al += tl;
			sp = (char *)sp + tl;
			sl -= tl;
			VBO_extend(bo, tl);
			if (st->len == st->space)
				st = NULL;
		}
	} while (!bo->vfc->failed && (ois == OIS_DATA || ois == OIS_STREAM));
	ObjIterEnd(&oi);
	if (bo->vfc->failed)
		return (F_STP_FAIL);

	if (!bo->do_stream)
		HSH_Unbusy(&wrk->stats, obj->objcore);

	assert(al == bo->ims_obj->len);
	assert(obj->len == al);
	EXP_Rearm(bo->ims_obj->objcore,
	    bo->ims_obj->objcore->exp.t_origin, 0, 0, 0);

	/* Recycle the backend connection before setting BOS_FINISHED to
	   give predictable backend reuse behavior for varnishtest */
	if (bo->vbc != NULL && bo->doclose == SC_NULL) {
		VDI_RecycleFd(&bo->vbc, &bo->acct);
		AZ(bo->vbc);
	}

	VBO_setstate(bo, BOS_FINISHED);
	VSLb_ts_busyobj(bo, "BerespBody", W_TIM_real(wrk));
	return (F_STP_DONE);
}
Esempio n. 20
0
static ssize_t
vrb_pull(struct req *req, ssize_t maxsize, objiterate_f *func, void *priv)
{
	ssize_t l, r = 0, yet;
	struct vfp_ctx *vfc;
	uint8_t *ptr;
	enum vfp_status vfps = VFP_ERROR;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

	CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC);
	CHECK_OBJ_NOTNULL(req->htc->vfc, VFP_CTX_MAGIC);
	vfc = req->htc->vfc;

	req->body_oc = HSH_Private(req->wrk);
	AN(req->body_oc);
	XXXAN(STV_NewObject(req->wrk, req->body_oc, TRANSIENT_STORAGE, 8));

	vfc->oc = req->body_oc;

	if (VFP_Open(vfc) < 0) {
		req->req_body_status = REQ_BODY_FAIL;
		HSH_DerefBoc(req->wrk, req->body_oc);
		AZ(HSH_DerefObjCore(req->wrk, &req->body_oc, 0));
		return (-1);
	}

	AZ(req->req_bodybytes);
	AN(req->htc);
	yet = req->htc->content_length;
	if (yet < 0)
		yet = 0;
	do {
		AZ(vfc->failed);
		if (maxsize >= 0 && req->req_bodybytes > maxsize) {
			(void)VFP_Error(vfc, "Request body too big to cache");
			break;
		}
		l = yet;
		if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK)
			break;
		AZ(vfc->failed);
		AN(ptr);
		AN(l);
		vfps = VFP_Suck(vfc, ptr, &l);
		if (l > 0 && vfps != VFP_ERROR) {
			req->req_bodybytes += l;
			req->acct.req_bodybytes += l;
			if (yet >= l)
				yet -= l;
			if (func != NULL) {
				r = func(priv, 1, ptr, l);
				if (r)
					break;
			} else {
				ObjExtend(req->wrk, req->body_oc, l);
			}
		}

	} while (vfps == VFP_OK);
	VFP_Close(vfc);
	VSLb_ts_req(req, "ReqBody", VTIM_real());
	if (func != NULL) {
		HSH_DerefBoc(req->wrk, req->body_oc);
		AZ(HSH_DerefObjCore(req->wrk, &req->body_oc, 0));
		if (vfps != VFP_END) {
			req->req_body_status = REQ_BODY_FAIL;
			if (r == 0)
				r = -1;
		}
		return (r);
	}

	ObjTrimStore(req->wrk, req->body_oc);
	AZ(ObjSetU64(req->wrk, req->body_oc, OA_LEN, req->req_bodybytes));
	HSH_DerefBoc(req->wrk, req->body_oc);

	if (vfps != VFP_END) {
		req->req_body_status = REQ_BODY_FAIL;
		AZ(HSH_DerefObjCore(req->wrk, &req->body_oc, 0));
		return (-1);
	}

	assert(req->req_bodybytes >= 0);
	if (req->req_bodybytes != req->htc->content_length) {
		/* We must update also the "pristine" req.* copy */
		http_Unset(req->http0, H_Content_Length);
		http_Unset(req->http0, H_Transfer_Encoding);
		http_PrintfHeader(req->http0, "Content-Length: %ju",
		    (uintmax_t)req->req_bodybytes);

		http_Unset(req->http, H_Content_Length);
		http_Unset(req->http, H_Transfer_Encoding);
		http_PrintfHeader(req->http, "Content-Length: %ju",
		    (uintmax_t)req->req_bodybytes);
	}

	req->req_body_status = REQ_BODY_CACHED;
	return (req->req_bodybytes);
}