static enum req_fsm_nxt cnt_synth(struct worker *wrk, struct req *req) { char date[40]; struct http *h; double now; 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; VTIM_format(now, date); http_PrintfHeader(h, "Date: %s", date); 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); AZ(req->synth_body); req->synth_body = VSB_new_auto(); AN(req->synth_body); VCL_synth_method(req->vcl, wrk, req, NULL, req->http->ws); http_Unset(h, H_Content_Length); AZ(VSB_finish(req->synth_body)); if (wrk->handling == VCL_RET_RESTART) { HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod); VSB_delete(req->synth_body); req->synth_body = NULL; req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); if (http_HdrIs(req->resp, H_Connection, "close")) req->doclose = SC_RESP_CLOSE; V1D_Deliver_Synth(req); VSLb_ts_req(req, "Resp", W_TIM_real(wrk)); VSB_delete(req->synth_body); req->synth_body = NULL; req->err_code = 0; req->err_reason = NULL; return (REQ_FSM_DONE); }
static char * macro_get(const char *b, const char *e) { struct macro *m; int l; char *retval = NULL; l = e - b; if (l == 4 && !memcmp(b, "date", l)) { double t = VTIM_real(); retval = malloc(64); AN(retval); VTIM_format(t, retval); return (retval); } AZ(pthread_mutex_lock(¯o_mtx)); VTAILQ_FOREACH(m, ¯o_list, list) if (!memcmp(b, m->name, l) && m->name[l] == '\0') break; if (m != NULL) retval = strdup(m->val); AZ(pthread_mutex_unlock(¯o_mtx)); return (retval); }
char * VRT_time_string(const struct sess *sp, double t) { char *p; AN(p = WS_Alloc(sp->http->ws, VTIM_FORMAT_SIZE)); VTIM_format(t, p); return (p); }
char * VRT_TIME_string(VRT_CTX, double t) { char *p; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); p = WS_Alloc(ctx->ws, VTIM_FORMAT_SIZE); if (p != NULL) VTIM_format(t, p); return (p); }
static void tst(const char *s, time_t good) { time_t t; char buf[BUFSIZ]; t = VTIM_parse(s); VTIM_format(t, buf); printf("%-30s -> %12jd -> %s\n", s, (intmax_t)t, buf); if (t != good) { printf("Parse error! Got: %jd should have %jd diff %jd\n", (intmax_t)t, (intmax_t)good, (intmax_t)(t - good)); exit(4); } }
static void mgt_panic_record(pid_t r) { char time_str[30]; if (child_panic != NULL) VSB_delete(child_panic); child_panic = VSB_new_auto(); AN(child_panic); VTIM_format(VTIM_real(), time_str); VSB_printf(child_panic, "Last panic at: %s\n", time_str); VSB_quote(child_panic, heritage.panic_str, strnlen(heritage.panic_str, heritage.panic_str_len), VSB_QUOTE_NONL); AZ(VSB_finish(child_panic)); MGT_complain(C_ERR, "Child (%jd) %s", (intmax_t)r, VSB_data(child_panic)); }
int main(int argc, char **argv) { time_t t; char buf[BUFSIZ]; time(&t); memset(buf, 0x55, sizeof buf); VTIM_format(t, buf); printf("scan = %d <%s>\n", VTIM_parse(buf), buf); /* Examples from RFC2616 section 3.3.1 */ tst("Sun, 06 Nov 1994 08:49:37 GMT", 784111777); tst("Sunday, 06-Nov-94 08:49:37 GMT", 784111777); tst("Sun Nov 6 08:49:37 1994", 784111777); tst_delta(); return (0); }
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); }
static void update(void) { char t[VTIM_FORMAT_SIZE]; unsigned w = COLS / hist_range; unsigned n = w * hist_range; unsigned bm[n], bh[n]; unsigned max; unsigned i, j, scale; int k, l; erase(); /* Draw horizontal axis */ for (i = 0; i < n; ++i) (void)mvaddch(LINES - 2, i, '-'); for (k = 0, l = hist_low; k < hist_range; ++k, ++l) { (void)mvaddch(LINES - 2, w * k, '+'); mvprintw(LINES - 1, w * k, "|1e%d", l); } if (end_of_file) mvprintw(0, 0, "%*s", COLS - 1, "EOF"); else mvprintw(0, 0, "%*s", COLS - 1, VSM_Name(VUT.vsm)); /* count our flock */ for (i = 0; i < n; ++i) bm[i] = bh[i] = 0; for (k = 0, max = 1; k < hist_buckets; ++k) { l = k * n / hist_buckets; bm[l] += bucket_miss[k]; bh[l] += bucket_hit[k]; if (bm[l] + bh[l] > max) max = bm[l] + bh[l]; } /* scale,time */ assert(LINES - 3 >= 0); for (i = 0; max / scales[i] > (unsigned)(LINES - 3); ++i) /* nothing */ ; scale = scales[i]; if (vsl_t0 > 0) { VTIM_format(vsl_ts, t); mvprintw(0, 0, "1:%d, n = %d, d = %g @ %s x %g", scale, nhist, delay, t, timebend); } else mvprintw(0, 0, "1:%d, n = %d, d = %g", scale, nhist, delay); for (j = 2; j < LINES - 3; j += 5) mvprintw(j, 0, "%d_", (LINES - 3 - j) * scale); /* show them */ for (i = 0; i < n; ++i) { for (j = 0; j < bm[i] / scale; ++j) (void)mvaddch(LINES - 3 - j, i, '#'); for (; j < (bm[i] + bh[i]) / scale; ++j) (void)mvaddch(LINES - 3 - j, i, '|'); } refresh(); }
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_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); }
static int cnt_error(struct sess *sp) { struct http *h; char date[40]; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); if (wrk->obj == NULL) { HSH_Prealloc(sp); AZ(wrk->busyobj); wrk->busyobj = VBO_GetBusyObj(wrk); wrk->obj = STV_NewObject(wrk, NULL, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); if (wrk->obj == NULL) wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); if (wrk->obj == NULL) { sp->doclose = "Out of objects"; sp->director = NULL; http_Setup(wrk->busyobj->beresp, NULL); http_Setup(wrk->busyobj->bereq, NULL); sp->step = STP_DONE; return(0); } AN(wrk->obj); wrk->obj->xid = sp->xid; wrk->obj->exp.entered = sp->t_req; } else { CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); /* XXX: Null the headers ? */ } CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC); h = wrk->obj->http; if (sp->err_code < 100 || sp->err_code > 999) sp->err_code = 501; http_PutProtocol(wrk, sp->vsl_id, h, "HTTP/1.1"); http_PutStatus(h, sp->err_code); VTIM_format(W_TIM_real(wrk), date); http_PrintfHeader(wrk, sp->vsl_id, h, "Date: %s", date); http_SetHeader(wrk, sp->vsl_id, h, "Server: Varnish"); if (sp->err_reason != NULL) http_PutResponse(wrk, sp->vsl_id, h, sp->err_reason); else http_PutResponse(wrk, sp->vsl_id, h, http_StatusMessage(sp->err_code)); VCL_error_method(sp); if (sp->handling == VCL_RET_RESTART && sp->restarts < cache_param->max_restarts) { HSH_Drop(wrk); VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->director = NULL; sp->restarts++; sp->step = STP_RECV; return (0); } else if (sp->handling == VCL_RET_RESTART) sp->handling = VCL_RET_DELIVER; /* We always close when we take this path */ sp->doclose = "error"; sp->wantbody = 1; assert(sp->handling == VCL_RET_DELIVER); sp->err_code = 0; sp->err_reason = NULL; http_Setup(wrk->busyobj->bereq, NULL); VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->step = STP_PREPRESP; return (0); }
static int 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); AZ(req->busyobj); bo = VBO_GetBusyObj(wrk, req); req->busyobj = bo; AZ(bo->stats); bo->stats = &wrk->stats; req->objcore = HSH_NewObjCore(wrk); req->obj = STV_NewObject(bo, &req->objcore, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); bo->stats = NULL; if (req->obj == NULL) { req->doclose = SC_OVERLOAD; req->director = NULL; http_Teardown(bo->beresp); http_Teardown(bo->bereq); return(1); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); 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"); if (req->err_reason != NULL) http_PutResponse(h, req->err_reason); else http_PutResponse(h, http_StatusMessage(req->err_code)); VCL_error_method(req); if (req->handling == VCL_RET_RESTART && req->restarts < cache_param->max_restarts) { HSH_Drop(wrk, &req->obj); VBO_DerefBusyObj(wrk, &req->busyobj); req->req_step = R_STP_RESTART; return (0); } else if (req->handling == VCL_RET_RESTART) req->handling = VCL_RET_DELIVER; /* We always close when we take this path */ req->doclose = SC_TX_ERROR; req->wantbody = 1; assert(req->handling == VCL_RET_DELIVER); req->err_code = 0; req->err_reason = NULL; http_Teardown(bo->bereq); VBO_DerefBusyObj(wrk, &req->busyobj); req->req_step = R_STP_PREPRESP; return (0); }
int main(int argc, char **argv) { time_t t; struct tm tm; double tt; char buf[BUFSIZ]; char buf1[BUFSIZ]; AZ(setenv("TZ", "UTC", 1)); assert(sizeof t >= 8); /* Brute force test against libc version */ for (t = -2209852800; t < 20000000000; t += 3599) { gmtime_r(&t, &tm); strftime(buf1, sizeof buf1, "%a, %d %b %Y %T GMT", &tm); VTIM_format(t, buf); if (strcmp(buf, buf1)) { printf("libc: <%s> Vtim <%s> %jd\n", buf1, buf, (intmax_t)t); exit(2); } tt = VTIM_parse(buf1); if (tt != t) { VTIM_format(tt, buf); printf(" fm: %12jd <%s>\n", (intmax_t)t, buf1); printf(" to: %12.0f <%s>\n", tt, buf); exit(2); } strftime(buf1, sizeof buf1, "%a %b %e %T %Y", &tm); tt = VTIM_parse(buf1); if (tt != t) { VTIM_format(tt, buf); printf(" fm: %12jd <%s>\n", (intmax_t)t, buf1); printf(" to: %12.0f <%s>\n", tt, buf); exit(2); } strftime(buf1, sizeof buf1, "%Y-%m-%dT%T", &tm); tt = VTIM_parse(buf1); if (tt != t) { VTIM_format(tt, buf); printf(" fm: %12jd <%s>\n", (intmax_t)t, buf1); printf(" to: %12.0f <%s>\n", tt, buf); exit(2); } if (tm.tm_year >= 69 && tm.tm_year < 169) { strftime(buf1, sizeof buf1, "%A, %d-%b-%y %T GMT", &tm); tt = VTIM_parse(buf1); if (tt != t) { VTIM_format(tt, buf); printf(" fm: %12jd <%s>\n", (intmax_t)t, buf1); printf(" to: %12.0f <%s>\n", tt, buf); exit(2); } } } /* Examples from RFC2616 section 3.3.1 */ tst("Sun, 06 Nov 1994 08:49:37 GMT", 784111777); tst("Sunday, 06-Nov-94 08:49:37 GMT", 784111777); tst("Sun Nov 6 08:49:37 1994", 784111777); tst("1994-11-06T08:49:37", 784111777); tst_delta(); return (0); }
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); }
static enum req_fsm_nxt cnt_synth(struct worker *wrk, struct req *req) { char date[40]; struct http *h; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); req->acct_req.synth++; HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod); h = req->resp; req->t_resp = VTIM_real(); if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; http_ClrHeader(h); http_PutProtocol(h, "HTTP/1.1"); http_PutStatus(h, req->err_code); VTIM_format(req->t_resp, date); http_PrintfHeader(h, "Date: %s", date); http_SetHeader(h, "Server: Varnish"); http_PrintfHeader(req->resp, "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK); if (req->err_reason != NULL) http_PutResponse(h, req->err_reason); else http_PutResponse(h, http_StatusMessage(req->err_code)); AZ(req->synth_body); req->synth_body = VSB_new_auto(); AN(req->synth_body); VCL_synth_method(req->vcl, wrk, req, NULL, req->http->ws); http_Unset(h, H_Content_Length); AZ(VSB_finish(req->synth_body)); if (wrk->handling == VCL_RET_RESTART) { http_ClrHeader(h); VSB_delete(req->synth_body); req->synth_body = NULL; req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); if (http_HdrIs(req->resp, H_Connection, "close")) req->doclose = SC_RESP_CLOSE; V1D_Deliver_Synth(req); VSB_delete(req->synth_body); req->synth_body = NULL; req->err_code = 0; req->err_reason = NULL; return (REQ_FSM_DONE); }
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_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); }