static void make_it_503(struct busyobj *bo) { HTTP_Setup(bo->beresp, bo->ws, bo->vsl, HTTP_Beresp); bo->err_code = 503; http_SetH(bo->beresp, HTTP_HDR_PROTO, "HTTP/1.1"); http_SetResp(bo->beresp, "HTTP/1.1", 503, "Backend fetch failed"); http_SetHeader(bo->beresp, "Content-Length: 0"); http_SetHeader(bo->beresp, "Connection: close"); }
static enum fetch_step vbf_stp_fetchhdr(struct worker *wrk, struct busyobj *bo) { int i; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); xxxassert (wrk->handling == VCL_RET_FETCH); HTTP_Setup(bo->beresp, bo->ws, bo->vsl, HTTP_Beresp); if (!bo->do_pass) vbf_release_req(bo); /* XXX: retry ?? */ assert(bo->state == BOS_INVALID); 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) { VSC_C_main->backend_retry++; i = V1F_fetch_hdr(wrk, bo, bo->req); } if (bo->do_pass) vbf_release_req(bo); /* XXX : retry ?? */ AZ(bo->req); if (i) { AZ(bo->vbc); bo->err_code = 503; http_SetH(bo->beresp, HTTP_HDR_PROTO, "HTTP/1.1"); http_SetResp(bo->beresp, "HTTP/1.1", 503, "Backend fetch failed"); http_SetHeader(bo->beresp, "Content-Length: 0"); http_SetHeader(bo->beresp, "Connection: close"); } else { AN(bo->vbc); } /* * 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); bo->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 (bo->fetch_objcore->objhead == NULL) bo->exp.ttl = -1.; AZ(bo->do_esi); VCL_backend_response_method(bo->vcl, wrk, NULL, bo, bo->beresp->ws); if (bo->do_esi) bo->do_stream = 0; if (wrk->handling == VCL_RET_DELIVER) return (F_STP_FETCH); if (wrk->handling == VCL_RET_RETRY) { assert(bo->state == BOS_INVALID); bo->retries++; if (bo->retries <= cache_param->max_retries) { VDI_CloseFd(&bo->vbc); return (F_STP_STARTFETCH); } // XXX: wrk->handling = VCL_RET_SYNTH; } return (F_STP_NOTYET); }
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_SetResp(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->exp.t_origin = bo->t_prev; bo->exp.ttl = 0; bo->exp.grace = 0; bo->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); if (vbf_beresp2obj(bo)) return (F_STP_FAIL); l = VSB_len(bo->synth_body); if (l > 0) { st = VFP_GetStorage(bo, 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 void v1d_dorange(struct req *req, const char *r) { ssize_t low, high, has_low; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); assert(req->obj->response == 200); if (strncmp(r, "bytes=", 6)) return; r += 6; /* The low end of range */ has_low = low = 0; if (!vct_isdigit(*r) && *r != '-') return; while (vct_isdigit(*r)) { has_low = 1; low *= 10; low += *r - '0'; r++; } if (low >= req->obj->len) return; if (*r != '-') return; r++; /* The high end of range */ if (vct_isdigit(*r)) { high = 0; while (vct_isdigit(*r)) { high *= 10; high += *r - '0'; r++; } if (!has_low) { low = req->obj->len - high; if (low < 0) low = 0; high = req->obj->len - 1; } } else high = req->obj->len - 1; if (*r != '\0') return; if (high >= req->obj->len) high = req->obj->len - 1; if (low > high) return; http_PrintfHeader(req->resp, "Content-Range: bytes %jd-%jd/%jd", (intmax_t)low, (intmax_t)high, (intmax_t)req->obj->len); http_Unset(req->resp, H_Content_Length); if (req->res_mode & RES_LEN) http_PrintfHeader(req->resp, "Content-Length: %jd", (intmax_t)(1 + high - low)); http_SetResp(req->resp, "HTTP/1.1", 206, "Partial Content"); req->range_off = 0; req->range_low = low; req->range_high = high + 1; VDP_push(req, v1d_range_bytes); }
static enum req_fsm_nxt cnt_deliver(struct worker *wrk, struct req *req) { char time_str[30]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC); CHECK_OBJ_NOTNULL(req->obj->objcore->objhead, OBJHEAD_MAGIC); CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC); assert(WRW_IsReleased(wrk)); assert(req->obj->objcore->refcnt > 0); req->t_resp = W_TIM_real(wrk); if (!(req->obj->objcore->flags & OC_F_PRIVATE)) { if ((req->t_resp - req->obj->objcore->last_lru) > cache_param->lru_timeout && EXP_Touch(req->obj->objcore)) req->obj->objcore->last_lru = req->t_resp; if (!cache_param->obj_readonly) req->obj->last_use = req->t_resp; /* XXX: locking ? */ } HTTP_Setup(req->resp, req->ws, req->vsl, HTTP_Resp); http_ClrHeader(req->resp); http_FilterResp(req->obj->http, req->resp, 0); http_Unset(req->resp, H_Date); VTIM_format(req->t_resp, time_str); http_PrintfHeader(req->resp, "Date: %s", time_str); if (req->wrk->stats.cache_hit) http_PrintfHeader(req->resp, "X-Varnish: %u %u", req->vsl->wid & VSL_IDENTMASK, req->obj->vxid & VSL_IDENTMASK); else http_PrintfHeader(req->resp, "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK); http_PrintfHeader(req->resp, "Age: %.0f", req->obj->exp.age + req->t_resp - req->obj->exp.entered); http_SetHeader(req->resp, "Via: 1.1 varnish"); VCL_deliver_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) { (void)HSH_DerefObj(&wrk->stats, &req->obj); AZ(req->obj); http_Teardown(req->resp); req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); if (!(req->obj->objcore->flags & OC_F_PASS) && req->obj->response == 200 && req->http->conds && RFC2616_Do_Cond(req)) { req->wantbody = 0; http_SetResp(req->resp, "HTTP/1.1", 304, "Not Modified"); // http_Unset(req->resp, H_Content_Length); } V1D_Deliver(req); /* No point in saving the body if it is hit-for-pass */ if (req->obj->objcore->flags & OC_F_PASS) STV_Freestore(req->obj); assert(WRW_IsReleased(wrk)); VSLb(req->vsl, SLT_Debug, "XXX REF %d", req->obj->objcore->refcnt); (void)HSH_DerefObj(&wrk->stats, &req->obj); http_Teardown(req->resp); return (REQ_FSM_DONE); }
static enum req_fsm_nxt cnt_deliver(struct worker *wrk, struct req *req) { char time_str[30]; double now; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC); CHECK_OBJ_NOTNULL(req->obj->objcore->objhead, OBJHEAD_MAGIC); CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC); assert(WRW_IsReleased(wrk)); assert(req->obj->objcore->refcnt > 0); now = W_TIM_real(wrk); VSLb_ts_req(req, "Process", now); if (req->obj->objcore->exp_flags & OC_EF_EXP) EXP_Touch(req->obj->objcore, now); HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod); http_ClrHeader(req->resp); http_FilterResp(req->obj->http, req->resp, 0); http_Unset(req->resp, H_Date); VTIM_format(now, time_str); http_PrintfHeader(req->resp, "Date: %s", time_str); if (req->wrk->stats.cache_hit) http_PrintfHeader(req->resp, "X-Varnish: %u %u", req->vsl->wid & VSL_IDENTMASK, req->obj->vxid & VSL_IDENTMASK); else http_PrintfHeader(req->resp, "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK); http_PrintfHeader(req->resp, "Age: %.0f", now - req->obj->exp.t_origin); http_SetHeader(req->resp, "Via: 1.1 varnish (v4)"); if (cache_param->http_gzip_support && req->obj->gziped && !RFC2616_Req_Gzip(req->http)) RFC2616_Weaken_Etag(req->resp); VCL_deliver_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) { (void)HSH_DerefObj(&wrk->stats, &req->obj); AZ(req->obj); http_Teardown(req->resp); req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); if (!(req->obj->objcore->flags & OC_F_PASS) && req->esi_level == 0 && http_GetStatus(req->obj->http) == 200 && req->http->conds && RFC2616_Do_Cond(req)) http_SetResp(req->resp, "HTTP/1.1", 304, "Not Modified"); V1D_Deliver(req); VSLb_ts_req(req, "Resp", W_TIM_real(wrk)); if (http_HdrIs(req->resp, H_Connection, "close")) req->doclose = SC_RESP_CLOSE; if (req->obj->objcore->flags & OC_F_PASS) { /* * No point in saving the body if it is hit-for-pass, * but we can't yank it until the fetching thread has * finished/abandoned also. */ while (req->obj->objcore->busyobj != NULL) (void)usleep(100000); STV_Freestore(req->obj); } assert(WRW_IsReleased(wrk)); VSLb(req->vsl, SLT_Debug, "XXX REF %d", req->obj->objcore->refcnt); (void)HSH_DerefObj(&wrk->stats, &req->obj); http_Teardown(req->resp); return (REQ_FSM_DONE); }