static enum fetch_step vbf_stp_fetchbody(struct worker *wrk, struct busyobj *bo) { ssize_t l; uint8_t *ptr; enum vfp_status vfps = VFP_ERROR; ssize_t est; struct vfp_ctx *vfc; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); vfc = bo->vfc; CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC); AN(vfc->vfp_nxt); est = bo->htc->content_length; if (est < 0) est = 0; do { if (vfc->oc->flags & OC_F_ABANDON) { /* * A pass object and delivery was terminated * We don't fail the fetch, in order for hit-for-pass * objects to be created. */ AN(vfc->oc->flags & OC_F_PASS); VSLb(wrk->vsl, SLT_Debug, "Fetch: Pass delivery abandoned"); bo->htc->doclose = SC_RX_BODY; break; } AZ(vfc->failed); l = est; assert(l >= 0); if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK) { bo->htc->doclose = SC_RX_BODY; break; } AZ(vfc->failed); vfps = VFP_Suck(vfc, ptr, &l); if (l > 0 && vfps != VFP_ERROR) { bo->acct.beresp_bodybytes += l; VFP_Extend(vfc, l); if (est >= l) est -= l; else est = 0; } } while (vfps == VFP_OK); if (vfc->failed) { (void)VFP_Error(vfc, "Fetch pipeline failed to process"); bo->htc->doclose = SC_RX_BODY; VFP_Close(vfc); VDI_Finish(wrk, bo); if (!bo->do_stream) { assert(bo->fetch_objcore->boc->state < BOS_STREAM); // XXX: doclose = ? return (F_STP_ERROR); } else { wrk->stats->fetch_failed++; return (F_STP_FAIL); } } ObjTrimStore(wrk, vfc->oc); return (F_STP_FETCHEND); }
static ssize_t vrb_pull(struct req *req, ssize_t maxsize, objiterate_f *func, void *priv) { ssize_t l, r = 0, yet; struct vfp_ctx *vfc; uint8_t *ptr; enum vfp_status vfps = VFP_ERROR; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(req->htc->vfc, VFP_CTX_MAGIC); vfc = req->htc->vfc; req->body_oc = HSH_Private(req->wrk); AN(req->body_oc); XXXAN(STV_NewObject(req->wrk, req->body_oc, TRANSIENT_STORAGE, 8)); vfc->oc = req->body_oc; if (VFP_Open(vfc) < 0) { req->req_body_status = REQ_BODY_FAIL; HSH_DerefBoc(req->wrk, req->body_oc); AZ(HSH_DerefObjCore(req->wrk, &req->body_oc, 0)); return (-1); } AZ(req->req_bodybytes); AN(req->htc); yet = req->htc->content_length; if (yet < 0) yet = 0; do { AZ(vfc->failed); if (maxsize >= 0 && req->req_bodybytes > maxsize) { (void)VFP_Error(vfc, "Request body too big to cache"); break; } l = yet; if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK) break; AZ(vfc->failed); AN(ptr); AN(l); vfps = VFP_Suck(vfc, ptr, &l); if (l > 0 && vfps != VFP_ERROR) { req->req_bodybytes += l; req->acct.req_bodybytes += l; if (yet >= l) yet -= l; if (func != NULL) { r = func(priv, 1, ptr, l); if (r) break; } else { ObjExtend(req->wrk, req->body_oc, l); } } } while (vfps == VFP_OK); VFP_Close(vfc); VSLb_ts_req(req, "ReqBody", VTIM_real()); if (func != NULL) { HSH_DerefBoc(req->wrk, req->body_oc); AZ(HSH_DerefObjCore(req->wrk, &req->body_oc, 0)); if (vfps != VFP_END) { req->req_body_status = REQ_BODY_FAIL; if (r == 0) r = -1; } return (r); } ObjTrimStore(req->wrk, req->body_oc); AZ(ObjSetU64(req->wrk, req->body_oc, OA_LEN, req->req_bodybytes)); HSH_DerefBoc(req->wrk, req->body_oc); if (vfps != VFP_END) { req->req_body_status = REQ_BODY_FAIL; AZ(HSH_DerefObjCore(req->wrk, &req->body_oc, 0)); return (-1); } assert(req->req_bodybytes >= 0); if (req->req_bodybytes != req->htc->content_length) { /* We must update also the "pristine" req.* copy */ http_Unset(req->http0, H_Content_Length); http_Unset(req->http0, H_Transfer_Encoding); http_PrintfHeader(req->http0, "Content-Length: %ju", (uintmax_t)req->req_bodybytes); http_Unset(req->http, H_Content_Length); http_Unset(req->http, H_Transfer_Encoding); http_PrintfHeader(req->http, "Content-Length: %ju", (uintmax_t)req->req_bodybytes); } req->req_body_status = REQ_BODY_CACHED; return (req->req_bodybytes); }
static void vbf_fetch_body_helper(struct busyobj *bo) { ssize_t l; uint8_t *ptr; enum vfp_status vfps = VFP_ERROR; ssize_t est; struct vfp_ctx *vfc; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); vfc = bo->vfc; CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC); AN(vfc->vfp_nxt); est = bo->htc->content_length; if (est < 0) est = 0; do { if (bo->abandon) { /* * A pass object and delivery was terminated * We don't fail the fetch, in order for hit-for-pass * objects to be created. */ AN(vfc->oc->flags & OC_F_PASS); VSLb(vfc->wrk->vsl, SLT_FetchError, "Pass delivery abandoned"); vfps = VFP_END; bo->htc->doclose = SC_RX_BODY; break; } AZ(vfc->failed); l = est; assert(l >= 0); if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK) { bo->htc->doclose = SC_RX_BODY; break; } AZ(vfc->failed); vfps = VFP_Suck(vfc, ptr, &l); if (l > 0 && vfps != VFP_ERROR) { bo->acct.beresp_bodybytes += l; VBO_extend(bo, l); if (est >= l) est -= l; else est = 0; } } while (vfps == VFP_OK); VFP_Close(vfc); if (vfps == VFP_ERROR) { AN(vfc->failed); (void)VFP_Error(vfc, "Fetch pipeline failed to process"); bo->htc->doclose = SC_RX_BODY; } if (!bo->do_stream) ObjTrimStore(bo->wrk, vfc->oc); }
ssize_t VRB_Cache(struct req *req, ssize_t maxsize) { ssize_t l, yet; struct vfp_ctx *vfc; uint8_t *ptr; enum vfp_status vfps = VFP_ERROR; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); assert (req->req_step == R_STP_RECV); switch(req->req_body_status) { case REQ_BODY_CACHED: return (req->req_bodybytes); case REQ_BODY_FAIL: return (-1); case REQ_BODY_NONE: return (0); case REQ_BODY_WITHOUT_LEN: case REQ_BODY_WITH_LEN: break; default: WRONG("Wrong req_body_status in VRB_Cache()"); } CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC); vfc = req->htc->vfc; VFP_Setup(vfc); vfc->wrk = req->wrk; if (req->htc->content_length > maxsize) { req->req_body_status = REQ_BODY_FAIL; (void)VFP_Error(vfc, "Request body too big to cache"); return (-1); } req->body_oc = HSH_Private(req->wrk); AN(req->body_oc); XXXAN(STV_NewObject(req->wrk, req->body_oc, TRANSIENT_STORAGE, 8)); vfc->http = req->http; vfc->oc = req->body_oc; V1F_Setup_Fetch(vfc, req->htc); if (VFP_Open(vfc) < 0) { req->req_body_status = REQ_BODY_FAIL; return (-1); } AZ(req->req_bodybytes); AN(req->htc); yet = req->htc->content_length; if (yet < 0) yet = 0; do { AZ(vfc->failed); if (req->req_bodybytes > maxsize) { req->req_body_status = REQ_BODY_FAIL; (void)VFP_Error(vfc, "Request body too big to cache"); VFP_Close(vfc); return(-1); } l = yet; if (VFP_GetStorage(vfc, &l, &ptr) != VFP_OK) break; AZ(vfc->failed); AN(ptr); AN(l); vfps = VFP_Suck(vfc, ptr, &l); if (l > 0 && vfps != VFP_ERROR) { req->req_bodybytes += l; req->acct.req_bodybytes += l; if (yet >= l) yet -= l; ObjExtend(req->wrk, req->body_oc, l); } } while (vfps == VFP_OK); VFP_Close(vfc); ObjTrimStore(req->wrk, req->body_oc); /* XXX: check missing: if (req->htc->content_length >= 0) MUSTBE (req->req_bodybytes == req->htc->content_length); */ if (vfps == VFP_END) { assert(req->req_bodybytes >= 0); if (req->req_bodybytes != req->htc->content_length) { /* We must update also the "pristine" req.* copy */ http_Unset(req->http0, H_Content_Length); http_Unset(req->http0, H_Transfer_Encoding); http_PrintfHeader(req->http0, "Content-Length: %ju", (uintmax_t)req->req_bodybytes); http_Unset(req->http, H_Content_Length); http_Unset(req->http, H_Transfer_Encoding); http_PrintfHeader(req->http, "Content-Length: %ju", (uintmax_t)req->req_bodybytes); } req->req_body_status = REQ_BODY_CACHED; } else { req->req_body_status = REQ_BODY_FAIL; } VSLb_ts_req(req, "ReqBody", VTIM_real()); return (vfps == VFP_END ? req->req_bodybytes : -1); }