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); }
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); }
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); }
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); }
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); }
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); }
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); }