static enum req_fsm_nxt cnt_pass(struct worker *wrk, struct req *req) { CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AN(req->vcl); AZ(req->objcore); VCL_pass_method(req->vcl, wrk, req, NULL, NULL); switch (wrk->handling) { case VCL_RET_SYNTH: req->req_step = R_STP_SYNTH; break; case VCL_RET_RESTART: req->req_step = R_STP_RESTART; break; case VCL_RET_FETCH: wrk->stats->s_pass++; req->objcore = HSH_Private(wrk); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); VBF_Fetch(wrk, req, req->objcore, NULL, VBF_PASS); req->req_step = R_STP_FETCH; break; default: WRONG("Illegal return from cnt_pass{}"); } return (REQ_FSM_MORE); }
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); }
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_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); }