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 enum req_fsm_nxt cnt_synth(struct worker *wrk, struct req *req) { struct http *h; double now; struct vsb *synth_body; ssize_t sz, szl; uint8_t *ptr; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk->stats->s_synth++; now = W_TIM_real(wrk); VSLb_ts_req(req, "Process", now); if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod); h = req->resp; http_TimeHeader(h, "Date: ", now); http_SetHeader(h, "Server: Varnish"); http_PrintfHeader(req->resp, "X-Varnish: %u", VXID(req->vsl->wid)); http_PutResponse(h, "HTTP/1.1", req->err_code, req->err_reason); synth_body = VSB_new_auto(); AN(synth_body); VCL_synth_method(req->vcl, wrk, req, NULL, synth_body); AZ(VSB_finish(synth_body)); http_Unset(h, H_Content_Length); http_PrintfHeader(req->resp, "Content-Length: %zd", VSB_len(synth_body)); /* Discard any lingering request body before delivery */ (void)VRB_Ignore(req); if (wrk->handling == VCL_RET_RESTART) { HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod); VSB_destroy(&synth_body); req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); req->objcore = HSH_Private(wrk); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); szl = -1; if (STV_NewObject(wrk, req->objcore, TRANSIENT_STORAGE, 1024)) { szl = VSB_len(synth_body); assert(szl >= 0); sz = szl; if (sz > 0 && ObjGetSpace(wrk, req->objcore, &sz, &ptr) && sz >= szl) { memcpy(ptr, VSB_data(synth_body), szl); ObjExtend(wrk, req->objcore, szl); } else if (sz > 0) { szl = -1; } } if (szl >= 0) AZ(ObjSetU64(wrk, req->objcore, OA_LEN, szl)); HSH_DerefBoc(wrk, req->objcore); VSB_destroy(&synth_body); if (szl < 0) { VSLb(req->vsl, SLT_Error, "Could not get storage"); req->doclose = SC_OVERLOAD; VSLb_ts_req(req, "Resp", W_TIM_real(wrk)); (void)HSH_DerefObjCore(wrk, &req->objcore); http_Teardown(req->resp); return (REQ_FSM_DONE); } req->req_step = R_STP_TRANSMIT; return (REQ_FSM_MORE); }
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); }