Ejemplo n.º 1
0
void
VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc,
    struct object *oldobj, enum vbf_fetch_mode_e mode)
{
	struct busyobj *bo;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
	CHECK_OBJ_ORNULL(oldobj, OBJECT_MAGIC);

	bo = VBO_GetBusyObj(wrk, req);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	bo->refcount = 2;

	oc->busyobj = bo;

	CHECK_OBJ_NOTNULL(bo->vcl, VCL_CONF_MAGIC);

	if (mode == VBF_PASS)
		bo->do_pass = 1;

	bo->vary = req->vary_b;
	req->vary_b = NULL;

	HSH_Ref(oc);
	bo->fetch_objcore = oc;

	if (oldobj != NULL) {
		if (http_GetHdr(oldobj->http, H_Last_Modified, NULL) ||
		   http_GetHdr(oldobj->http, H_ETag, NULL)) {
			HSH_Ref(oldobj->objcore);
			bo->ims_obj = oldobj;
		}
	}

	AZ(bo->req);
	bo->req = req;

	bo->fetch_task.priv = bo;
	bo->fetch_task.func = vbf_fetch_thread;

	if (Pool_Task(wrk->pool, &bo->fetch_task, POOL_QUEUE_FRONT))
		vbf_fetch_thread(wrk, bo);
	if (mode == VBF_BACKGROUND) {
		VBO_waitstate(bo, BOS_REQ_DONE);
	} else {
		VBO_waitstate(bo, BOS_FETCHING);
		if (!bo->do_stream)
			VBO_waitstate(bo, BOS_FINISHED);
		assert(bo->state != BOS_FAILED || (oc->flags & OC_F_FAILED));
	}
	VBO_DerefBusyObj(wrk, &bo);
}
Ejemplo n.º 2
0
static void
ved_stripgzip(struct req *req, struct busyobj *bo)
{
	ssize_t start, last, stop, lpad;
	ssize_t l;
	char *p;
	uint32_t icrc;
	uint32_t ilen;
	uint64_t olen;
	uint8_t *dbits;
	uint8_t *pp;
	uint8_t tailbuf[8];
	enum objiter_status ois;
	void *oi;
	void *sp;
	ssize_t sl, ll, dl;
	struct ecx *ecx;
	struct req *preq;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
	CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);
	preq = ecx->preq;

	if (bo != NULL)
		VBO_waitstate(bo, BOS_FINISHED);

	AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED));

	/*
	 * This is the interesting case: Deliver all the deflate
	 * blocks, stripping the "LAST" bit of the last one and
	 * padding it, as necessary, to a byte boundary.
	 */

	p = ObjGetattr(req->wrk, req->objcore, OA_GZIPBITS, &l);
	AN(p);
	assert(l == 32);
	start = vbe64dec(p);
	last = vbe64dec(p + 8);
	stop = vbe64dec(p + 16);
	olen = ObjGetLen(req->wrk, req->objcore);
	assert(start > 0 && start < olen * 8);
	assert(last > 0 && last < olen * 8);
	assert(stop > 0 && stop < olen * 8);
	assert(last >= start);
	assert(last < stop);

	/* The start bit must be byte aligned. */
	AZ(start & 7);

	/*
	 * XXX: optimize for the case where the 'last'
	 * XXX: bit is in a empty copy block
	 */

	memset(tailbuf, 0xdd, sizeof tailbuf);
	dbits = WS_Alloc(req->ws, 8);
	AN(dbits);
	ll = 0;
	oi = ObjIterBegin(req->wrk, req->objcore);
	do {
		ois = ObjIter(req->objcore, oi, &sp, &sl);
		pp = sp;
		if (sl > 0) {
			/* Skip over the GZIP header */
			dl = start / 8 - ll;
			if (dl > 0) {
				/* Before start, skip */
				if (dl > sl)
					dl = sl;
				ll += dl;
				sl -= dl;
				pp += dl;
			}
		}
		if (sl > 0) {
			/* The main body of the object */
			dl = last / 8 - ll;
			if (dl > 0) {
				if (dl > sl)
					dl = sl;
				if (ved_bytes(req, preq, VDP_NULL, pp, dl))
					break;
				ll += dl;
				sl -= dl;
				pp += dl;
			}
		}
		if (sl > 0 && ll == last / 8) {
			/* Remove the "LAST" bit */
			dbits[0] = *pp;
			dbits[0] &= ~(1U << (last & 7));
			if (ved_bytes(req, preq, VDP_NULL, dbits, 1))
				break;
			ll++;
			sl--;
			pp++;
		}
		if (sl > 0) {
			/* Last block */
			dl = stop / 8 - ll;
			if (dl > 0) {
				if (dl > sl)
					dl = sl;
				if (ved_bytes(req, preq, VDP_NULL, pp, dl))
					break;
				ll += dl;
				sl -= dl;
				pp += dl;
			}
		}
		if (sl > 0 && (stop & 7) && ll == stop / 8) {
			/* Add alignment to byte boundary */
			dbits[1] = *pp;
			ll++;
			sl--;
			pp++;
			switch((int)(stop & 7)) {
			case 1: /*
				 * x000....
				 * 00000000 00000000 11111111 11111111
				 */
			case 3: /*
				 * xxx000..
				 * 00000000 00000000 11111111 11111111
				 */
			case 5: /*
				 * xxxxx000
				 * 00000000 00000000 11111111 11111111
				 */
				dbits[2] = 0x00; dbits[3] = 0x00;
				dbits[4] = 0xff; dbits[5] = 0xff;
				lpad = 5;
				break;
			case 2: /* xx010000 00000100 00000001 00000000 */
				dbits[1] |= 0x08;
				dbits[2] = 0x20;
				dbits[3] = 0x80;
				dbits[4] = 0x00;
				lpad = 4;
				break;
			case 4: /* xxxx0100 00000001 00000000 */
				dbits[1] |= 0x20;
				dbits[2] = 0x80;
				dbits[3] = 0x00;
				lpad = 3;
				break;
			case 6: /* xxxxxx01 00000000 */
				dbits[1] |= 0x80;
				dbits[2] = 0x00;
				lpad = 2;
				break;
			case 7:	/*
				 * xxxxxxx0
				 * 00......
				 * 00000000 00000000 11111111 11111111
				 */
				dbits[2] = 0x00;
				dbits[3] = 0x00; dbits[4] = 0x00;
				dbits[5] = 0xff; dbits[6] = 0xff;
				lpad = 6;
				break;
			case 0: /* xxxxxxxx */
			default:
				WRONG("compiler must be broken");
			}
			if (ved_bytes(req, preq, VDP_NULL, dbits + 1, lpad))
				break;
		}
		if (sl > 0) {
			/* Recover GZIP tail */
			dl = olen - ll;
			assert(dl >= 0);
			if (dl > sl)
				dl = sl;
			if (dl > 0) {
				assert(dl <= 8);
				l = ll - (olen - 8);
				assert(l >= 0);
				assert(l <= 8);
				assert(l + dl <= 8);
				memcpy(tailbuf + l, pp, dl);
				ll += dl;
				sl -= dl;
				pp += dl;
			}
		}
	} while (ois == OIS_DATA || ois == OIS_STREAM);
	ObjIterEnd(req->objcore, &oi);
	(void)ved_bytes(req, preq, VDP_FLUSH, NULL, 0);

	icrc = vle32dec(tailbuf);
	ilen = vle32dec(tailbuf + 4);

	ecx->crc = crc32_combine(ecx->crc, icrc, ilen);
	ecx->l_crc += ilen;
}
Ejemplo n.º 3
0
void
VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc,
    struct objcore *oldoc, enum vbf_fetch_mode_e mode)
{
	struct busyobj *bo, *bo_fetch;
	const char *how;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
	CHECK_OBJ_ORNULL(oldoc, OBJCORE_MAGIC);


	switch(mode) {
	case VBF_PASS:		how = "pass"; break;
	case VBF_NORMAL:	how = "fetch"; break;
	case VBF_BACKGROUND:	how = "bgfetch"; break;
	default:		WRONG("Wrong fetch mode");
	}

	bo = VBO_GetBusyObj(wrk, req);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	VSLb(bo->vsl, SLT_Begin, "bereq %u %s", VXID(req->vsl->wid), how);
	VSLb(req->vsl, SLT_Link, "bereq %u %s", VXID(bo->vsl->wid), how);

	THR_SetBusyobj(bo);

	bo_fetch = bo;
	bo->refcount = 2;

	oc->busyobj = bo;

	AN(bo->vcl);

	if (mode == VBF_PASS)
		bo->do_pass = 1;

	bo->vary = req->vary_b;
	req->vary_b = NULL;

	if (mode != VBF_BACKGROUND)
		HSH_Ref(oc);
	bo->fetch_objcore = oc;

	AZ(bo->stale_oc);
	if (oldoc != NULL) {
		assert(oldoc->refcnt > 0);
		HSH_Ref(oldoc);
		bo->stale_oc = oldoc;
	}

	AZ(bo->req);
	bo->req = req;

	bo->fetch_task.priv = bo_fetch;
	bo->fetch_task.func = vbf_fetch_thread;

	if (Pool_Task(wrk->pool, &bo->fetch_task, TASK_QUEUE_BO)) {
		wrk->stats->fetch_no_thread++;
		(void)vbf_stp_fail(req->wrk, bo);
		if (bo->stale_oc != NULL)
			(void)HSH_DerefObjCore(wrk, &bo->stale_oc);
		VBO_DerefBusyObj(wrk, &bo_fetch);
	} else {
		bo_fetch = NULL; /* ref transferred to fetch thread */
		if (mode == VBF_BACKGROUND) {
			VBO_waitstate(bo, BOS_REQ_DONE);
		} else {
			VBO_waitstate(bo, BOS_STREAM);
			if (bo->state == BOS_FAILED) {
				AN((oc->flags & OC_F_FAILED));
			} else {
				AZ(bo->fetch_objcore->flags & OC_F_BUSY);
			}
		}
	}
	AZ(bo_fetch);
	VSLb_ts_req(req, "Fetch", W_TIM_real(wrk));
	VBO_DerefBusyObj(wrk, &bo);
	THR_SetBusyobj(NULL);
}
Ejemplo n.º 4
0
static enum req_fsm_nxt
cnt_deliver(struct worker *wrk, struct req *req)
{
	struct busyobj *bo;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore->objhead, OBJHEAD_MAGIC);
	AN(req->vcl);

	assert(req->objcore->refcnt > 0);

	if (req->objcore->exp_flags & OC_EF_EXP)
		EXP_Touch(req->objcore, req->t_prev);

	HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
	AZ(HTTP_Decode(req->resp,
	    ObjGetattr(req->wrk, req->objcore, OA_HEADERS, NULL)));
	http_ForceField(req->resp, HTTP_HDR_PROTO, "HTTP/1.1");

	if (req->is_hit)
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u %u", VXID(req->vsl->wid),
		    ObjGetXID(wrk, req->objcore));
	else
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u", VXID(req->vsl->wid));

	/* We base Age calculation upon the last timestamp taken during
	   client request processing. This gives some inaccuracy, but
	   since Age is only full second resolution that shouldn't
	   matter. (Last request timestamp could be a Start timestamp
	   taken before the object entered into cache leading to negative
	   age. Truncate to zero in that case).
	*/
	http_PrintfHeader(req->resp, "Age: %.0f",
	    fmax(0., req->t_prev - req->objcore->exp.t_origin));

	http_SetHeader(req->resp, "Via: 1.1 varnish-v4");

	if (cache_param->http_gzip_support &&
	    ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) &&
	    !RFC2616_Req_Gzip(req->http))
		RFC2616_Weaken_Etag(req->resp);

	VCL_deliver_method(req->vcl, wrk, req, NULL, NULL);
	VSLb_ts_req(req, "Process", W_TIM_real(wrk));

	/* Stop the insanity before it turns "Hotel California" on us */
	if (req->restarts >= cache_param->max_restarts)
		wrk->handling = VCL_RET_DELIVER;

	if (wrk->handling != VCL_RET_DELIVER) {
		(void)HSH_DerefObjCore(wrk, &req->objcore);
		http_Teardown(req->resp);

		switch (wrk->handling) {
		case VCL_RET_RESTART:
			req->req_step = R_STP_RESTART;
			break;
		case VCL_RET_SYNTH:
			req->req_step = R_STP_SYNTH;
			break;
		default:
			INCOMPL();
		}

		return (REQ_FSM_MORE);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	if (!(req->objcore->flags & OC_F_PASS)
	    && req->esi_level == 0
	    && http_IsStatus(req->resp, 200)
	    && req->http->conds && RFC2616_Do_Cond(req))
		http_PutResponse(req->resp, "HTTP/1.1", 304, NULL);

	/* Grab a ref to the bo if there is one, and hand it down */
	bo = HSH_RefBusy(req->objcore);
	if (bo != NULL) {
		if (req->esi_level == 0 && bo->state == BOS_FINISHED) {
			VBO_DerefBusyObj(wrk, &bo);
		} else if (!bo->do_stream) {
			VBO_waitstate(bo, BOS_FINISHED);
			VBO_DerefBusyObj(wrk, &bo);
		}
	}

	cnt_vdp(req, bo);

	if (bo != NULL)
		VBO_DerefBusyObj(wrk, &bo);

	VSLb_ts_req(req, "Resp", W_TIM_real(wrk));

	if (http_HdrIs(req->resp, H_Connection, "close"))
		req->doclose = SC_RESP_CLOSE;

	if ((req->objcore->flags & OC_F_PASS) && bo != NULL) {
		VBO_waitstate(bo, BOS_FINISHED);
		ObjSlim(wrk, req->objcore);
	}

	(void)HSH_DerefObjCore(wrk, &req->objcore);
	http_Teardown(req->resp);
	return (REQ_FSM_DONE);
}
Ejemplo n.º 5
0
void
VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc,
    struct object *oldobj, enum vbf_fetch_mode_e mode)
{
	struct busyobj *bo;
	const char *how;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
	CHECK_OBJ_ORNULL(oldobj, OBJECT_MAGIC);


	switch(mode) {
	case VBF_PASS:		how = "pass"; break;
	case VBF_NORMAL:	how = "fetch"; break;
	case VBF_BACKGROUND:	how = "bgfetch"; break;
	default:		WRONG("Wrong fetch mode");
	}

	bo = VBO_GetBusyObj(wrk, req);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	VSLb(bo->vsl, SLT_Begin, "bereq %u %s ", VXID(req->vsl->wid), how);
	VSLb(req->vsl, SLT_Link, "bereq %u %s ", VXID(bo->vsl->wid), how);

	THR_SetBusyobj(bo);

	bo->refcount = 2;

	oc->busyobj = bo;

	CHECK_OBJ_NOTNULL(bo->vcl, VCL_CONF_MAGIC);

	if (mode == VBF_PASS)
		bo->do_pass = 1;

	bo->vary = req->vary_b;
	req->vary_b = NULL;

	if (mode != VBF_BACKGROUND)
		HSH_Ref(oc);
	bo->fetch_objcore = oc;

	AZ(bo->ims_obj);
	if (oldobj != NULL) {
		if (http_GetHdr(oldobj->http, H_Last_Modified, NULL) ||
		   http_GetHdr(oldobj->http, H_ETag, NULL)) {
			assert(oldobj->objcore->refcnt > 0);
			HSH_Ref(oldobj->objcore);
			bo->ims_obj = oldobj;
		}
	}

	AZ(bo->req);
	bo->req = req;

	bo->fetch_task.priv = bo;
	bo->fetch_task.func = vbf_fetch_thread;

	if (Pool_Task(wrk->pool, &bo->fetch_task, POOL_QUEUE_FRONT))
		vbf_fetch_thread(wrk, bo);
	if (mode == VBF_BACKGROUND) {
		VBO_waitstate(bo, BOS_REQ_DONE);
	} else {
		VBO_waitstate(bo, BOS_STREAM);
		if (bo->state == BOS_FAILED) {
			AN((oc->flags & OC_F_FAILED));
		} else {
			AZ(bo->fetch_objcore->flags & OC_F_BUSY);
		}
	}
	VSLb_ts_req(req, "Fetch", W_TIM_real(wrk));
	THR_SetBusyobj(NULL);
	VBO_DerefBusyObj(wrk, &bo);
}