static int cnt_error(struct sess *sp) { struct worker *w; struct http *h; char date[40]; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); w = sp->wrk; if (sp->obj == NULL) { HSH_Prealloc(sp); sp->obj = HSH_NewObject(sp, 1); sp->obj->xid = sp->xid; sp->obj->entered = sp->t_req; } else { /* XXX: Null the headers ? */ } CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); h = sp->obj->http; http_PutProtocol(w, sp->fd, h, "HTTP/1.1"); http_PutStatus(w, sp->fd, h, sp->err_code); TIM_format(TIM_real(), date); http_PrintfHeader(w, sp->fd, h, "Date: %s", date); http_PrintfHeader(w, sp->fd, h, "Server: Varnish"); http_PrintfHeader(w, sp->fd, h, "Retry-After: %d", params->err_ttl); if (sp->err_reason != NULL) http_PutResponse(w, sp->fd, h, sp->err_reason); else http_PutResponse(w, sp->fd, h, http_StatusMessage(sp->err_code)); VCL_error_method(sp); if (sp->handling == VCL_RET_RESTART) { HSH_Drop(sp); sp->director = NULL; sp->restarts++; sp->step = STP_RECV; return (0); } /* We always close when we take this path */ sp->doclose = "error"; sp->wantbody = 1; assert(sp->handling == VCL_RET_DELIVER); sp->err_code = 0; sp->err_reason = NULL; sp->wrk->bereq = NULL; sp->step = STP_DELIVER; return (0); }
static int cnt_error(struct worker *wrk, struct req *req) { struct http *h; struct busyobj *bo; char date[40]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AZ(req->objcore); AZ(req->obj); AZ(req->busyobj); bo = VBO_GetBusyObj(wrk, req); req->busyobj = bo; AZ(bo->stats); bo->stats = &wrk->stats; req->objcore = HSH_NewObjCore(wrk); req->obj = STV_NewObject(bo, &req->objcore, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); bo->stats = NULL; if (req->obj == NULL) { req->doclose = SC_OVERLOAD; req->director = NULL; http_Teardown(bo->beresp); http_Teardown(bo->bereq); return(1); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); req->obj->vxid = bo->vsl->wid; req->obj->exp.entered = req->t_req; h = req->obj->http; if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; http_PutProtocol(h, "HTTP/1.1"); http_PutStatus(h, req->err_code); VTIM_format(W_TIM_real(wrk), date); http_PrintfHeader(h, "Date: %s", date); http_SetHeader(h, "Server: Varnish"); if (req->err_reason != NULL) http_PutResponse(h, req->err_reason); else http_PutResponse(h, http_StatusMessage(req->err_code)); VCL_error_method(req); if (req->handling == VCL_RET_RESTART && req->restarts < cache_param->max_restarts) { HSH_Drop(wrk, &req->obj); VBO_DerefBusyObj(wrk, &req->busyobj); req->req_step = R_STP_RESTART; return (0); } else if (req->handling == VCL_RET_RESTART) req->handling = VCL_RET_DELIVER; /* We always close when we take this path */ req->doclose = SC_TX_ERROR; req->wantbody = 1; assert(req->handling == VCL_RET_DELIVER); req->err_code = 0; req->err_reason = NULL; http_Teardown(bo->bereq); VBO_DerefBusyObj(wrk, &req->busyobj); req->req_step = R_STP_PREPRESP; return (0); }
static int cnt_fetch(struct sess *sp) { int i, transient; struct http *hp, *hp2; char *b; unsigned handling; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC); AN(sp->director); AZ(sp->vbe); /* sp->wrk->http[0] is (still) bereq */ sp->wrk->beresp = &sp->wrk->http[1]; http_Setup(sp->wrk->beresp, sp->wrk->ws); i = FetchHdr(sp); /* * Save a copy before it might get mangled in VCL. When it comes to * dealing with the body, we want to see the unadultered headers. */ sp->wrk->beresp1 = &sp->wrk->http[2]; *sp->wrk->beresp1 = *sp->wrk->beresp; if (i) { if (sp->objhead) { CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC); CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC); HSH_DerefObjCore(sp); } AZ(sp->obj); sp->wrk->bereq = NULL; sp->wrk->beresp = NULL; sp->wrk->beresp1 = NULL; sp->err_code = 503; sp->step = STP_ERROR; return (0); } sp->err_code = http_GetStatus(sp->wrk->beresp); /* * Initial cacheability determination per [RFC2616, 13.4] * We do not support ranges yet, so 206 is out. */ switch (sp->err_code) { case 200: /* OK */ case 203: /* Non-Authoritative Information */ case 300: /* Multiple Choices */ case 301: /* Moved Permanently */ case 302: /* Moved Temporarily */ case 410: /* Gone */ case 404: /* Not Found */ sp->wrk->cacheable = 1; break; default: sp->wrk->cacheable = 0; break; } sp->wrk->entered = TIM_real(); sp->wrk->age = 0; sp->wrk->ttl = RFC2616_Ttl(sp); if (sp->wrk->ttl == 0.) sp->wrk->cacheable = 0; sp->wrk->do_esi = 0; sp->wrk->grace = NAN; VCL_fetch_method(sp); /* * When we fetch the body, we may hit the LRU cleanup and that * will overwrite sp->handling, so we have to save our plans * here. */ handling = sp->handling; if (sp->objhead == NULL) transient = 1; else if (sp->handling == VCL_RET_DELIVER) transient = 0; else transient = 1; /* * XXX: If we have a Length: header, we should allocate the body * XXX: also. */ sp->obj = HSH_NewObject(sp, transient); if (sp->objhead != NULL) { CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC); CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC); sp->objcore->obj = sp->obj; sp->obj->objcore = sp->objcore; sp->obj->objhead = sp->objhead; sp->objhead = NULL; /* refcnt follows pointer. */ sp->objcore = NULL; /* refcnt follows pointer. */ } BAN_NewObj(sp->obj); sp->obj->xid = sp->xid; sp->obj->response = sp->err_code; sp->obj->cacheable = sp->wrk->cacheable; sp->obj->ttl = sp->wrk->ttl; sp->obj->grace = sp->wrk->grace; if (sp->obj->ttl == 0. && sp->obj->grace == 0.) sp->obj->cacheable = 0; sp->obj->age = sp->wrk->age; sp->obj->entered = sp->wrk->entered; WS_Assert(sp->obj->ws_o); /* Filter into object */ hp = sp->wrk->beresp; hp2 = sp->obj->http; hp2->logtag = HTTP_Obj; http_CopyResp(hp2, hp); http_FilterFields(sp->wrk, sp->fd, hp2, hp, HTTPH_A_INS); http_CopyHome(sp->wrk, sp->fd, hp2); if (http_GetHdr(hp, H_Last_Modified, &b)) sp->obj->last_modified = TIM_parse(b); i = FetchBody(sp); AZ(sp->wrk->wfd); AZ(sp->vbe); AN(sp->director); if (i) { HSH_Drop(sp); AZ(sp->obj); sp->wrk->bereq = NULL; sp->wrk->beresp = NULL; sp->wrk->beresp1 = NULL; sp->err_code = 503; sp->step = STP_ERROR; return (0); } if (!transient) HSH_Object(sp); if (sp->wrk->do_esi) ESI_Parse(sp); switch (handling) { case VCL_RET_RESTART: HSH_Drop(sp); sp->director = NULL; sp->restarts++; sp->wrk->bereq = NULL; sp->wrk->beresp = NULL; sp->wrk->beresp1 = NULL; sp->step = STP_RECV; return (0); case VCL_RET_PASS: if (sp->obj->objcore != NULL) sp->obj->objcore->flags |= OC_F_PASS; if (sp->obj->ttl - sp->t_req < params->default_ttl) sp->obj->ttl = sp->t_req + params->default_ttl; break; case VCL_RET_DELIVER: break; case VCL_RET_ERROR: HSH_Drop(sp); sp->wrk->bereq = NULL; sp->wrk->beresp = NULL; sp->wrk->beresp1 = NULL; sp->step = STP_ERROR; return (0); default: WRONG("Illegal action in vcl_fetch{}"); } sp->obj->cacheable = 1; if (sp->obj->objhead != NULL) { VRY_Create(sp); EXP_Insert(sp->obj); AN(sp->obj->ban); HSH_Unbusy(sp); } sp->acct_req.fetch++; sp->wrk->bereq = NULL; sp->wrk->beresp = NULL; sp->wrk->beresp1 = NULL; sp->step = STP_DELIVER; return (0); }
static enum req_fsm_nxt cnt_error(struct worker *wrk, struct req *req) { struct http *h; struct busyobj *bo; char date[40]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AZ(req->objcore); AZ(req->obj); req->acct_req.error++; bo = VBO_GetBusyObj(wrk, req); AZ(bo->stats); bo->stats = &wrk->stats; bo->fetch_objcore = HSH_Private(wrk); bo->fetch_obj = STV_NewObject(bo, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); req->obj = bo->fetch_obj; bo->stats = NULL; if (req->obj == NULL) { req->doclose = SC_OVERLOAD; req->director = NULL; AZ(HSH_DerefObjCore(&wrk->stats, &bo->fetch_objcore)); bo->fetch_objcore = NULL; http_Teardown(bo->beresp); http_Teardown(bo->bereq); VBO_DerefBusyObj(wrk, &bo); return (REQ_FSM_DONE); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); AZ(req->objcore); req->obj->vxid = bo->vsl->wid; req->obj->exp.entered = req->t_req; h = req->obj->http; if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; http_PutProtocol(h, "HTTP/1.1"); http_PutStatus(h, req->err_code); VTIM_format(W_TIM_real(wrk), date); http_PrintfHeader(h, "Date: %s", date); http_SetHeader(h, "Server: Varnish"); CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); HSH_Ref(req->obj->objcore); if (req->err_reason != NULL) http_PutResponse(h, req->err_reason); else http_PutResponse(h, http_StatusMessage(req->err_code)); VCL_error_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) { VBO_DerefBusyObj(wrk, &bo); HSH_Drop(wrk, &req->obj); req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); /* We always close when we take this path */ req->doclose = SC_TX_ERROR; req->wantbody = 1; assert(wrk->handling == VCL_RET_DELIVER); req->err_code = 0; req->err_reason = NULL; http_Teardown(bo->bereq); CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); VBO_DerefBusyObj(wrk, &bo); req->req_step = R_STP_DELIVER; CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); return (REQ_FSM_MORE); }
static int cnt_fetchbody(struct sess *sp) { int i; struct http *hp, *hp2; char *b; uint16_t nhttp; unsigned l; struct vsb *vary = NULL; int varyl = 0, pass; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); assert(sp->handling == VCL_RET_HIT_FOR_PASS || sp->handling == VCL_RET_DELIVER); if (wrk->objcore == NULL) { /* This is a pass from vcl_recv */ pass = 1; /* VCL may have fiddled this, but that doesn't help */ wrk->busyobj->exp.ttl = -1.; } else if (sp->handling == VCL_RET_HIT_FOR_PASS) { /* pass from vcl_fetch{} -> hit-for-pass */ /* XXX: the bereq was not filtered pass... */ pass = 1; } else { /* regular object */ pass = 0; } /* * The VCL variables beresp.do_g[un]zip tells us how we want the * object processed before it is stored. * * The backend Content-Encoding header tells us what we are going * to receive, which we classify in the following three classes: * * "Content-Encoding: gzip" --> object is gzip'ed. * no Content-Encoding --> object is not gzip'ed. * anything else --> do nothing wrt gzip * */ /* We do nothing unless the param is set */ if (!cache_param->http_gzip_support) wrk->busyobj->do_gzip = wrk->busyobj->do_gunzip = 0; wrk->busyobj->is_gzip = http_HdrIs(wrk->busyobj->beresp, H_Content_Encoding, "gzip"); wrk->busyobj->is_gunzip = !http_GetHdr(wrk->busyobj->beresp, H_Content_Encoding, NULL); /* It can't be both */ assert(wrk->busyobj->is_gzip == 0 || wrk->busyobj->is_gunzip == 0); /* We won't gunzip unless it is gzip'ed */ if (wrk->busyobj->do_gunzip && !wrk->busyobj->is_gzip) wrk->busyobj->do_gunzip = 0; /* If we do gunzip, remove the C-E header */ if (wrk->busyobj->do_gunzip) http_Unset(wrk->busyobj->beresp, H_Content_Encoding); /* We wont gzip unless it is ungziped */ if (wrk->busyobj->do_gzip && !wrk->busyobj->is_gunzip) wrk->busyobj->do_gzip = 0; /* If we do gzip, add the C-E header */ if (wrk->busyobj->do_gzip) http_SetHeader(wrk, sp->vsl_id, wrk->busyobj->beresp, "Content-Encoding: gzip"); /* But we can't do both at the same time */ assert(wrk->busyobj->do_gzip == 0 || wrk->busyobj->do_gunzip == 0); /* ESI takes precedence and handles gzip/gunzip itself */ if (wrk->busyobj->do_esi) wrk->busyobj->vfp = &vfp_esi; else if (wrk->busyobj->do_gunzip) wrk->busyobj->vfp = &vfp_gunzip; else if (wrk->busyobj->do_gzip) wrk->busyobj->vfp = &vfp_gzip; else if (wrk->busyobj->is_gzip) wrk->busyobj->vfp = &vfp_testgzip; if (wrk->busyobj->do_esi || sp->esi_level > 0) wrk->busyobj->do_stream = 0; if (!sp->wantbody) wrk->busyobj->do_stream = 0; l = http_EstimateWS(wrk->busyobj->beresp, pass ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp); /* Create Vary instructions */ if (wrk->objcore != NULL) { CHECK_OBJ_NOTNULL(wrk->objcore, OBJCORE_MAGIC); vary = VRY_Create(sp, wrk->busyobj->beresp); if (vary != NULL) { varyl = VSB_len(vary); assert(varyl > 0); l += varyl; } } /* * Space for producing a Content-Length: header including padding * A billion gigabytes is enough for anybody. */ l += strlen("Content-Length: XxxXxxXxxXxxXxxXxx") + sizeof(void *); if (wrk->busyobj->exp.ttl < cache_param->shortlived || wrk->objcore == NULL) wrk->storage_hint = TRANSIENT_STORAGE; wrk->obj = STV_NewObject(wrk, wrk->storage_hint, l, nhttp); if (wrk->obj == NULL) { /* * Try to salvage the transaction by allocating a * shortlived object on Transient storage. */ wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE, l, nhttp); if (wrk->busyobj->exp.ttl > cache_param->shortlived) wrk->busyobj->exp.ttl = cache_param->shortlived; wrk->busyobj->exp.grace = 0.0; wrk->busyobj->exp.keep = 0.0; } if (wrk->obj == NULL) { sp->err_code = 503; sp->step = STP_ERROR; VDI_CloseFd(wrk, &wrk->busyobj->vbc); VBO_DerefBusyObj(wrk, &wrk->busyobj); return (0); } CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC); wrk->storage_hint = NULL; if (wrk->busyobj->do_gzip || (wrk->busyobj->is_gzip && !wrk->busyobj->do_gunzip)) wrk->obj->gziped = 1; if (vary != NULL) { wrk->obj->vary = (void *)WS_Alloc(wrk->obj->http->ws, varyl); AN(wrk->obj->vary); memcpy(wrk->obj->vary, VSB_data(vary), varyl); VRY_Validate(wrk->obj->vary); VSB_delete(vary); } wrk->obj->xid = sp->xid; wrk->obj->response = sp->err_code; WS_Assert(wrk->obj->ws_o); /* Filter into object */ hp = wrk->busyobj->beresp; hp2 = wrk->obj->http; hp2->logtag = HTTP_Obj; http_CopyResp(hp2, hp); http_FilterFields(wrk, sp->vsl_id, hp2, hp, pass ? HTTPH_R_PASS : HTTPH_A_INS); http_CopyHome(wrk, sp->vsl_id, hp2); if (http_GetHdr(hp, H_Last_Modified, &b)) wrk->obj->last_modified = VTIM_parse(b); else wrk->obj->last_modified = floor(wrk->busyobj->exp.entered); assert(WRW_IsReleased(wrk)); /* * If we can deliver a 304 reply, we don't bother streaming. * Notice that vcl_deliver{} could still nuke the headers * that allow the 304, in which case we return 200 non-stream. */ if (wrk->obj->response == 200 && sp->http->conds && RFC2616_Do_Cond(sp)) wrk->busyobj->do_stream = 0; AssertObjCorePassOrBusy(wrk->obj->objcore); if (wrk->busyobj->do_stream) { sp->step = STP_PREPRESP; return (0); } /* Use unmodified headers*/ i = FetchBody(wrk, wrk->obj); http_Setup(wrk->busyobj->bereq, NULL); http_Setup(wrk->busyobj->beresp, NULL); wrk->busyobj->vfp = NULL; assert(WRW_IsReleased(wrk)); AZ(wrk->busyobj->vbc); AN(sp->director); if (i) { HSH_Drop(wrk); VBO_DerefBusyObj(wrk, &wrk->busyobj); AZ(wrk->obj); sp->err_code = 503; sp->step = STP_ERROR; return (0); } if (wrk->obj->objcore != NULL) { EXP_Insert(wrk->obj); AN(wrk->obj->objcore); AN(wrk->obj->objcore->ban); HSH_Unbusy(wrk); } VBO_DerefBusyObj(wrk, &wrk->busyobj); wrk->acct_tmp.fetch++; sp->step = STP_PREPRESP; return (0); }
static int cnt_error(struct sess *sp) { struct http *h; char date[40]; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); if (wrk->obj == NULL) { HSH_Prealloc(sp); AZ(wrk->busyobj); wrk->busyobj = VBO_GetBusyObj(wrk); wrk->obj = STV_NewObject(wrk, NULL, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); if (wrk->obj == NULL) wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); if (wrk->obj == NULL) { sp->doclose = "Out of objects"; sp->director = NULL; http_Setup(wrk->busyobj->beresp, NULL); http_Setup(wrk->busyobj->bereq, NULL); sp->step = STP_DONE; return(0); } AN(wrk->obj); wrk->obj->xid = sp->xid; wrk->obj->exp.entered = sp->t_req; } else { CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); /* XXX: Null the headers ? */ } CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC); h = wrk->obj->http; if (sp->err_code < 100 || sp->err_code > 999) sp->err_code = 501; http_PutProtocol(wrk, sp->vsl_id, h, "HTTP/1.1"); http_PutStatus(h, sp->err_code); VTIM_format(W_TIM_real(wrk), date); http_PrintfHeader(wrk, sp->vsl_id, h, "Date: %s", date); http_SetHeader(wrk, sp->vsl_id, h, "Server: Varnish"); if (sp->err_reason != NULL) http_PutResponse(wrk, sp->vsl_id, h, sp->err_reason); else http_PutResponse(wrk, sp->vsl_id, h, http_StatusMessage(sp->err_code)); VCL_error_method(sp); if (sp->handling == VCL_RET_RESTART && sp->restarts < cache_param->max_restarts) { HSH_Drop(wrk); VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->director = NULL; sp->restarts++; sp->step = STP_RECV; return (0); } else if (sp->handling == VCL_RET_RESTART) sp->handling = VCL_RET_DELIVER; /* We always close when we take this path */ sp->doclose = "error"; sp->wantbody = 1; assert(sp->handling == VCL_RET_DELIVER); sp->err_code = 0; sp->err_reason = NULL; http_Setup(wrk->busyobj->bereq, NULL); VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->step = STP_PREPRESP; return (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); }