static int
cnt_deliver(struct sess *sp)
{

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);

    sp->t_resp = TIM_real();
    if (sp->obj->objhead != NULL) {
        if ((sp->t_resp - sp->obj->last_lru) > params->lru_timeout &&
                EXP_Touch(sp->obj))
            sp->obj->last_lru = sp->t_resp;	/* XXX: locking ? */
        sp->obj->last_use = sp->t_resp;	/* XXX: locking ? */
    }
    sp->wrk->resp = &sp->wrk->http[2];
    http_Setup(sp->wrk->resp, sp->wrk->ws);
    RES_BuildHttp(sp);
    VCL_deliver_method(sp);
    switch (sp->handling) {
    case VCL_RET_DELIVER:
        break;
    case VCL_RET_RESTART:
        INCOMPL();
        break;
    default:
        WRONG("Illegal action in vcl_deliver{}");
    }

    sp->director = NULL;
    sp->restarts = 0;

    RES_WriteObj(sp);
    AZ(sp->wrk->wfd);
    HSH_Deref(sp->wrk, &sp->obj);
    sp->wrk->resp = NULL;
    sp->step = STP_DONE;
    return (0);
}
Esempio n. 2
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);
}
Esempio n. 3
0
static int
cnt_prepresp(struct worker *wrk, struct req *req)
{
	struct busyobj *bo;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	bo = req->busyobj;
	CHECK_OBJ_ORNULL(bo, BUSYOBJ_MAGIC);

	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC);

	req->res_mode = 0;

	if (bo == NULL) {
		if (!req->disable_esi && req->obj->esidata != NULL) {
			/* In ESI mode, we can't know the aggregate length */
			req->res_mode &= ~RES_LEN;
			req->res_mode |= RES_ESI;
		} else {
			req->res_mode |= RES_LEN;
		}
	} else {
		AZ(bo->do_esi);
	}

	if (req->esi_level > 0) {
		/* Included ESI object, always CHUNKED or EOF */
		req->res_mode &= ~RES_LEN;
		req->res_mode |= RES_ESI_CHILD;
	}

	if (cache_param->http_gzip_support && req->obj->gziped &&
	    !RFC2616_Req_Gzip(req->http)) {
		/*
		 * We don't know what it uncompresses to
		 * XXX: we could cache that
		 */
		req->res_mode &= ~RES_LEN;
		req->res_mode |= RES_GUNZIP;
	}

	if (!(req->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) {
		/* We havn't chosen yet, do so */
		if (!req->wantbody) {
			/* Nothing */
		} else if (req->http->protover >= 11) {
			req->res_mode |= RES_CHUNKED;
		} else {
			req->res_mode |= RES_EOF;
			req->doclose = SC_TX_EOF;
		}
	}

	req->t_resp = W_TIM_real(wrk);
	if (req->obj->objcore->objhead != NULL) {
		if ((req->t_resp - req->obj->last_lru) >
		    cache_param->lru_timeout &&
		    EXP_Touch(req->obj->objcore))
			req->obj->last_lru = req->t_resp;
		if (!cache_param->obj_readonly)
			req->obj->last_use = req->t_resp; /* XXX: locking ? */
	}
	HTTP_Setup(req->resp, req->ws, req->vsl, HTTP_Resp);
	RES_BuildHttp(req);

	VCL_deliver_method(req);
	switch (req->handling) {
	case VCL_RET_DELIVER:
		break;
	case VCL_RET_RESTART:
		if (req->restarts >= cache_param->max_restarts)
			break;
		if (bo != NULL) {
			AN(bo->do_stream);
			(void)HSH_Deref(&wrk->stats, NULL, &req->obj);
			VBO_DerefBusyObj(wrk, &req->busyobj);
		} else {
			(void)HSH_Deref(&wrk->stats, NULL, &req->obj);
		}
		AZ(req->obj);
		http_Teardown(req->resp);
		req->req_step = R_STP_RESTART;
		return (0);
	default:
		WRONG("Illegal action in vcl_deliver{}");
	}
	req->req_step = R_STP_DELIVER;
	return (0);
}
Esempio 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->obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore->objhead, OBJHEAD_MAGIC);
	CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC);
	assert(WRW_IsReleased(wrk));

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

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

	HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
	http_FilterResp(req->obj->http, req->resp, 0);
	http_ForceField(req->resp, HTTP_HDR_PROTO, "HTTP/1.1");

	if (req->wrk->stats.cache_hit)
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u %u", VXID(req->vsl->wid),
		    VXID(req->obj->vxid));
	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->obj->objcore->exp.t_origin));

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

	if (cache_param->http_gzip_support && req->obj->gziped &&
	    !RFC2616_Req_Gzip(req->http))
		RFC2616_Weaken_Etag(req->resp);

	VCL_deliver_method(req->vcl, wrk, req, NULL, req->http->ws);
	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_DerefObj(&wrk->stats, &req->obj);
		AZ(req->obj);
		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->obj->objcore->flags & OC_F_PASS)
	    && req->esi_level == 0
	    && http_GetStatus(req->obj->http) == 200
	    && req->http->conds && RFC2616_Do_Cond(req)) {
		http_PutResponse(req->resp, "HTTP/1.1", 304, NULL);
		req->wantbody = 0;
	}

	/* Grab a ref to the bo if there is one, and hand it down */
	bo = HSH_RefBusy(req->obj->objcore);
	V1D_Deliver(req, bo);
	if (bo != NULL)
		VBO_DerefBusyObj(req->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->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/abandoned 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);
	(void)HSH_DerefObj(&wrk->stats, &req->obj);
	http_Teardown(req->resp);
	return (REQ_FSM_DONE);
}
Esempio n. 5
0
static enum req_fsm_nxt
cnt_deliver(struct worker *wrk, struct req *req)
{
	char time_str[30];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore->objhead, OBJHEAD_MAGIC);
	CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC);
	assert(WRW_IsReleased(wrk));

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

	req->t_resp = W_TIM_real(wrk);
	if (!(req->obj->objcore->flags & OC_F_PRIVATE)) {
		if ((req->t_resp - req->obj->objcore->last_lru) >
		    cache_param->lru_timeout && EXP_Touch(req->obj->objcore))
			req->obj->objcore->last_lru = req->t_resp;
		if (!cache_param->obj_readonly)
			req->obj->last_use = req->t_resp; /* XXX: locking ? */
	}

	HTTP_Setup(req->resp, req->ws, req->vsl, HTTP_Resp);

	http_ClrHeader(req->resp);
	http_FilterResp(req->obj->http, req->resp, 0);

	http_Unset(req->resp, H_Date);
	VTIM_format(req->t_resp, time_str);
	http_PrintfHeader(req->resp, "Date: %s", time_str);

	if (req->wrk->stats.cache_hit)
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u %u", req->vsl->wid & VSL_IDENTMASK,
		    req->obj->vxid & VSL_IDENTMASK);
	else
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK);

	http_PrintfHeader(req->resp, "Age: %.0f",
	    req->obj->exp.age + req->t_resp - req->obj->exp.entered);

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

	VCL_deliver_method(req->vcl, wrk, req, NULL, req->http->ws);

	/* 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_RESTART) {
		(void)HSH_DerefObj(&wrk->stats, &req->obj);
		AZ(req->obj);
		http_Teardown(req->resp);
		req->req_step = R_STP_RESTART;
		return (REQ_FSM_MORE);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	if (!(req->obj->objcore->flags & OC_F_PASS)
	    && req->obj->response == 200
	    && req->http->conds && RFC2616_Do_Cond(req)) {
		req->wantbody = 0;
		http_SetResp(req->resp, "HTTP/1.1", 304, "Not Modified");
		// http_Unset(req->resp, H_Content_Length);
	}

	V1D_Deliver(req);

	/* No point in saving the body if it is hit-for-pass */
	if (req->obj->objcore->flags & OC_F_PASS)
		STV_Freestore(req->obj);

	assert(WRW_IsReleased(wrk));
VSLb(req->vsl, SLT_Debug, "XXX REF %d", req->obj->objcore->refcnt);
	(void)HSH_DerefObj(&wrk->stats, &req->obj);
	http_Teardown(req->resp);
	return (REQ_FSM_DONE);
}
Esempio n. 6
0
static int
cnt_prepresp(struct sess *sp)
{
    struct worker *wrk;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    wrk = sp->wrk;
    CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);

    CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);

    if (wrk->busyobj != NULL) {
        CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
        AN(wrk->busyobj->do_stream);
        AssertObjCorePassOrBusy(wrk->obj->objcore);
    }

    wrk->res_mode = 0;

    if (wrk->busyobj == NULL)
        wrk->res_mode |= RES_LEN;

    if (wrk->busyobj != NULL &&
            (wrk->busyobj->h_content_length != NULL ||
             !wrk->busyobj->do_stream) &&
            !wrk->busyobj->do_gzip && !wrk->busyobj->do_gunzip)
        wrk->res_mode |= RES_LEN;

    if (!sp->disable_esi && wrk->obj->esidata != NULL) {
        /* In ESI mode, we don't know the aggregate length */
        wrk->res_mode &= ~RES_LEN;
        wrk->res_mode |= RES_ESI;
    }

    if (sp->esi_level > 0) {
        wrk->res_mode &= ~RES_LEN;
        wrk->res_mode |= RES_ESI_CHILD;
    }

    if (cache_param->http_gzip_support && wrk->obj->gziped &&
            !RFC2616_Req_Gzip(sp)) {
        /*
         * We don't know what it uncompresses to
         * XXX: we could cache that
         */
        wrk->res_mode &= ~RES_LEN;
        wrk->res_mode |= RES_GUNZIP;
    }

    if (!(wrk->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) {
        if (wrk->obj->len == 0 &&
                (wrk->busyobj == NULL || !wrk->busyobj->do_stream))
            /*
             * If the object is empty, neither ESI nor GUNZIP
             * can make it any different size
             */
            wrk->res_mode |= RES_LEN;
        else if (!sp->wantbody) {
            /* Nothing */
        } else if (sp->http->protover >= 11) {
            wrk->res_mode |= RES_CHUNKED;
        } else {
            wrk->res_mode |= RES_EOF;
            sp->doclose = "EOF mode";
        }
    }

    sp->t_resp = W_TIM_real(wrk);
    if (wrk->obj->objcore != NULL) {
        if ((sp->t_resp - wrk->obj->last_lru) >
                cache_param->lru_timeout &&
                EXP_Touch(wrk->obj->objcore))
            wrk->obj->last_lru = sp->t_resp;
        wrk->obj->last_use = sp->t_resp;	/* XXX: locking ? */
    }
    http_Setup(wrk->resp, wrk->ws);
    RES_BuildHttp(sp);
    VCL_deliver_method(sp);
    switch (sp->handling) {
    case VCL_RET_DELIVER:
        break;
    case VCL_RET_RESTART:
        if (sp->restarts >= cache_param->max_restarts)
            break;
        if (wrk->busyobj != NULL) {
            AN(wrk->busyobj->do_stream);
            VDI_CloseFd(wrk, &wrk->busyobj->vbc);
            HSH_Drop(wrk);
            VBO_DerefBusyObj(wrk, &wrk->busyobj);
        } else {
            (void)HSH_Deref(wrk, NULL, &wrk->obj);
        }
        AZ(wrk->obj);
        sp->restarts++;
        sp->director = NULL;
        http_Setup(wrk->resp, NULL);
        sp->step = STP_RECV;
        return (0);
    default:
        WRONG("Illegal action in vcl_deliver{}");
    }
    if (wrk->busyobj != NULL && wrk->busyobj->do_stream) {
        AssertObjCorePassOrBusy(wrk->obj->objcore);
        sp->step = STP_STREAMBODY;
    } else {
        sp->step = STP_DELIVER;
    }
    return (0);
}
Esempio n. 7
0
static enum req_fsm_nxt
cnt_deliver(struct worker *wrk, struct req *req)
{
	char time_str[30];
	double now;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore->objhead, OBJHEAD_MAGIC);
	CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC);
	assert(WRW_IsReleased(wrk));

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

	now = W_TIM_real(wrk);
	VSLb_ts_req(req, "Process", now);
	if (req->obj->objcore->exp_flags & OC_EF_EXP)
		EXP_Touch(req->obj->objcore, now);

	HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);

	http_ClrHeader(req->resp);
	http_FilterResp(req->obj->http, req->resp, 0);

	http_Unset(req->resp, H_Date);
	VTIM_format(now, time_str);
	http_PrintfHeader(req->resp, "Date: %s", time_str);

	if (req->wrk->stats.cache_hit)
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u %u", req->vsl->wid & VSL_IDENTMASK,
		    req->obj->vxid & VSL_IDENTMASK);
	else
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK);

	http_PrintfHeader(req->resp, "Age: %.0f",
	    now - req->obj->exp.t_origin);

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

	if (cache_param->http_gzip_support && req->obj->gziped &&
	    !RFC2616_Req_Gzip(req->http))
		RFC2616_Weaken_Etag(req->resp);

	VCL_deliver_method(req->vcl, wrk, req, NULL, req->http->ws);

	/* 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_RESTART) {
		(void)HSH_DerefObj(&wrk->stats, &req->obj);
		AZ(req->obj);
		http_Teardown(req->resp);
		req->req_step = R_STP_RESTART;
		return (REQ_FSM_MORE);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	if (!(req->obj->objcore->flags & OC_F_PASS)
	    && req->esi_level == 0
	    && http_GetStatus(req->obj->http) == 200
	    && req->http->conds && RFC2616_Do_Cond(req))
		http_SetResp(req->resp, "HTTP/1.1", 304, "Not Modified");

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

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

	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/abandoned 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);
	(void)HSH_DerefObj(&wrk->stats, &req->obj);
	http_Teardown(req->resp);
	return (REQ_FSM_DONE);
}