static enum fetch_step vbf_stp_retry(struct worker *wrk, struct busyobj *bo) { struct vfp_ctx *vfc; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); vfc = bo->vfc; CHECK_OBJ_NOTNULL(vfc, VFP_CTX_MAGIC); assert(bo->state == BOS_REQ_DONE); VSLb_ts_busyobj(bo, "Retry", W_TIM_real(wrk)); /* VDI_Finish must have been called before */ assert(bo->director_state == DIR_S_NULL); /* reset other bo attributes - See VBO_GetBusyObj */ bo->storage_hint = NULL; bo->do_esi = 0; bo->do_stream = 1; /* reset fetch processors */ vfc->failed = 0; VFP_Close(vfc); VFP_Setup(vfc); // XXX: BereqEnd + BereqAcct ? VSL_ChgId(bo->vsl, "bereq", "retry", VXID_Get(wrk, VSL_BACKENDMARKER)); VSLb_ts_busyobj(bo, "Start", bo->t_prev); http_VSL_log(bo->bereq); return (F_STP_STARTFETCH); }
static enum fetch_step vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) { int i; double now; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AZ(bo->storage); bo->storage = bo->do_pass ? stv_transient : STV_next(); if (bo->retries > 0) http_Unset(bo->bereq, "\012X-Varnish:"); http_PrintfHeader(bo->bereq, "X-Varnish: %u", VXID(bo->vsl->wid)); VCL_backend_fetch_method(bo->vcl, wrk, NULL, bo, NULL); bo->uncacheable = bo->do_pass; if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL) return (F_STP_FAIL); assert (wrk->handling == VCL_RET_FETCH); HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod); assert(bo->fetch_objcore->boc->state <= BOS_REQ_DONE); AZ(bo->htc); VFP_Setup(bo->vfc, wrk); bo->vfc->oc = bo->fetch_objcore; bo->vfc->resp = bo->beresp; bo->vfc->req = bo->bereq; i = VDI_GetHdr(wrk, bo); now = W_TIM_real(wrk); VSLb_ts_busyobj(bo, "Beresp", now); if (i) { assert(bo->director_state == DIR_S_NULL); return (F_STP_ERROR); } http_VSL_log(bo->beresp); if (bo->htc->body_status == BS_ERROR) { bo->htc->doclose = SC_RX_BODY; VDI_Finish(bo->wrk, bo); VSLb(bo->vsl, SLT_Error, "Body cannot be fetched"); assert(bo->director_state == DIR_S_NULL); return (F_STP_ERROR); } if (!http_GetHdr(bo->beresp, H_Date, NULL)) { /* * RFC 2616 14.18 Date: The Date general-header field * represents the date and time at which the message was * originated, having the same semantics as orig-date in * RFC 822. ... A received message that does not have a * Date header field MUST be assigned one by the recipient * if the message will be cached by that recipient or * gatewayed via a protocol which requires a Date. * * If we didn't get a Date header, we assign one here. */ http_TimeHeader(bo->beresp, "Date: ", now); } /* * 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); if (bo->fetch_objcore->flags & OC_F_PRIVATE) { /* private objects have negative TTL */ bo->fetch_objcore->t_origin = now; bo->fetch_objcore->ttl = -1.; bo->fetch_objcore->grace = 0; bo->fetch_objcore->keep = 0; } else { /* What does RFC2616 think about TTL ? */ RFC2616_Ttl(bo, now, &bo->fetch_objcore->t_origin, &bo->fetch_objcore->ttl, &bo->fetch_objcore->grace, &bo->fetch_objcore->keep ); } AZ(bo->do_esi); AZ(bo->was_304); if (http_IsStatus(bo->beresp, 304)) { if (bo->stale_oc != NULL && ObjCheckFlag(bo->wrk, bo->stale_oc, OF_IMSCAND)) { if (ObjCheckFlag(bo->wrk, bo->stale_oc, OF_CHGGZIP)) { /* * If we changed the gzip status of the object * the stored Content_Encoding controls we * must weaken any new ETag we get. */ http_Unset(bo->beresp, H_Content_Encoding); RFC2616_Weaken_Etag(bo->beresp); } http_Unset(bo->beresp, H_Content_Length); HTTP_Merge(bo->wrk, bo->stale_oc, bo->beresp); assert(http_IsStatus(bo->beresp, 200)); bo->was_304 = 1; } else if (!bo->do_pass) { /* * Backend sent unallowed 304 */ VSLb(bo->vsl, SLT_Error, "304 response but not conditional fetch"); bo->htc->doclose = SC_RX_BAD; VDI_Finish(bo->wrk, bo); return (F_STP_ERROR); } } VCL_backend_response_method(bo->vcl, wrk, NULL, bo, NULL); if (wrk->handling == VCL_RET_ABANDON || wrk->handling == VCL_RET_FAIL) { bo->htc->doclose = SC_RESP_CLOSE; VDI_Finish(bo->wrk, bo); return (F_STP_FAIL); } if (wrk->handling == VCL_RET_RETRY) { if (bo->htc->body_status != BS_NONE) bo->htc->doclose = SC_RESP_CLOSE; if (bo->director_state != DIR_S_NULL) VDI_Finish(bo->wrk, bo); if (bo->retries++ < cache_param->max_retries) return (F_STP_RETRY); VSLb(bo->vsl, SLT_VCL_Error, "Too many retries, delivering 503"); assert(bo->director_state == DIR_S_NULL); return (F_STP_ERROR); } assert(bo->fetch_objcore->boc->state <= BOS_REQ_DONE); if (bo->fetch_objcore->boc->state != BOS_REQ_DONE) { bo->req = NULL; ObjSetState(wrk, bo->fetch_objcore, BOS_REQ_DONE); } if (bo->do_esi) bo->do_stream = 0; if (wrk->handling == VCL_RET_PASS) { bo->fetch_objcore->flags |= OC_F_HFP; bo->uncacheable = 1; wrk->handling = VCL_RET_DELIVER; } if (bo->do_pass || bo->uncacheable) bo->fetch_objcore->flags |= OC_F_PASS; assert(wrk->handling == VCL_RET_DELIVER); return (bo->was_304 ? F_STP_CONDFETCH : F_STP_FETCH); }
static enum req_fsm_nxt cnt_recv(struct worker *wrk, struct req *req) { unsigned recv_handling; struct SHA256Context sha256ctx; const char *xff; const char *ci, *cp; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AN(req->vcl); AZ(req->objcore); AZ(req->err_code); AZ(isnan(req->t_first)); AZ(isnan(req->t_prev)); AZ(isnan(req->t_req)); ci = SES_Get_String_Attr(req->sp, SA_CLIENT_IP); cp = SES_Get_String_Attr(req->sp, SA_CLIENT_PORT); VSLb(req->vsl, SLT_ReqStart, "%s %s", ci, cp); http_VSL_log(req->http); if (req->restarts == 0) { /* * This really should be done earlier, but we want to capture * it in the VSL log. */ http_CollectHdr(req->http, H_X_Forwarded_For); if (http_GetHdr(req->http, H_X_Forwarded_For, &xff)) { http_Unset(req->http, H_X_Forwarded_For); http_PrintfHeader(req->http, "X-Forwarded-For: %s, %s", xff, ci); } else { http_PrintfHeader(req->http, "X-Forwarded-For: %s", ci); } } /* By default we use the first backend */ AZ(req->director_hint); req->director_hint = VCL_DefaultDirector(req->vcl); AN(req->director_hint); req->d_ttl = -1; req->disable_esi = 0; req->hash_always_miss = 0; req->hash_ignore_busy = 0; req->client_identity = NULL; http_CollectHdr(req->http, H_Cache_Control); VFP_Setup(req->htc->vfc); req->htc->vfc->http = req->http; req->htc->vfc->wrk = wrk; if (req->transport->req_body != NULL) { req->transport->req_body(req); if (req->req_body_status == REQ_BODY_FAIL) { req->doclose = SC_OVERLOAD; return (REQ_FSM_DONE); } } VCL_recv_method(req->vcl, wrk, req, NULL, NULL); /* Attempts to cache req.body may fail */ if (req->req_body_status == REQ_BODY_FAIL) { req->doclose = SC_RX_BODY; return (REQ_FSM_DONE); } recv_handling = wrk->handling; /* We wash the A-E header here for the sake of VRY */ if (cache_param->http_gzip_support && (recv_handling != VCL_RET_PIPE) && (recv_handling != VCL_RET_PASS)) { if (RFC2616_Req_Gzip(req->http)) { http_ForceHeader(req->http, H_Accept_Encoding, "gzip"); } else { http_Unset(req->http, H_Accept_Encoding); } } SHA256_Init(&sha256ctx); VCL_hash_method(req->vcl, wrk, req, NULL, &sha256ctx); assert(wrk->handling == VCL_RET_LOOKUP); SHA256_Final(req->digest, &sha256ctx); switch(recv_handling) { case VCL_RET_PURGE: req->req_step = R_STP_PURGE; return (REQ_FSM_MORE); case VCL_RET_HASH: req->req_step = R_STP_LOOKUP; return (REQ_FSM_MORE); case VCL_RET_PIPE: if (req->esi_level == 0) { req->req_step = R_STP_PIPE; return (REQ_FSM_MORE); } VSLb(req->vsl, SLT_VCL_Error, "vcl_recv{} returns pipe for ESI included object." " Doing pass."); req->req_step = R_STP_PASS; return (REQ_FSM_DONE); case VCL_RET_PASS: req->req_step = R_STP_PASS; return (REQ_FSM_MORE); case VCL_RET_SYNTH: req->req_step = R_STP_SYNTH; return (REQ_FSM_MORE); default: WRONG("Illegal return from vcl_recv{}"); } }
static enum fetch_step vbf_stp_error(struct worker *wrk, struct busyobj *bo) { struct storage *st; ssize_t l; double now; char time_str[VTIM_FORMAT_SIZE]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); now = W_TIM_real(wrk); VSLb_ts_busyobj(bo, "Error", now); AN(bo->fetch_objcore->flags & OC_F_BUSY); AZ(bo->synth_body); bo->synth_body = VSB_new_auto(); AN(bo->synth_body); // XXX: reset all beresp flags ? HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod); http_PutResponse(bo->beresp, "HTTP/1.1", 503, "Backend fetch failed"); VTIM_format(now, time_str); http_PrintfHeader(bo->beresp, "Date: %s", time_str); http_SetHeader(bo->beresp, "Server: Varnish"); bo->fetch_objcore->exp.t_origin = bo->t_prev; bo->fetch_objcore->exp.ttl = 0; bo->fetch_objcore->exp.grace = 0; bo->fetch_objcore->exp.keep = 0; VCL_backend_error_method(bo->vcl, wrk, NULL, bo, bo->bereq->ws); AZ(VSB_finish(bo->synth_body)); if (wrk->handling == VCL_RET_RETRY) { VSB_delete(bo->synth_body); bo->synth_body = NULL; if (bo->retries++ < cache_param->max_retries) return (F_STP_RETRY); bo->synth_body = NULL; return (F_STP_FAIL); } assert(wrk->handling == VCL_RET_DELIVER); VFP_Setup(bo->vfc); bo->vfc->bo = bo; bo->vfc->http = bo->beresp; bo->vfc->vsl = bo->vsl; if (vbf_beresp2obj(bo)) return (F_STP_FAIL); bo->vfc->body = bo->fetch_obj->body; l = VSB_len(bo->synth_body); if (l > 0) { st = VFP_GetStorage(bo->vfc, l); if (st != NULL) { if (st->space < l) { VSLb(bo->vsl, SLT_Error, "No space for %zd bytes of synth body", l); } else { memcpy(st->ptr, VSB_data(bo->synth_body), l); VBO_extend(bo, l); } } } VSB_delete(bo->synth_body); bo->synth_body = NULL; HSH_Unbusy(&wrk->stats, bo->fetch_objcore); VBO_setstate(bo, BOS_FINISHED); return (F_STP_DONE); }
static enum fetch_step vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) { int i, do_ims; double now; char time_str[VTIM_FORMAT_SIZE]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AZ(bo->vbc); assert(bo->doclose == SC_NULL); AZ(bo->storage_hint); if (bo->do_pass) AN(bo->req); else AZ(bo->req); HTTP_Setup(bo->bereq, bo->ws, bo->vsl, SLT_BereqMethod); HTTP_Copy(bo->bereq, bo->bereq0); http_PrintfHeader(bo->bereq, "X-Varnish: %u", VXID(bo->vsl->wid)); VCL_backend_fetch_method(bo->vcl, wrk, NULL, bo, bo->bereq->ws); bo->uncacheable = bo->do_pass; if (wrk->handling == VCL_RET_ABANDON) return (F_STP_FAIL); assert (wrk->handling == VCL_RET_FETCH); HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod); assert(bo->state <= BOS_REQ_DONE); i = V1F_fetch_hdr(wrk, bo, bo->req); /* * 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) { VSLb_ts_busyobj(bo, "Beresp", W_TIM_real(wrk)); VSC_C_main->backend_retry++; i = V1F_fetch_hdr(wrk, bo, bo->req); } now = W_TIM_real(wrk); VSLb_ts_busyobj(bo, "Beresp", now); if (i) { AZ(bo->vbc); return (F_STP_ERROR); } AN(bo->vbc); http_VSL_log(bo->beresp); if (!http_GetHdr(bo->beresp, H_Date, NULL)) { /* * RFC 2616 14.18 Date: The Date general-header field * represents the date and time at which the message was * originated, having the same semantics as orig-date in * RFC 822. ... A received message that does not have a * Date header field MUST be assigned one by the recipient * if the message will be cached by that recipient or * gatewayed via a protocol which requires a Date. * * If we didn't get a Date header, we assign one here. */ VTIM_format(now, time_str); http_PrintfHeader(bo->beresp, "Date: %s", time_str); } /* * 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->htc.body_status = RFC2616_Body(bo, &wrk->stats); if (bo->htc.body_status == BS_ERROR) { AN (bo->vbc); VDI_CloseFd(&bo->vbc, &bo->acct); VSLb(bo->vsl, SLT_Error, "Body cannot be fetched"); return (F_STP_ERROR); } /* * What does RFC2616 think about TTL ? */ EXP_Clr(&bo->fetch_objcore->exp); RFC2616_Ttl(bo, now); /* private objects have negative TTL */ if (bo->fetch_objcore->flags & OC_F_PRIVATE) bo->fetch_objcore->exp.ttl = -1.; AZ(bo->do_esi); if (bo->ims_obj != NULL && bo->beresp->status == 304) { http_Merge(bo->ims_obj->http, bo->beresp, bo->ims_obj->changed_gzip); assert(bo->beresp->status == 200); do_ims = 1; } else do_ims = 0; VFP_Setup(bo->vfc); bo->vfc->bo = bo; bo->vfc->http = bo->beresp; bo->vfc->vsl = bo->vsl; VCL_backend_response_method(bo->vcl, wrk, NULL, bo, bo->beresp->ws); if (wrk->handling == VCL_RET_ABANDON) return (F_STP_FAIL); if (wrk->handling == VCL_RET_RETRY) { AN (bo->vbc); VDI_CloseFd(&bo->vbc, &bo->acct); bo->doclose = SC_NULL; bo->retries++; if (bo->retries <= cache_param->max_retries) return (F_STP_RETRY); VSLb(bo->vsl, SLT_VCL_Error, "Too many retries, delivering 503"); return (F_STP_ERROR); } assert(bo->state == BOS_REQ_DONE); if (bo->do_esi) bo->do_stream = 0; if (bo->do_pass || bo->uncacheable) bo->fetch_objcore->flags |= OC_F_PASS; assert(wrk->handling == VCL_RET_DELIVER); return (do_ims ? F_STP_CONDFETCH : F_STP_FETCH); }
int VRB_Iterate(struct req *req, objiterate_f *func, void *priv) { char buf[8192]; ssize_t l; int i; struct vfp_ctx *vfc; enum vfp_status vfps = VFP_ERROR; int ret = 0; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AN(func); switch(req->req_body_status) { case REQ_BODY_CACHED: if (ObjIterate(req->wrk, req->body_oc, priv, func)) return (-1); return (0); case REQ_BODY_NONE: return (0); case REQ_BODY_WITH_LEN: case REQ_BODY_WITHOUT_LEN: break; case REQ_BODY_TAKEN: VSLb(req->vsl, SLT_VCL_Error, "Uncached req.body can only be consumed once."); return (-1); case REQ_BODY_FAIL: VSLb(req->vsl, SLT_FetchError, "Had failed reading req.body before."); return (-1); default: WRONG("Wrong req_body_status in VRB_IterateReqBody()"); } Lck_Lock(&req->sp->mtx); if (req->req_body_status == REQ_BODY_WITH_LEN || req->req_body_status == REQ_BODY_WITHOUT_LEN) { req->req_body_status = REQ_BODY_TAKEN; i = 0; } else i = -1; Lck_Unlock(&req->sp->mtx); if (i) { VSLb(req->vsl, SLT_VCL_Error, "Multiple attempts to access non-cached req.body"); return (i); } CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC); vfc = req->htc->vfc; VFP_Setup(vfc); vfc->http = req->http; vfc->wrk = req->wrk; V1F_Setup_Fetch(vfc, req->htc); if (VFP_Open(vfc) < 0) { VSLb(req->vsl, SLT_FetchError, "Could not open Fetch Pipeline"); return (-1); } do { l = sizeof buf; vfps = VFP_Suck(vfc, buf, &l); if (vfps == VFP_ERROR) { req->req_body_status = REQ_BODY_FAIL; ret = -1; break; } else if (l > 0) { req->req_bodybytes += l; req->acct.req_bodybytes += l; l = func(priv, 1, buf, l); if (l) { req->req_body_status = REQ_BODY_FAIL; ret = -1; break; } } } while (vfps == VFP_OK); VFP_Close(vfc); VSLb_ts_req(req, "ReqBody", VTIM_real()); return (ret); }
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 enum fetch_step vbf_stp_error(struct worker *wrk, struct busyobj *bo) { ssize_t l, ll, o; double now; uint8_t *ptr; char time_str[VTIM_FORMAT_SIZE]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); assert(bo->director_state == DIR_S_NULL); now = W_TIM_real(wrk); VSLb_ts_busyobj(bo, "Error", now); AN(bo->fetch_objcore->flags & OC_F_BUSY); AZ(bo->synth_body); bo->synth_body = VSB_new_auto(); AN(bo->synth_body); // XXX: reset all beresp flags ? HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod); http_PutResponse(bo->beresp, "HTTP/1.1", 503, "Backend fetch failed"); VTIM_format(now, time_str); http_PrintfHeader(bo->beresp, "Date: %s", time_str); http_SetHeader(bo->beresp, "Server: Varnish"); bo->fetch_objcore->exp.t_origin = bo->t_prev; bo->fetch_objcore->exp.ttl = 0; bo->fetch_objcore->exp.grace = 0; bo->fetch_objcore->exp.keep = 0; VCL_backend_error_method(bo->vcl, wrk, NULL, bo, bo->bereq->ws); AZ(VSB_finish(bo->synth_body)); if (wrk->handling == VCL_RET_RETRY) { VSB_delete(bo->synth_body); bo->synth_body = NULL; if (bo->retries++ < cache_param->max_retries) return (F_STP_RETRY); return (F_STP_FAIL); } assert(wrk->handling == VCL_RET_DELIVER); VFP_Setup(bo->vfc); bo->vfc->bo = bo; bo->vfc->wrk = bo->wrk; bo->vfc->oc = bo->fetch_objcore; bo->vfc->http = bo->beresp; bo->vfc->esi_req = bo->bereq; if (vbf_beresp2obj(bo)) return (F_STP_FAIL); ll = VSB_len(bo->synth_body); o = 0; while (ll > 0) { l = ll; if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK) break; memcpy(ptr, VSB_data(bo->synth_body) + o, l); VBO_extend(bo, l); ll -= l; o += l; } VSB_delete(bo->synth_body); bo->synth_body = NULL; HSH_Unbusy(wrk, bo->fetch_objcore); VBO_setstate(bo, BOS_FINISHED); return (F_STP_DONE); }
static enum fetch_step vbf_stp_startfetch(struct worker *wrk, struct busyobj *bo) { int i, do_ims; double now; char time_str[VTIM_FORMAT_SIZE]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); assert(bo->doclose == SC_NULL); AZ(bo->storage_hint); if (bo->do_pass) AN(bo->req); else AZ(bo->req); http_PrintfHeader(bo->bereq, "X-Varnish: %u", VXID(bo->vsl->wid)); VCL_backend_fetch_method(bo->vcl, wrk, NULL, bo, bo->bereq->ws); bo->uncacheable = bo->do_pass; if (wrk->handling == VCL_RET_ABANDON) return (F_STP_FAIL); assert (wrk->handling == VCL_RET_FETCH); HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod); assert(bo->state <= BOS_REQ_DONE); i = VDI_GetHdr(wrk, bo); now = W_TIM_real(wrk); VSLb_ts_busyobj(bo, "Beresp", now); if (i) { assert(bo->director_state == DIR_S_NULL); return (F_STP_ERROR); } http_VSL_log(bo->beresp); if (!http_GetHdr(bo->beresp, H_Date, NULL)) { /* * RFC 2616 14.18 Date: The Date general-header field * represents the date and time at which the message was * originated, having the same semantics as orig-date in * RFC 822. ... A received message that does not have a * Date header field MUST be assigned one by the recipient * if the message will be cached by that recipient or * gatewayed via a protocol which requires a Date. * * If we didn't get a Date header, we assign one here. */ VTIM_format(now, time_str); http_PrintfHeader(bo->beresp, "Date: %s", time_str); } /* * 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 */ if (!strcasecmp(http_GetMethod(bo->bereq), "head")) { /* * A HEAD request can never have a body in the reply, * no matter what the headers might say. * [RFC2516 4.3 p33] */ wrk->stats->fetch_head++; bo->htc->body_status = BS_NONE; } else if (http_GetStatus(bo->beresp) <= 199) { /* * 1xx responses never have a body. * [RFC2616 4.3 p33] * ... but we should never see them. */ wrk->stats->fetch_1xx++; bo->htc->body_status = BS_ERROR; } else if (http_IsStatus(bo->beresp, 204)) { /* * 204 is "No Content", obviously don't expect a body. * [RFC2616 10.2.5 p60] */ wrk->stats->fetch_204++; bo->htc->body_status = BS_NONE; } else if (http_IsStatus(bo->beresp, 304)) { /* * 304 is "Not Modified" it has no body. * [RFC2616 10.3.5 p63] */ wrk->stats->fetch_304++; bo->htc->body_status = BS_NONE; } else if (bo->htc->body_status == BS_CHUNKED) { wrk->stats->fetch_chunked++; } else if (bo->htc->body_status == BS_LENGTH) { assert(bo->htc->content_length > 0); wrk->stats->fetch_length++; } else if (bo->htc->body_status == BS_EOF) { wrk->stats->fetch_eof++; } else if (bo->htc->body_status == BS_ERROR) { wrk->stats->fetch_bad++; } else if (bo->htc->body_status == BS_NONE) { wrk->stats->fetch_none++; } else { WRONG("wrong bodystatus"); } if (bo->htc->body_status == BS_ERROR) { bo->doclose = SC_RX_BODY; VDI_Finish(bo->director_resp, bo->wrk, bo); VSLb(bo->vsl, SLT_Error, "Body cannot be fetched"); assert(bo->director_state == DIR_S_NULL); return (F_STP_ERROR); } /* * What does RFC2616 think about TTL ? */ EXP_Clr(&bo->fetch_objcore->exp); RFC2616_Ttl(bo, now); /* private objects have negative TTL */ if (bo->fetch_objcore->flags & OC_F_PRIVATE) bo->fetch_objcore->exp.ttl = -1.; AZ(bo->do_esi); if (bo->ims_oc != NULL && http_IsStatus(bo->beresp, 304)) { if (ObjCheckFlag(bo->wrk, bo->ims_oc, OF_CHGGZIP)) { /* * If we changed the gzip status of the object * the stored Content_Encoding controls we * must weaken any new ETag we get. */ http_Unset(bo->beresp, H_Content_Encoding); RFC2616_Weaken_Etag(bo->beresp); } HTTP_Merge(bo->wrk, bo->ims_oc, bo->beresp); assert(http_IsStatus(bo->beresp, 200)); do_ims = 1; } else do_ims = 0; VFP_Setup(bo->vfc); bo->vfc->bo = bo; bo->vfc->oc = bo->fetch_objcore; bo->vfc->wrk = bo->wrk; bo->vfc->http = bo->beresp; bo->vfc->esi_req = bo->bereq; VCL_backend_response_method(bo->vcl, wrk, NULL, bo, bo->beresp->ws); if (wrk->handling == VCL_RET_ABANDON) { bo->doclose = SC_RESP_CLOSE; VDI_Finish(bo->director_resp, bo->wrk, bo); return (F_STP_FAIL); } if (wrk->handling == VCL_RET_RETRY) { bo->doclose = SC_RESP_CLOSE; VDI_Finish(bo->director_resp, bo->wrk, bo); bo->doclose = SC_NULL; bo->retries++; if (bo->retries <= cache_param->max_retries) return (F_STP_RETRY); VSLb(bo->vsl, SLT_VCL_Error, "Too many retries, delivering 503"); assert(bo->director_state == DIR_S_NULL); return (F_STP_ERROR); } assert(bo->state == BOS_REQ_DONE); if (bo->do_esi) bo->do_stream = 0; if (bo->do_pass || bo->uncacheable) bo->fetch_objcore->flags |= OC_F_PASS; assert(wrk->handling == VCL_RET_DELIVER); return (do_ims ? F_STP_CONDFETCH : F_STP_FETCH); }