Exemplo n.º 1
0
vfp_nop_end(struct worker *wrk)
{
	struct storage *st;

	st = VTAILQ_LAST(&wrk->busyobj->fetch_obj->store, storagehead);
	if (st == NULL)
		return (0);

	if (st->len == 0) {
		VTAILQ_REMOVE(&wrk->busyobj->fetch_obj->store, st, list);
		STV_free(st);
		return (0);
	}
	if (st->len < st->space)
		STV_trim(st, st->len);
	return (0);
}
Exemplo n.º 2
0
vfp_nop_end(struct sess *sp)
{
	struct storage *st;

	st = VTAILQ_LAST(&sp->obj->store, storagehead);
	if (st == NULL)
		return (0);

	if (st->len == 0) {
		VTAILQ_REMOVE(&sp->obj->store, st, list);
		STV_free(st);
		return (0);
	}
	if (st->len < st->space)
		STV_trim(st, st->len);
	return (0);
}
Exemplo n.º 3
0
enum req_fsm_nxt
CNT_Request(struct worker *wrk, struct req *req)
{
	enum req_fsm_nxt nxt;
	struct storage *st;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

	/*
	 * Possible entrance states
	 */
	assert(
	    req->req_step == R_STP_LOOKUP ||
	    req->req_step == R_STP_RECV);

	AN(req->vsl->wid & VSL_CLIENTMARKER);

	req->wrk = wrk;

	for (nxt = REQ_FSM_MORE; nxt == REQ_FSM_MORE; ) {
		/*
		 * This is a good place to be paranoid about the various
		 * pointers still pointing to the things we expect.
		 */
		CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
		CHECK_OBJ_ORNULL(wrk->nobjhead, OBJHEAD_MAGIC);
		CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

		/*
		 * We don't want the thread workspace to be used for
		 * anything of long duration, so mandate that it be
		 * empty on state-transitions.
		 */
		WS_Assert(wrk->aws);
		assert(wrk->aws->s == wrk->aws->f);

		switch (req->req_step) {
#define REQ_STEP(l,u,arg) \
		    case R_STP_##u: \
			if (DO_DEBUG(DBG_REQ_STATE)) \
				cnt_diag(req, #u); \
			nxt = cnt_##l arg; \
			break;
#include "tbl/steps.h"
#undef REQ_STEP
		default:
			WRONG("State engine misfire");
		}
		WS_Assert(wrk->aws);
		CHECK_OBJ_ORNULL(wrk->nobjhead, OBJHEAD_MAGIC);
	}
	if (nxt == REQ_FSM_DONE) {
		AN(req->vsl->wid);
		if (req->res_mode & (RES_ESI|RES_ESI_CHILD))
			VSLb(req->vsl, SLT_ESI_BodyBytes, "%ju",
			    (uintmax_t)req->resp_bodybytes);

		while (!VTAILQ_EMPTY(&req->body->list)) {
			st = VTAILQ_FIRST(&req->body->list);
			VTAILQ_REMOVE(&req->body->list, st, list);
			STV_free(st);
		}
		req->wrk = NULL;
	}
	assert(WRW_IsReleased(wrk));
	return (nxt);
}
Exemplo n.º 4
0
void
V1F_fetch_body(struct worker *wrk, struct busyobj *bo)
{
	int cls;
	struct storage *st;
	ssize_t cl;
	struct http_conn *htc;
	struct object *obj;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	htc = &bo->htc;
	CHECK_OBJ_ORNULL(bo->vbc, VBC_MAGIC);
	obj = bo->fetch_obj;
	CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(obj->http, HTTP_MAGIC);

	assert(bo->state == BOS_FETCHING);

	/*
	 * XXX: The busyobj needs a dstat, but it is not obvious which one
	 * XXX: it should be (own/borrowed).  For now borrow the wrk's.
	 */
	AZ(bo->stats);
	bo->stats = &wrk->stats;

	AN(bo->vfp);
	AZ(bo->vgz_rx);
	assert(VTAILQ_EMPTY(&obj->store));

	/* XXX: pick up estimate from objdr ? */
	cl = 0;
	cls = bo->should_close;
	switch (htc->body_status) {
	case BS_NONE:
		break;
	case BS_ZERO:
		break;
	case BS_LENGTH:
		cl = vbf_fetch_number(bo->h_content_length, 10);

		bo->vfp->begin(bo, cl);
		if (bo->state == BOS_FETCHING && cl > 0)
			cls |= vbf_fetch_straight(bo, htc, cl);
		if (bo->vfp->end(bo))
			assert(bo->state == BOS_FAILED);
		break;
	case BS_CHUNKED:
		bo->vfp->begin(bo, cl > 0 ? cl : 0);
		if (bo->state == BOS_FETCHING)
			cls |= vbf_fetch_chunked(bo, htc);
		if (bo->vfp->end(bo))
			assert(bo->state == BOS_FAILED);
		break;
	case BS_EOF:
		bo->vfp->begin(bo, cl > 0 ? cl : 0);
		if (bo->state == BOS_FETCHING)
			vbf_fetch_eof(bo, htc);
		cls = 1;
		if (bo->vfp->end(bo))
			assert(bo->state == BOS_FAILED);
		break;
	case BS_ERROR:
		cls |= VFP_Error(bo, "error incompatible Transfer-Encoding");
		break;
	default:
		INCOMPL();
	}
	bo->t_body = VTIM_mono();
	AZ(bo->vgz_rx);

	/*
	 * 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) {
		/* XXX: is any of this 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);
		}
	}

	bo->vfp = NULL;

	VSLb(bo->vsl, SLT_Fetch_Body, "%u(%s) cls %d",
	    htc->body_status, body_status_2str(htc->body_status), cls);

	http_Teardown(bo->bereq);
	http_Teardown(bo->beresp);

	if (bo->vbc != NULL) {
		if (cls)
			VDI_CloseFd(&bo->vbc);
		else
			VDI_RecycleFd(&bo->vbc);
	}
	AZ(bo->vbc);

	if (bo->state == BOS_FAILED) {
		wrk->stats.fetch_failed++;
	} else {
		assert(bo->state == BOS_FETCHING);

		VSLb(bo->vsl, SLT_Length, "%zd", obj->len);

		{
		/* Sanity check fetch methods accounting */
			ssize_t uu;

			uu = 0;
			VTAILQ_FOREACH(st, &obj->store, list)
				uu += st->len;
			if (bo->do_stream)
				/* Streaming might have started freeing stuff */
				assert(uu <= obj->len);

			else
				assert(uu == obj->len);
		}
	}
	bo->stats = NULL;
}
Exemplo n.º 5
0
enum req_fsm_nxt
CNT_Request(struct worker *wrk, struct req *req)
{
	enum req_fsm_nxt nxt;
	struct storage *st;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

	/*
	 * Possible entrance states
	 */
	assert(
	    req->req_step == R_STP_LOOKUP ||
	    req->req_step == R_STP_RECV);

	AN(req->vsl->wid & VSL_CLIENTMARKER);

	req->wrk = wrk;

	for (nxt = REQ_FSM_MORE; nxt == REQ_FSM_MORE; ) {
		/*
		 * This is a good place to be paranoid about the various
		 * pointers still pointing to the things we expect.
		 */
		CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
		CHECK_OBJ_ORNULL(wrk->nobjhead, OBJHEAD_MAGIC);
		CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

		/*
		 * We don't want the thread workspace to be used for
		 * anything of long duration, so mandate that it be
		 * empty on state-transitions.
		 */
		WS_Assert(wrk->aws);
		assert(wrk->aws->s == wrk->aws->f);

		switch (req->req_step) {
#define REQ_STEP(l,u,arg) \
		    case R_STP_##u: \
			if (DO_DEBUG(DBG_REQ_STATE)) \
				cnt_diag(req, #u); \
			nxt = cnt_##l arg; \
		        break;
#include "tbl/steps.h"
#undef REQ_STEP
		default:
			WRONG("State engine misfire");
		}
		WS_Assert(wrk->aws);
		CHECK_OBJ_ORNULL(wrk->nobjhead, OBJHEAD_MAGIC);
	}
	if (nxt == REQ_FSM_DONE) {
		/* XXX: Workaround for pipe */
		if (req->sp->fd >= 0) {
			VSLb(req->vsl, SLT_Length, "%ju",
			    (uintmax_t)req->resp_bodybytes);
		}
		VSLb(req->vsl, SLT_ReqEnd, "%.9f %.9f %.9f %.9f %.9f",
		    req->t_req,
		    req->sp->t_idle,
		    req->sp->t_idle - req->t_resp,
		    req->t_resp - req->t_req,
		    req->sp->t_idle - req->t_resp);

		while (!VTAILQ_EMPTY(&req->body)) {
			st = VTAILQ_FIRST(&req->body);
			VTAILQ_REMOVE(&req->body, st, list);
			STV_free(st);
		}

		/* done == 2 was charged by cache_hash.c */
		SES_Charge(wrk, req);

		/*
		 * Nuke the VXID, cache_http1_fsm.c::http1_dissect() will
		 * allocate a new one when necessary.
		 */
		VSLb(req->vsl, SLT_End, "%s", "");
		req->vsl->wid = 0;
	}

	req->wrk = NULL;

	assert(WRW_IsReleased(wrk));
	return (nxt);
}
Exemplo n.º 6
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);
		}
	}
}
Exemplo n.º 7
0
int
FetchBody(struct worker *wrk, struct object *obj)
{
	int cls;
	struct storage *st;
	int mklen;
	ssize_t cl;
	struct http_conn *htc;
	struct busyobj *bo;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	bo = wrk->busyobj;
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	AZ(bo->fetch_obj);
	CHECK_OBJ_NOTNULL(bo->vbc, VBC_MAGIC);
	CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(obj->http, HTTP_MAGIC);

	htc = &bo->htc;

	if (bo->vfp == NULL)
		bo->vfp = &vfp_nop;

	AssertObjCorePassOrBusy(obj->objcore);

	AZ(bo->vgz_rx);
	AZ(VTAILQ_FIRST(&obj->store));

	bo->fetch_obj = obj;
	bo->fetch_failed = 0;

	/* XXX: pick up estimate from objdr ? */
	cl = 0;
	switch (bo->body_status) {
	case BS_NONE:
		cls = 0;
		mklen = 0;
		break;
	case BS_ZERO:
		cls = 0;
		mklen = 1;
		break;
	case BS_LENGTH:
		cl = fetch_number(bo->h_content_length, 10);
		bo->vfp->begin(wrk, cl > 0 ? cl : 0);
		cls = fetch_straight(wrk, htc, cl);
		mklen = 1;
		if (bo->vfp->end(wrk))
			cls = -1;
		break;
	case BS_CHUNKED:
		bo->vfp->begin(wrk, cl);
		cls = fetch_chunked(wrk, htc);
		mklen = 1;
		if (bo->vfp->end(wrk))
			cls = -1;
		break;
	case BS_EOF:
		bo->vfp->begin(wrk, cl);
		cls = fetch_eof(wrk, htc);
		mklen = 1;
		if (bo->vfp->end(wrk))
			cls = -1;
		break;
	case BS_ERROR:
		cls = 1;
		mklen = 0;
		break;
	default:
		cls = 0;
		mklen = 0;
		INCOMPL();
	}
	AZ(bo->vgz_rx);

	/*
	 * It is OK for ->end to just leave the last storage segment
	 * sitting on wrk->storage, we will always call vfp_nop_end()
	 * to get it trimmed or thrown out if empty.
	 */
	AZ(vfp_nop_end(wrk));

	bo->fetch_obj = NULL;

	WSLB(wrk, SLT_Fetch_Body, "%u(%s) cls %d mklen %d",
	    bo->body_status, body_status(bo->body_status),
	    cls, mklen);

	if (bo->body_status == BS_ERROR) {
		VDI_CloseFd(wrk, &bo->vbc);
		return (__LINE__);
	}

	if (cls < 0) {
		wrk->stats.fetch_failed++;
		/* XXX: Wouldn't this store automatically be released ? */
		while (!VTAILQ_EMPTY(&obj->store)) {
			st = VTAILQ_FIRST(&obj->store);
			VTAILQ_REMOVE(&obj->store, st, list);
			STV_free(st);
		}
		VDI_CloseFd(wrk, &bo->vbc);
		obj->len = 0;
		return (__LINE__);
	}
	AZ(bo->fetch_failed);

	if (cls == 0 && bo->should_close)
		cls = 1;

	WSLB(wrk, SLT_Length, "%zd", obj->len);

	{
	/* Sanity check fetch methods accounting */
		ssize_t uu;

		uu = 0;
		VTAILQ_FOREACH(st, &obj->store, list)
			uu += st->len;
		if (bo->do_stream)
			/* Streaming might have started freeing stuff */
			assert (uu <= obj->len);

		else
			assert(uu == obj->len);
	}

	if (mklen > 0) {
		http_Unset(obj->http, H_Content_Length);
		http_PrintfHeader(wrk, bo->vbc->vsl_id, obj->http,
		    "Content-Length: %zd", obj->len);
	}

	if (cls)
		VDI_CloseFd(wrk, &bo->vbc);
	else
		VDI_RecycleFd(wrk, &bo->vbc);

	return (0);
}
Exemplo n.º 8
0
int
FetchBody(struct sess *sp)
{
	int cls;
	struct storage *st;
	struct worker *w;
	int mklen;

	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
	CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
	w = sp->wrk;
	CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(sp->obj->http, HTTP_MAGIC);

	if (w->vfp == NULL)
		w->vfp = &vfp_nop;

	AN(sp->director);
	AssertObjCorePassOrBusy(sp->obj->objcore);

	AZ(w->vgz_rx);
	AZ(VTAILQ_FIRST(&sp->obj->store));
	switch (w->body_status) {
	case BS_NONE:
		cls = 0;
		mklen = 0;
		break;
	case BS_ZERO:
		cls = 0;
		mklen = 1;
		break;
	case BS_LENGTH:
		cls = fetch_straight(sp, w->htc,
		    w->h_content_length);
		mklen = 1;
		XXXAZ(w->vfp->end(sp));
		break;
	case BS_CHUNKED:
		cls = fetch_chunked(sp, w->htc);
		mklen = 1;
		XXXAZ(w->vfp->end(sp));
		break;
	case BS_EOF:
		cls = fetch_eof(sp, w->htc);
		mklen = 1;
		XXXAZ(w->vfp->end(sp));
		break;
	case BS_ERROR:
		cls = 1;
		mklen = 0;
		break;
	default:
		cls = 0;
		mklen = 0;
		INCOMPL();
	}
	AZ(w->vgz_rx);

	/*
	 * It is OK for ->end to just leave the last storage segment
	 * sitting on w->storage, we will always call vfp_nop_end()
	 * to get it trimmed or thrown out if empty.
	 */
	AZ(vfp_nop_end(sp));

	WSL(w, SLT_Fetch_Body, sp->vbc->vsl_id, "%u(%s) cls %d mklen %u",
	    w->body_status, body_status(w->body_status),
	    cls, mklen);

	if (w->body_status == BS_ERROR) {
		VDI_CloseFd(sp);
		return (__LINE__);
	}

	if (cls < 0) {
		w->stats.fetch_failed++;
		/* XXX: Wouldn't this store automatically be released ? */
		while (!VTAILQ_EMPTY(&sp->obj->store)) {
			st = VTAILQ_FIRST(&sp->obj->store);
			VTAILQ_REMOVE(&sp->obj->store, st, list);
			STV_free(st);
		}
		VDI_CloseFd(sp);
		sp->obj->len = 0;
		return (__LINE__);
	}

	if (cls == 0 && w->do_close)
		cls = 1;

	WSL(w, SLT_Length, sp->vbc->vsl_id, "%u", sp->obj->len);

	{
	/* Sanity check fetch methods accounting */
		ssize_t uu;

		uu = 0;
		VTAILQ_FOREACH(st, &sp->obj->store, list)
			uu += st->len;
		if (sp->objcore == NULL || (sp->objcore->flags & OC_F_PASS))
			/* Streaming might have started freeing stuff */
			assert (uu <= sp->obj->len);
		else
			assert(uu == sp->obj->len);
	}

	if (mklen > 0) {
		http_Unset(sp->obj->http, H_Content_Length);
		http_PrintfHeader(w, sp->vsl_id, sp->obj->http,
		    "Content-Length: %jd", (intmax_t)sp->obj->len);
	}

	if (cls)
		VDI_CloseFd(sp);
	else
		VDI_RecycleFd(sp);

	return (0);
}