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 int cnt_fetch(struct worker *wrk, struct req *req) { int i, need_host_hdr; struct busyobj *bo; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC); bo = req->busyobj; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AN(req->director); AZ(bo->vbc); AZ(bo->should_close); AZ(req->storage_hint); HTTP_Setup(bo->beresp, bo->ws, bo->vsl, HTTP_Beresp); need_host_hdr = !http_GetHdr(bo->bereq, H_Host, NULL); req->acct_req.fetch++; i = FetchHdr(req, need_host_hdr, req->objcore->objhead == NULL); /* * If we recycle a backend connection, there is a finite chance * that the backend closed it before we get a request to it. * Do a single retry in that case. */ if (i == 1) { VSC_C_main->backend_retry++; i = FetchHdr(req, need_host_hdr, req->objcore->objhead == NULL); } if (i) { req->handling = VCL_RET_ERROR; req->err_code = 503; } else { /* * These two headers can be spread over multiple actual headers * and we rely on their content outside of VCL, so collect them * into one line here. */ http_CollectHdr(bo->beresp, H_Cache_Control); http_CollectHdr(bo->beresp, H_Vary); /* * Figure out how the fetch is supposed to happen, before the * headers are adultered by VCL * NB: Also sets other wrk variables */ bo->body_status = RFC2616_Body(bo, &wrk->stats); req->err_code = http_GetStatus(bo->beresp); /* * What does RFC2616 think about TTL ? */ EXP_Clr(&bo->exp); bo->exp.entered = W_TIM_real(wrk); RFC2616_Ttl(bo); /* pass from vclrecv{} has negative TTL */ if (req->objcore->objhead == NULL) bo->exp.ttl = -1.; AZ(bo->do_esi); AZ(bo->do_pass); VCL_fetch_method(req); if (bo->do_pass) req->objcore->flags |= OC_F_PASS; switch (req->handling) { case VCL_RET_DELIVER: req->req_step = R_STP_FETCHBODY; return (0); default: break; } /* We are not going to fetch the body, Close the connection */ VDI_CloseFd(&bo->vbc); } /* Clean up partial fetch */ AZ(bo->vbc); if (req->objcore->objhead != NULL || req->handling == VCL_RET_ERROR) { CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); AZ(HSH_Deref(&wrk->stats, req->objcore, NULL)); req->objcore = NULL; } assert(bo->refcount == 2); VBO_DerefBusyObj(wrk, &bo); VBO_DerefBusyObj(wrk, &req->busyobj); req->director = NULL; req->storage_hint = NULL; switch (req->handling) { case VCL_RET_RESTART: req->req_step = R_STP_RESTART; return (0); case VCL_RET_ERROR: req->req_step = R_STP_ERROR; return (0); default: WRONG("Illegal action in vcl_fetch{}"); } }
static int cnt_fetch(struct sess *sp) { int i, need_host_hdr; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC); CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); AN(sp->director); AZ(wrk->busyobj->vbc); AZ(wrk->busyobj->should_close); AZ(wrk->storage_hint); http_Setup(wrk->busyobj->beresp, wrk->ws); need_host_hdr = !http_GetHdr(wrk->busyobj->bereq, H_Host, NULL); i = FetchHdr(sp, need_host_hdr); /* * If we recycle a backend connection, there is a finite chance * that the backend closed it before we get a request to it. * Do a single retry in that case. */ if (i == 1) { VSC_C_main->backend_retry++; i = FetchHdr(sp, need_host_hdr); } if (i) { sp->handling = VCL_RET_ERROR; sp->err_code = 503; } else { /* * These two headers can be spread over multiple actual headers * and we rely on their content outside of VCL, so collect them * into one line here. */ http_CollectHdr(wrk->busyobj->beresp, H_Cache_Control); http_CollectHdr(wrk->busyobj->beresp, H_Vary); /* * Figure out how the fetch is supposed to happen, before the * headers are adultered by VCL * NB: Also sets other wrk variables */ wrk->busyobj->body_status = RFC2616_Body(sp); sp->err_code = http_GetStatus(wrk->busyobj->beresp); /* * What does RFC2616 think about TTL ? */ EXP_Clr(&wrk->busyobj->exp); wrk->busyobj->exp.entered = W_TIM_real(wrk); RFC2616_Ttl(sp); /* pass from vclrecv{} has negative TTL */ if (wrk->objcore == NULL) wrk->busyobj->exp.ttl = -1.; AZ(wrk->busyobj->do_esi); VCL_fetch_method(sp); switch (sp->handling) { case VCL_RET_HIT_FOR_PASS: if (wrk->objcore != NULL) wrk->objcore->flags |= OC_F_PASS; sp->step = STP_FETCHBODY; return (0); case VCL_RET_DELIVER: AssertObjCorePassOrBusy(wrk->objcore); sp->step = STP_FETCHBODY; return (0); default: break; } /* We are not going to fetch the body, Close the connection */ VDI_CloseFd(wrk, &wrk->busyobj->vbc); } /* Clean up partial fetch */ AZ(wrk->busyobj->vbc); if (wrk->objcore != NULL) { CHECK_OBJ_NOTNULL(wrk->objcore, OBJCORE_MAGIC); AZ(HSH_Deref(wrk, wrk->objcore, NULL)); wrk->objcore = NULL; } VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->director = NULL; wrk->storage_hint = NULL; switch (sp->handling) { case VCL_RET_RESTART: sp->restarts++; sp->step = STP_RECV; return (0); case VCL_RET_ERROR: sp->step = STP_ERROR; return (0); default: WRONG("Illegal action in vcl_fetch{}"); } }